mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: using 声明登记释放栈指令与 GC 根
This commit is contained in:
Generated
+19
-19
@@ -1160,7 +1160,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1226,7 +1226,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1235,7 +1235,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1255,7 +1255,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1269,7 +1269,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1284,7 +1284,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_engine"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1296,7 +1296,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1305,7 +1305,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1319,7 +1319,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1331,7 +1331,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1340,7 +1340,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1355,7 +1355,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1371,7 +1371,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1384,7 +1384,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1402,7 +1402,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1415,7 +1415,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.13.14"
|
||||
version = "0.13.15"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -297,6 +297,12 @@ define_opcodes! {
|
||||
FOR_IN_DONE = 0x2B => "FOR_IN_DONE",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [],
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
// using/await using 声明登记:rd = 资源值寄存器,a = 释放提示(0 = 同步、1 = 异步)。
|
||||
// 无寄存器 def(值压入 VM 释放栈,释放时机由作用域出口点决定);
|
||||
// pure = false 防 DCE 删除压栈副作用。
|
||||
DISPOSE_REGISTER = 0x2C => "DISPOSE_REGISTER",
|
||||
def = None, uses = [SlotSpec::Slot(Slot::Rd)],
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
FOR_IN_CLEANUP = 0x2D => "FOR_IN_CLEANUP",
|
||||
def = None, uses = [],
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
|
||||
@@ -43,6 +43,17 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
}
|
||||
// using/await using 声明登记:把资源值压入 VM 释放栈(释放时机由
|
||||
// 作用域出口点决定,本指令只登记)。a 槽为释放提示:0 = 同步、1 = 异步。
|
||||
if matches!(decl.kind, VariableDeclarationKind::Using | VariableDeclarationKind::AwaitUsing) {
|
||||
let hint = u16::from(matches!(decl.kind, VariableDeclarationKind::AwaitUsing));
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::DISPOSE_REGISTER,
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Imm(hint),
|
||||
Operand::None,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
let BindingPattern::BindingIdentifier(bi) = &d.id else {
|
||||
return Err("destructuring declaration requires an initializer".into());
|
||||
|
||||
@@ -286,6 +286,9 @@ impl Vm {
|
||||
OpCode::MAKE_CELL_FRESH => {
|
||||
self.dispatch_make_cell_fresh(rd, instr)?;
|
||||
}
|
||||
OpCode::DISPOSE_REGISTER => {
|
||||
self.dispatch_dispose_register(rd, a);
|
||||
}
|
||||
OpCode::CELL_GET => {
|
||||
self.dispatch_cell_get(rd, a, b)?;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use super::frames::Completion;
|
||||
use super::Vm;
|
||||
use crate::session_gc::SessionGc;
|
||||
|
||||
/// GC 根组来源:`for_each_value` 枚举的 25 个根组,变体顺序与根清单
|
||||
/// GC 根组来源:`for_each_value` 枚举的 26 个根组,变体顺序与根清单
|
||||
/// 的枚举顺序一致。
|
||||
///
|
||||
/// 变体下标是逐组计数数组(`SessionGc::root_counts`)的下标;`COUNT` 与
|
||||
@@ -40,11 +40,12 @@ pub(crate) enum RootGroup {
|
||||
ForInIters,
|
||||
Global,
|
||||
WorkerObjects,
|
||||
DisposeStack,
|
||||
}
|
||||
|
||||
impl RootGroup {
|
||||
/// 根组总数(与变体数同源,绑定逐组计数数组的长度)。
|
||||
pub const COUNT: usize = 25;
|
||||
pub const COUNT: usize = 26;
|
||||
}
|
||||
|
||||
impl Vm {
|
||||
@@ -52,7 +53,7 @@ impl Vm {
|
||||
/// 覆盖执行核心的全部 JsValue 持有点:regs/帧/各栈段/cell/在途异常与完成/
|
||||
/// 挂起信号/迭代器/微任务/global/Worker 对象注册表。
|
||||
///
|
||||
/// 闭包接收根组来源(`RootGroup`)与根值:组是枚举顺序中的 25 根组之一,
|
||||
/// 闭包接收根组来源(`RootGroup`)与根值:组是枚举顺序中的 26 根组之一,
|
||||
/// 调用方按组计数(如 `SessionGc` 的逐组计数)。
|
||||
pub(crate) fn for_each_value(&self, mut f: impl FnMut(RootGroup, JsValue)) {
|
||||
for value in &self.regs {
|
||||
@@ -82,6 +83,10 @@ impl Vm {
|
||||
for &v in &self.spill_stack {
|
||||
f(RootGroup::SpillStack, v);
|
||||
}
|
||||
// 释放栈持 using 声明的资源值:漏根 → sweep 释放 → 释放点解引用悬垂。
|
||||
for &v in &self.dispose_stack {
|
||||
f(RootGroup::DisposeStack, v);
|
||||
}
|
||||
for cell_vec in &self.cell_stack {
|
||||
for &cell_ptr in cell_vec {
|
||||
if cell_ptr.is_null() {
|
||||
|
||||
@@ -230,6 +230,10 @@ pub struct Vm {
|
||||
/// VM 级 spill 栈。`CallFrame.spill_offset` 定位本帧区:调用子函数时从边界后分配,
|
||||
/// 帧恢复时截断到边界,子函数 spill 数据随帧丢弃。
|
||||
pub(crate) spill_stack: Vec<JsValue>,
|
||||
/// using/await using 声明的资源释放栈:DISPOSE_REGISTER 把资源值压入,
|
||||
/// 作用域出口点逆序释放(释放点由后续指令族承担)。栈内 JsValue 是 GC 根
|
||||
/// (`for_each_value` 遍历);run 边界清空,防跨 run 残留条目在下一 run 被误释放。
|
||||
pub(crate) dispose_stack: Vec<JsValue>,
|
||||
/// 本次 native 调用的 spill 溢出实参区:`spill_stack[base..base+count)`。
|
||||
/// 实参数超过寄存器窗口(253)时,窗口外的实参转存 spill 栈(GC 根),
|
||||
/// native 侧经 `VmHost::native_arg_count`/`native_arg_at` 读取。仅在一次
|
||||
|
||||
@@ -649,6 +649,18 @@ impl Vm {
|
||||
self.iters.pop_for_in();
|
||||
}
|
||||
|
||||
/// using/await using 声明登记:把资源值(rd 槽)压入释放栈。
|
||||
///
|
||||
/// a 槽是释放提示(0 = 同步、1 = 异步),登记期原样保留供释放点分派;
|
||||
/// 本指令只登记,释放时机由作用域出口点决定。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 释放栈增长(栈内 JsValue 是 GC 根,run 边界清空)。
|
||||
pub(crate) fn dispatch_dispose_register(&mut self, rd: usize, a: usize) {
|
||||
vm_trace!("DISPOSE_REGISTER rd={} hint={}", rd, a);
|
||||
self.dispose_stack.push(self.regs[rd]);
|
||||
}
|
||||
|
||||
pub(crate) fn dispatch_for_of_init(&mut self, a: usize) -> Result<(), String> {
|
||||
vm_trace!("FOR_OF_INIT r{}={:?}", a, self.regs[a]);
|
||||
let iterable = self.regs[a];
|
||||
|
||||
@@ -1143,4 +1143,23 @@ mod tests {
|
||||
vm.drain_microtasks();
|
||||
assert!(vm.job_queue.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn using_declaration_registers_dispose_stack() {
|
||||
// using 声明经 DISPOSE_REGISTER 把资源值压入释放栈;run 边界(下次 run
|
||||
// 入口)清栈,上一 run 的残留条目不得跨 run 可见。
|
||||
let mut vm = Vm::new();
|
||||
let module = Arc::new(compile("function f() { using x = { a: 1 }; } f();"));
|
||||
vm.run(&module).expect("run");
|
||||
assert_eq!(vm.dispose_stack.len(), 1, "using 声明应登记一个资源值");
|
||||
assert!(vm.dispose_stack[0].is_object(), "登记值应为资源对象");
|
||||
|
||||
// 二次 run 入口清栈后重新登记:残留条目不跨 run 存活。
|
||||
vm.run(&module).expect("run2");
|
||||
assert_eq!(vm.dispose_stack.len(), 1, "二次 run 应恰好登记一条新条目");
|
||||
|
||||
// 执行状态清空同样清释放栈。
|
||||
vm.clear_execution_state();
|
||||
assert!(vm.dispose_stack.is_empty(), "执行状态清空应清空释放栈");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +130,7 @@ impl Vm {
|
||||
saved_immutables_stack: Vec::new(),
|
||||
save_stack: Vec::new(),
|
||||
spill_stack: Vec::new(),
|
||||
dispose_stack: Vec::new(),
|
||||
native_overflow_base: 0,
|
||||
native_overflow_count: 0,
|
||||
try_stack: Vec::new(),
|
||||
@@ -291,6 +292,7 @@ impl Vm {
|
||||
saved_immutables_stack: Vec::new(),
|
||||
save_stack: Vec::new(),
|
||||
spill_stack: Vec::new(),
|
||||
dispose_stack: Vec::new(),
|
||||
native_overflow_base: 0,
|
||||
native_overflow_count: 0,
|
||||
try_stack: Vec::new(),
|
||||
@@ -515,6 +517,9 @@ impl Vm {
|
||||
self.saved_immutables_stack.clear();
|
||||
self.save_stack.clear();
|
||||
self.spill_stack.clear();
|
||||
// 释放栈条目持资源值(session 对象指针):跨 run/reset 残留会在下一 run
|
||||
// 被误释放或悬垂,随执行状态一并清空。
|
||||
self.dispose_stack.clear();
|
||||
self.native_overflow_base = 0;
|
||||
self.native_overflow_count = 0;
|
||||
// native pack 实参区上界与溢出描述符同构:仅一次 native 调用期间有效,
|
||||
|
||||
Reference in New Issue
Block a user