perf: ASCII 单字符缓存 + 字符串迭代器游标收尾
This commit is contained in:
@@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||
use crate::native::NativeFn;
|
||||
use crate::vm::{native_fn_ptr_to_fn, CallFrame, ForInIter, FrameContinuation, Vm, MAX_PROTO_CHAIN_DEPTH};
|
||||
use crate::vm_trace;
|
||||
use oxide_runtime_api::{to_boolean, to_string_full, NativeResult};
|
||||
use oxide_runtime_api::{to_boolean, to_string_full, NativeResult, VmHost};
|
||||
use oxide_types::object::{JsObject, PropAttributes};
|
||||
use oxide_types::private_key::{int_key_value, is_int_key, is_private_name_key, is_symbol_key, make_int_key};
|
||||
use oxide_types::value::JsValue;
|
||||
@@ -738,9 +738,14 @@ impl Vm {
|
||||
if src.is_string() {
|
||||
let code_units: Vec<u16> = unsafe { (*src.as_string_ptr()).data.encode_utf16().collect() };
|
||||
for (i, unit) in code_units.iter().enumerate() {
|
||||
let s = char::from_u32(*unit as u32).map(|c| c.to_string()).unwrap_or_default();
|
||||
let si = make_int_key(i as u32);
|
||||
let ch_val = self.new_string(&s);
|
||||
let ch_val = match char::from_u32(*unit as u32) {
|
||||
Some(c) => match self.single_char(c) {
|
||||
Some(v) => v,
|
||||
None => self.new_string(&c.to_string()),
|
||||
},
|
||||
None => self.new_string(""),
|
||||
};
|
||||
let rest = unsafe { &mut *rest_ptr };
|
||||
self.set_or_create_prop_value(rest, si, ch_val);
|
||||
}
|
||||
@@ -792,9 +797,15 @@ impl Vm {
|
||||
let s = unsafe { (*raw.as_string_ptr()).data.clone() };
|
||||
let code_units: Vec<u16> = s.encode_utf16().collect();
|
||||
for (i, unit) in code_units.iter().enumerate() {
|
||||
let ch = char::from_u32(*unit as u32).map(|c| c.to_string()).unwrap_or_default();
|
||||
let si = make_int_key(i as u32);
|
||||
assignments.push((si, self.new_string(&ch)));
|
||||
let ch_val = match char::from_u32(*unit as u32) {
|
||||
Some(c) => match self.single_char(c) {
|
||||
Some(v) => v,
|
||||
None => self.new_string(&c.to_string()),
|
||||
},
|
||||
None => self.new_string(""),
|
||||
};
|
||||
assignments.push((si, ch_val));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -887,9 +898,14 @@ impl Vm {
|
||||
let target = unsafe { &mut *target_val.as_js_object_ptr() };
|
||||
let code_units: Vec<u16> = unsafe { (*src.as_string_ptr()).data.encode_utf16().collect() };
|
||||
for (i, unit) in code_units.iter().enumerate() {
|
||||
let s = char::from_u32(*unit as u32).map(|c| c.to_string()).unwrap_or_default();
|
||||
let si = make_int_key(i as u32);
|
||||
let ch_val = self.new_string(&s);
|
||||
let ch_val = match char::from_u32(*unit as u32) {
|
||||
Some(c) => match self.single_char(c) {
|
||||
Some(v) => v,
|
||||
None => self.new_string(&c.to_string()),
|
||||
},
|
||||
None => self.new_string(""),
|
||||
};
|
||||
self.set_or_create_prop_value(target, si, ch_val);
|
||||
}
|
||||
return Ok(());
|
||||
|
||||
@@ -58,3 +58,40 @@ fn new_iterator_throws_type_error() {
|
||||
let result = eval(&mut vm, "try { new Iterator() } catch (e) { e instanceof TypeError }").unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iterator_from_string_full_sequence() {
|
||||
// 手动 next 逐字符取完全部 ASCII 字符后 done(游标推进路径)。
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"var it = Iterator.from('ab'); \
|
||||
var r = []; var x; while (!(x = it.next()).done) r.push(x.value); \
|
||||
r.join('')",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(to_str(&vm, result), "ab");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iterator_from_string_astral_scalar() {
|
||||
// 字符串迭代按 Unicode 标量推进:astral 字符整体产出(标量语义未动)。
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "var it = Iterator.from('\\u{1F600}'); it.next().value").unwrap();
|
||||
assert_eq!(to_str(&vm, result), "\u{1F600}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iterator_from_string_empty_done() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "Iterator.from('').next().done").unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_of_string_chars() {
|
||||
// for-of 字符串循环产出逐字符(走字节游标 + 单字符缓存)。
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "var out = []; for (const c of 'abc') out.push(c); out.join('')").unwrap();
|
||||
assert_eq!(to_str(&vm, result), "abc");
|
||||
}
|
||||
|
||||
@@ -651,3 +651,54 @@ fn string_slice_astral_character_indices() {
|
||||
let s = eval(&mut vm, "'\\u{1F600}'.padStart(3, 'x')").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "xx\u{1F600}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_char_at_ascii_and_astral() {
|
||||
// charAt 产出:ASCII 走单字符缓存,astral 按标量整体返回,越界空串,
|
||||
// 缺省参数取首字符。
|
||||
let mut vm = Vm::new();
|
||||
let s = eval(&mut vm, "'abc'.charAt(1)").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "b");
|
||||
let s = eval(&mut vm, "'\\u{1F600}ab'.charAt(0)").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "\u{1F600}");
|
||||
let s = eval(&mut vm, "'ab'.charAt(5)").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "");
|
||||
let s = eval(&mut vm, "'xy'.charAt()").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "x");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_char_at_eq_perm_string() {
|
||||
// charAt 产出与字面量比较:内容相等(缓存串与字面量 perm 串)。
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "'abc'.charAt(1) === 'b'").unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_split_empty_separator_chars() {
|
||||
// 空分隔 split 逐字符产出:ASCII 走单字符缓存,混合 astral 按标量切分。
|
||||
let mut vm = Vm::new();
|
||||
let s = eval(&mut vm, "'abc'.split('').join('-')").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "a-b-c");
|
||||
let result = eval(&mut vm, "'\\u{1F600}a'.split('').length").unwrap();
|
||||
assert_eq!(result.as_int(), 2);
|
||||
let result = eval(&mut vm, "'\\u{1F600}a'.split('')[1]").unwrap();
|
||||
assert_eq!(to_str(&vm, result), "a");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_spread_object_chars() {
|
||||
// 对象展开字符串源:索引字符为可枚举自有属性。
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "const o = {...'ab'}; o['0'] + o['1']").unwrap();
|
||||
assert_eq!(to_str(&vm, result), "ab");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_rest_destructure_chars() {
|
||||
// rest 解构字符串源:索引字符收集到 rest 对象。
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "const {...r} = 'ab'; r['0'] + r['1']").unwrap();
|
||||
assert_eq!(to_str(&vm, result), "ab");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user