chore: 全仓 rustfmt 格式化归拢

This commit is contained in:
2026-08-16 12:50:36 +08:00
parent 4572ecffaa
commit 5df04a8e58
28 changed files with 166 additions and 247 deletions
+2 -2
View File
@@ -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 的定点读写视图)。
+2 -10
View File
@@ -25,12 +25,7 @@ pub fn module_object<H: VmHost>(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<H: VmHost>(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),
+28 -58
View File
@@ -455,7 +455,8 @@ fn instant_like_epoch_ns<H: VmHost>(vm: &mut H, value: JsValue) -> Result<i128,
}
// 对象按规范走 ToString -> 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<H: VmHost>(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<H: VmHost>(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<H: VmHost>(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<H: VmHost>(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<H: VmHost>(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<H: VmHost>(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<H: VmHost>(
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<usize> {
/// roundingIncrement → roundingMode → smallestUnit。date_only 时单位限定
/// year/month/week/day,smallestUnit 缺省 "day"(含时间时缺省 "nanosecond")。
fn parse_difference_settings<H: VmHost>(
vm: &mut H,
options_value: JsValue,
date_only: bool,
vm: &mut H, options_value: JsValue, date_only: bool,
) -> Result<DifferenceSettings, JsValue> {
let unit_index = |value: &str| -> Option<usize> {
if date_only {
@@ -4178,22 +4146,27 @@ fn parse_difference_settings<H: VmHost>(
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<H: VmHost>(
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<H: VmHost>(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<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
plain_date_time_apply_duration(vm, args, 1)
@@ -4470,7 +4442,6 @@ fn date_like_ymd<H: VmHost>(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<H: VmHost>(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> {
NaiveDate::from_ymd_opt(year, month, day)
}
/// `Temporal.PlainDate.prototype.until(other, options)`:date-only 单位
/// (year/month/week/day)差值 + 舍入语义。
pub fn plain_date_until<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
@@ -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]");
}
-1
View File
@@ -191,4 +191,3 @@ fn average_metrics(metrics: &[MetricCollection]) -> MetricCollection {
ic_misses: (metrics.iter().map(|m| m.ic_misses as f64).sum::<f64>() / n) as u64,
}
}
+3 -3
View File
@@ -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;
+1 -3
View File
@@ -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);
@@ -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]
+16 -3
View File
@@ -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)。
+1 -2
View File
@@ -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));
+1 -3
View File
@@ -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<u32, String> {
pub(crate) fn emit_await_expression(&self, ae: &AwaitExpression, ctx: &mut CompileCtx) -> Result<u32, String> {
// 求值被等待的值(`await undefined` 时求值 undefined)。
let value_reg = self.emit_expression(&ae.argument, ctx)?;
ctx.inst(Inst::await_expr(Operand::Reg(value_reg)));
+3 -1
View File
@@ -55,7 +55,9 @@ impl Emitter {
Ok(r)
}
pub(crate) fn emit_function_expression(&self, fe: &oxide_parser::Function, ctx: &mut CompileCtx) -> Result<u32, String> {
pub(crate) fn emit_function_expression(
&self, fe: &oxide_parser::Function, ctx: &mut CompileCtx,
) -> Result<u32, String> {
// 函数表达式:编译函数体为子模块,create_closure 实例化闭包
let mut param_names = Vec::new();
for (idx, param) in fe.params.items.iter().enumerate() {
+2 -2
View File
@@ -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;
+20 -32
View File
@@ -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);
}
}
_ => {}
},
_ => {}
}
}
+3 -8
View File
@@ -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) => {
@@ -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()) {
+27 -56
View File
@@ -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(
&[
+4 -1
View File
@@ -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]
+3 -6
View File
@@ -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");
+5 -1
View File
@@ -30,7 +30,11 @@ pub fn bind_global(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
("__moduleObject", oxide_builtins::module::module_object::<crate::vm::Vm> as *const (), 0),
("__moduleSet", oxide_builtins::module::module_set::<crate::vm::Vm> as *const (), 3),
("__moduleGet", oxide_builtins::module::module_get::<crate::vm::Vm> as *const (), 2),
("__moduleLinkGet", oxide_builtins::module::module_link_get::<crate::vm::Vm> as *const (), 2),
(
"__moduleLinkGet",
oxide_builtins::module::module_link_get::<crate::vm::Vm> as *const (),
2,
),
("__moduleStar", oxide_builtins::module::module_star::<crate::vm::Vm> as *const (), 2),
("__moduleSeal", oxide_builtins::module::module_seal::<crate::vm::Vm> as *const (), 1),
("__moduleEval", oxide_builtins::module::module_eval::<crate::vm::Vm> as *const (), 1),
+3 -15
View File
@@ -550,26 +550,14 @@ pub fn bind_temporal(core: &Arc<KernelCore>, session: &KernelSession, global: &m
oxide_builtins::temporal::plain_date_time_to_json::<crate::vm::Vm> as *const (),
0,
),
(
"add",
oxide_builtins::temporal::plain_date_time_add::<crate::vm::Vm> as *const (),
1,
),
("add", oxide_builtins::temporal::plain_date_time_add::<crate::vm::Vm> as *const (), 1),
(
"subtract",
oxide_builtins::temporal::plain_date_time_subtract::<crate::vm::Vm> as *const (),
1,
),
(
"until",
oxide_builtins::temporal::plain_date_time_until::<crate::vm::Vm> as *const (),
1,
),
(
"since",
oxide_builtins::temporal::plain_date_time_since::<crate::vm::Vm> as *const (),
1,
),
("until", oxide_builtins::temporal::plain_date_time_until::<crate::vm::Vm> as *const (), 1),
("since", oxide_builtins::temporal::plain_date_time_since::<crate::vm::Vm> as *const (), 1),
(
"equals",
oxide_builtins::temporal::plain_date_time_equals::<crate::vm::Vm> as *const (),
+2 -10
View File
@@ -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)
}
+1 -1
View File
@@ -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;
@@ -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),
];
@@ -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);
}
+3 -9
View File
@@ -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");
}
@@ -108,4 +108,3 @@ fn yield_star_inner_without_return() {
"1,9,true"
);
}
+1 -4
View File
@@ -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]