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:
@@ -34,8 +34,17 @@ pub use oxide_parser::VariableDeclarationKind;
|
||||
/// AST 语法树节点与运算符类型,re-export 自 parser。
|
||||
pub use oxide_parser::{AssignmentOperator, BinaryOperator, Expression, Statement, UnaryOperator};
|
||||
|
||||
/// 编译入口(marker 类型)。方法按语法域组织在 `impl Emitter` 中。
|
||||
pub struct Emitter;
|
||||
/// 编译入口。方法按语法域组织在 `impl Emitter` 中。
|
||||
pub struct Emitter {
|
||||
/// 源码是否为 `oxide_kernel::string_forge::source_escape` 产物
|
||||
/// (eval/Function 动态编译):源文本内的孤立 surrogate 单元 / FFFD 以
|
||||
/// `\uXXXX` 转义文本承载(oxc 不可见裸单元——Rust str 无孤立 surrogate,
|
||||
/// 转义文本是唯一注入形态),反斜杠原样透传。正则字面量的源文本切片据此
|
||||
/// 经 `source_escape_to_key` 还原池键 marker 形态入池(物化时
|
||||
/// `decode_key` 还原为原始单元,`.source` 按原始源返回);静态源切片不含
|
||||
/// 注入 marker,走 `pool_key_plain`。
|
||||
source_encoded: bool,
|
||||
}
|
||||
|
||||
/// 判断 f64 是否为整数值且在 i32 范围内(整数常量编码用)。
|
||||
pub fn is_int_literal(value: f64) -> bool {
|
||||
@@ -194,6 +203,9 @@ pub struct CompileCtx {
|
||||
/// 是否为 eval 脚本:脚本顶层 var/function 声明落全局对象时属性
|
||||
/// configurable:true(普通脚本顶层为 false)。仅动态脚本入口设置。
|
||||
pub(crate) is_eval_script: bool,
|
||||
/// 源码是否为 `source_escape` 产物(动态编译入口):正则字面量源文本切片
|
||||
/// 的池键形态据此选择(见 [`Emitter::source_encoded`])。
|
||||
pub(crate) source_encoded: bool,
|
||||
pub(crate) static_block_this_reg: Option<u8>,
|
||||
pub(crate) field_buffer: Option<FieldBuffer>,
|
||||
/// 类构造器模块中 `@@field_keys` upvalue 下标(实例字段 computed key 数组)。
|
||||
@@ -343,6 +355,7 @@ impl CompileCtx {
|
||||
is_global_scope: false,
|
||||
repl_persist: false,
|
||||
is_eval_script: false,
|
||||
source_encoded: false,
|
||||
static_block_this_reg: None,
|
||||
field_buffer: None,
|
||||
field_keys_uv: None,
|
||||
@@ -825,9 +838,16 @@ impl ConstantKey {
|
||||
}
|
||||
|
||||
impl Emitter {
|
||||
/// 构造空 `Emitter`(无内部状态,所有状态在 `CompileCtx` 中)。
|
||||
/// 构造空 `Emitter`(静态编译口径:源文本为良形 UTF-8,无注入 marker)。
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
Self { source_encoded: false }
|
||||
}
|
||||
|
||||
/// 置位编码源口径(见 [`Emitter::source_encoded`]):仅动态编译入口
|
||||
/// (eval / Function 构造器)经编译器设置。
|
||||
pub fn with_source_encoded(mut self, enable: bool) -> Self {
|
||||
self.source_encoded = enable;
|
||||
self
|
||||
}
|
||||
|
||||
/// 生成运行时抛 `kind` 类型错误的指令序列,返回一个未定义 dummy 寄存器
|
||||
@@ -1151,6 +1171,8 @@ impl Emitter {
|
||||
|
||||
// 传递 enclosing_this_reg:嵌套箭头函数捕获正确的 `this`。
|
||||
ctx.enclosing_this_reg = parent_ctx.enclosing_this_reg;
|
||||
// 编码源口径是整棵编译树属性(嵌套函数仍在同一编码源内)。
|
||||
ctx.source_encoded = parent_ctx.source_encoded;
|
||||
|
||||
// 箭头函数词法继承 super;类方法体顶层编译也需要类提供的 super 上下文。
|
||||
if matches!(body_context, FunctionBodyContext::Arrow | FunctionBodyContext::ClassElement) {
|
||||
@@ -1694,6 +1716,7 @@ impl Emitter {
|
||||
ctx.is_global_scope = true;
|
||||
ctx.repl_persist = repl_persist;
|
||||
ctx.is_eval_script = is_eval_script;
|
||||
ctx.source_encoded = self.source_encoded;
|
||||
// 脚本顶层严格模式由源码 "use strict" directive 决定(嵌套函数经父 ctx 继承)。
|
||||
ctx.is_strict = program.has_use_strict_directive();
|
||||
|
||||
|
||||
@@ -89,10 +89,22 @@ impl Emitter {
|
||||
if regress::Regex::with_flags(&pattern, flags.as_str()).is_err() {
|
||||
return Err(format!("SyntaxError: Invalid regular expression: /{pattern}/{flags}"));
|
||||
}
|
||||
let pat_ci = ctx.add_constant(Constant::String(pattern));
|
||||
// 源文本池键:静态源切片经 `pool_key_plain` 逃逸真实 FFFD(防
|
||||
// 物化侧把裸 FFFD+hex4 误读为 surrogate marker),转义文本
|
||||
// `decode_key` 逐字透传,正则引擎自行解析转义;编码源切片经
|
||||
// `source_escape_to_key` 把注入的 `\ud800`..`\udfff`/`\ufffd`
|
||||
// 转义文本还原为池键 marker 形态(物化还原原始单元,
|
||||
// `.source` 按原始源返回),用户转义文本逐字透传。
|
||||
let pattern_key = if ctx.source_encoded {
|
||||
oxide_kernel::string_forge::source_escape_to_key(&pattern)
|
||||
} else {
|
||||
crate::shared::string_pool::pool_key_plain(&pattern)
|
||||
};
|
||||
let flags_key = crate::shared::string_pool::pool_key_plain(&flags);
|
||||
let pat_ci = ctx.add_constant(Constant::String(pattern_key));
|
||||
let pat_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(pat_reg), pat_ci));
|
||||
let flags_ci = ctx.add_constant(Constant::String(flags));
|
||||
let flags_ci = ctx.add_constant(Constant::String(flags_key));
|
||||
let flags_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(flags_reg), flags_ci));
|
||||
let r = ctx.alloc_reg();
|
||||
|
||||
Reference in New Issue
Block a user