refactor: 扁平化对象属性存储并优化常量池与 IC 热路径

This commit is contained in:
爱特每羊队
2026-06-13 23:59:47 +08:00
parent dcc7db2575
commit bf74adf7f5
26 changed files with 307 additions and 87 deletions
+7 -7
View File
@@ -227,9 +227,9 @@ fn make_pair(
// Pre-allocate Vec slots so wire_ctor_proto can overwrite vec[0] later.
// Proto: 1 property ("constructor"), Ctor: 2 properties ("prototype", "name").
proto.ensure_hash_props().push(Box::new(JsValue::undefined())); // slot 0: "constructor" placeholder
ctor.ensure_hash_props().push(Box::new(JsValue::undefined())); // slot 0: "prototype" placeholder
ctor.ensure_hash_props().push(Box::new(JsValue::undefined())); // slot 1: "name" placeholder
proto.ensure_hash_props().push(JsValue::undefined()); // slot 0: "constructor" placeholder
ctor.ensure_hash_props().push(JsValue::undefined()); // slot 0: "prototype" placeholder
ctor.ensure_hash_props().push(JsValue::undefined()); // slot 1: "name" placeholder
(P::new(proto), P::new(ctor))
}
@@ -299,13 +299,13 @@ impl BuiltinWorld {
let ctor = unsafe { &mut *ctor_ptr };
let vec = ctor.ensure_hash_props();
if !vec.is_empty() {
*vec[0] = JsValue::from_js_object(proto.as_ptr() as *mut JsObject);
vec[0] = JsValue::from_js_object(proto.as_ptr() as *mut JsObject);
}
let proto_ptr = proto.as_ptr() as *mut JsObject;
let proto = unsafe { &mut *proto_ptr };
let pvec = proto.ensure_hash_props();
if !pvec.is_empty() {
*pvec[0] = JsValue::from_js_object(ctor_ptr);
pvec[0] = JsValue::from_js_object(ctor_ptr);
}
}
@@ -626,11 +626,11 @@ impl BuiltinWorld {
wrapper.set_shape_id(name_shape);
wrapper
.ensure_hash_props()
.push(Box::new(JsValue::string(string_forge.intern(method_name).0, 0)));
.push(JsValue::string(string_forge.intern(method_name).0, 0));
let wrapper_val = JsValue::from_js_object(Box::into_raw(wrapper));
let new_shape = shape_forge.make_shape(proto.shape_id(), si);
proto.set_shape_id(new_shape);
proto.ensure_hash_props().push(Box::new(wrapper_val));
proto.ensure_hash_props().push(wrapper_val);
proto.bump_generation();
Ok(())
}
+9 -1
View File
@@ -9,13 +9,21 @@ use crate::{kernel_debug, kernel_info};
pub use oxide_compiler::compiler::structural_hash;
/// Shared compiled-module cache.
///
/// Concurrency model:
/// - Read-heavy after warmup: cache hits dominate steady-state execution.
/// - Backed by a fixed-shard `DashMap` so lookup contention stays predictable across
/// developer machines and CI hosts.
pub struct CodeForge {
map: DashMap<u64, Arc<CompiledModule>>,
}
impl CodeForge {
pub fn new() -> Self {
Self { map: DashMap::new() }
Self {
map: DashMap::with_shard_amount(16),
}
}
pub fn get_or_compile(
+3 -3
View File
@@ -103,15 +103,15 @@ impl OxideKernel {
let nan_shape = shape_forge.make_shape(EMPTY_SHAPE_ID, si_nan);
global_obj.set_shape_id(nan_shape);
global_obj.ensure_hash_props().push(Box::new(JsValue::float(f64::NAN)));
global_obj.ensure_hash_props().push(JsValue::float(f64::NAN));
let undef_shape = shape_forge.make_shape(nan_shape, si_undef);
global_obj.set_shape_id(undef_shape);
global_obj.ensure_hash_props().push(Box::new(JsValue::undefined()));
global_obj.ensure_hash_props().push(JsValue::undefined());
let inf_shape = shape_forge.make_shape(undef_shape, si_infinity);
global_obj.set_shape_id(inf_shape);
global_obj.ensure_hash_props().push(Box::new(JsValue::float(f64::INFINITY)));
global_obj.ensure_hash_props().push(JsValue::float(f64::INFINITY));
let global_object = P::new(global_obj);
+8 -1
View File
@@ -18,6 +18,13 @@ pub struct Shape {
pub parent: Option<ShapeId>,
}
/// Shared hidden-class store.
///
/// Concurrency model:
/// - `shapes` is append-mostly behind an `RwLock`.
/// - `transitions` is a sharded `DashMap` keyed by `(parent_shape, property_name)`.
/// - Shard count is fixed for reproducible contention behavior across machines instead
/// of relying on DashMap's CPU-dependent default.
pub struct ShapeForge {
shapes: RwLock<Vec<Option<Arc<Shape>>>>,
transitions: DashMap<u64, ShapeId>,
@@ -28,7 +35,7 @@ impl ShapeForge {
pub fn new() -> Self {
let forge = Self {
shapes: RwLock::new(Vec::with_capacity(256)),
transitions: DashMap::with_capacity(256),
transitions: DashMap::with_capacity_and_shard_amount(256, 16),
next_id: AtomicU32::new(2),
};
{
+8
View File
@@ -24,6 +24,14 @@ struct StringForgeInner {
entries: Vec<StringEntry>,
}
/// Global string interning pool shared by all VMs.
///
/// Concurrency model:
/// `StringForge` keeps a single `RwLock` around the interner state.
/// - `lookup()` takes a shared read lock and scales across readers.
/// - `intern()` uses a read-check then write-check pattern to keep hot-path hits cheap.
/// - New string insertion is serialized, which matches the workload here: most strings
/// are interned early and later accesses are dominated by reads.
pub struct StringForge {
inner: RwLock<StringForgeInner>,
}