mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 编译缓存键补模板段值、spread 实参、赋值目标属性名与数组 spread 形态
This commit is contained in:
@@ -16,9 +16,19 @@ pub(super) fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher, i
|
||||
Expression::CallExpression(call) => {
|
||||
(call.arguments.len() as u32).hash(h);
|
||||
hash_expression(&call.callee, h, include_binding_names);
|
||||
// spread 实参改指令形态(CALL 变 CALL_SPREAD)与装载方式,逐位打形态标记。
|
||||
for arg in &call.arguments {
|
||||
if let Some(expr) = arg.as_expression() {
|
||||
hash_expression(expr, h, include_binding_names);
|
||||
match arg {
|
||||
Argument::SpreadElement(sp) => {
|
||||
1u8.hash(h);
|
||||
hash_expression(&sp.argument, h, include_binding_names);
|
||||
}
|
||||
other => {
|
||||
0u8.hash(h);
|
||||
if let Some(expr) = other.as_expression() {
|
||||
hash_expression(expr, h, include_binding_names);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,6 +79,11 @@ pub(super) fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher, i
|
||||
}
|
||||
Expression::TemplateLiteral(tl) => {
|
||||
(tl.quasis.len() as u32).hash(h);
|
||||
// 段值是字节码依赖(发射侧把 cooked 写入常量池);cooked 为 None 与
|
||||
// Some(空串) 的池键都是空串,字节码相同,口径上合并。
|
||||
for q in &tl.quasis {
|
||||
q.value.cooked.as_deref().unwrap_or("").hash(h);
|
||||
}
|
||||
for expr in &tl.expressions {
|
||||
hash_expression(expr, h, include_binding_names);
|
||||
}
|
||||
@@ -76,6 +91,12 @@ pub(super) fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher, i
|
||||
Expression::TaggedTemplateExpression(tt) => {
|
||||
hash_expression(&tt.tag, h, include_binding_names);
|
||||
(tt.quasi.quasis.len() as u32).hash(h);
|
||||
// 发射侧同时消费 cooked 与 raw;cooked 为 None 时写标记字,与
|
||||
// Some(空串) 的常量下标字不同,须保留 None 区分。
|
||||
for q in &tt.quasi.quasis {
|
||||
q.value.cooked.hash(h);
|
||||
q.value.raw.hash(h);
|
||||
}
|
||||
for expr in &tt.quasi.expressions {
|
||||
hash_expression(expr, h, include_binding_names);
|
||||
}
|
||||
@@ -128,9 +149,19 @@ pub(super) fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher, i
|
||||
Expression::NewExpression(ne) => {
|
||||
hash_expression(&ne.callee, h, include_binding_names);
|
||||
(ne.arguments.len() as u32).hash(h);
|
||||
// spread 实参改指令形态(NEW_EXPRESSION 变 NEW_EXPRESSION_SPREAD),逐位打形态标记。
|
||||
for arg in &ne.arguments {
|
||||
if let Some(expr) = arg.as_expression() {
|
||||
hash_expression(expr, h, include_binding_names);
|
||||
match arg {
|
||||
Argument::SpreadElement(sp) => {
|
||||
1u8.hash(h);
|
||||
hash_expression(&sp.argument, h, include_binding_names);
|
||||
}
|
||||
other => {
|
||||
0u8.hash(h);
|
||||
if let Some(expr) = other.as_expression() {
|
||||
hash_expression(expr, h, include_binding_names);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,15 +200,19 @@ pub(super) fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher, i
|
||||
}
|
||||
Expression::ArrayExpression(arr) => {
|
||||
(arr.elements.len() as u32).hash(h);
|
||||
// 元素形态(spread / 省略 / 值)逐位打标记:spread 源改变装载指令,
|
||||
// 位置敏感,`[...a]` 与 `[a]` 不得同键。
|
||||
for element in &arr.elements {
|
||||
match element {
|
||||
ArrayExpressionElement::SpreadElement(spread) => {
|
||||
1u8.hash(h);
|
||||
hash_expression(&spread.argument, h, include_binding_names);
|
||||
}
|
||||
ArrayExpressionElement::Elision(_) => {
|
||||
1u8.hash(h);
|
||||
2u8.hash(h);
|
||||
}
|
||||
other => {
|
||||
0u8.hash(h);
|
||||
if let Some(expr) = other.as_expression() {
|
||||
hash_expression(expr, h, include_binding_names);
|
||||
}
|
||||
@@ -262,9 +297,19 @@ pub(super) fn hash_chain_element(element: &ChainElement, h: &mut rustc_hash::FxH
|
||||
hash_expression(&call.callee, h, include_binding_names);
|
||||
call.optional.hash(h);
|
||||
(call.arguments.len() as u32).hash(h);
|
||||
// spread 实参改指令形态(CALL_SPREAD),逐位打形态标记。
|
||||
for arg in &call.arguments {
|
||||
if let Some(expr) = arg.as_expression() {
|
||||
hash_expression(expr, h, include_binding_names);
|
||||
match arg {
|
||||
Argument::SpreadElement(sp) => {
|
||||
1u8.hash(h);
|
||||
hash_expression(&sp.argument, h, include_binding_names);
|
||||
}
|
||||
other => {
|
||||
0u8.hash(h);
|
||||
if let Some(expr) = other.as_expression() {
|
||||
hash_expression(expr, h, include_binding_names);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
//! 其内部绑定名仅精确键计入。
|
||||
|
||||
use oxide_parser::{
|
||||
ArrayAssignmentTarget, ArrayExpressionElement, AssignmentTarget, AssignmentTargetMaybeDefault,
|
||||
ArrayAssignmentTarget, ArrayExpressionElement, Argument, AssignmentTarget, AssignmentTargetMaybeDefault,
|
||||
AssignmentTargetProperty, BindingPattern, ChainElement, Class, ClassElement, Declaration,
|
||||
ExportDefaultDeclarationKind, Expression, ForStatementInit, ForStatementLeft, Function, ImportDeclarationSpecifier,
|
||||
ModuleExportName, ObjectAssignmentTarget, ObjectPropertyKind, PropertyKey, SimpleAssignmentTarget, Statement,
|
||||
|
||||
@@ -13,14 +13,20 @@ pub(super) fn hash_simple_assignment_target(
|
||||
}
|
||||
SimpleAssignmentTarget::StaticMemberExpression(member) => {
|
||||
expression::hash_expression(&member.object, h, include_binding_names);
|
||||
// 属性名是字节码依赖(发射侧写入常量池作 IC_SET 等键);optional 与
|
||||
// 读侧口径对齐(写侧发射当前忽略该标志,防未来写侧开始区分时再漏)。
|
||||
member.property.name.as_str().hash(h);
|
||||
member.optional.hash(h);
|
||||
}
|
||||
SimpleAssignmentTarget::ComputedMemberExpression(member) => {
|
||||
expression::hash_expression(&member.object, h, include_binding_names);
|
||||
expression::hash_expression(&member.expression, h, include_binding_names);
|
||||
member.optional.hash(h);
|
||||
}
|
||||
SimpleAssignmentTarget::PrivateFieldExpression(member) => {
|
||||
expression::hash_expression(&member.object, h, include_binding_names);
|
||||
member.field.name.as_str().hash(h);
|
||||
member.optional.hash(h);
|
||||
}
|
||||
SimpleAssignmentTarget::TSAsExpression(ts) => {
|
||||
expression::hash_expression(&ts.expression, h, include_binding_names);
|
||||
|
||||
@@ -227,3 +227,44 @@ fn function_async_generator_flags_distinguished() {
|
||||
// 同源等价回归
|
||||
assert_eq!(compiled("async function f(){ return 1 }"), compiled("async function f(){ return 1 }"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn template_segment_values_distinguished() {
|
||||
// 模板段值是字节码依赖(发射侧把 cooked 写入常量池):段值不入哈希时
|
||||
// 同键异码,缓存命中复用错误字节码。
|
||||
assert_ne!(compiled("`${a}x`"), compiled("`${a}y`"));
|
||||
assert_ne!(compiled("t`${a}x`"), compiled("t`${a}y`"));
|
||||
// 段值在两种哈希粒度下都计入(非绑定名输入)。
|
||||
assert_ne!(structural("`${a}x`"), structural("`${a}y`"));
|
||||
// 同源等价回归。
|
||||
assert_eq!(compiled("`${a}x`"), compiled("`${a}x`"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_spread_arguments_distinguished() {
|
||||
assert_ne!(compiled("f(...a)"), compiled("f(...b)"));
|
||||
assert_ne!(compiled("new F(...a)"), compiled("new F(...b)"));
|
||||
assert_ne!(compiled("o.m(...a)"), compiled("o.m(...b)"));
|
||||
// spread 与非 spread 同长同表达式须区分(逐位形态标记)。
|
||||
assert_ne!(compiled("f(a, ...b)"), compiled("f(a, b)"));
|
||||
// spread 形态标记在两种哈希粒度下都计入(标记本身非绑定名输入)。
|
||||
assert_ne!(structural("f(...a, 1)"), structural("f(a, 1)"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_spread_elements_distinguished() {
|
||||
// spread 元素与值元素同位置须区分(形态标记逐位计入)。
|
||||
assert_ne!(compiled("[...a]"), compiled("[a]"), "spread vs value element must differ");
|
||||
assert_ne!(structural("[...a, 1]"), structural("[a, 1]"), "spread element shape must be in both granularities");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assignment_target_member_names_distinguished() {
|
||||
// 赋值目标静态成员属性名是字节码依赖(发射侧写入常量池):属性名不入哈希时
|
||||
// 同键异码。覆盖赋值、自增减与 for 头三个调用点。
|
||||
assert_ne!(compiled("a.x = 1"), compiled("a.y = 1"));
|
||||
assert_ne!(compiled("a.x++"), compiled("a.y++"));
|
||||
assert_ne!(compiled("for (a.x of iter) {}"), compiled("for (a.y of iter) {}"));
|
||||
// 属性名在两种哈希粒度下都计入。
|
||||
assert_ne!(structural("a.x = 1"), structural("a.y = 1"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user