mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 数组 for-in 可枚举滤按元素区偏移取命名属性元数据
This commit is contained in:
Generated
+18
-18
@@ -1095,7 +1095,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_builtins"
|
name = "oxide_builtins"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"fast-float",
|
"fast-float",
|
||||||
@@ -1120,7 +1120,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_bytecode"
|
name = "oxide_bytecode"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"oxide_log",
|
"oxide_log",
|
||||||
@@ -1128,7 +1128,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_cfg"
|
name = "oxide_cfg"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_emit",
|
"oxide_emit",
|
||||||
@@ -1139,7 +1139,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_cli"
|
name = "oxide_cli"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
"ansi_term",
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
@@ -1159,7 +1159,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_code_cache"
|
name = "oxide_code_cache"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lru",
|
"lru",
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
@@ -1168,7 +1168,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_compiler"
|
name = "oxide_compiler"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1187,7 +1187,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_dce"
|
name = "oxide_dce"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1201,7 +1201,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_emit"
|
name = "oxide_emit"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
@@ -1216,7 +1216,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_ir"
|
name = "oxide_ir"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_log",
|
"oxide_log",
|
||||||
@@ -1225,7 +1225,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_kernel"
|
name = "oxide_kernel"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
@@ -1240,7 +1240,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_liveness"
|
name = "oxide_liveness"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1252,7 +1252,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_log"
|
name = "oxide_log"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-appender",
|
"tracing-appender",
|
||||||
@@ -1261,7 +1261,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_parser"
|
name = "oxide_parser"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
"oxc_ast",
|
"oxc_ast",
|
||||||
@@ -1276,7 +1276,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_regalloc"
|
name = "oxide_regalloc"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_cfg",
|
"oxide_cfg",
|
||||||
@@ -1292,7 +1292,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_runtime_api"
|
name = "oxide_runtime_api"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@@ -1304,7 +1304,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_test262"
|
name = "oxide_test262"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxide_bytecode",
|
"oxide_bytecode",
|
||||||
"oxide_compiler",
|
"oxide_compiler",
|
||||||
@@ -1321,7 +1321,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_types"
|
name = "oxide_types"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"hashbrown 0.14.5",
|
"hashbrown 0.14.5",
|
||||||
@@ -1333,7 +1333,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxide_vm"
|
name = "oxide_vm"
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.8.15"
|
version = "0.8.16"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
rust-version = "1.80"
|
rust-version = "1.80"
|
||||||
|
|||||||
@@ -538,7 +538,11 @@ impl Vm {
|
|||||||
.kernel_core
|
.kernel_core
|
||||||
.shape_forge()
|
.shape_forge()
|
||||||
.lookup_position(cur.shape_id(), shape.property_name)
|
.lookup_position(cur.shape_id(), shape.property_name)
|
||||||
.and_then(|pos| cur.prop_meta_at(pos))
|
// 数组命名属性存储下标 = 元素区偏移加 shape 槽位;
|
||||||
|
// 普通对象槽位即下标,空数组偏移为零。
|
||||||
|
.and_then(|pos| {
|
||||||
|
cur.prop_meta_at(if cur.is_array() { cur.array_prop_count + pos } else { pos })
|
||||||
|
})
|
||||||
.map(|meta| meta.attributes.enumerable())
|
.map(|meta| meta.attributes.enumerable())
|
||||||
.unwrap_or(PropAttributes::DEFAULT_DATA.enumerable());
|
.unwrap_or(PropAttributes::DEFAULT_DATA.enumerable());
|
||||||
if enumerable {
|
if enumerable {
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use oxide_compiler::compiler::Compiler;
|
||||||
|
use oxide_parser::Allocator;
|
||||||
|
use oxide_vm::vm::Vm;
|
||||||
|
|
||||||
|
fn eval(source: &str) -> String {
|
||||||
|
let allocator = Allocator::default();
|
||||||
|
let program = match oxide_parser::parse(&allocator, source) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(e) => return format!("parse error: {}", e[0].message),
|
||||||
|
};
|
||||||
|
let module = match Compiler::new().compile(&program) {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(e) => return format!("compile error: {e}"),
|
||||||
|
};
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
match vm.run(&Arc::new(module)) {
|
||||||
|
Ok(result) => format!("{result}"),
|
||||||
|
Err(e) => format!("vm error: {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数组命名属性可枚举性判定与形状槽位、存储下标两口径对齐:for-in 枚举
|
||||||
|
// 命名属性时按元素区偏移取元数据,非空数组不可枚举命名属性被滤出、
|
||||||
|
// 元素不可枚举不连带误滤命名属性,与 Object.keys 同形。
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_in_array_non_enum_named_property_filtered() {
|
||||||
|
// 非空数组不可枚举命名属性不进入 for-in 枚举:
|
||||||
|
// 单元素数组加不可枚举命名属性后仅枚举下标键。
|
||||||
|
assert_eq!(
|
||||||
|
eval(
|
||||||
|
"var g = [1]; \
|
||||||
|
Object.defineProperty(g, 'x', { value: 9, enumerable: false }); \
|
||||||
|
var ka = []; for (var k in g) ka.push(k); \
|
||||||
|
ka.length === 1 && ka[0] === '0'"
|
||||||
|
),
|
||||||
|
"true",
|
||||||
|
"non-enumerable named property on a non-empty array is filtered out of for-in"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_in_array_multi_element_non_enum_named_filtered() {
|
||||||
|
// 多元素数组可枚举命名属性保留、不可枚举命名属性滤出:
|
||||||
|
// 下标键升序加可枚举命名属性,无不可枚举命名属性。
|
||||||
|
assert_eq!(
|
||||||
|
eval(
|
||||||
|
"var h = [1, 2, 3]; h.p = 1; \
|
||||||
|
Object.defineProperty(h, 'q', { value: 2, enumerable: false }); \
|
||||||
|
var kb = []; for (var k in h) kb.push(k); \
|
||||||
|
kb.length === 4 && kb[0] === '0' && kb[1] === '1' && kb[2] === '2' && kb[3] === 'p'"
|
||||||
|
),
|
||||||
|
"true",
|
||||||
|
"enumerable named property kept, non-enumerable one filtered on multi-element array"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_in_array_non_enum_element_does_not_filter_named() {
|
||||||
|
// 元素不可枚举不连带误滤命名属性:for-in 与 Object.keys 同形,
|
||||||
|
// 两者都只含可枚举命名属性。
|
||||||
|
assert_eq!(
|
||||||
|
eval(
|
||||||
|
"var n = [1]; \
|
||||||
|
Object.defineProperty(n, '0', { value: 1, enumerable: false }); \
|
||||||
|
n.named = 5; \
|
||||||
|
var kc = []; for (var k in n) kc.push(k); \
|
||||||
|
var keys = Object.keys(n); \
|
||||||
|
kc.length === 1 && kc[0] === 'named' && keys.length === 1 && keys[0] === 'named'"
|
||||||
|
),
|
||||||
|
"true",
|
||||||
|
"non-enumerable array element does not drag the enumerable named property out of for-in"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_in_array_accessor_presence_unchanged() {
|
||||||
|
// accessor 命名属性存在性回归:Object.hasOwn / in / hasOwnProperty
|
||||||
|
// 三判全真,形状槽命中即在场。
|
||||||
|
assert_eq!(
|
||||||
|
eval(
|
||||||
|
"var a = [1]; \
|
||||||
|
Object.defineProperty(a, 'ctor2', { get: function() { return 'g'; } }); \
|
||||||
|
Object.hasOwn(a, 'ctor2') && ('ctor2' in a) && a.hasOwnProperty('ctor2')"
|
||||||
|
),
|
||||||
|
"true",
|
||||||
|
"accessor named property on array is present for hasOwn, in, hasOwnProperty"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_in_array_accessor_getter_read_and_keys() {
|
||||||
|
// accessor 命名属性读值与键表回归:getter 触发读值,
|
||||||
|
// Object.keys 只含下标键不含 accessor 命名属性。
|
||||||
|
assert_eq!(
|
||||||
|
eval(
|
||||||
|
"var a = [1]; \
|
||||||
|
Object.defineProperty(a, 'ctor2', { get: function() { return 'g'; } }); \
|
||||||
|
a.ctor2 === 'g' && Object.keys(a).length === 1 && Object.keys(a)[0] === '0'"
|
||||||
|
),
|
||||||
|
"true",
|
||||||
|
"accessor getter fires on read and Object.keys lists only the index key"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_in_empty_array_accessor_and_data_zero_drift() {
|
||||||
|
// 空数组 for-in 零扰动:空数组元素区偏移为零,
|
||||||
|
// accessor 与数据命名属性按插入序全枚举。
|
||||||
|
assert_eq!(
|
||||||
|
eval(
|
||||||
|
"var z = []; \
|
||||||
|
Object.defineProperty(z, 'a', { get: function() { return 1; }, enumerable: true }); \
|
||||||
|
z.b = 2; \
|
||||||
|
var kz = []; for (var k in z) kz.push(k); \
|
||||||
|
kz.length === 2 && kz[0] === 'a' && kz[1] === 'b'"
|
||||||
|
),
|
||||||
|
"true",
|
||||||
|
"empty array for-in enumerates accessor and data named properties in insertion order"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_in_array_all_elements_enumerable_zero_drift() {
|
||||||
|
// 全元素可枚举数组 for-in 零扰动:仅下标键升序枚举。
|
||||||
|
assert_eq!(
|
||||||
|
eval(
|
||||||
|
"var t = [1, 2]; \
|
||||||
|
var kt = []; for (var k in t) kt.push(k); \
|
||||||
|
kt.length === 2 && kt[0] === '0' && kt[1] === '1'"
|
||||||
|
),
|
||||||
|
"true",
|
||||||
|
"plain array for-in enumerates index keys in ascending order"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_in_ordinary_object_zero_drift() {
|
||||||
|
// 普通对象 for-in 零漂移:命名属性按插入序全枚举,
|
||||||
|
// 数组偏移分支不触及普通对象路径。
|
||||||
|
assert_eq!(
|
||||||
|
eval(
|
||||||
|
"var o = { a: 1, b: 2 }; \
|
||||||
|
var ko = []; for (var k in o) ko.push(k); \
|
||||||
|
ko.length === 2 && ko[0] === 'a' && ko[1] === 'b'"
|
||||||
|
),
|
||||||
|
"true",
|
||||||
|
"ordinary object for-in keeps insertion order"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_in_array_element_accessor_arm_untouched() {
|
||||||
|
// 元素区 accessor 定义后读值、存在性、描述符三面不变:
|
||||||
|
// 下标 0 的 accessor 触发 getter,hasOwn 判在,描述符 get 在场。
|
||||||
|
assert_eq!(
|
||||||
|
eval(
|
||||||
|
"var j = [1, 2]; \
|
||||||
|
Object.defineProperty(j, 0, { get: function() { return 'e'; } }); \
|
||||||
|
j[0] === 'e' && Object.hasOwn(j, 0) && Object.getOwnPropertyDescriptor(j, 0).get !== undefined"
|
||||||
|
),
|
||||||
|
"true",
|
||||||
|
"element-area accessor keeps working: getter fires, hasOwn true, descriptor get present"
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user