mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-26 19:51:11 +08:00
refactor: 对象分配统一入口并新增会话分配入口
This commit is contained in:
@@ -104,7 +104,7 @@ impl Vm {
|
|||||||
&mut self, callee: JsValue, this_value: JsValue, args: &[JsValue],
|
&mut self, callee: JsValue, this_value: JsValue, args: &[JsValue],
|
||||||
) -> Result<JsValue, String> {
|
) -> Result<JsValue, String> {
|
||||||
let gen_proto_val = JsValue::from_js_object(self.async_generator_proto.as_ptr() as *mut JsObject);
|
let gen_proto_val = JsValue::from_js_object(self.async_generator_proto.as_ptr() as *mut JsObject);
|
||||||
let obj = self.epoch.alloc(JsObject::new_empty(EMPTY_SHAPE_ID, gen_proto_val));
|
let obj = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, gen_proto_val));
|
||||||
let obj_ref = unsafe { &mut *obj };
|
let obj_ref = unsafe { &mut *obj };
|
||||||
obj_ref.type_tag = JsObject::OBJ_TYPE_ASYNC_GENERATOR;
|
obj_ref.type_tag = JsObject::OBJ_TYPE_ASYNC_GENERATOR;
|
||||||
let state = Box::new(AsyncGeneratorState {
|
let state = Box::new(AsyncGeneratorState {
|
||||||
@@ -119,7 +119,6 @@ impl Vm {
|
|||||||
suspended: crate::suspended::SuspendedFrame::new_empty(),
|
suspended: crate::suspended::SuspendedFrame::new_empty(),
|
||||||
});
|
});
|
||||||
obj_ref.set_native_data(Box::into_raw(state) as *mut u8);
|
obj_ref.set_native_data(Box::into_raw(state) as *mut u8);
|
||||||
self.gc_state.track_epoch_object(obj);
|
|
||||||
let gen_val = JsValue::from_js_object(obj);
|
let gen_val = JsValue::from_js_object(obj);
|
||||||
// 调用时参数初始化(含默认值/解构/arguments 创建):副作用与异常在 `g()` 时刻生效。
|
// 调用时参数初始化(含默认值/解构/arguments 创建):副作用与异常在 `g()` 时刻生效。
|
||||||
self.initialize_async_generator(gen_val)?;
|
self.initialize_async_generator(gen_val)?;
|
||||||
|
|||||||
@@ -253,13 +253,8 @@ impl Vm {
|
|||||||
pub(crate) fn dispatch_new_session_object(&mut self, rd: usize) -> Result<(), String> {
|
pub(crate) fn dispatch_new_session_object(&mut self, rd: usize) -> Result<(), String> {
|
||||||
vm_trace!("NEW_SESSION_OBJECT rd={}", rd);
|
vm_trace!("NEW_SESSION_OBJECT rd={}", rd);
|
||||||
let proto_ptr = &*self.object_prototype as *const JsObject as *mut JsObject;
|
let proto_ptr = &*self.object_prototype as *const JsObject as *mut JsObject;
|
||||||
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr));
|
let obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr));
|
||||||
obj.set_session_epoch(true);
|
let obj_ptr = self.alloc_session_object(obj);
|
||||||
let obj_ptr = self.gc_state.session_epoch.alloc(obj) as *mut JsObject;
|
|
||||||
self.gc_state.session_object_ptrs.push(obj_ptr);
|
|
||||||
// 直 session 分配计入堆账目(与 promote 同式:对象头 + 对象堆数据)。
|
|
||||||
self.gc_state.session_bytes_allocated += std::mem::size_of::<JsObject>()
|
|
||||||
+ crate::session_gc::SessionGc::object_heap_data_bytes(unsafe { &*obj_ptr }) as usize;
|
|
||||||
self.regs[rd] = JsValue::object(obj_ptr as *mut u8);
|
self.regs[rd] = JsValue::object(obj_ptr as *mut u8);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ impl Vm {
|
|||||||
&mut self, callee: JsValue, this_value: JsValue, args: &[JsValue],
|
&mut self, callee: JsValue, this_value: JsValue, args: &[JsValue],
|
||||||
) -> Result<JsValue, String> {
|
) -> Result<JsValue, String> {
|
||||||
let gen_proto_val = JsValue::from_js_object(self.generator_proto.as_ptr() as *mut JsObject);
|
let gen_proto_val = JsValue::from_js_object(self.generator_proto.as_ptr() as *mut JsObject);
|
||||||
let obj = self.epoch.alloc(JsObject::new_empty(EMPTY_SHAPE_ID, gen_proto_val));
|
let obj = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, gen_proto_val));
|
||||||
let obj_ref = unsafe { &mut *obj };
|
let obj_ref = unsafe { &mut *obj };
|
||||||
obj_ref.type_tag = JsObject::OBJ_TYPE_GENERATOR;
|
obj_ref.type_tag = JsObject::OBJ_TYPE_GENERATOR;
|
||||||
let state = Box::new(GeneratorState {
|
let state = Box::new(GeneratorState {
|
||||||
@@ -115,7 +115,6 @@ impl Vm {
|
|||||||
suspended: crate::suspended::SuspendedFrame::new_empty(),
|
suspended: crate::suspended::SuspendedFrame::new_empty(),
|
||||||
});
|
});
|
||||||
obj_ref.set_native_data(Box::into_raw(state) as *mut u8);
|
obj_ref.set_native_data(Box::into_raw(state) as *mut u8);
|
||||||
self.gc_state.track_epoch_object(obj);
|
|
||||||
let gen_val = JsValue::from_js_object(obj);
|
let gen_val = JsValue::from_js_object(obj);
|
||||||
// 调用时参数初始化(含默认值/解构/arguments 创建):副作用与异常在 `g()` 时刻生效。
|
// 调用时参数初始化(含默认值/解构/arguments 创建):副作用与异常在 `g()` 时刻生效。
|
||||||
self.initialize_generator(gen_val)?;
|
self.initialize_generator(gen_val)?;
|
||||||
|
|||||||
@@ -13,6 +13,14 @@ use super::{native_fn_ptr_to_fn, Vm};
|
|||||||
use crate::native::NativeFn;
|
use crate::native::NativeFn;
|
||||||
use crate::{vm_debug, vm_trace};
|
use crate::{vm_debug, vm_trace};
|
||||||
|
|
||||||
|
/// 对象分配统一入口的后端:epoch arena(短命对象,晋升进 session)与
|
||||||
|
/// session arena(长命对象,session GC mark/sweep 回收)二选一。
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum AllocBackend {
|
||||||
|
Epoch,
|
||||||
|
Session,
|
||||||
|
}
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
fn pack_sync_native_call_args(
|
fn pack_sync_native_call_args(
|
||||||
&mut self, receiver: JsValue, callee: JsValue, args: &[JsValue],
|
&mut self, receiver: JsValue, callee: JsValue, args: &[JsValue],
|
||||||
@@ -40,12 +48,45 @@ impl Vm {
|
|||||||
unsafe { (*obj_ptr).is_session_epoch() }
|
unsafe { (*obj_ptr).is_session_epoch() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 在当前 epoch arena 分配对象并登记 GC 追踪表,返回裸指针。
|
/// 按指定后端分配对象并登记追踪表与堆账目,返回裸指针。
|
||||||
pub(crate) fn alloc_object(&mut self, obj: JsObject) -> *mut JsObject {
|
///
|
||||||
|
/// # 步骤
|
||||||
|
/// 1. Epoch 后端:epoch arena 分配并登记 `epoch_object_ptrs`。
|
||||||
|
/// 2. Session 后端:先置 session 归属位再分配,登记 `session_object_ptrs`,
|
||||||
|
/// 计入堆账目(与晋升同式:对象头 + 对象堆数据,读分配后的 arena 对象)。
|
||||||
|
///
|
||||||
|
/// # 注意事项
|
||||||
|
/// Session 后端先置位后分配,置位与登记顺序在两个后端内固定;
|
||||||
|
/// 换后端只改本函数内的分配原语,调用点不动。
|
||||||
|
fn alloc_with_backend(&mut self, mut obj: JsObject, backend: AllocBackend) -> *mut JsObject {
|
||||||
|
match backend {
|
||||||
|
AllocBackend::Epoch => {
|
||||||
let ptr = self.epoch.alloc(obj);
|
let ptr = self.epoch.alloc(obj);
|
||||||
self.gc_state.track_epoch_object(ptr);
|
self.gc_state.track_epoch_object(ptr);
|
||||||
ptr
|
ptr
|
||||||
}
|
}
|
||||||
|
AllocBackend::Session => {
|
||||||
|
obj.set_session_epoch(true);
|
||||||
|
let ptr = self.gc_state.session_epoch.alloc(obj) as *mut JsObject;
|
||||||
|
self.gc_state.session_object_ptrs.push(ptr);
|
||||||
|
// 直 session 分配计入堆账目(与 promote 同式:对象头 + 对象堆数据)。
|
||||||
|
self.gc_state.session_bytes_allocated += std::mem::size_of::<JsObject>()
|
||||||
|
+ crate::session_gc::SessionGc::object_heap_data_bytes(unsafe { &*ptr }) as usize;
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 在当前 epoch arena 分配对象并登记 GC 追踪表,返回裸指针。
|
||||||
|
pub(crate) fn alloc_object(&mut self, obj: JsObject) -> *mut JsObject {
|
||||||
|
self.alloc_with_backend(obj, AllocBackend::Epoch)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 在当前 session arena 分配对象:置 session 归属位、登记 session 对象表
|
||||||
|
/// 并计入堆账目,返回裸指针。
|
||||||
|
pub(crate) fn alloc_session_object(&mut self, obj: JsObject) -> *mut JsObject {
|
||||||
|
self.alloc_with_backend(obj, AllocBackend::Session)
|
||||||
|
}
|
||||||
|
|
||||||
/// native / 字节码函数的统一同步调用入口,返回结果或错误文本。
|
/// native / 字节码函数的统一同步调用入口,返回结果或错误文本。
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -1207,17 +1207,9 @@ impl Vm {
|
|||||||
// 免 promote 搬移——若按 epoch 分配,首次写入 session 根会把对象搬到新
|
// 免 promote 搬移——若按 epoch 分配,首次写入 session 根会把对象搬到新
|
||||||
// 地址,缓存中的旧指针与新实例分叉,同一 site 两次取值将返回不同对象。
|
// 地址,缓存中的旧指针与新实例分叉,同一 site 两次取值将返回不同对象。
|
||||||
let mut alloc_session_array = |n: usize| {
|
let mut alloc_session_array = |n: usize| {
|
||||||
let mut clone =
|
let clone =
|
||||||
JsObject::new_array(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, proto_val, n, self.epoch.bump());
|
JsObject::new_array(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, proto_val, n, self.epoch.bump());
|
||||||
// 标记 session 归属:session_epoch 分配的对象须显式置位,GC/释放路径
|
self.alloc_session_object(clone)
|
||||||
// 据 SESSION_EPOCH_BIT 判定归属(与 promote_object 的 clone 路径一致)。
|
|
||||||
clone.set_session_epoch(true);
|
|
||||||
let ptr = self.gc_state.session_epoch.alloc(clone) as *mut JsObject;
|
|
||||||
self.gc_state.session_object_ptrs.push(ptr);
|
|
||||||
// 直 session 分配计入堆账目(与 promote 同式:对象头 + 对象堆数据)。
|
|
||||||
self.gc_state.session_bytes_allocated += std::mem::size_of::<JsObject>()
|
|
||||||
+ crate::session_gc::SessionGc::object_heap_data_bytes(unsafe { &*ptr }) as usize;
|
|
||||||
ptr
|
|
||||||
};
|
};
|
||||||
let cooked = alloc_session_array(n);
|
let cooked = alloc_session_array(n);
|
||||||
let raw = alloc_session_array(n);
|
let raw = alloc_session_array(n);
|
||||||
|
|||||||
@@ -805,12 +805,7 @@ impl Vm {
|
|||||||
// 函数对象直接 session 分配:寿命从调用级延至 session 级(session GC
|
// 函数对象直接 session 分配:寿命从调用级延至 session 级(session GC
|
||||||
// mark/sweep 回收)。若按 epoch 分配,写入全局等逃逸根时 promote 屏障会
|
// mark/sweep 回收)。若按 epoch 分配,写入全局等逃逸根时 promote 屏障会
|
||||||
// 深克隆进 session,全局属性与局部槽指针分裂、严格相等恒 false。
|
// 深克隆进 session,全局属性与局部槽指针分裂、严格相等恒 false。
|
||||||
obj.set_session_epoch(true);
|
let obj_ptr = self.alloc_session_object(obj);
|
||||||
let obj_ptr = self.gc_state.session_epoch.alloc(obj) as *mut JsObject;
|
|
||||||
self.gc_state.session_object_ptrs.push(obj_ptr);
|
|
||||||
// 直 session 分配计入堆账目(与 promote 同式:对象头 + 对象堆数据)。
|
|
||||||
self.gc_state.session_bytes_allocated += std::mem::size_of::<JsObject>()
|
|
||||||
+ crate::session_gc::SessionGc::object_heap_data_bytes(unsafe { &*obj_ptr }) as usize;
|
|
||||||
let func_val = JsValue::object(obj_ptr as *mut u8);
|
let func_val = JsValue::object(obj_ptr as *mut u8);
|
||||||
|
|
||||||
if !is_arrow && !(is_async && !is_generator) {
|
if !is_arrow && !(is_async && !is_generator) {
|
||||||
@@ -826,13 +821,8 @@ impl Vm {
|
|||||||
// prototype 子对象与函数本体同走 session 分配:`f.prototype ===
|
// prototype 子对象与函数本体同走 session 分配:`f.prototype ===
|
||||||
// globalThis.f.prototype` 要求两侧同一对象,epoch 分配会在逃逸写时
|
// globalThis.f.prototype` 要求两侧同一对象,epoch 分配会在逃逸写时
|
||||||
// 被递归克隆出第二份。
|
// 被递归克隆出第二份。
|
||||||
let mut prototype = JsObject::new_empty(EMPTY_SHAPE_ID, proto_of_proto);
|
let prototype = JsObject::new_empty(EMPTY_SHAPE_ID, proto_of_proto);
|
||||||
prototype.set_session_epoch(true);
|
let prototype_obj = self.alloc_session_object(prototype);
|
||||||
let prototype_obj = self.gc_state.session_epoch.alloc(prototype) as *mut JsObject;
|
|
||||||
self.gc_state.session_object_ptrs.push(prototype_obj);
|
|
||||||
// 直 session 分配计入堆账目(与 promote 同式:对象头 + 对象堆数据)。
|
|
||||||
self.gc_state.session_bytes_allocated += std::mem::size_of::<JsObject>()
|
|
||||||
+ crate::session_gc::SessionGc::object_heap_data_bytes(unsafe { &*prototype_obj }) as usize;
|
|
||||||
let prototype_val = JsValue::from_js_object(prototype_obj);
|
let prototype_val = JsValue::from_js_object(prototype_obj);
|
||||||
|
|
||||||
if !is_generator {
|
if !is_generator {
|
||||||
|
|||||||
Reference in New Issue
Block a user