mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
perf: forEach/map 支持 ArrayLike,新增 array_ptr_len3! 宏
This commit is contained in:
@@ -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<H: VmHost>(vm: &mut H, msg: &str) -> JsValue {
|
fn array_type_error<H: VmHost>(vm: &mut H, msg: &str) -> JsValue {
|
||||||
crate::error::create_type_error(vm, msg)
|
crate::error::create_type_error(vm, msg)
|
||||||
}
|
}
|
||||||
@@ -554,31 +568,21 @@ pub fn array_flat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
|
|
||||||
pub fn array_for_each<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn array_for_each<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
builtins_debug!("Array.prototype.forEach called with {} args", args.len());
|
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 {
|
if args.len() < 2 {
|
||||||
builtins_error!("Array.prototype.forEach: invalid receiver");
|
|
||||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||||
}
|
}
|
||||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||||
Ok(callback) => callback,
|
Ok(callback) => callback,
|
||||||
Err(err) => {
|
Err(err) => return NativeResult::Err(err),
|
||||||
builtins_error!("Array.prototype.forEach: invalid receiver");
|
|
||||||
return NativeResult::Err(err);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||||
for i in 0..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])]) {
|
match invoke_native_callback(vm, callback_val, this_val, &[elem, JsValue::int(i as i32), vm.reg(args[0])]) {
|
||||||
NativeResult::Ok(_) => {}
|
NativeResult::Ok(_) => {}
|
||||||
NativeResult::Err(err) => {
|
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||||
builtins_error!("Array.prototype.forEach: invalid receiver");
|
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||||
return NativeResult::Err(err);
|
|
||||||
}
|
|
||||||
NativeResult::TailCall { .. } => {
|
|
||||||
builtins_error!("Array.prototype.forEach: invalid receiver");
|
|
||||||
return unexpected_tail_call_error(vm);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NativeResult::Ok(JsValue::undefined())
|
NativeResult::Ok(JsValue::undefined())
|
||||||
@@ -586,45 +590,31 @@ pub fn array_for_each<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
|
|
||||||
pub fn array_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn array_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
builtins_debug!("Array.prototype.map called with {} args", args.len());
|
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 {
|
if args.len() < 2 {
|
||||||
builtins_error!("Array.prototype.map: invalid receiver");
|
|
||||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||||
}
|
}
|
||||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||||
Ok(callback) => callback,
|
Ok(callback) => callback,
|
||||||
Err(err) => {
|
Err(err) => return NativeResult::Err(err),
|
||||||
builtins_error!("Array.prototype.map: invalid receiver");
|
|
||||||
return NativeResult::Err(err);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||||
let new_arr = create_new_array(vm, n);
|
let new_arr = create_new_array(vm, n);
|
||||||
for i in 0..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])]) {
|
match invoke_native_callback(vm, callback_val, this_val, &[elem, JsValue::int(i as i32), vm.reg(args[0])]) {
|
||||||
NativeResult::Ok(mapped) => unsafe {
|
NativeResult::Ok(mapped) => unsafe { (*new_arr).set_prop_at(i, mapped); },
|
||||||
(*new_arr).set_prop_at(i, mapped);
|
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||||
},
|
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe { (*new_arr).set_prop_count(n); }
|
||||||
(*new_arr).set_prop_count(n);
|
|
||||||
}
|
|
||||||
NativeResult::Ok(JsValue::from_js_object(new_arr))
|
NativeResult::Ok(JsValue::from_js_object(new_arr))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn array_filter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn array_filter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
builtins_debug!("Array.prototype.filter called with {} args", args.len());
|
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 {
|
if args.len() < 2 {
|
||||||
builtins_error!("Array.prototype.filter: invalid receiver");
|
builtins_error!("Array.prototype.filter: invalid receiver");
|
||||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||||
@@ -639,21 +629,13 @@ pub fn array_filter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||||
let mut kept: Vec<JsValue> = Vec::new();
|
let mut kept: Vec<JsValue> = Vec::new();
|
||||||
for i in 0..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])]) {
|
match invoke_native_callback(vm, callback_val, this_val, &[elem, JsValue::int(i as i32), vm.reg(args[0])]) {
|
||||||
NativeResult::Ok(result_val) => {
|
NativeResult::Ok(result_val) => {
|
||||||
if oxide_runtime_api::to_boolean(result_val) {
|
if oxide_runtime_api::to_boolean(result_val) { kept.push(elem); }
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||||
|
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let new_arr = create_new_array(vm, kept.len());
|
let new_arr = create_new_array(vm, kept.len());
|
||||||
|
|||||||
Reference in New Issue
Block a user