perf: 函数调用 bytecode 改 Arc 共享(O(1) 帧切换 + IC 写时复制)
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
//! 或由其它模块克隆复制。`Display` 输出可读的反汇编文本,供调试用。
|
||||
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::opcode::{self, OpCode};
|
||||
|
||||
@@ -47,7 +48,7 @@ pub struct UpvalueCapture {
|
||||
/// - `is_class_constructor` / `is_derived_constructor` / `needs_home_object` — 类相关;
|
||||
/// - `upvalue_captures` / `cells_needed` — 闭包捕获描述。
|
||||
pub struct CompiledModule {
|
||||
pub bytecode: Vec<opcode::Instr>,
|
||||
pub bytecode: Arc<[opcode::Instr]>,
|
||||
pub constants: Vec<Constant>,
|
||||
pub n_registers: u8,
|
||||
pub n_args: u8,
|
||||
@@ -83,7 +84,7 @@ impl CompiledModule {
|
||||
/// 构造空模块:空字节码、空常量池、零寄存器与全部标志默认关闭。
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
bytecode: Vec::new(),
|
||||
bytecode: Arc::from(Vec::new()),
|
||||
constants: Vec::new(),
|
||||
n_registers: 0,
|
||||
n_args: 0,
|
||||
|
||||
@@ -168,12 +168,12 @@ mod tests {
|
||||
fn cache_hit_debug_verifies_bytecode() {
|
||||
let forge = forge(16);
|
||||
let mut m1 = CompiledModule::new();
|
||||
m1.bytecode = vec![1, 2, 3];
|
||||
m1.bytecode = Arc::from(vec![1, 2, 3]);
|
||||
forge.insert(42, m1);
|
||||
let _ = forge
|
||||
.get_or_insert_with(42, || {
|
||||
let mut m = CompiledModule::new();
|
||||
m.bytecode = vec![4, 5, 6];
|
||||
m.bytecode = Arc::from(vec![4, 5, 6]);
|
||||
Ok(m)
|
||||
})
|
||||
.unwrap();
|
||||
@@ -183,12 +183,12 @@ mod tests {
|
||||
fn cache_hit_returns_cached_not_recompiled() {
|
||||
let forge = forge(16);
|
||||
let mut m = CompiledModule::new();
|
||||
m.bytecode = vec![1, 2, 3];
|
||||
m.bytecode = Arc::from(vec![1, 2, 3]);
|
||||
let cached = forge.insert(99, m);
|
||||
let result = forge
|
||||
.get_or_insert_with(99, || {
|
||||
let mut m = CompiledModule::new();
|
||||
m.bytecode = vec![1, 2, 3];
|
||||
m.bytecode = Arc::from(vec![1, 2, 3]);
|
||||
Ok(m)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
//! imm16 重写为对应子模块的 `flat_id`。运行时以 `flat_id` 为平表下标,闭包自足,
|
||||
//! 不再依赖调用上下文。
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use oxide_bytecode::module::CompiledModule;
|
||||
use oxide_bytecode::opcode::{self, OpCode};
|
||||
|
||||
@@ -20,7 +22,7 @@ fn assign_ids(module: &mut CompiledModule, next_id: &mut u32) {
|
||||
sub.flat_id = *next_id;
|
||||
*next_id += 1;
|
||||
}
|
||||
for instr in &mut module.bytecode {
|
||||
for instr in Arc::make_mut(&mut module.bytecode).iter_mut() {
|
||||
if opcode::opcode(*instr) == OpCode::CREATE_CLOSURE {
|
||||
let rel = opcode::imm16(*instr) as usize;
|
||||
// rel 应为 1-based 子模块下标;0 表示无引用(异常输入),按未解析处理。
|
||||
@@ -51,10 +53,10 @@ mod tests {
|
||||
#[test]
|
||||
fn flatten_assigns_global_ids_and_rewrites_closures() {
|
||||
let mut leaf = CompiledModule::new();
|
||||
leaf.bytecode = vec![opcode::encode(OpCode::CREATE_CLOSURE, 1, 1, 0)];
|
||||
leaf.bytecode = Arc::from(vec![opcode::encode(OpCode::CREATE_CLOSURE, 1, 1, 0)]);
|
||||
let mut mid = CompiledModule::new();
|
||||
mid.sub_modules = vec![leaf];
|
||||
mid.bytecode = vec![opcode::encode(OpCode::CREATE_CLOSURE, 2, 1, 0)];
|
||||
mid.bytecode = Arc::from(vec![opcode::encode(OpCode::CREATE_CLOSURE, 2, 1, 0)]);
|
||||
let mut top = module_with_closure(vec![mid]);
|
||||
|
||||
flatten_submodules(&mut top);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
//! label 用前缀和:`label_pos` 记 Inst 下标,平铺时维护 inst→instr 映射,
|
||||
//! 跳转 offset 以 Instr(含 ext 字)为单位。
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use oxide_bytecode::module::CompiledModule;
|
||||
use oxide_bytecode::opcode::{self, OpCode};
|
||||
|
||||
@@ -75,7 +77,7 @@ pub fn lower(f: &IRFunction) -> Result<CompiledModule, String> {
|
||||
}
|
||||
|
||||
Ok(CompiledModule {
|
||||
bytecode: instrs,
|
||||
bytecode: Arc::from(instrs),
|
||||
constants: f.constants.clone(),
|
||||
n_registers: f.n_registers as u8,
|
||||
n_args: f.param_layout.count as u8,
|
||||
|
||||
@@ -482,7 +482,7 @@ impl Vm {
|
||||
return Err(self.error_message_text("RangeError", "Maximum call stack size exceeded"));
|
||||
}
|
||||
|
||||
let sub_bytecode = self.sub_modules[sub_idx].bytecode.clone();
|
||||
let sub_bytecode = Arc::clone(&self.sub_modules[sub_idx].bytecode);
|
||||
let sub_n_args = self.sub_modules[sub_idx].n_args as usize;
|
||||
let sub_n_registers = self.sub_modules[sub_idx].n_registers;
|
||||
let sub_param_base = self.sub_modules[sub_idx].param_base as usize;
|
||||
|
||||
@@ -305,6 +305,7 @@ impl Vm {
|
||||
let obj = unsafe { &*obj_ptr };
|
||||
let prop_name_si = self.property_key_si(self.regs[b]);
|
||||
let (cached_shape_id, cached_slot, cached_depth) = ic_helper::read_ic_entry(&self.bytecode, &mut self.pc);
|
||||
let ic_pc = self.pc;
|
||||
if obj.has_prop_meta() {
|
||||
let val = self.ordinary_get_with_target(obj, prop_name_si, val, a as u8)?;
|
||||
if self.accessor_frame_target_reg.take().is_none() {
|
||||
@@ -322,7 +323,7 @@ impl Vm {
|
||||
prop_cache_miss();
|
||||
if template.prop_name == prop_name_si {
|
||||
if template.position < obj.prop_vec_len() as u32 {
|
||||
ic_helper::write_ic_back(&mut self.bytecode, self.pc, obj.shape_id(), template.position, 0);
|
||||
ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, obj.shape_id(), template.position, 0);
|
||||
ic_debug!(
|
||||
"IC_GET propforge hit shape={} prop={} slot={}",
|
||||
obj.shape_id(),
|
||||
@@ -345,7 +346,7 @@ impl Vm {
|
||||
// 先试自身属性(快路径,depth=0)。
|
||||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(obj.shape_id(), prop_name_si) {
|
||||
if !obj.is_accessor_meta(pos) {
|
||||
ic_helper::write_ic_back(&mut self.bytecode, self.pc, obj.shape_id(), pos, 0);
|
||||
ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, obj.shape_id(), pos, 0);
|
||||
ic_debug!("IC_GET write-back own shape={} slot={}", obj.shape_id(), pos);
|
||||
}
|
||||
} else {
|
||||
@@ -356,7 +357,7 @@ impl Vm {
|
||||
let co_ref = unsafe { &*cursor };
|
||||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(co_ref.shape_id(), prop_name_si) {
|
||||
if !co_ref.is_accessor_meta(pos) {
|
||||
ic_helper::write_ic_back(&mut self.bytecode, self.pc, co_ref.shape_id(), pos, depth);
|
||||
ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, co_ref.shape_id(), pos, depth);
|
||||
ic_debug!(
|
||||
"IC_GET write-back proto shape={} slot={} depth={}",
|
||||
co_ref.shape_id(),
|
||||
@@ -399,6 +400,7 @@ impl Vm {
|
||||
}
|
||||
|
||||
let (cached_shape_id, cached_slot, cached_depth) = ic_helper::read_ic_entry(&self.bytecode, &mut self.pc);
|
||||
let ic_pc = self.pc;
|
||||
let value = self.promote_if_needed_for_write_ptr(obj_ptr, self.regs[a]);
|
||||
let receiver = self.regs[rd];
|
||||
let obj = unsafe { &mut *obj_ptr };
|
||||
@@ -414,7 +416,7 @@ impl Vm {
|
||||
self.profiling.record_ic_miss();
|
||||
prop_cache_miss();
|
||||
obj.set_prop_shape(pos, value);
|
||||
ic_helper::write_ic_back(&mut self.bytecode, self.pc, obj.shape_id(), pos, 0);
|
||||
ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, obj.shape_id(), pos, 0);
|
||||
ic_debug!("IC_SET write-back shape={} slot={}", obj.shape_id(), pos);
|
||||
} else {
|
||||
self.profiling.record_ic_miss();
|
||||
@@ -423,7 +425,7 @@ impl Vm {
|
||||
self.ordinary_set_dispatch(obj, prop_name_si, value, receiver)?;
|
||||
if old_shape != obj.shape_id() {
|
||||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(obj.shape_id(), prop_name_si) {
|
||||
ic_helper::write_ic_back(&mut self.bytecode, self.pc, obj.shape_id(), pos, 0);
|
||||
ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, obj.shape_id(), pos, 0);
|
||||
ic_debug!("IC_SET write-back shape={} slot={}", obj.shape_id(), pos);
|
||||
self.kernel_core.prop_forge().upsert(
|
||||
obj.shape_id(),
|
||||
|
||||
@@ -18,7 +18,7 @@ use crate::vm::{CallFrame, Completion, ForInIter, TryHandler, Vm};
|
||||
pub(crate) struct SuspendedFrame {
|
||||
pub regs: Box<[JsValue; 256]>,
|
||||
pub pc: usize,
|
||||
pub bytecode: Vec<opcode::Instr>,
|
||||
pub bytecode: Arc<[opcode::Instr]>,
|
||||
/// 模块 flat_id(恢复时经 sub_modules 重激活 immutables;跨 run 失效据此报错)。
|
||||
pub sub_idx: u32,
|
||||
pub active_reg_limit: u8,
|
||||
@@ -34,7 +34,7 @@ pub(crate) struct SuspendedFrame {
|
||||
pub last_for_of_result: JsValue,
|
||||
/// `yield*` 委托中的内层迭代器;异步函数恒为 None。
|
||||
pub delegated_iterator: Option<JsValue>,
|
||||
pub saved_bytecode_stack: Vec<Vec<opcode::Instr>>,
|
||||
pub saved_bytecode_stack: Vec<Arc<[opcode::Instr]>>,
|
||||
pub saved_immutables_stack: Vec<*const [JsValue]>,
|
||||
pub exception_value: Option<JsValue>,
|
||||
pub pending_exception: Option<JsValue>,
|
||||
@@ -47,7 +47,7 @@ impl SuspendedFrame {
|
||||
pub fn new_empty() -> Self { SuspendedFrame {
|
||||
regs: Box::new([JsValue::undefined(); 256]),
|
||||
pc: 0,
|
||||
bytecode: Vec::new(),
|
||||
bytecode: Arc::default(),
|
||||
sub_idx: 0,
|
||||
active_reg_limit: 0,
|
||||
root_reg_limit: 0,
|
||||
@@ -349,7 +349,7 @@ mod tests {
|
||||
frame.regs[0] = JsValue::float(1.0);
|
||||
frame.regs[7] = JsValue::float(2.0);
|
||||
frame.pc = 11;
|
||||
frame.bytecode = vec![0u32];
|
||||
frame.bytecode = Arc::from(vec![0u32]);
|
||||
frame.sub_idx = 3;
|
||||
frame.active_reg_limit = 4;
|
||||
frame.root_reg_limit = 5;
|
||||
@@ -367,7 +367,7 @@ mod tests {
|
||||
frame.for_of_iters.push(JsValue::float(6.0));
|
||||
frame.last_for_of_result = JsValue::float(7.0);
|
||||
frame.delegated_iterator = Some(JsValue::float(8.0));
|
||||
frame.saved_bytecode_stack.push(vec![0u32]);
|
||||
frame.saved_bytecode_stack.push(Arc::from(vec![0u32]));
|
||||
frame.saved_immutables_stack.push(std::ptr::slice_from_raw_parts(std::ptr::null(), 0));
|
||||
frame.exception_value = Some(JsValue::float(9.0));
|
||||
frame.pending_exception = Some(JsValue::float(10.0));
|
||||
|
||||
+28
-16
@@ -197,7 +197,7 @@ impl Completion {
|
||||
pub(crate) struct InlineSyncState {
|
||||
pub(crate) regs: Box<[JsValue; 256]>,
|
||||
pub(crate) pc: usize,
|
||||
pub(crate) bytecode: Vec<opcode::Instr>,
|
||||
pub(crate) bytecode: Arc<[opcode::Instr]>,
|
||||
pub(crate) active_immutables: *const [JsValue],
|
||||
pub(crate) active_reg_limit: u8,
|
||||
pub(crate) root_reg_limit: u8,
|
||||
@@ -210,7 +210,7 @@ pub(crate) struct InlineSyncState {
|
||||
pub(crate) for_in_iters: Vec<*mut ForInIter<'static>>,
|
||||
pub(crate) for_of_iters: Vec<JsValue>,
|
||||
pub(crate) last_for_of_result: JsValue,
|
||||
pub(crate) saved_bytecode_stack: Vec<Vec<opcode::Instr>>,
|
||||
pub(crate) saved_bytecode_stack: Vec<Arc<[opcode::Instr]>>,
|
||||
pub(crate) saved_immutables_stack: Vec<*const [JsValue]>,
|
||||
pub(crate) save_stack: Vec<JsValue>,
|
||||
pub(crate) spill_stack: Vec<JsValue>,
|
||||
@@ -229,7 +229,10 @@ pub(crate) struct InlineSyncState {
|
||||
pub struct Vm {
|
||||
pub(crate) regs: [JsValue; 256],
|
||||
pub(crate) pc: usize,
|
||||
pub(crate) bytecode: Vec<opcode::Instr>,
|
||||
/// 当前活动字节码。以 `Arc<[Instr]>` 共享:函数调用经 `Arc::clone` 换帧(O(1)),
|
||||
/// 不再逐帧深拷贝。与 sub_modules 源共享同一缓冲,IC 写回经 `bytecode_mut` 的
|
||||
/// `Arc::make_mut` 写时复制,保证独占后才改写(miss 时才深拷贝,频率低)。
|
||||
pub(crate) bytecode: Arc<[opcode::Instr]>,
|
||||
/// 每次 run 转换一次的不可变常量缓存。下标 0 = 顶层模块,sub_idx+1 = sub_modules[sub_idx]。
|
||||
/// 每个 `OnceLock` 保存该模块常量本次运行中只转换一次的 `JsValue` 结果,每次 `run()` 重建。
|
||||
/// 不可变常量是标量 + perm 字符串,只读,不作为 GC 根。
|
||||
@@ -267,7 +270,8 @@ pub struct Vm {
|
||||
/// 全局扁平模块表:下标 = 模块 `flat_id`(顶层 0,子模块 flatten 后全局唯一)。
|
||||
/// 闭包 `sub_module_index` 即 flat_id,逃逸闭包也能自足解析。
|
||||
pub(crate) sub_modules: Arc<Vec<CompiledModule>>,
|
||||
pub(crate) saved_bytecode_stack: Vec<Vec<opcode::Instr>>,
|
||||
/// 帧切换时暂存调用方字节码的 Arc 栈(与 `bytecode` 同共享语义)。
|
||||
pub(crate) saved_bytecode_stack: Vec<Arc<[opcode::Instr]>>,
|
||||
pub(crate) saved_immutables_stack: Vec<*const [JsValue]>,
|
||||
/// 共享寄存器保存栈。每个活动 `CallFrame` 在 push 时把调用方活跃寄存器
|
||||
/// (`regs[..caller_reg_limit]`)按 `saved_reg_offset` 存到这里;恢复时复制回
|
||||
@@ -521,6 +525,13 @@ impl Vm {
|
||||
self.active_immutables = vec.as_slice() as *const [JsValue];
|
||||
}
|
||||
|
||||
/// 当前活动字节码的可变访问入口。bytecode 以 `Arc<[Instr]>` 与 sub_modules 源共享,
|
||||
/// IC 写回经 `Arc::make_mut` 保证独占:独占时零拷贝原地写,共享时先深拷贝再写
|
||||
/// (IC miss 才触发,频率低)。所有写操作必须经此方法,防止共享缓冲被多实例污染。
|
||||
pub(crate) fn bytecode_mut(&mut self) -> &mut [opcode::Instr] {
|
||||
Arc::make_mut(&mut self.bytecode)
|
||||
}
|
||||
|
||||
/// GC 根收集的统一遍历(对象与字符串都产出)。与 `rewrite_values` 字段一一对应。
|
||||
/// 覆盖执行核心的全部 JsValue 持有点:regs/帧/各栈段/cell/在途异常与完成/
|
||||
/// 挂起信号/迭代器/微任务/global。新增执行字段必须同时登记在此与
|
||||
@@ -1036,7 +1047,7 @@ impl Vm {
|
||||
return self.raise_error_kind("RangeError", "Maximum call stack size exceeded");
|
||||
}
|
||||
|
||||
let sub_bytecode = self.sub_modules[sub_idx].bytecode.clone();
|
||||
let sub_bytecode = Arc::clone(&self.sub_modules[sub_idx].bytecode);
|
||||
let sub_n_args = self.sub_modules[sub_idx].n_args as usize;
|
||||
let sub_n_registers = self.sub_modules[sub_idx].n_registers;
|
||||
let sub_param_base = self.sub_modules[sub_idx].param_base as usize;
|
||||
@@ -1902,7 +1913,7 @@ impl Vm {
|
||||
/// 原子树 flat_id 自 1 连续,因此拷贝顺序即新 id 顺序,`out` 下标对齐平表槽位。
|
||||
fn rehome_subtree(module: &CompiledModule, base: u32, out: &mut Vec<CompiledModule>) {
|
||||
let new_id = base + module.flat_id - 1;
|
||||
let mut bytecode = module.bytecode.clone();
|
||||
let mut bytecode = module.bytecode.to_vec();
|
||||
for instr in &mut bytecode {
|
||||
if opcode::opcode(*instr) == OpCode::CREATE_CLOSURE {
|
||||
let old = opcode::imm16(*instr) as u32;
|
||||
@@ -1916,7 +1927,7 @@ fn rehome_subtree(module: &CompiledModule, base: u32, out: &mut Vec<CompiledModu
|
||||
}
|
||||
}
|
||||
let mut rehomed = module.clone();
|
||||
rehomed.bytecode = bytecode;
|
||||
rehomed.bytecode = Arc::from(bytecode);
|
||||
rehomed.flat_id = new_id;
|
||||
out.push(rehomed);
|
||||
for sub in &module.sub_modules {
|
||||
@@ -1927,6 +1938,7 @@ fn rehome_subtree(module: &CompiledModule, base: u32, out: &mut Vec<CompiledModu
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{opcode, JsValue, TryHandler, Vm};
|
||||
use std::sync::Arc;
|
||||
use oxide_bytecode::module::CompiledModule;
|
||||
use oxide_runtime_api::NativeResult;
|
||||
use oxide_types::object::NativeFnPtr;
|
||||
@@ -2025,7 +2037,7 @@ mod tests {
|
||||
.push(std::ptr::dangling_mut::<super::ForInIter<'static>>());
|
||||
vm.iters.for_of_iters.push(JsValue::undefined());
|
||||
vm.saved_bytecode_stack
|
||||
.push(vec![opcode::encode(opcode::OpCode::HALT, 0, 0, 0)]);
|
||||
.push(Arc::from(vec![opcode::encode(opcode::OpCode::HALT, 0, 0, 0)]));
|
||||
vm.saved_immutables_stack
|
||||
.push(std::ptr::slice_from_raw_parts(std::ptr::null(), 0));
|
||||
vm.try_stack.push(TryHandler {
|
||||
@@ -2071,10 +2083,10 @@ mod tests {
|
||||
#[test]
|
||||
fn for_of_close_pops_iterator_stack() {
|
||||
let module = CompiledModule {
|
||||
bytecode: vec![
|
||||
bytecode: Arc::from(vec![
|
||||
opcode::encode(opcode::OpCode::FOR_OF_CLOSE, 0, 0, 0),
|
||||
opcode::encode(opcode::OpCode::HALT, 0, 0, 0),
|
||||
],
|
||||
]),
|
||||
n_registers: 1,
|
||||
..CompiledModule::new()
|
||||
};
|
||||
@@ -2089,9 +2101,9 @@ mod tests {
|
||||
#[test]
|
||||
fn write_ic_back_updates_three_extension_words() {
|
||||
let mut vm = Vm::new();
|
||||
vm.bytecode = vec![0, 0, 0];
|
||||
vm.bytecode = Arc::from(vec![0, 0, 0]);
|
||||
vm.pc = 3;
|
||||
crate::ic_helper::write_ic_back(&mut vm.bytecode, vm.pc, 0x1234_5678, 7, 0);
|
||||
crate::ic_helper::write_ic_back(Arc::make_mut(&mut vm.bytecode), vm.pc, 0x1234_5678, 7, 0);
|
||||
assert_eq!(vm.bytecode[0], 0x0034_5678);
|
||||
assert_eq!(vm.bytecode[1], 7);
|
||||
assert_eq!(vm.bytecode[2], 0);
|
||||
@@ -2100,9 +2112,9 @@ mod tests {
|
||||
#[test]
|
||||
fn write_ic_back_stores_proto_depth() {
|
||||
let mut vm = Vm::new();
|
||||
vm.bytecode = vec![0, 0, 0];
|
||||
vm.bytecode = Arc::from(vec![0, 0, 0]);
|
||||
vm.pc = 3;
|
||||
crate::ic_helper::write_ic_back(&mut vm.bytecode, vm.pc, 0xAAAA_BBBB, 42, 2);
|
||||
crate::ic_helper::write_ic_back(Arc::make_mut(&mut vm.bytecode), vm.pc, 0xAAAA_BBBB, 42, 2);
|
||||
assert_eq!(vm.bytecode[0], 0x00AA_BBBB);
|
||||
assert_eq!(vm.bytecode[1], 42);
|
||||
assert_eq!(vm.bytecode[2], 2);
|
||||
@@ -2111,10 +2123,10 @@ mod tests {
|
||||
#[test]
|
||||
fn unimplemented_profile_opcode_fails_explicitly() {
|
||||
let module = CompiledModule {
|
||||
bytecode: vec![
|
||||
bytecode: Arc::from(vec![
|
||||
opcode::encode(opcode::OpCode::PROFILE_SHAPE, 0, 0, 0),
|
||||
opcode::encode(opcode::OpCode::HALT, 0, 0, 0),
|
||||
],
|
||||
]),
|
||||
n_registers: 1,
|
||||
..CompiledModule::new()
|
||||
};
|
||||
|
||||
@@ -109,7 +109,7 @@ impl Vm {
|
||||
}
|
||||
|
||||
let new_obj_val = JsValue::object(new_obj as *mut u8);
|
||||
let sub_bytecode = self.sub_modules[sub_idx].bytecode.clone();
|
||||
let sub_bytecode = Arc::clone(&self.sub_modules[sub_idx].bytecode);
|
||||
let sub_n_args = self.sub_modules[sub_idx].n_args as usize;
|
||||
let sub_n_registers = self.sub_modules[sub_idx].n_registers;
|
||||
let sub_param_base = self.sub_modules[sub_idx].param_base as usize;
|
||||
|
||||
@@ -278,6 +278,7 @@ impl Vm {
|
||||
let ext1 = self.bytecode[self.pc + 1];
|
||||
let ext2 = self.bytecode[self.pc + 2];
|
||||
self.pc += 3;
|
||||
let ic_pc = self.pc;
|
||||
if obj.has_prop_meta() {
|
||||
return self.ordinary_get(obj, prop_name_si, receiver);
|
||||
}
|
||||
@@ -291,7 +292,7 @@ impl Vm {
|
||||
if template.prop_name != prop_name_si {
|
||||
self.proto_chain_ic_get(obj, prop_name_si, receiver)?
|
||||
} else if template.position < obj.prop_vec_len() as u32 {
|
||||
crate::ic_helper::write_ic_back(&mut self.bytecode, self.pc, obj.shape_id(), template.position, 0);
|
||||
crate::ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, obj.shape_id(), template.position, 0);
|
||||
obj.get_prop_shape(template.position)
|
||||
} else {
|
||||
self.proto_chain_ic_get(obj, prop_name_si, receiver)?
|
||||
@@ -304,11 +305,12 @@ impl Vm {
|
||||
|
||||
/// 执行 ordinary_get 并把 IC 按原型链深度写回。
|
||||
fn proto_chain_ic_get(&mut self, obj: &JsObject, prop_name_si: u32, receiver: JsValue) -> Result<JsValue, String> {
|
||||
let ic_pc = self.pc;
|
||||
let resolved = self.ordinary_get(obj, prop_name_si, receiver)?;
|
||||
// 快路径:自身属性(depth=0)。
|
||||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(obj.shape_id(), prop_name_si) {
|
||||
if !obj.is_accessor_meta(pos) {
|
||||
crate::ic_helper::write_ic_back(&mut self.bytecode, self.pc, obj.shape_id(), pos, 0);
|
||||
crate::ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, obj.shape_id(), pos, 0);
|
||||
}
|
||||
return Ok(resolved);
|
||||
}
|
||||
@@ -319,7 +321,7 @@ impl Vm {
|
||||
let co = unsafe { &*cursor };
|
||||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(co.shape_id(), prop_name_si) {
|
||||
if !co.is_accessor_meta(pos) {
|
||||
crate::ic_helper::write_ic_back(&mut self.bytecode, self.pc, co.shape_id(), pos, depth);
|
||||
crate::ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, co.shape_id(), pos, depth);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -336,6 +338,7 @@ impl Vm {
|
||||
&mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue,
|
||||
) -> Result<(), String> {
|
||||
ic_trace!("set_member_prop: shape_id={} prop_name_si={}", obj.shape_id(), prop_name_si);
|
||||
let ic_pc = self.pc;
|
||||
let val = self.promote_if_needed_for_write_ptr(obj as *mut JsObject, val);
|
||||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(obj.shape_id(), prop_name_si) {
|
||||
if obj.has_prop_meta() {
|
||||
@@ -343,7 +346,7 @@ impl Vm {
|
||||
return Ok(());
|
||||
}
|
||||
obj.set_prop_shape(pos, val);
|
||||
crate::ic_helper::write_ic_back(&mut self.bytecode, self.pc, obj.shape_id(), pos, 0);
|
||||
crate::ic_helper::write_ic_back(self.bytecode_mut(), ic_pc, obj.shape_id(), pos, 0);
|
||||
} else {
|
||||
self.ordinary_set(obj, prop_name_si, val, receiver)?;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ impl Vm {
|
||||
) -> Result<(), String> {
|
||||
self.regs = [JsValue::undefined(); 256];
|
||||
self.pc = 0;
|
||||
self.bytecode = Vec::new();
|
||||
self.bytecode = Arc::default();
|
||||
self.active_reg_limit = 1;
|
||||
self.root_reg_limit = 1;
|
||||
self.try_stack.clear();
|
||||
@@ -222,7 +222,7 @@ impl Vm {
|
||||
|
||||
self.regs = [JsValue::undefined(); 256];
|
||||
self.pc = 0;
|
||||
self.bytecode = sub.bytecode.clone();
|
||||
self.bytecode = Arc::clone(&sub.bytecode);
|
||||
self.activate_immutables(sub_idx, &sub.constants);
|
||||
self.active_reg_limit = sub.n_registers.max(1);
|
||||
self.root_reg_limit = self.active_reg_limit;
|
||||
@@ -300,7 +300,7 @@ impl Vm {
|
||||
vm_info!("rerun: clearing IC caches");
|
||||
self.clear_execution_state();
|
||||
self.active_reg_limit = self.root_reg_limit;
|
||||
crate::ic_helper::clear_ic_caches(&mut self.bytecode);
|
||||
crate::ic_helper::clear_ic_caches(self.bytecode_mut());
|
||||
self.dispatch()
|
||||
}
|
||||
|
||||
@@ -315,7 +315,7 @@ impl Vm {
|
||||
self.cell_stack.push(Vec::new());
|
||||
self.sub_modules = Arc::new(collect_flat_modules(module));
|
||||
self.immutables_cache = (0..self.sub_modules.len()).map(|_| OnceLock::new()).collect();
|
||||
self.bytecode = module.bytecode.clone();
|
||||
self.bytecode = Arc::clone(&module.bytecode);
|
||||
self.activate_immutables(0, &module.constants);
|
||||
self.root_reg_limit = module.n_registers.max(1);
|
||||
self.active_reg_limit = self.root_reg_limit;
|
||||
|
||||
@@ -25,7 +25,7 @@ impl Vm {
|
||||
let mut vm = Self {
|
||||
regs: [JsValue::undefined(); 256],
|
||||
pc: 0,
|
||||
bytecode: Vec::new(),
|
||||
bytecode: Arc::default(),
|
||||
immutables_cache: Vec::new(),
|
||||
active_immutables: std::ptr::slice_from_raw_parts(std::ptr::null(), 0),
|
||||
frames: smallvec::SmallVec::new(),
|
||||
@@ -118,7 +118,7 @@ impl Vm {
|
||||
let mut vm = Self {
|
||||
regs: [JsValue::undefined(); 256],
|
||||
pc: 0,
|
||||
bytecode: Vec::new(),
|
||||
bytecode: Arc::default(),
|
||||
immutables_cache: Vec::new(),
|
||||
active_immutables: std::ptr::slice_from_raw_parts(std::ptr::null(), 0),
|
||||
frames: smallvec::SmallVec::new(),
|
||||
@@ -266,7 +266,7 @@ impl Vm {
|
||||
|
||||
fn clear_full_reset_state(&mut self) {
|
||||
self.clear_execution_state();
|
||||
self.bytecode.clear();
|
||||
self.bytecode = Arc::default();
|
||||
self.immutables_cache.clear();
|
||||
self.active_immutables = std::ptr::slice_from_raw_parts(std::ptr::null(), 0);
|
||||
self.free_epoch_object_heap_data();
|
||||
@@ -334,7 +334,7 @@ impl Vm {
|
||||
pub fn reset(&mut self) {
|
||||
self.clear_execution_state();
|
||||
self.maybe_collect_session_gc();
|
||||
self.bytecode.clear();
|
||||
self.bytecode = Arc::default();
|
||||
self.immutables_cache.clear();
|
||||
self.active_immutables = std::ptr::slice_from_raw_parts(std::ptr::null(), 0);
|
||||
self.free_epoch_object_heap_data();
|
||||
|
||||
Reference in New Issue
Block a user