mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
vm/kernel/emit/builtins: 动态源编码重设计 + 数值键 2^32 边界 + 单元域解码/Source 面——14 头独占 test262 回归 13 修 0 新增
全量 A/B 差分撞出 14 个头独占回归,本提交闭合 13(text-self.js 双树同败归 pre-existing):
数值键 u32 回绕(release 态,debug 为 panic 故单测未现):canonical_index_str/
units 的 v.checked_mul(10)? + d as u32 在乘积合法而和溢出 2^32 时静默回绕
(10 位数字串 "4294967296".."4294967299" 误判整数键 0..3,属性查找回
退、Object.keys 串键),改 checked_mul+checked_add 双段防溢出;str/units 各
钉一枚 2^30-1/2^30/2^32-1/2^32 边界(Group B 5 文件:defineProperty/
defineProperties 2^32 键族 + Array property-cast-number)。
decodeURI/decodeURIComponent 单元域重写(Group A 2 文件):decode_uri_units
按单元扫描(非 % 单元原样透传——孤立 surrogate 往返不再被 lossy 串值面
打碎),%XX 解单元入缓冲;string_arg_units 经 to_units_full 取单元。
动态源编码(eval/Function/$262.evalScript)重设计(Group A 6 文件 + value-u):
source_escape 旧设计把源码域反斜杠恒双写(与 marker 起始区分),但源码即
JS 程序、反斜杠恒为字面量内转义序列起始,双写改变程序语义——
/\u{1d306}/u 变 /\\u{1d306}/u,u 模式撞裸 { 直接 SyntaxError(value-u 回归
根因)。现反斜杠原样透传;孤立 surrogate/FFFD 单元仍以 \\uXXXX 转义文本
注入(Rust str 无法承载裸孤立 surrogate,转义文本是唯一注入形态);
source_escape_to_key 逆路径仅还原注入 marker(\\ud800..\\udfff/\\ufffd
小写转义文本 → FFFD+hex4 池键形态,物化 decode_key 还原原始单元,正则
.source 按原始源返回;用户转义文本 \\u0041/\\u{1d306} 等逐字透传),
\\+marker 拼接形态(数据反斜杠紧邻注入,S7.8.5_A1.4 族 cu=d800 断言)按
前瞻还原 [数据反斜杠, 单元]。source_encoded 标志经 Compiler→Emitter→CompileCtx
(嵌套继承)贯通,仅动态编译入口置位;静态源切片维持 pool_key_plain 不变。
RegExp [[Source]]/[[Flags]] 单元域(regexp 构造器):to_units_full →
new_string_units_owned 入键(旧 lossy to_string 把孤立 surrogate 单元打成
FFFD,src_match 探针 false);regress 编译仍 lossy(既有缺口,另行报告)。
三并钉:source_escape marker 形态 / 反斜杠透传 / decode_key∘to_key∘escape
闭环(含 \\+marker 相邻与 astral 对)。实测:Group A 8/8、Group B 5/5、
value-u 1/1;8178 文件回归子集(13 目录)双树 A/B 差分 HEAD-only=∅、
13 文件转双树同 pass;text-self.js 双树同 compile 败
(requested module export is not exported: default)归 pre-existing;
七 crate 单测 2879/1(唯一失败 compile_class_declaration_emits_constructor
为 HEAD~0 既有,本提交未引入)。
This commit is contained in:
@@ -9,7 +9,7 @@ use std::sync::Arc;
|
||||
|
||||
use oxide_kernel::kernel::{KernelCore, KernelSession};
|
||||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||||
use oxide_runtime_api::{to_string_full, NativeResult};
|
||||
use oxide_runtime_api::{to_units_full, NativeResult};
|
||||
use oxide_types::object::JsObject;
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
@@ -36,10 +36,12 @@ pub fn eval_script(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
if args.len() < 2 {
|
||||
return NativeResult::Ok(JsValue::undefined());
|
||||
}
|
||||
let code = match to_string_full(vm.reg(args[1]), vm) {
|
||||
Ok(s) => s,
|
||||
let units = match to_units_full(vm.reg(args[1]), vm) {
|
||||
Ok(u) => u,
|
||||
Err(e) => return NativeResult::Err(oxide_builtins::error::create_from_text(vm, &e)),
|
||||
};
|
||||
// 动态路径源契约:源码域转义形态传源(见 `create_dynamic_function`)。
|
||||
let code = oxide_kernel::string_forge::source_escape(&units);
|
||||
match vm.create_dynamic_function(&[], &code) {
|
||||
Ok(func) => {
|
||||
let global = JsValue::from_js_object(vm.session().global_object().as_ptr() as *mut JsObject);
|
||||
|
||||
@@ -75,7 +75,9 @@ fn canonical_index_units(units: &[u16]) -> Option<u32> {
|
||||
0x30..=0x39 => u - 0x30,
|
||||
_ => return None,
|
||||
};
|
||||
v = v.checked_mul(10)? + d as u32;
|
||||
// 两位都须 overflow 检查:`checked_mul(10) + d` 的裸加在 10 位串
|
||||
// (如 "4294967296")会 mod 2^32 回绕出假规范下标。
|
||||
v = v.checked_mul(10)?.checked_add(d as u32)?;
|
||||
}
|
||||
(v < INT_KEY_COUNT).then_some(v)
|
||||
}
|
||||
@@ -1424,7 +1426,14 @@ impl Vm {
|
||||
// 其它原始值(BigInt 等):ToPropertyKey 一律转字符串并走规范化,避免与
|
||||
// 数字键区间分裂(`o[5n]` 与 `o["5"]`/`o[5]` 必须同键)。
|
||||
let units = oxide_runtime_api::to_units_full(val, self)?;
|
||||
Ok(self.string_key_units(&units))
|
||||
if std::env::var("OXIDE_KEY_PROBE").is_ok() {
|
||||
eprintln!("[KEYPROBE] tail fallback units={:?}", units);
|
||||
}
|
||||
let si = self.string_key_units(&units);
|
||||
if std::env::var("OXIDE_KEY_PROBE").is_ok() {
|
||||
eprintln!("[KEYPROBE] tail result si={}", si);
|
||||
}
|
||||
Ok(si)
|
||||
}
|
||||
|
||||
/// 从单元序列推导属性键 si(`property_key_si` 字符串分支的口径抽取):
|
||||
@@ -2697,6 +2706,11 @@ impl Vm {
|
||||
/// 动态编译函数(`Function` 构造器路径):把参数列表与函数体 wrap 成匿名函数
|
||||
/// 源码,走完整编译链后取匿名函数模块追加进 VM 平表,返回对应函数对象。
|
||||
///
|
||||
/// # 源契约
|
||||
/// `params` 与 `body` 须为 `string_forge::source_escape` 产物(源码域转义
|
||||
/// 形态):孤立 surrogate / FFFD 单元以 `\uXXXX` 转义文本承载,反斜杠
|
||||
/// 原样透传。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. wrap 源码 `function anonymous(p...) { body }`,parse + compile。
|
||||
/// 2. 取 `sub_modules[0]`(匿名函数模块),把其子树 flat_id 重编号到平表末尾
|
||||
@@ -2720,7 +2734,10 @@ impl Vm {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program = oxide_parser::parse(&allocator, &source)
|
||||
.map_err(|errs| errs.into_iter().map(|e| e.message).collect::<Vec<_>>().join("\n"))?;
|
||||
let mut module = oxide_compiler::compiler::Compiler::new().compile(&program)?;
|
||||
// 动态路径源契约:调用方以源码域转义(`string_forge::source_escape`)
|
||||
// 形态传源;正则字面量源文本常量与静态同路径(`pool_key_plain`)。
|
||||
let mut module =
|
||||
oxide_compiler::compiler::Compiler::new().with_source_encoded(true).compile(&program)?;
|
||||
let anonymous = module.sub_modules.remove(0);
|
||||
// 形参数以编译结果为准:单个实参 "a,b,c" 拼接后解析为 3 个形参
|
||||
// (ES 动态函数把非末位实参以逗号连接成参数串再解析)。
|
||||
@@ -2771,8 +2788,10 @@ impl Vm {
|
||||
let program = oxide_parser::parse(&allocator, code)
|
||||
.map_err(|errs| errs.into_iter().map(|e| e.message).collect::<Vec<_>>().join("\n"))?;
|
||||
// eval 脚本:顶层 var/function 声明落全局属性 configurable:true。
|
||||
// 动态路径源契约同 `create_dynamic_function`(源码域转义形态传源)。
|
||||
let module = oxide_compiler::compiler::Compiler::new()
|
||||
.with_eval_script(true)
|
||||
.with_source_encoded(true)
|
||||
.compile(&program)?;
|
||||
// 根模块 flat_id=0 传 base+1,重编号后落 base(避开 sub_module_index()==0
|
||||
// 守卫)。make_mut 彼时平表 Arc 强引用唯一持有者是本表,原地扩展不分叉。
|
||||
@@ -2833,6 +2852,8 @@ impl Vm {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{opcode, ForOfEntry, JsValue, TryHandler, Vm};
|
||||
use super::{canonical_index_of, canonical_index_units};
|
||||
use oxide_types::private_key::INT_KEY_COUNT;
|
||||
use oxide_bytecode::module::CompiledModule;
|
||||
use oxide_runtime_api::{NativeResult, VmHost};
|
||||
use oxide_types::object::NativeFnPtr;
|
||||
@@ -3389,4 +3410,40 @@ mod tests {
|
||||
);
|
||||
assert!(!frame.is_derived_constructor, "普通函数非 derived 构造器");
|
||||
}
|
||||
|
||||
fn units_of(s: &str) -> Vec<u16> {
|
||||
s.chars().map(|c| c as u16).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn canonical_index_str_boundaries() {
|
||||
assert_eq!(canonical_index_of("0"), Some(0));
|
||||
assert_eq!(canonical_index_of("1073741823"), Some(INT_KEY_COUNT - 1));
|
||||
// 2^30 起不再是整数键候选;2^32 边界串(ToUint32 回绕源)必须走字符串键
|
||||
assert_eq!(canonical_index_of("1073741824"), None);
|
||||
assert_eq!(canonical_index_of("4294967295"), None);
|
||||
assert_eq!(canonical_index_of("4294967296"), None);
|
||||
assert_eq!(canonical_index_of("4294967299"), None);
|
||||
// 非规范形态:前导零、符号、小数、空串
|
||||
assert_eq!(canonical_index_of("007"), None);
|
||||
assert_eq!(canonical_index_of("-1"), None);
|
||||
assert_eq!(canonical_index_of("1.5"), None);
|
||||
assert_eq!(canonical_index_of(""), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn canonical_index_units_boundaries() {
|
||||
assert_eq!(canonical_index_units(&units_of("0")), Some(0));
|
||||
assert_eq!(canonical_index_units(&units_of("1073741823")), Some(INT_KEY_COUNT - 1));
|
||||
assert_eq!(canonical_index_units(&units_of("1073741824")), None);
|
||||
// 10 位串在 u32 累加尾位溢出:回绕会造出假规范下标,须溢出检查归 None
|
||||
assert_eq!(canonical_index_units(&units_of("4294967295")), None);
|
||||
assert_eq!(canonical_index_units(&units_of("4294967296")), None);
|
||||
assert_eq!(canonical_index_units(&units_of("4294967299")), None);
|
||||
assert_eq!(canonical_index_units(&units_of("9999999999")), None);
|
||||
assert_eq!(canonical_index_units(&units_of("007")), None);
|
||||
assert_eq!(canonical_index_units(&units_of("-1")), None);
|
||||
assert_eq!(canonical_index_units(&units_of("1.5")), None);
|
||||
assert_eq!(canonical_index_units(&[]), None);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user