diff --git a/crates/oxide_builtins/src/lib.rs b/crates/oxide_builtins/src/lib.rs index 63c120e..d002435 100644 --- a/crates/oxide_builtins/src/lib.rs +++ b/crates/oxide_builtins/src/lib.rs @@ -11,10 +11,10 @@ pub mod array; /// ArrayBuffer 内置对象实现(字节缓冲区与 byteLength/slice/isView)。 pub mod array_buffer; -/// Boolean 内置对象实现(constructor 与 prototype 的 valueOf/toString)。 -pub mod boolean; /// BigInt 内置对象实现(constructor 与 prototype 的 toString)。 pub mod bigint; +/// Boolean 内置对象实现(constructor 与 prototype 的 valueOf/toString)。 +pub mod boolean; /// builtins 层日志宏(`builtins_error`/`builtins_info` 等),target 为 `oxide::builtins`。 pub mod builtins_log; /// DataView 内置对象实现(对 ArrayBuffer 的定点读写视图)。 diff --git a/crates/oxide_builtins/src/module.rs b/crates/oxide_builtins/src/module.rs index 8e05cbc..045d1d8 100644 --- a/crates/oxide_builtins/src/module.rs +++ b/crates/oxide_builtins/src/module.rs @@ -25,12 +25,7 @@ pub fn module_object(vm: &mut H, _args: &[u8]) -> NativeResult { let tag_si = vm.kernel_core().perm_interner().intern("@@toStringTag").0; let tag_val = vm.new_string("Module"); let obj_ref = unsafe { &mut *obj }; - if let Err(e) = vm.define_data_property( - obj_ref, - tag_si, - tag_val, - PropAttributes::new(false, false, false), - ) { + if let Err(e) = vm.define_data_property(obj_ref, tag_si, tag_val, PropAttributes::new(false, false, false)) { return NativeResult::Err(crate::error::create_error(vm, &e)); } NativeResult::Ok(JsValue::from_js_object(obj)) @@ -98,10 +93,7 @@ pub fn module_link_get(vm: &mut H, args: &[u8]) -> NativeResult { let name_si = vm.property_key_si(name_val); let obj = unsafe { &*ns_ptr }; if vm.get_own_property_slot(obj, name_si).is_none() { - return NativeResult::Err(crate::error::create_syntax_error( - vm, - "requested module export is not exported", - )); + return NativeResult::Err(crate::error::create_syntax_error(vm, "requested module export is not exported")); } match vm.ordinary_get(obj, name_si, ns_val) { Ok(v) => NativeResult::Ok(v), diff --git a/crates/oxide_builtins/src/temporal.rs b/crates/oxide_builtins/src/temporal.rs index ae057eb..6dc1848 100644 --- a/crates/oxide_builtins/src/temporal.rs +++ b/crates/oxide_builtins/src/temporal.rs @@ -455,7 +455,8 @@ fn instant_like_epoch_ns(vm: &mut H, value: JsValue) -> Result ParseTemporalInstantString(解析失败 RangeError)。 let input = oxide_runtime_api::to_string_full(value, vm).map_err(|error| native_engine_error(vm, &error))?; - return parse_instant_string(&input).ok_or_else(|| crate::error::create_range_error(vm, "invalid ISO 8601 string")); + return parse_instant_string(&input) + .ok_or_else(|| crate::error::create_range_error(vm, "invalid ISO 8601 string")); } // 非字符串原始值(undefined/null/boolean/number/bigint/symbol)按规范直接抛 TypeError。 if !value.is_string() { @@ -1728,16 +1729,9 @@ pub fn duration_total(vm: &mut H, args: &[u8]) -> NativeResult { match parse_plain_date_time_string(&text) .or_else(|_| parse_plain_date_string(&text).map(|(y, m, d)| (y, m, d, 0.0))) { - Ok((year, month, day, _time_ns)) => Some(( - i128::from(year), - i128::from(month), - i128::from(day), - )), + Ok((year, month, day, _time_ns)) => Some((i128::from(year), i128::from(month), i128::from(day))), Err(_) => { - return NativeResult::Err(crate::error::create_range_error( - vm, - "invalid relativeTo string", - )); + return NativeResult::Err(crate::error::create_range_error(vm, "invalid relativeTo string")); } } } else if relative_raw.is_object() { @@ -1934,10 +1928,7 @@ pub fn duration_add(vm: &mut H, args: &[u8]) -> NativeResult { let other = native_try!(duration_like_values(vm, other_val)); let receiver = duration_values(obj); if receiver[..3].iter().any(|value| *value != 0.0) || other[..3].iter().any(|value| *value != 0.0) { - return NativeResult::Err(crate::error::create_range_error( - vm, - "cannot add durations with calendar units", - )); + return NativeResult::Err(crate::error::create_range_error(vm, "cannot add durations with calendar units")); } // 最大单位取 receiver 与参数中最大的非零时间单位(days=3 最大,ns=9 最小)。 let mut largest = 9_usize; @@ -1952,15 +1943,8 @@ pub fn duration_add(vm: &mut H, args: &[u8]) -> NativeResult { } // 分量按精确整数求和(f64 分量是精确整数;超过 2^53 的和需在 i128 上保持精确,规范按数学值计算)。 let mut total_ns = 0_i128; - const SUM_SCALES: [i128; 7] = [ - 86_400_000_000_000, - 3_600_000_000_000, - 60_000_000_000, - 1_000_000_000, - 1_000_000, - 1_000, - 1, - ]; + const SUM_SCALES: [i128; 7] = + [86_400_000_000_000, 3_600_000_000_000, 60_000_000_000, 1_000_000_000, 1_000_000, 1_000, 1]; for (index, scale) in (3..10).zip(SUM_SCALES) { let Some(a) = duration_component_integer(receiver[index]) else { return NativeResult::Err(crate::error::create_range_error(vm, "invalid duration")); @@ -1986,7 +1970,7 @@ pub fn duration_add(vm: &mut H, args: &[u8]) -> NativeResult { break; } let base = match unit { - 7..=9 => 1_000, + 7..=9 => 1_000, 6 | 5 => 60, _ => 24, }; @@ -2007,10 +1991,7 @@ pub fn duration_add(vm: &mut H, args: &[u8]) -> NativeResult { ]; for (index, scale) in (3..10).zip(UNIT_SCALES) { if values[index] != 0.0 && values[index].abs() * scale >= MAX_TIME_NANOSECONDS { - return NativeResult::Err(crate::error::create_range_error( - vm, - "duration time fields are out of range", - )); + return NativeResult::Err(crate::error::create_range_error(vm, "duration time fields are out of range")); } } make_duration(vm, values) @@ -2173,15 +2154,8 @@ pub fn duration_round(vm: &mut H, args: &[u8]) -> NativeResult { let Some(time_ns) = duration_time_nanoseconds(&values) else { return NativeResult::Err(crate::error::create_range_error(vm, "duration is out of range")); }; - const UNIT_NS: [i128; 7] = [ - 86_400_000_000_000, - 3_600_000_000_000, - 60_000_000_000, - 1_000_000_000, - 1_000_000, - 1_000, - 1, - ]; + const UNIT_NS: [i128; 7] = + [86_400_000_000_000, 3_600_000_000_000, 60_000_000_000, 1_000_000_000, 1_000_000, 1_000, 1]; let quantum = if smallest_index == 3 { increment * UNIT_NS[0] } else { @@ -2810,10 +2784,7 @@ fn parse_plain_date_string(input: &str) -> Result<(i32, u32, u32), String> { parse_temporal_string_impl(input, false).map(|(year, month, day, _)| (year, month, day)) } -fn parse_temporal_string_impl( - input: &str, - enforce_date_time_range: bool, -) -> Result<(i32, u32, u32, f64), String> { +fn parse_temporal_string_impl(input: &str, enforce_date_time_range: bool) -> Result<(i32, u32, u32, f64), String> { let trimmed = input.trim(); if trimmed.contains('\u{2212}') { return Err("variant minus sign is not valid for PlainDateTime".into()); @@ -3167,8 +3138,7 @@ fn plain_date_time_object_parts( let (hour, minute, second) = (hour as u32, minute as u32, second as u32); let (millisecond, microsecond, nanosecond) = (millisecond as u32, microsecond as u32, nanosecond as u32); if !valid_iso_date(year, month, day) - || (!ignore_time - && !valid_plain_time(hour, minute, second, millisecond, microsecond, nanosecond)) + || (!ignore_time && !valid_plain_time(hour, minute, second, millisecond, microsecond, nanosecond)) { return Err(crate::error::create_range_error(vm, "invalid date-time component")); } @@ -4097,9 +4067,7 @@ fn plain_date_unit_index(value: &str) -> Option { /// roundingIncrement → roundingMode → smallestUnit。date_only 时单位限定 /// year/month/week/day,smallestUnit 缺省 "day"(含时间时缺省 "nanosecond")。 fn parse_difference_settings( - vm: &mut H, - options_value: JsValue, - date_only: bool, + vm: &mut H, options_value: JsValue, date_only: bool, ) -> Result { let unit_index = |value: &str| -> Option { if date_only { @@ -4178,22 +4146,27 @@ fn parse_difference_settings( return Err(crate::error::create_range_error(vm, "invalid roundingIncrement")); } } - Ok(DifferenceSettings { largest_index, smallest_index, increment, mode }) + Ok(DifferenceSettings { + largest_index, + smallest_index, + increment, + mode, + }) } /// 差值核心:internal = end - start,按设置取整;since 用 NegateRoundingMode /// 的舍入模式并在最后整体取反(不调换两端,调换会改变 0.5 边界所在的年长)。 #[allow(clippy::too_many_arguments)] fn difference_core( - vm: &mut H, - start: (i128, i128, i128), - start_time_ns: i128, - end: (i128, i128, i128), - end_time_ns: i128, - settings: DifferenceSettings, - since: bool, + vm: &mut H, start: (i128, i128, i128), start_time_ns: i128, end: (i128, i128, i128), end_time_ns: i128, + settings: DifferenceSettings, since: bool, ) -> NativeResult { - let DifferenceSettings { largest_index, smallest_index, increment, mut mode } = settings; + let DifferenceSettings { + largest_index, + smallest_index, + increment, + mut mode, + } = settings; if since { mode = match mode { InstantRoundingMode::Ceil => InstantRoundingMode::Floor, @@ -4381,7 +4354,6 @@ pub fn plain_date_time_since(vm: &mut H, args: &[u8]) -> NativeResult plain_date_time_difference(vm, args, true) } - /// `Temporal.PlainDateTime.prototype.add(durationLike, options)`。 pub fn plain_date_time_add(vm: &mut H, args: &[u8]) -> NativeResult { plain_date_time_apply_duration(vm, args, 1) @@ -4470,7 +4442,6 @@ fn date_like_ymd(vm: &mut H, val: JsValue) -> Result<(i32, u32, u32), Ok(ymd) } - /// `Temporal.PlainDate.prototype.dayOfWeek` getter:ISO 周几(周一 1 … 周日 7)。 pub fn plain_date_day_of_week(vm: &mut H, args: &[u8]) -> NativeResult { let date = match plain_date_naive(vm, args) { @@ -4719,7 +4690,6 @@ fn add_signed_months(date: NaiveDate, months: i64) -> Option { NaiveDate::from_ymd_opt(year, month, day) } - /// `Temporal.PlainDate.prototype.until(other, options)`:date-only 单位 /// (year/month/week/day)差值 + 舍入语义。 pub fn plain_date_until(vm: &mut H, args: &[u8]) -> NativeResult { diff --git a/crates/oxide_builtins/tests/builtins_json_tests.rs b/crates/oxide_builtins/tests/builtins_json_tests.rs index 27ebac5..e0ad381 100644 --- a/crates/oxide_builtins/tests/builtins_json_tests.rs +++ b/crates/oxide_builtins/tests/builtins_json_tests.rs @@ -44,7 +44,8 @@ fn replacer_function_skip_property() { #[test] fn replacer_function_array_null() { - let (_vm, result) = eval(r#"JSON.stringify([1,2,3], function(k,v){if(k==='1')return undefined;return v})"#).unwrap(); + let (_vm, result) = + eval(r#"JSON.stringify([1,2,3], function(k,v){if(k==='1')return undefined;return v})"#).unwrap(); assert_eq!(stringify_val(&result), "[1,null,3]"); } diff --git a/crates/oxide_cli/src/bench/js_stress.rs b/crates/oxide_cli/src/bench/js_stress.rs index 5468d8c..ebe3065 100644 --- a/crates/oxide_cli/src/bench/js_stress.rs +++ b/crates/oxide_cli/src/bench/js_stress.rs @@ -191,4 +191,3 @@ fn average_metrics(metrics: &[MetricCollection]) -> MetricCollection { ic_misses: (metrics.iter().map(|m| m.ic_misses as f64).sum::() / n) as u64, } } - diff --git a/crates/oxide_compiler/src/hash/mod.rs b/crates/oxide_compiler/src/hash/mod.rs index 0c481a2..0cf3734 100644 --- a/crates/oxide_compiler/src/hash/mod.rs +++ b/crates/oxide_compiler/src/hash/mod.rs @@ -5,9 +5,9 @@ //! `compiled_module_hash` 纳入绑定名(精确匹配避免错误复用)。 use oxide_parser::{ - ArrayExpressionElement, BindingPattern, ChainElement, Class, ClassElement, Declaration, ExportDefaultDeclarationKind, - Expression, ForStatementInit, ForStatementLeft, Function, ImportDeclarationSpecifier, ModuleExportName, - ObjectPropertyKind, PropertyKey, SimpleAssignmentTarget, Statement, + ArrayExpressionElement, BindingPattern, ChainElement, Class, ClassElement, Declaration, + ExportDefaultDeclarationKind, Expression, ForStatementInit, ForStatementLeft, Function, ImportDeclarationSpecifier, + ModuleExportName, ObjectPropertyKind, PropertyKey, SimpleAssignmentTarget, Statement, }; use std::hash::Hash; diff --git a/crates/oxide_compiler/src/hash/statement.rs b/crates/oxide_compiler/src/hash/statement.rs index 69a570a..0fc3c69 100644 --- a/crates/oxide_compiler/src/hash/statement.rs +++ b/crates/oxide_compiler/src/hash/statement.rs @@ -193,9 +193,7 @@ fn hash_for_statement(fr: &oxide_parser::ForStatement<'_>, h: &mut rustc_hash::F hash_statement(&fr.body, h, include_binding_names); } -fn hash_function_declaration( - fd: &Function<'_>, h: &mut rustc_hash::FxHasher, include_binding_names: bool, -) { +fn hash_function_declaration(fd: &Function<'_>, h: &mut rustc_hash::FxHasher, include_binding_names: bool) { if include_binding_names { if let Some(id) = &fd.id { id.name.as_str().hash(h); diff --git a/crates/oxide_compiler/tests/hash_collision_tests.rs b/crates/oxide_compiler/tests/hash_collision_tests.rs index fecba68..84f2d2c 100644 --- a/crates/oxide_compiler/tests/hash_collision_tests.rs +++ b/crates/oxide_compiler/tests/hash_collision_tests.rs @@ -60,7 +60,11 @@ fn await_yield_plain_distinguished() { fn object_literals_distinguished() { assert_ne!(compiled("var o = { a: 1 }"), compiled("var o = { a: 2 }")); assert_ne!(compiled("var o = { a: 1 }"), compiled("var o = { b: 1 }")); - assert_ne!(compiled("var o = { a: 1 }"), compiled("var o = { a: 1, b: 2 }"), "property count must be hashed"); + assert_ne!( + compiled("var o = { a: 1 }"), + compiled("var o = { a: 1, b: 2 }"), + "property count must be hashed" + ); } #[test] diff --git a/crates/oxide_emit/src/class/method.rs b/crates/oxide_emit/src/class/method.rs index eaea220..7682086 100644 --- a/crates/oxide_emit/src/class/method.rs +++ b/crates/oxide_emit/src/class/method.rs @@ -25,7 +25,14 @@ impl Emitter { } if matches!(method.key, PropertyKey::PrivateIdentifier(_)) { let home_reg = if method.r#static { ctor_reg } else { proto_reg }; - self.emit_private_method_init(Operand::Reg(home_reg), method, Operand::Reg(home_reg), self_binding, class_self_cell, ctx)?; + self.emit_private_method_init( + Operand::Reg(home_reg), + method, + Operand::Reg(home_reg), + self_binding, + class_self_cell, + ctx, + )?; continue; } let home_reg = if method.r#static { ctor_reg } else { proto_reg }; @@ -39,8 +46,14 @@ impl Emitter { } else { self.class_property_name(&method.key)? }; - let accessor_reg = - self.emit_class_method_function(method, &method_name, Operand::Reg(home_reg), ctx, self_binding, class_self_cell)?; + let accessor_reg = self.emit_class_method_function( + method, + &method_name, + Operand::Reg(home_reg), + ctx, + self_binding, + class_self_cell, + )?; match method.kind { MethodDefinitionKind::Method => { // class 方法按规范为非枚举数据属性(DefineMethod:writable/configurable,enumerable=false)。 diff --git a/crates/oxide_emit/src/closure.rs b/crates/oxide_emit/src/closure.rs index 214d70f..c01fe47 100644 --- a/crates/oxide_emit/src/closure.rs +++ b/crates/oxide_emit/src/closure.rs @@ -410,8 +410,7 @@ impl Emitter { } } oxide_parser::Declaration::FunctionDeclaration(fd) => { - let body: &[Statement] = - fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]); + let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]); let mut inner = shadow.clone(); inner.extend(self.collect_fn_param_names(&fd.params)); inner.extend(self.collect_own_binding_names(&[], body)); diff --git a/crates/oxide_emit/src/expr/await_expr.rs b/crates/oxide_emit/src/expr/await_expr.rs index c236718..f964021 100644 --- a/crates/oxide_emit/src/expr/await_expr.rs +++ b/crates/oxide_emit/src/expr/await_expr.rs @@ -7,9 +7,7 @@ use oxide_ir::operand::Operand; use oxide_parser::AwaitExpression; impl Emitter { - pub(crate) fn emit_await_expression( - &self, ae: &AwaitExpression, ctx: &mut CompileCtx, - ) -> Result { + pub(crate) fn emit_await_expression(&self, ae: &AwaitExpression, ctx: &mut CompileCtx) -> Result { // 求值被等待的值(`await undefined` 时求值 undefined)。 let value_reg = self.emit_expression(&ae.argument, ctx)?; ctx.inst(Inst::await_expr(Operand::Reg(value_reg))); diff --git a/crates/oxide_emit/src/expr/function/mod.rs b/crates/oxide_emit/src/expr/function/mod.rs index 761ae97..712a5e4 100644 --- a/crates/oxide_emit/src/expr/function/mod.rs +++ b/crates/oxide_emit/src/expr/function/mod.rs @@ -55,7 +55,9 @@ impl Emitter { Ok(r) } - pub(crate) fn emit_function_expression(&self, fe: &oxide_parser::Function, ctx: &mut CompileCtx) -> Result { + pub(crate) fn emit_function_expression( + &self, fe: &oxide_parser::Function, ctx: &mut CompileCtx, + ) -> Result { // 函数表达式:编译函数体为子模块,create_closure 实例化闭包 let mut param_names = Vec::new(); for (idx, param) in fe.params.items.iter().enumerate() { diff --git a/crates/oxide_emit/src/lib.rs b/crates/oxide_emit/src/lib.rs index 30e16d6..c28fc29 100644 --- a/crates/oxide_emit/src/lib.rs +++ b/crates/oxide_emit/src/lib.rs @@ -7,11 +7,11 @@ pub mod class; pub mod closure; -pub mod module; pub mod emit; -mod emit_log; pub mod emit_ctx; +mod emit_log; pub mod expr; +pub mod module; pub mod prepass; pub mod shared; pub mod stmt; diff --git a/crates/oxide_emit/src/prepass.rs b/crates/oxide_emit/src/prepass.rs index fd2a0c5..fb65cb7 100644 --- a/crates/oxide_emit/src/prepass.rs +++ b/crates/oxide_emit/src/prepass.rs @@ -5,7 +5,9 @@ //! 支持提升语义。 use crate::{CompileCtx, Emitter}; -use oxide_parser::{BindingPattern, Declaration, ExportDefaultDeclarationKind, Expression, Statement, VariableDeclarationKind}; +use oxide_parser::{ + BindingPattern, Declaration, ExportDefaultDeclarationKind, Expression, Statement, VariableDeclarationKind, +}; impl Emitter { /// 在临时寄存器池之前分配 builtin 槽位。 @@ -390,12 +392,8 @@ impl Emitter { for d in &decl.declarations { if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id { let reg = ctx.alloc_reg(); - let _ = ctx.declare_initialized( - bi.name.as_str(), - reg, - VariableDeclarationKind::Var, - false, - ); + let _ = + ctx.declare_initialized(bi.name.as_str(), reg, VariableDeclarationKind::Var, false); } } } @@ -547,33 +545,23 @@ impl Emitter { } } } - Statement::ExportDefaultDeclaration(exp) => { - match &exp.declaration { - ExportDefaultDeclarationKind::ClassDeclaration(cd) => { - if let Some(id) = &cd.id { - let reg = ctx.alloc_reg(); - let _ = ctx.declare_predeclared( - id.name.as_str(), - reg, - VariableDeclarationKind::Const, - true, - ); - } + Statement::ExportDefaultDeclaration(exp) => match &exp.declaration { + ExportDefaultDeclarationKind::ClassDeclaration(cd) => { + if let Some(id) = &cd.id { + let reg = ctx.alloc_reg(); + let _ = + ctx.declare_predeclared(id.name.as_str(), reg, VariableDeclarationKind::Const, true); } - ExportDefaultDeclarationKind::FunctionDeclaration(fd) => { - if let Some(id) = &fd.id { - let reg = ctx.alloc_reg(); - let _ = ctx.declare_predeclared( - id.name.as_str(), - reg, - VariableDeclarationKind::Const, - true, - ); - } - } - _ => {} } - } + ExportDefaultDeclarationKind::FunctionDeclaration(fd) => { + if let Some(id) = &fd.id { + let reg = ctx.alloc_reg(); + let _ = + ctx.declare_predeclared(id.name.as_str(), reg, VariableDeclarationKind::Const, true); + } + } + _ => {} + }, _ => {} } } diff --git a/crates/oxide_emit/src/shared/binding.rs b/crates/oxide_emit/src/shared/binding.rs index 746c5f8..110e4a2 100644 --- a/crates/oxide_emit/src/shared/binding.rs +++ b/crates/oxide_emit/src/shared/binding.rs @@ -76,12 +76,7 @@ impl Emitter { }; if let Some(&cell_idx) = ctx.captured_bindings.get(name) { let op = if fresh_cell { OpCode::MAKE_CELL_FRESH } else { OpCode::MAKE_CELL }; - ctx.inst(Inst::new( - op, - Operand::Reg(src_reg), - Operand::Imm(cell_idx as u16), - Operand::None, - )); + ctx.inst(Inst::new(op, Operand::Reg(src_reg), Operand::Imm(cell_idx as u16), Operand::None)); } else if !ctx.with_stack.is_empty() && !ctx.is_with_internal_binding(name) { // with 内 var 初始化:对象有该属性则写对象,否则写提升槽(动态解析)。 // ponytail: with 内顶层 var 不写全局对象属性,with 语句本身已是稀见用例。 @@ -131,8 +126,8 @@ impl Emitter { } pub(crate) fn emit_binding_pattern( - &self, pattern: &BindingPattern, src_reg: u32, kind: VariableDeclarationKind, is_const: bool, - fresh_cell: bool, ctx: &mut CompileCtx, + &self, pattern: &BindingPattern, src_reg: u32, kind: VariableDeclarationKind, is_const: bool, fresh_cell: bool, + ctx: &mut CompileCtx, ) -> Result<(), String> { match pattern { BindingPattern::BindingIdentifier(bi) => { diff --git a/crates/oxide_emit/src/stmt/declaration/var.rs b/crates/oxide_emit/src/stmt/declaration/var.rs index eb05533..3783427 100644 --- a/crates/oxide_emit/src/stmt/declaration/var.rs +++ b/crates/oxide_emit/src/stmt/declaration/var.rs @@ -56,14 +56,13 @@ impl Emitter { } else { // let/const 无初始化器:复用本块预声明槽位,否则新声明 // (for 头等未预声明路径)。 - let var_reg = - if let Some(reg) = ctx.scopes.symbols.consume_predeclared_slot(bi.name.as_str()) { - reg - } else { - let r = ctx.alloc_reg(); - ctx.declare(bi.name.as_str(), r, decl.kind, is_const)?; - r - }; + let var_reg = if let Some(reg) = ctx.scopes.symbols.consume_predeclared_slot(bi.name.as_str()) { + reg + } else { + let r = ctx.alloc_reg(); + ctx.declare(bi.name.as_str(), r, decl.kind, is_const)?; + r + }; var_reg }; if let Some(&cell_idx) = ctx.captured_bindings.get(bi.name.as_str()) { diff --git a/crates/oxide_ir/src/contract.rs b/crates/oxide_ir/src/contract.rs index bc44c79..1e5edc4 100644 --- a/crates/oxide_ir/src/contract.rs +++ b/crates/oxide_ir/src/contract.rs @@ -423,7 +423,9 @@ mod tests { assert!(!Inst::new(OpCode::SET_PROP, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f)); assert!(!Inst::new(OpCode::SUPER_GET_PROP, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f)); assert!(!Inst::new(OpCode::DEFINE_ACCESSOR, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f)); - assert!(!Inst::new(OpCode::DEFINE_ACCESSOR_DYNAMIC, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f)); + assert!( + !Inst::new(OpCode::DEFINE_ACCESSOR_DYNAMIC, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f) + ); assert!(!Inst::new(OpCode::DELETE_PROP_STATIC, Operand::Reg(0), Operand::Reg(0), Operand::None).is_pure(&f)); assert!(!Inst::new(OpCode::DELETE_PROP_DYNAMIC, Operand::Reg(0), Operand::None, Operand::Reg(2)).is_pure(&f)); // 调用 / 异常 / 控制流 @@ -495,48 +497,24 @@ mod tests { /// 每个 opcode 构造一条规范指令:rd/a/b 置 Reg(1/2/3),ext 按族填真实布局。 fn canonical_inst(op: OpCode) -> Inst { match op { - OpCode::CALL | OpCode::CALL_NATIVE => { - Inst::call(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 2) - } - OpCode::NEW_EXPRESSION => { - Inst::new_expression(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 2) - } + OpCode::CALL | OpCode::CALL_NATIVE => Inst::call(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 2), + OpCode::NEW_EXPRESSION => Inst::new_expression(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 2), OpCode::SUPER_CALL => Inst::super_call(Operand::Reg(1), Operand::Reg(2), 2), - OpCode::CALL_SPREAD => { - Inst::call_spread(Operand::Reg(1), Operand::Reg(2), &[5, 0x8000_0000 | 9]) - } + OpCode::CALL_SPREAD => Inst::call_spread(Operand::Reg(1), Operand::Reg(2), &[5, 0x8000_0000 | 9]), OpCode::NEW_EXPRESSION_SPREAD => { Inst::new_expression_spread(Operand::Reg(1), Operand::Reg(2), &[5, 0x8000_0000 | 9]) } - OpCode::SUPER_CALL_SPREAD => { - Inst::super_call_spread(Operand::Reg(1), &[5, 0x8000_0000 | 9]) - } + OpCode::SUPER_CALL_SPREAD => Inst::super_call_spread(Operand::Reg(1), &[5, 0x8000_0000 | 9]), OpCode::IC_GET_PROP => Inst::ic_get(Operand::Reg(1), Operand::Reg(2)), OpCode::IC_SET_PROP => Inst::ic_set(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)), - OpCode::MEMBER_INC => { - Inst::member_inc(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) - } - OpCode::MEMBER_DEC => { - Inst::member_dec(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) - } - OpCode::COMPOUND_MEMBER_ADD => { - Inst::compound_member_add(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) - } - OpCode::COMPOUND_MEMBER_SUB => { - Inst::compound_member_sub(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) - } - OpCode::COMPOUND_MEMBER_MUL => { - Inst::compound_member_mul(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) - } - OpCode::COMPOUND_MEMBER_DIV => { - Inst::compound_member_div(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) - } - OpCode::COMPOUND_MEMBER_MOD => { - Inst::compound_member_mod(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) - } - OpCode::COMPOUND_MEMBER_EXP => { - Inst::compound_member_exp(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) - } + OpCode::MEMBER_INC => Inst::member_inc(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)), + OpCode::MEMBER_DEC => Inst::member_dec(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)), + OpCode::COMPOUND_MEMBER_ADD => Inst::compound_member_add(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)), + OpCode::COMPOUND_MEMBER_SUB => Inst::compound_member_sub(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)), + OpCode::COMPOUND_MEMBER_MUL => Inst::compound_member_mul(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)), + OpCode::COMPOUND_MEMBER_DIV => Inst::compound_member_div(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)), + OpCode::COMPOUND_MEMBER_MOD => Inst::compound_member_mod(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)), + OpCode::COMPOUND_MEMBER_EXP => Inst::compound_member_exp(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)), OpCode::COMPOUND_MEMBER_BIT_AND => { Inst::compound_member_bit_and(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) } @@ -546,35 +524,23 @@ mod tests { OpCode::COMPOUND_MEMBER_BIT_XOR => { Inst::compound_member_bit_xor(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) } - OpCode::COMPOUND_MEMBER_SHL => { - Inst::compound_member_shl(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) - } - OpCode::COMPOUND_MEMBER_SHR => { - Inst::compound_member_shr(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) - } + OpCode::COMPOUND_MEMBER_SHL => Inst::compound_member_shl(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)), + OpCode::COMPOUND_MEMBER_SHR => Inst::compound_member_shr(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)), OpCode::COMPOUND_MEMBER_USHR => { Inst::compound_member_ushr(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3)) } OpCode::TEMPLATE_STR => Inst::template_str(Operand::Reg(1), 2, 10, &[0x1234, 0x8000_0000 | 5]), OpCode::CONCAT_N => Inst::concat_n(Operand::Reg(1), &[2, 5, 9]), - OpCode::GET_PRIVATE => { - Inst::get_private(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 7, 99) - } - OpCode::SET_PRIVATE => { - Inst::set_private(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 7, 99) - } - OpCode::INIT_PRIVATE => { - Inst::init_private(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), true) - } + OpCode::GET_PRIVATE => Inst::get_private(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 7, 99), + OpCode::SET_PRIVATE => Inst::set_private(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 7, 99), + OpCode::INIT_PRIVATE => Inst::init_private(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), true), OpCode::PRIVATE_BRAND_IN => { Inst::private_brand_in(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 7, 99) } OpCode::SPILL => Inst::inst_spill(Operand::Reg(1), 42), OpCode::UNSPILL => Inst::inst_unspill(Operand::Reg(1), 42), OpCode::REST_OBJECT => Inst::rest_object(Operand::Reg(1), Operand::Reg(2), 7, None), - OpCode::DEFINE_ACCESSOR => { - Inst::define_accessor(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 42) - } + OpCode::DEFINE_ACCESSOR => Inst::define_accessor(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 42), OpCode::DEFINE_ACCESSOR_DYNAMIC => { Inst::define_accessor_dynamic(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 7) } @@ -703,7 +669,12 @@ mod tests { ); assert_contract(OpCode::FOR_AWAIT_OF_DONE, Some(1), &[2], false); // 自增/自减:def=rd, uses=[rd] - assert_group(&[OpCode::INC_PRE, OpCode::INC_POST, OpCode::DEC_PRE, OpCode::DEC_POST], Some(1), &[1], false); + assert_group( + &[OpCode::INC_PRE, OpCode::INC_POST, OpCode::DEC_PRE, OpCode::DEC_POST], + Some(1), + &[1], + false, + ); // 占位 opcode:def=rd 保守,不可删 assert_group( &[ diff --git a/crates/oxide_liveness/tests/smoke.rs b/crates/oxide_liveness/tests/smoke.rs index 09a6750..ef5fcd0 100644 --- a/crates/oxide_liveness/tests/smoke.rs +++ b/crates/oxide_liveness/tests/smoke.rs @@ -40,7 +40,10 @@ fn smoke_try_catch() { let (info, cfg, _) = run_liveness("function x() {} function y(e) {} function f() { try { x(); } catch (e) { y(e); } } f()"); // entry 块 liveIn 不含 reg 0(异常边 reg0 截断在真实产物上成立) - assert!(!oxide_liveness::bitset_get(&info.block_live_in[cfg.entry], 0), "entry 块 liveIn 不得含 reg0"); + assert!( + !oxide_liveness::bitset_get(&info.block_live_in[cfg.entry], 0), + "entry 块 liveIn 不得含 reg0" + ); } #[test] diff --git a/crates/oxide_test262/src/main.rs b/crates/oxide_test262/src/main.rs index 6417d70..94553e7 100644 --- a/crates/oxide_test262/src/main.rs +++ b/crates/oxide_test262/src/main.rs @@ -464,8 +464,8 @@ impl oxide_emit::module::ModuleSourceLoader for Test262ModuleLoader { let canonical = full .canonicalize() .map_err(|e| format!("cannot resolve module {specifier}: {e}"))?; - let content = std::fs::read_to_string(&canonical) - .map_err(|e| format!("cannot read module {specifier}: {e}"))?; + let content = + std::fs::read_to_string(&canonical).map_err(|e| format!("cannot read module {specifier}: {e}"))?; Ok(ResolvedModule { source: content, path: canonical.to_string_lossy().to_string(), @@ -607,10 +607,7 @@ fn judge_async_result( return TestResult::fail( path.to_path_buf(), dur, - format!( - "expected runtime error ({}), got: async complete", - neg.error_type - ), + format!("expected runtime error ({}), got: async complete", neg.error_type), ); } return TestResult::pass(path.to_path_buf(), dur, "async ok"); diff --git a/crates/oxide_vm/src/bindings/bind_global.rs b/crates/oxide_vm/src/bindings/bind_global.rs index a926669..7d34e71 100644 --- a/crates/oxide_vm/src/bindings/bind_global.rs +++ b/crates/oxide_vm/src/bindings/bind_global.rs @@ -30,7 +30,11 @@ pub fn bind_global(core: &Arc, session: &KernelSession, global: &mut ("__moduleObject", oxide_builtins::module::module_object:: as *const (), 0), ("__moduleSet", oxide_builtins::module::module_set:: as *const (), 3), ("__moduleGet", oxide_builtins::module::module_get:: as *const (), 2), - ("__moduleLinkGet", oxide_builtins::module::module_link_get:: as *const (), 2), + ( + "__moduleLinkGet", + oxide_builtins::module::module_link_get:: as *const (), + 2, + ), ("__moduleStar", oxide_builtins::module::module_star:: as *const (), 2), ("__moduleSeal", oxide_builtins::module::module_seal:: as *const (), 1), ("__moduleEval", oxide_builtins::module::module_eval:: as *const (), 1), diff --git a/crates/oxide_vm/src/bindings/bind_temporal.rs b/crates/oxide_vm/src/bindings/bind_temporal.rs index 8f5447e..7102536 100644 --- a/crates/oxide_vm/src/bindings/bind_temporal.rs +++ b/crates/oxide_vm/src/bindings/bind_temporal.rs @@ -550,26 +550,14 @@ pub fn bind_temporal(core: &Arc, session: &KernelSession, global: &m oxide_builtins::temporal::plain_date_time_to_json:: as *const (), 0, ), - ( - "add", - oxide_builtins::temporal::plain_date_time_add:: as *const (), - 1, - ), + ("add", oxide_builtins::temporal::plain_date_time_add:: as *const (), 1), ( "subtract", oxide_builtins::temporal::plain_date_time_subtract:: as *const (), 1, ), - ( - "until", - oxide_builtins::temporal::plain_date_time_until:: as *const (), - 1, - ), - ( - "since", - oxide_builtins::temporal::plain_date_time_since:: as *const (), - 1, - ), + ("until", oxide_builtins::temporal::plain_date_time_until:: as *const (), 1), + ("since", oxide_builtins::temporal::plain_date_time_since:: as *const (), 1), ( "equals", oxide_builtins::temporal::plain_date_time_equals:: as *const (), diff --git a/crates/oxide_vm/src/dispatch/arithmetic.rs b/crates/oxide_vm/src/dispatch/arithmetic.rs index 1992dc4..9261515 100644 --- a/crates/oxide_vm/src/dispatch/arithmetic.rs +++ b/crates/oxide_vm/src/dispatch/arithmetic.rs @@ -104,16 +104,8 @@ impl Vm { return self.new_string_owned(buf); } // 大链走 Cons rope:非字符串操作数先转叶子,再 O(1) 链接(文本惰性扁平化)。 - let lv = if lhs.is_string() { - lhs - } else { - self.string_leaf(lhs) - }; - let rv = if rhs.is_string() { - rhs - } else { - self.string_leaf(rhs) - }; + let lv = if lhs.is_string() { lhs } else { self.string_leaf(lhs) }; + let rv = if rhs.is_string() { rhs } else { self.string_leaf(rhs) }; self.new_cons_string(lv, rv) } diff --git a/crates/oxide_vm/src/lib.rs b/crates/oxide_vm/src/lib.rs index 956f99c..28b196e 100644 --- a/crates/oxide_vm/src/lib.rs +++ b/crates/oxide_vm/src/lib.rs @@ -7,8 +7,8 @@ //! 核心入口为 [`vm::Vm`];`VmPool` 负责 VM 实例的复用;`session_gc` 提供 //! session 内存回收;`bindings` 把内置对象绑定到每个 session 的 global 上。 -mod async_func; mod async_from_sync; +mod async_func; mod async_generator; /// 内置对象绑定模块:向 session 的 global 对象安装 Object/Array/... 及各原型。 pub mod bindings; diff --git a/crates/oxide_vm/tests/builtins_function_tests.rs b/crates/oxide_vm/tests/builtins_function_tests.rs index 329f13b..5326729 100644 --- a/crates/oxide_vm/tests/builtins_function_tests.rs +++ b/crates/oxide_vm/tests/builtins_function_tests.rs @@ -193,8 +193,16 @@ fn function_symbol_has_instance_bound() { fn function_symbol_has_instance_poisoned_prototype_throws() { let mut vm = Vm::new(); // 可调用但 prototype 非对象 → TypeError(OrdinaryHasInstance 唯一抛错点)。 - let err = eval(&mut vm, "var f = function(){}; f.prototype = 1; try { f[Symbol.hasInstance]({}) } catch (e) { e }").unwrap(); - let name = eval(&mut vm, "var f = function(){}; f.prototype = null; try { f[Symbol.hasInstance]({}) } catch (e) { e.name }").unwrap(); + let err = eval( + &mut vm, + "var f = function(){}; f.prototype = 1; try { f[Symbol.hasInstance]({}) } catch (e) { e }", + ) + .unwrap(); + let name = eval( + &mut vm, + "var f = function(){}; f.prototype = null; try { f[Symbol.hasInstance]({}) } catch (e) { e.name }", + ) + .unwrap(); let _ = err; assert_eq!(vm.lookup_str(name).unwrap_or_default(), "TypeError"); } @@ -208,7 +216,10 @@ fn bound_function_construct_semantics() { ("function C(v){ this.v = v; } var B = C.bind({}, 1); new B(2).v", 1.0), ("function C(a, b){ this.s = a + b; } var B = C.bind(null, 2); new B(3).s", 5.0), // 多层 bound 链:绑定实参按 内层先、外层后 拼接。 - ("function C(v){ this.v = v; } var B = C.bind({}, 1); var D = B.bind({}, 2); new D().v", 1.0), + ( + "function C(v){ this.v = v; } var B = C.bind({}, 1); var D = B.bind({}, 2); new D().v", + 1.0, + ), // native 构造器 target。 ("var arr = Array.bind(null); new arr(3).length", 3.0), ]; diff --git a/crates/oxide_vm/tests/builtins_symbol_tests.rs b/crates/oxide_vm/tests/builtins_symbol_tests.rs index af058bd..84d3a1b 100644 --- a/crates/oxide_vm/tests/builtins_symbol_tests.rs +++ b/crates/oxide_vm/tests/builtins_symbol_tests.rs @@ -211,7 +211,8 @@ fn has_instance_preserves_ordinary_has_instance() { #[test] fn symbol_keys_stay_distinct() { let mut vm = Vm::new(); - let result = eval(&mut vm, "var s1=Symbol('a'), s2=Symbol('b'); var o={}; o[s1]=1; o[s2]=2; [o[s1],o[s2]]").unwrap(); + let result = + eval(&mut vm, "var s1=Symbol('a'), s2=Symbol('b'); var o={}; o[s1]=1; o[s2]=2; [o[s1],o[s2]]").unwrap(); let arr = unsafe { &*result.as_js_object_ptr() }; assert_eq!(arr.get_prop_at(0).as_int(), 1); assert_eq!(arr.get_prop_at(1).as_int(), 2); @@ -248,7 +249,11 @@ fn symbol_keys_excluded_from_for_in() { #[test] fn get_own_property_symbols_roundtrip() { let mut vm = Vm::new(); - let result = eval(&mut vm, "var s=Symbol('x'); var o={}; o[s]=7; var k=Object.getOwnPropertySymbols(o)[0]; o[k]").unwrap(); + let result = eval( + &mut vm, + "var s=Symbol('x'); var o={}; o[s]=7; var k=Object.getOwnPropertySymbols(o)[0]; o[k]", + ) + .unwrap(); assert_eq!(result.as_int(), 7); } diff --git a/crates/oxide_vm/tests/gc_runtime_tests.rs b/crates/oxide_vm/tests/gc_runtime_tests.rs index f48ce01..5b835c2 100644 --- a/crates/oxide_vm/tests/gc_runtime_tests.rs +++ b/crates/oxide_vm/tests/gc_runtime_tests.rs @@ -67,9 +67,8 @@ fn reset_preserves_session_strings_after_runtime_gc() { #[test] fn strings_only_then_reset_keeps_global_subtree_strings() { let mut vm = vm_with_threshold(4096); - let first = compile( - "globalThis.kept = { s: 'he' + 'llo' }; var t; for (var i = 0; i < 500000; i++) { t = 'x' + i; } 0", - ); + let first = + compile("globalThis.kept = { s: 'he' + 'llo' }; var t; for (var i = 0; i < 500000; i++) { t = 'x' + i; } 0"); vm.run(&first).expect("run1"); assert!(vm.session_gc_stats().total_collections > 0, "run1 应触发执行期字符串 GC"); vm.reset(); @@ -92,12 +91,7 @@ fn regexp_exec_strings_survive_runtime_gc() { ); let result = vm.run(&module).expect("run"); let text = vm.lookup_str(result).expect("exec 结果应为字符串").to_string(); - let expected = format!( - "{}|{}|{}", - "a".repeat(500) + &"b".repeat(500), - "a".repeat(500), - "b".repeat(500) - ); + let expected = format!("{}|{}|{}", "a".repeat(500) + &"b".repeat(500), "a".repeat(500), "b".repeat(500)); assert_eq!(text, expected); assert!(vm.session_gc_stats().total_collections > 0, "执行期应触发字符串 GC"); } diff --git a/crates/oxide_vm/tests/generator_yield_star_tests.rs b/crates/oxide_vm/tests/generator_yield_star_tests.rs index 21258ef..643b715 100644 --- a/crates/oxide_vm/tests/generator_yield_star_tests.rs +++ b/crates/oxide_vm/tests/generator_yield_star_tests.rs @@ -108,4 +108,3 @@ fn yield_star_inner_without_return() { "1,9,true" ); } - diff --git a/crates/oxide_vm/tests/object_tests.rs b/crates/oxide_vm/tests/object_tests.rs index 623fca3..cb6c742 100644 --- a/crates/oxide_vm/tests/object_tests.rs +++ b/crates/oxide_vm/tests/object_tests.rs @@ -125,10 +125,7 @@ fn eval_computed_compound_assign_getter_order() { fn eval_computed_compound_assign_read_error_skips_rhs() { // 读取抛错时 RHS 不求值,其副作用不泄漏。 assert_eq!(eval("var h={get a(){throw 1}}; try{h[\"a\"]+=1}catch(e){e}"), "1"); - assert_eq!( - eval("var side=0; var h={get a(){throw 1}}; try{h[\"a\"]+=(side=99)}catch(e){} side"), - "0" - ); + assert_eq!(eval("var side=0; var h={get a(){throw 1}}; try{h[\"a\"]+=(side=99)}catch(e){} side"), "0"); } #[test]