perf: new_string_owned 零拷贝路径替代 new_string 二次克隆(B2)
This commit is contained in:
@@ -211,7 +211,7 @@ pub fn date_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
} else {
|
||||
"Invalid Date".to_string()
|
||||
};
|
||||
return NativeResult::Ok(vm.new_string(&s));
|
||||
return NativeResult::Ok(vm.new_string_owned(s));
|
||||
}
|
||||
|
||||
let mut obj = JsObject::new_empty(
|
||||
@@ -866,7 +866,7 @@ fn date_to_string_inner<H: VmHost>(vm: &mut H, args: &[u8], format_str: &str, in
|
||||
Some(dt) => dt.format(format_str).to_string(),
|
||||
None => invalid.to_string(),
|
||||
};
|
||||
NativeResult::Ok(vm.new_string(&s))
|
||||
NativeResult::Ok(vm.new_string_owned(s))
|
||||
}
|
||||
|
||||
/// `Date.prototype.toISOString()`:输出 ISO 8601 格式(`YYYY-MM-DDTHH:MM:SS.mmmZ`)。
|
||||
@@ -885,7 +885,7 @@ pub fn date_to_json<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
Some(dt) => dt.format("%Y-%m-%dT%H:%M:%S%.3fZ").to_string(),
|
||||
None => return NativeResult::Ok(JsValue::null()),
|
||||
};
|
||||
NativeResult::Ok(vm.new_string(&s))
|
||||
NativeResult::Ok(vm.new_string_owned(s))
|
||||
}
|
||||
|
||||
/// `Date.prototype.toString()`:本地时间完整字符串(如 `Wed Aug 05 2026 12:00:00 GMT+0000`)。
|
||||
|
||||
@@ -274,5 +274,5 @@ pub fn function_to_string<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
} else {
|
||||
format!("function {name}() {{ {body} }}")
|
||||
};
|
||||
NativeResult::Ok(vm.new_string(&result))
|
||||
NativeResult::Ok(vm.new_string_owned(result))
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ pub fn json_stringify<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
{
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "Converting circular structure to JSON"));
|
||||
};
|
||||
NativeResult::Ok(vm.new_string(&output))
|
||||
NativeResult::Ok(vm.new_string_owned(output))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
||||
@@ -213,7 +213,7 @@ pub fn number_to_string<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
if neg {
|
||||
result.insert(0, '-');
|
||||
}
|
||||
NativeResult::Ok(vm.new_string(&result))
|
||||
NativeResult::Ok(vm.new_string_owned(result))
|
||||
}
|
||||
|
||||
/// `Number.prototype.toFixed(digits)`:固定小数位数(0..100)输出字符串,
|
||||
@@ -330,7 +330,7 @@ pub fn number_to_exponential<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
}
|
||||
}
|
||||
let result = format!("{}{}", sign_prefix, s);
|
||||
return NativeResult::Ok(vm.new_string(&result));
|
||||
return NativeResult::Ok(vm.new_string_owned(result));
|
||||
}
|
||||
let raw = oxide_runtime_api::to_integer_or_infinity(vm.reg(args[1]));
|
||||
if !(0.0..=100.0).contains(&raw) {
|
||||
|
||||
@@ -275,7 +275,7 @@ pub fn regexp_to_string<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
vm.lookup_str(val).unwrap_or_default()
|
||||
};
|
||||
let result = format!("/{}/{}", source, flags);
|
||||
NativeResult::Ok(vm.new_string(&result))
|
||||
NativeResult::Ok(vm.new_string_owned(result))
|
||||
}
|
||||
|
||||
// RegExp 对象 hash 槽中属性的固定下标(构造顺序:lastIndex/source/flags/global/...)。
|
||||
|
||||
@@ -51,7 +51,7 @@ pub fn string_from_char_code<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
out.push('\u{FFFD}');
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(vm.new_string(&out))
|
||||
NativeResult::Ok(vm.new_string_owned(out))
|
||||
}
|
||||
|
||||
/// `String.fromCodePoint(...codes)`:把各参数按 ToNumber 语义转成 code point
|
||||
@@ -84,7 +84,7 @@ pub fn string_from_code_point<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResul
|
||||
out.push(char::from_u32(code).unwrap());
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(vm.new_string(&out))
|
||||
NativeResult::Ok(vm.new_string_owned(out))
|
||||
}
|
||||
|
||||
/// `String.prototype.valueOf`:返回包装对象的原始字符串;其它 this 抛 TypeError。
|
||||
@@ -127,7 +127,7 @@ pub fn string_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let str_val = vm.new_string(&s);
|
||||
let str_val = vm.new_string_owned(s);
|
||||
|
||||
let string_proto = vm.session().builtin_world().string_proto.as_ptr() as *mut JsObject;
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
@@ -309,7 +309,7 @@ pub(crate) fn regex_replace_fn<H: VmHost>(
|
||||
last_end = range.end;
|
||||
}
|
||||
out.push_str(&text[last_end..]);
|
||||
NativeResult::Ok(vm.new_string(&out))
|
||||
NativeResult::Ok(vm.new_string_owned(out))
|
||||
}
|
||||
|
||||
/// 字符串模式 + 函数 replacer:all 全替换否则替换首个。回调参数
|
||||
@@ -351,7 +351,7 @@ fn string_replace_fn<H: VmHost>(vm: &mut H, text: &str, pattern: &str, replacer:
|
||||
last_end = p + search_length;
|
||||
}
|
||||
out.push_str(&text[last_end..]);
|
||||
NativeResult::Ok(vm.new_string(&out))
|
||||
NativeResult::Ok(vm.new_string_owned(out))
|
||||
}
|
||||
|
||||
fn char_len(s: &str) -> usize {
|
||||
@@ -507,7 +507,7 @@ pub fn string_concat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(vm.new_string(&result))
|
||||
NativeResult::Ok(vm.new_string_owned(result))
|
||||
}
|
||||
|
||||
/// `String.prototype.slice(start, end)`:按字符区间(支持负索引)取子串。
|
||||
@@ -594,7 +594,7 @@ pub fn string_substr<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
len as usize - start
|
||||
};
|
||||
let result = take_chars(&s[byte_index_at_char(&s, start)..], length.min(len as usize - start));
|
||||
NativeResult::Ok(vm.new_string(&result))
|
||||
NativeResult::Ok(vm.new_string_owned(result))
|
||||
}
|
||||
|
||||
/// `String.prototype.at(index)`:按字符索引取字符(支持负索引);越界返回 undefined。
|
||||
@@ -658,14 +658,14 @@ pub fn string_last_index_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
pub fn string_to_upper_case<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.toUpperCase called with {} args", args.len());
|
||||
let s = try_string!(this_string(vm, args));
|
||||
NativeResult::Ok(vm.new_string(&s.to_uppercase()))
|
||||
NativeResult::Ok(vm.new_string_owned(s.to_uppercase()))
|
||||
}
|
||||
|
||||
/// `String.prototype.toLowerCase`:全小写转换。
|
||||
pub fn string_to_lower_case<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.toLowerCase called with {} args", args.len());
|
||||
let s = try_string!(this_string(vm, args));
|
||||
NativeResult::Ok(vm.new_string(&s.to_lowercase()))
|
||||
NativeResult::Ok(vm.new_string_owned(s.to_lowercase()))
|
||||
}
|
||||
|
||||
/// `String.prototype.trim`:去除两端空白。
|
||||
@@ -684,7 +684,7 @@ pub fn string_repeat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
} else {
|
||||
1
|
||||
};
|
||||
NativeResult::Ok(vm.new_string(&s.repeat(n)))
|
||||
NativeResult::Ok(vm.new_string_owned(s.repeat(n)))
|
||||
}
|
||||
|
||||
/// `String.prototype.padStart(targetLength, padString)`:在头部补足 padString 到目标长度。
|
||||
@@ -703,14 +703,14 @@ pub fn string_pad_start<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
let pad = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { " ".to_string() };
|
||||
if s_len >= target || pad.is_empty() {
|
||||
return NativeResult::Ok(vm.new_string(&s));
|
||||
return NativeResult::Ok(vm.new_string_owned(s));
|
||||
}
|
||||
let needed = target - s_len;
|
||||
let pad_len = char_len(&pad).max(1);
|
||||
let reps = needed.div_ceil(pad_len);
|
||||
let mut out = take_chars(&pad.repeat(reps), needed);
|
||||
out.push_str(&s);
|
||||
NativeResult::Ok(vm.new_string(&out))
|
||||
NativeResult::Ok(vm.new_string_owned(out))
|
||||
}
|
||||
|
||||
/// `String.prototype.padEnd(targetLength, padString)`:在尾部补足 padString 到目标长度。
|
||||
@@ -729,14 +729,14 @@ pub fn string_pad_end<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
let pad = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { " ".to_string() };
|
||||
if s_len >= target || pad.is_empty() {
|
||||
return NativeResult::Ok(vm.new_string(&s));
|
||||
return NativeResult::Ok(vm.new_string_owned(s));
|
||||
}
|
||||
let needed = target - s_len;
|
||||
let pad_len = char_len(&pad).max(1);
|
||||
let reps = needed.div_ceil(pad_len);
|
||||
let mut out = s;
|
||||
out.push_str(&take_chars(&pad.repeat(reps), needed));
|
||||
NativeResult::Ok(vm.new_string(&out))
|
||||
NativeResult::Ok(vm.new_string_owned(out))
|
||||
}
|
||||
|
||||
/// `String.prototype.startsWith(searchString, position)`:是否以指定子串开头。
|
||||
@@ -846,7 +846,7 @@ pub fn string_replace<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.replace called with {} args", args.len());
|
||||
let s = try_string!(this_string(vm, args));
|
||||
if args.len() < 2 {
|
||||
return NativeResult::Ok(vm.new_string(&s));
|
||||
return NativeResult::Ok(vm.new_string_owned(s));
|
||||
}
|
||||
let pattern_val = vm.reg(args[1]);
|
||||
|
||||
@@ -870,7 +870,7 @@ pub fn string_replace<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let replacement = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { String::new() };
|
||||
// 手动展开 $ 引用(regress 的 replace 对 $n 展开为空)。
|
||||
let result = regex_replace_manual(regex, &s, &replacement, is_global);
|
||||
return NativeResult::Ok(vm.new_string(&result));
|
||||
return NativeResult::Ok(vm.new_string_owned(result));
|
||||
}
|
||||
// 无原生正则的类正则对象回退到字符串路径。
|
||||
}
|
||||
@@ -887,7 +887,7 @@ pub fn string_replace<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
let replacement = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { String::new() };
|
||||
let result = s.replacen(&pattern, &replacement, 1);
|
||||
NativeResult::Ok(vm.new_string(&result))
|
||||
NativeResult::Ok(vm.new_string_owned(result))
|
||||
}
|
||||
|
||||
/// `String.prototype.match(pattern)`:按 RegExp 匹配;global 返回全部匹配数组,
|
||||
@@ -1059,7 +1059,7 @@ pub fn string_to_well_formed<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
out.push(c);
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(vm.new_string(&out))
|
||||
NativeResult::Ok(vm.new_string_owned(out))
|
||||
}
|
||||
|
||||
/// `String.prototype.normalize(form)`:按 NFC/NFD/NFKC/NFKD 规范化为 Unicode 规范形式。
|
||||
@@ -1074,7 +1074,7 @@ pub fn string_normalize<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
"NFKD" => s.nfkd().collect(),
|
||||
_ => s.nfc().collect(),
|
||||
};
|
||||
NativeResult::Ok(vm.new_string(&result))
|
||||
NativeResult::Ok(vm.new_string_owned(result))
|
||||
}
|
||||
|
||||
pub(crate) const MALL_INPUT: &str = "__mal_input__";
|
||||
@@ -1234,7 +1234,7 @@ pub fn string_replace_all<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.replaceAll called with {} args", args.len());
|
||||
let s = try_string!(this_string(vm, args));
|
||||
if args.len() < 2 {
|
||||
return NativeResult::Ok(vm.new_string(&s));
|
||||
return NativeResult::Ok(vm.new_string_owned(s));
|
||||
}
|
||||
let pattern_val = vm.reg(args[1]);
|
||||
if is_regexp_obj(pattern_val, vm) {
|
||||
@@ -1242,7 +1242,7 @@ pub fn string_replace_all<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let re = unsafe { &*re_ptr };
|
||||
let fn_ptr = match re.native_fn() {
|
||||
Some(p) => p,
|
||||
None => return NativeResult::Ok(vm.new_string(&s)),
|
||||
None => return NativeResult::Ok(vm.new_string_owned(s)),
|
||||
};
|
||||
// SAFETY: fn_ptr 持有 regexp_constructor 存放的 `Box<regress::Regex>` 指针。
|
||||
let regex = unsafe { &*(fn_ptr.as_ptr() as *const regress::Regex) };
|
||||
@@ -1257,7 +1257,7 @@ pub fn string_replace_all<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
let replacement = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { String::new() };
|
||||
let result = regex_replace_manual(regex, &s, &replacement, true);
|
||||
return NativeResult::Ok(vm.new_string(&result));
|
||||
return NativeResult::Ok(vm.new_string_owned(result));
|
||||
}
|
||||
let pattern = as_string(vm, pattern_val);
|
||||
if args.len() > 2 {
|
||||
@@ -1271,5 +1271,5 @@ pub fn string_replace_all<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
let replacement = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { String::new() };
|
||||
let result = s.replace(&pattern, &replacement);
|
||||
NativeResult::Ok(vm.new_string(&result))
|
||||
NativeResult::Ok(vm.new_string_owned(result))
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ pub fn symbol_to_string<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let idx = sym.as_symbol_index();
|
||||
let desc = vm.symbol_description(idx).unwrap_or("").to_string();
|
||||
let result = format!("Symbol({})", desc);
|
||||
NativeResult::Ok(vm.new_string(&result))
|
||||
NativeResult::Ok(vm.new_string_owned(result))
|
||||
}
|
||||
|
||||
/// `Symbol.prototype.valueOf`:Symbol 原样返回;包装对象解盒返回其原始 Symbol。
|
||||
|
||||
@@ -1134,7 +1134,7 @@ fn instant_default_string<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid Instant"));
|
||||
};
|
||||
match format_instant_iso(epoch_ns, None, true, None) {
|
||||
Some(output) => NativeResult::Ok(vm.new_string(&output)),
|
||||
Some(output) => NativeResult::Ok(vm.new_string_owned(output)),
|
||||
None => NativeResult::Err(crate::error::create_range_error(vm, "invalid Instant")),
|
||||
}
|
||||
}
|
||||
@@ -1219,7 +1219,7 @@ pub fn instant_to_string<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "Instant outside supported range"));
|
||||
}
|
||||
match format_instant_iso(rounded_ns, offset_minutes, include_seconds, output_digits) {
|
||||
Some(output) => NativeResult::Ok(vm.new_string(&output)),
|
||||
Some(output) => NativeResult::Ok(vm.new_string_owned(output)),
|
||||
None => NativeResult::Err(crate::error::create_range_error(vm, "invalid Instant")),
|
||||
}
|
||||
}
|
||||
@@ -1890,7 +1890,7 @@ pub fn duration_to_string<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
output.push_str("0S");
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(vm.new_string(&output))
|
||||
NativeResult::Ok(vm.new_string_owned(output))
|
||||
}
|
||||
|
||||
/// `Temporal.Duration.prototype.valueOf()` 始终拒绝隐式数值转换。
|
||||
@@ -3514,7 +3514,7 @@ fn format_plain_date_time_iso(
|
||||
fn plain_date_time_iso_string<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let (year, month, day, total_ns) = native_try!(plain_date_time_parts(vm, args));
|
||||
let output = format_plain_date_time_iso(year, month, day, total_ns as i128, true, None, "never");
|
||||
NativeResult::Ok(vm.new_string(&output))
|
||||
NativeResult::Ok(vm.new_string_owned(output))
|
||||
}
|
||||
|
||||
/// `Temporal.PlainDateTime.prototype.toString(options)`:按精度、舍入模式与日历显示输出 ISO 8601。
|
||||
@@ -3601,7 +3601,7 @@ pub fn plain_date_time_to_string<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeRe
|
||||
output_digits,
|
||||
&calendar_name,
|
||||
);
|
||||
NativeResult::Ok(vm.new_string(&output))
|
||||
NativeResult::Ok(vm.new_string_owned(output))
|
||||
}
|
||||
|
||||
/// 按 duration-like 分量对 PlainDateTime 做加减:先平衡时间(溢出为天),
|
||||
|
||||
@@ -75,6 +75,8 @@ pub trait VmHost {
|
||||
// 对象分配 / 字符串创建
|
||||
fn alloc_object(&mut self, obj: JsObject) -> *mut JsObject;
|
||||
fn new_string(&mut self, s: &str) -> JsValue;
|
||||
/// move 接收 `String` 创建会话字符串,避免一次整串克隆。
|
||||
fn new_string_owned(&mut self, s: String) -> JsValue;
|
||||
/// 分配 BigInt 值(num_bigint::BigInt box 登记到 VM,返回携带指针的 `JsValue`)。
|
||||
fn new_bigint(&mut self, v: num_bigint::BigInt) -> JsValue;
|
||||
/// 读取 BigInt 值;调用方须保证 `val.is_bigint()`。
|
||||
|
||||
@@ -1805,6 +1805,9 @@ impl oxide_runtime_api::VmHost for Vm {
|
||||
fn new_string(&mut self, s: &str) -> JsValue {
|
||||
self.new_string(s)
|
||||
}
|
||||
fn new_string_owned(&mut self, s: String) -> JsValue {
|
||||
Vm::new_string_owned(self, s)
|
||||
}
|
||||
fn new_bigint(&mut self, v: num_bigint::BigInt) -> JsValue {
|
||||
Vm::new_bigint(self, v)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user