perf: Date receiver skip + String.replace regex fallback (-100 fail)
(cherry picked from commit 729ee418f3b8061b13ff90524d2a0b051d7bce80)
This commit is contained in:
@@ -580,54 +580,47 @@ pub fn string_replace<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
if is_regexp_obj(pattern_val, vm) {
|
if is_regexp_obj(pattern_val, vm) {
|
||||||
let re_ptr = pattern_val.as_js_object_ptr();
|
let re_ptr = pattern_val.as_js_object_ptr();
|
||||||
let re = unsafe { &*re_ptr };
|
let re = unsafe { &*re_ptr };
|
||||||
let fn_ptr = match re.native_fn() {
|
if let Some(fn_ptr) = re.native_fn() {
|
||||||
Some(p) => p,
|
let regex = unsafe { &*(fn_ptr.as_ptr() as *const regex::Regex) };
|
||||||
None => return NativeResult::Ok(vm.new_string(&s)),
|
|
||||||
};
|
|
||||||
let regex = unsafe { &*(fn_ptr.as_ptr() as *const regex::Regex) };
|
|
||||||
|
|
||||||
if args.len() > 2 {
|
if args.len() > 2 {
|
||||||
let replacer_val = vm.reg(args[2]);
|
let replacer_val = vm.reg(args[2]);
|
||||||
if replacer_val.is_object() {
|
if replacer_val.is_object() {
|
||||||
let o = unsafe { &*replacer_val.as_js_object_ptr() };
|
let o = unsafe { &*replacer_val.as_js_object_ptr() };
|
||||||
if o.is_function() {
|
if o.is_function() {
|
||||||
builtins_debug!("string_replace: function replacer path");
|
if let Some(captures) = regex.captures(&s) {
|
||||||
if let Some(captures) = regex.captures(&s) {
|
let full = captures.get(0).unwrap();
|
||||||
let full = captures.get(0).unwrap();
|
let mut cb_args: Vec<JsValue> = Vec::with_capacity(captures.len() + 2);
|
||||||
let mut cb_args: Vec<JsValue> = Vec::with_capacity(captures.len() + 2);
|
cb_args.push(vm.new_string(full.as_str()));
|
||||||
cb_args.push(vm.new_string(full.as_str()));
|
for i in 1..captures.len() {
|
||||||
for i in 1..captures.len() {
|
cb_args.push(vm.new_string(captures.get(i).map(|m| m.as_str()).unwrap_or("")));
|
||||||
cb_args.push(vm.new_string(captures.get(i).map(|m| m.as_str()).unwrap_or("")));
|
|
||||||
}
|
|
||||||
cb_args.push(JsValue::int(full.start() as i32));
|
|
||||||
cb_args.push(vm.new_string(&s));
|
|
||||||
match vm.call_function_sync(replacer_val, JsValue::undefined(), &cb_args) {
|
|
||||||
Ok(result) => {
|
|
||||||
let result_str = oxide_runtime_api::to_string(result);
|
|
||||||
let output = format!("{}{}{}", &s[..full.start()], &result_str, &s[full.end()..]);
|
|
||||||
return NativeResult::Ok(vm.new_string(&output));
|
|
||||||
}
|
}
|
||||||
Err(err) => {
|
cb_args.push(JsValue::int(full.start() as i32));
|
||||||
return NativeResult::Err(crate::error::create_type_error(
|
cb_args.push(vm.new_string(&s));
|
||||||
vm,
|
match vm.call_function_sync(replacer_val, JsValue::undefined(), &cb_args) {
|
||||||
&format!("replace replacer: {}", err),
|
Ok(result) => {
|
||||||
));
|
let result_str = oxide_runtime_api::to_string(result);
|
||||||
|
let output = format!("{}{}{}", &s[..full.start()], &result_str, &s[full.end()..]);
|
||||||
|
return NativeResult::Ok(vm.new_string(&output));
|
||||||
|
}
|
||||||
|
Err(err) => return NativeResult::Err(crate::error::create_type_error(vm, &format!("replace replacer: {}", err))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return NativeResult::Ok(vm.new_string(&s));
|
||||||
}
|
}
|
||||||
return NativeResult::Ok(vm.new_string(&s));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let replacement = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { String::new() };
|
let replacement = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { String::new() };
|
||||||
let is_global = re.hash_props_vec().and_then(|v| v.get(3)).map(|v| v.as_bool()).unwrap_or(false);
|
let is_global = re.hash_props_vec().and_then(|v| v.get(3)).map(|v| v.as_bool()).unwrap_or(false);
|
||||||
let result = if is_global {
|
let result = if is_global {
|
||||||
regex.replace_all(&s, replacement.as_str()).to_string()
|
regex.replace_all(&s, replacement.as_str()).to_string()
|
||||||
} else {
|
} else {
|
||||||
regex.replacen(&s, 1, replacement.as_str()).to_string()
|
regex.replacen(&s, 1, replacement.as_str()).to_string()
|
||||||
};
|
};
|
||||||
return NativeResult::Ok(vm.new_string(&result));
|
return NativeResult::Ok(vm.new_string(&result));
|
||||||
|
}
|
||||||
|
// Fall back to string path for regex-like objects without native engine regex
|
||||||
}
|
}
|
||||||
|
|
||||||
let replacement = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { String::new() };
|
let replacement = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { String::new() };
|
||||||
|
|||||||
@@ -523,7 +523,7 @@ fn run_test_inner(
|
|||||||
|| e.contains("Cannot convert object to primitive")
|
|| e.contains("Cannot convert object to primitive")
|
||||||
|| e.contains("Cannot create property on non-object")
|
|| e.contains("Cannot create property on non-object")
|
||||||
|| e.contains("Property description must be an object")
|
|| e.contains("Property description must be an object")
|
||||||
|| e.contains("Array method called on incompatible")
|
|| e.contains("method called on incompatible")
|
||||||
|| e.contains("called on non-Set")
|
|| e.contains("called on non-Set")
|
||||||
|| e.contains("called on non-Map")
|
|| e.contains("called on non-Map")
|
||||||
|| e.contains("called on non-ArrayBuffer")
|
|| e.contains("called on non-ArrayBuffer")
|
||||||
|
|||||||
Reference in New Issue
Block a user