perf: 消除热路径冗余检查
This commit is contained in:
@@ -228,13 +228,11 @@ pub fn array_is_array<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
pub fn array_push<H: VmHost>(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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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::<JsObject>() != 0 {
|
||||
self.raise_type_error(error_msg)?;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user