From 45ecf8142eb9e59d568cbe23c5ff2a37f6881887 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Sun, 28 Jun 2026 18:35:02 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20forEach/map=20=E6=94=AF=E6=8C=81=20Arra?= =?UTF-8?q?yLike=EF=BC=8C=E6=96=B0=E5=A2=9E=20array=5Fptr=5Flen3!=20?= =?UTF-8?q?=E5=AE=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_builtins/src/array.rs | 80 ++++++++++++------------------ 1 file changed, 31 insertions(+), 49 deletions(-) diff --git a/crates/oxide_builtins/src/array.rs b/crates/oxide_builtins/src/array.rs index ea8d6f1c..651ac046 100644 --- a/crates/oxide_builtins/src/array.rs +++ b/crates/oxide_builtins/src/array.rs @@ -33,6 +33,20 @@ macro_rules! array_ptr_len { }}; } +macro_rules! array_ptr_len3 { + ($vm:expr, $args:expr) => {{ + let this_val = $vm.reg($args[0]); + let (arr_ptr, len, is_arr) = match get_this_arraylike($vm, this_val) { + Ok(v) => v, + Err(err) => { + builtins_error!("Array method: invalid receiver"); + return NativeResult::Err(err); + } + }; + (arr_ptr, len, is_arr) + }}; +} + fn array_type_error(vm: &mut H, msg: &str) -> JsValue { crate::error::create_type_error(vm, msg) } @@ -554,31 +568,21 @@ pub fn array_flat(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_for_each(vm: &mut H, args: &[u8]) -> NativeResult { builtins_debug!("Array.prototype.forEach called with {} args", args.len()); - let (arr_ptr, n) = array_ptr_len!(vm, args); + let (arr_ptr, n, is_array) = array_ptr_len3!(vm, args); if args.len() < 2 { - builtins_error!("Array.prototype.forEach: invalid receiver"); return NativeResult::Err(array_type_error(vm, "callback is not a function")); } let callback_val = match require_callback(vm, vm.reg(args[1])) { Ok(callback) => callback, - Err(err) => { - builtins_error!("Array.prototype.forEach: invalid receiver"); - return NativeResult::Err(err); - } + Err(err) => return NativeResult::Err(err), }; let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() }; for i in 0..n { - let elem = unsafe { (*arr_ptr).get_prop_at(i) }; + let elem = arraylike_get(vm, arr_ptr, is_array, i); match invoke_native_callback(vm, callback_val, this_val, &[elem, JsValue::int(i as i32), vm.reg(args[0])]) { NativeResult::Ok(_) => {} - NativeResult::Err(err) => { - builtins_error!("Array.prototype.forEach: invalid receiver"); - return NativeResult::Err(err); - } - NativeResult::TailCall { .. } => { - builtins_error!("Array.prototype.forEach: invalid receiver"); - return unexpected_tail_call_error(vm); - } + NativeResult::Err(err) => return NativeResult::Err(err), + NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm), } } NativeResult::Ok(JsValue::undefined()) @@ -586,45 +590,31 @@ pub fn array_for_each(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_map(vm: &mut H, args: &[u8]) -> NativeResult { builtins_debug!("Array.prototype.map called with {} args", args.len()); - let (arr_ptr, n) = array_ptr_len!(vm, args); + let (arr_ptr, n, is_array) = array_ptr_len3!(vm, args); if args.len() < 2 { - builtins_error!("Array.prototype.map: invalid receiver"); return NativeResult::Err(array_type_error(vm, "callback is not a function")); } let callback_val = match require_callback(vm, vm.reg(args[1])) { Ok(callback) => callback, - Err(err) => { - builtins_error!("Array.prototype.map: invalid receiver"); - return NativeResult::Err(err); - } + Err(err) => return NativeResult::Err(err), }; let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() }; let new_arr = create_new_array(vm, n); for i in 0..n { - let elem = unsafe { (*arr_ptr).get_prop_at(i) }; + let elem = arraylike_get(vm, arr_ptr, is_array, i); match invoke_native_callback(vm, callback_val, this_val, &[elem, JsValue::int(i as i32), vm.reg(args[0])]) { - NativeResult::Ok(mapped) => unsafe { - (*new_arr).set_prop_at(i, mapped); - }, - NativeResult::Err(err) => { - builtins_error!("Array.prototype.map: invalid receiver"); - return NativeResult::Err(err); - } - NativeResult::TailCall { .. } => { - builtins_error!("Array.prototype.map: invalid receiver"); - return unexpected_tail_call_error(vm); - } + NativeResult::Ok(mapped) => unsafe { (*new_arr).set_prop_at(i, mapped); }, + NativeResult::Err(err) => return NativeResult::Err(err), + NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm), } } - unsafe { - (*new_arr).set_prop_count(n); - } + unsafe { (*new_arr).set_prop_count(n); } NativeResult::Ok(JsValue::from_js_object(new_arr)) } pub fn array_filter(vm: &mut H, args: &[u8]) -> NativeResult { builtins_debug!("Array.prototype.filter called with {} args", args.len()); - let (arr_ptr, n) = array_ptr_len!(vm, args); + let (arr_ptr, n, is_array) = array_ptr_len3!(vm, args); if args.len() < 2 { builtins_error!("Array.prototype.filter: invalid receiver"); return NativeResult::Err(array_type_error(vm, "callback is not a function")); @@ -639,21 +629,13 @@ pub fn array_filter(vm: &mut H, args: &[u8]) -> NativeResult { let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() }; let mut kept: Vec = Vec::new(); for i in 0..n { - let elem = unsafe { (*arr_ptr).get_prop_at(i) }; + let elem = arraylike_get(vm, arr_ptr, is_array, i); match invoke_native_callback(vm, callback_val, this_val, &[elem, JsValue::int(i as i32), vm.reg(args[0])]) { NativeResult::Ok(result_val) => { - if oxide_runtime_api::to_boolean(result_val) { - kept.push(elem); - } - } - NativeResult::Err(err) => { - builtins_error!("Array.prototype.filter: invalid receiver"); - return NativeResult::Err(err); - } - NativeResult::TailCall { .. } => { - builtins_error!("Array.prototype.filter: invalid receiver"); - return unexpected_tail_call_error(vm); + if oxide_runtime_api::to_boolean(result_val) { kept.push(elem); } } + NativeResult::Err(err) => return NativeResult::Err(err), + NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm), } } let new_arr = create_new_array(vm, kept.len());