From 7877aad75dc30c4b3d804eeab4ed540a36c1fb02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E7=89=B9=E6=AF=8F=E7=BE=8A=E9=98=9F?= Date: Tue, 30 Jun 2026 21:02:45 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=B6=88=E9=99=A4=E7=83=AD=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E5=86=97=E4=BD=99=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_builtins/src/array.rs | 6 ++---- crates/oxide_types/src/value.rs | 8 +++++++- crates/oxide_vm/src/dispatch/arithmetic.rs | 10 ++++++++-- crates/oxide_vm/src/vm.rs | 16 +++++++++++----- crates/oxide_vm/src/vm_dispatch_misc.rs | 1 + crates/oxide_vm/src/vm_props.rs | 4 ++-- 6 files changed, 31 insertions(+), 14 deletions(-) diff --git a/crates/oxide_builtins/src/array.rs b/crates/oxide_builtins/src/array.rs index df31acf..8ca688d 100644 --- a/crates/oxide_builtins/src/array.rs +++ b/crates/oxide_builtins/src/array.rs @@ -228,13 +228,11 @@ pub fn array_is_array(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_push(vm: &mut H, args: &[u8]) -> NativeResult { builtins_debug!("Array.prototype.push called with {} args", args.len()); let arr_ptr = array_ptr!(vm, args); - let mut len = unsafe { &*arr_ptr }.prop_count(); for &arg_reg in args.iter().skip(1) { let val = vm.promote_if_needed_for_write_ptr(arr_ptr, vm.reg(arg_reg)); - unsafe { &mut *arr_ptr }.set_prop_at(len, val); - len += 1; + unsafe { &mut *arr_ptr }.push_prop(val); } - unsafe { &mut *arr_ptr }.set_prop_count(len); + let len = unsafe { &*arr_ptr }.prop_count(); NativeResult::Ok(JsValue::int(len as i32)) } diff --git a/crates/oxide_types/src/value.rs b/crates/oxide_types/src/value.rs index 0410de7..9655ae8 100644 --- a/crates/oxide_types/src/value.rs +++ b/crates/oxide_types/src/value.rs @@ -23,7 +23,7 @@ const TAG_STRING: u64 = 5; const TAG_SYMBOL: u64 = 6; /// 48-bit pointer mask (x86-64 canonical VA) -const PTR_MASK: u64 = 0x0000_FFFF_FFFF_FFFF; +pub const PTR_MASK: u64 = 0x0000_FFFF_FFFF_FFFF; /// 32-bit integer payload mask const INT_MASK: u64 = 0x0000_0000_FFFF_FFFF; @@ -81,6 +81,12 @@ impl JsValue { Self(bits) } + /// Raw NaN-boxed bits. For checked pointer extraction after is_object(). + #[inline(always)] + pub fn to_bits(self) -> u64 { + self.0 + } + pub fn int(v: i32) -> Self { Self(make_tag(TAG_INT) | (v as u32 as u64)) } diff --git a/crates/oxide_vm/src/dispatch/arithmetic.rs b/crates/oxide_vm/src/dispatch/arithmetic.rs index 9f24940..6fc479f 100644 --- a/crates/oxide_vm/src/dispatch/arithmetic.rs +++ b/crates/oxide_vm/src/dispatch/arithmetic.rs @@ -7,8 +7,14 @@ impl Vm { #[inline(always)] pub(crate) fn dispatch_add(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> { vm_trace!("ADD rd={} r{}={:?} r{}={:?}", rd, a, self.regs[a], b, self.regs[b]); - let lhs = self.coerce_primitive_bounded(self.regs[a], false)?; - let rhs = self.coerce_primitive_bounded(self.regs[b], false)?; + let lv = self.regs[a]; + let rv = self.regs[b]; + if lv.is_int() && rv.is_int() { + self.regs[rd] = JsValue::float(lv.as_int() as f64 + rv.as_int() as f64); + return Ok(()); + } + let lhs = self.coerce_primitive_bounded(lv, false)?; + let rhs = self.coerce_primitive_bounded(rv, false)?; if lhs.is_string() || rhs.is_string() { let mut buf = std::mem::take(&mut self.string_buf); buf.clear(); diff --git a/crates/oxide_vm/src/vm.rs b/crates/oxide_vm/src/vm.rs index c328f70..72bdd35 100644 --- a/crates/oxide_vm/src/vm.rs +++ b/crates/oxide_vm/src/vm.rs @@ -17,7 +17,7 @@ use oxide_runtime_api::NativeResult; use oxide_types::error::{JsError, JsErrorKind}; use oxide_types::mem::{Epoch, P}; use oxide_types::object::{Cell, JsObject, NativeFnPtr, PropAttributes}; -use oxide_types::value::JsValue; +use oxide_types::value::{JsValue, PTR_MASK}; pub(crate) const MAX_PROTO_CHAIN_DEPTH: usize = 1024; @@ -77,9 +77,15 @@ macro_rules! throw_err { macro_rules! binary_arith { ($self:ident, $a:expr, $b:expr, $rd:expr, $op:tt) => {{ - let l = $self.coerce_number_bounded($self.regs[$a])?; - let r = $self.coerce_number_bounded($self.regs[$b])?; - $self.regs[$rd] = JsValue::float(l $op r); + let lv = $self.regs[$a]; + let rv = $self.regs[$b]; + if lv.is_int() && rv.is_int() { + $self.regs[$rd] = JsValue::float(lv.as_int() as f64 $op rv.as_int() as f64); + } else { + let l = $self.coerce_number_bounded(lv)?; + let r = $self.coerce_number_bounded(rv)?; + $self.regs[$rd] = JsValue::float(l $op r); + } }} } @@ -440,7 +446,7 @@ impl Vm { self.raise_type_error(error_msg)?; return Ok(None); } - let ptr = val.as_js_object_ptr(); + let ptr = (val.to_bits() & PTR_MASK) as *mut JsObject; let addr = ptr as usize; if ptr.is_null() || addr < 0x10000 || addr % std::mem::align_of::() != 0 { self.raise_type_error(error_msg)?; diff --git a/crates/oxide_vm/src/vm_dispatch_misc.rs b/crates/oxide_vm/src/vm_dispatch_misc.rs index dbaab0a..64b084c 100644 --- a/crates/oxide_vm/src/vm_dispatch_misc.rs +++ b/crates/oxide_vm/src/vm_dispatch_misc.rs @@ -583,6 +583,7 @@ impl Vm { { let val = src_obj.get_prop_at(pos); let rest = unsafe { &mut *rest_ptr }; + let val = self.promote_if_needed_for_write_ptr(rest_ptr, val); self.set_or_create_prop_value(rest, shape.property_name, val); } } diff --git a/crates/oxide_vm/src/vm_props.rs b/crates/oxide_vm/src/vm_props.rs index d052b71..1d249f6 100644 --- a/crates/oxide_vm/src/vm_props.rs +++ b/crates/oxide_vm/src/vm_props.rs @@ -120,9 +120,11 @@ impl Vm { pub(crate) fn ordinary_set( &mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue, ) -> Result<(), String> { + let val = self.promote_if_needed_for_write_ptr(obj as *mut JsObject, val); self.ordinary_set_inner(obj, prop_name_si, val, receiver, false) } + /// Dispatch-time entry: caller (dispatch_set_prop etc.) already promoted the value. pub(crate) fn ordinary_set_dispatch( &mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue, ) -> Result<(), String> { @@ -138,7 +140,6 @@ impl Vm { prop_name_si, use_frame_push ); - let val = self.promote_if_needed_for_write_ptr(obj as *mut JsObject, val); if let Some(pos) = self.get_own_property_slot(obj, prop_name_si) { if let Some(meta) = obj.prop_meta_at(pos) { if meta.is_accessor { @@ -260,7 +261,6 @@ impl Vm { pub(crate) fn set_or_create_prop_value(&mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue) { vm_trace!("set_or_create_prop_value: shape_id={} prop_name_si={}", obj.shape_id(), prop_name_si); - let val = self.promote_if_needed_for_write_ptr(obj as *mut JsObject, val); if let Some(pos) = self.kernel_core.shape_forge().lookup_position(obj.shape_id(), prop_name_si) { obj.set_prop_at(pos, val); } else {