diff --git a/crates/oxide_vm/src/dispatch/property.rs b/crates/oxide_vm/src/dispatch/property.rs index fe1ff94..e8a4272 100644 --- a/crates/oxide_vm/src/dispatch/property.rs +++ b/crates/oxide_vm/src/dispatch/property.rs @@ -207,23 +207,36 @@ impl Vm { prop_cache_miss(); ic_debug!("IC_GET miss shape={} prop={}", obj.shape_id(), prop_name_si); let resolved = self.ordinary_get(obj, prop_name_si, val)?; - // Walk proto chain to find which object actually owns this property. - let mut cursor = obj_ptr; - let mut depth = 0u8; - loop { - 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) { - ic_helper::write_ic_back(&mut self.bytecode, self.pc, co.shape_id(), pos, depth); - ic_debug!("IC_GET write-back shape={} slot={} depth={}", co.shape_id(), pos, depth); + // Try own property first (fast path, 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_debug!("IC_GET write-back own shape={} slot={}", obj.shape_id(), pos); + } + } else { + // Walk proto chain to find which object actually owns this property. + let mut cursor = obj.proto().as_js_object_ptr(); + let mut depth = 1u8; + while !cursor.is_null() { + 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_debug!( + "IC_GET write-back proto shape={} slot={} depth={}", + co_ref.shape_id(), + pos, + depth + ); + } + break; } - break; + if !co_ref.proto().is_object() { + break; + } + cursor = co_ref.proto().as_js_object_ptr(); + depth += 1; } - if !co.proto().is_object() { - break; - } - cursor = co.proto().as_js_object_ptr(); - depth += 1; } self.regs[a] = resolved; } diff --git a/crates/oxide_vm/src/ic_helper.rs b/crates/oxide_vm/src/ic_helper.rs index a516b4f..524c34b 100644 --- a/crates/oxide_vm/src/ic_helper.rs +++ b/crates/oxide_vm/src/ic_helper.rs @@ -87,6 +87,12 @@ pub(crate) fn ic_get_hit(obj: &JsObject, shape_id: u32, slot_index: u32, proto_d if shape_id == 0 { return None; } + if proto_depth == 0 { + if obj.shape_id() == shape_id && slot_index < obj.prop_vec_len() as u32 { + return Some(obj.get_prop_at(slot_index)); + } + return None; + } let target = resolve_proto_target_raw(obj as *const JsObject, proto_depth); if target.is_null() { return None; @@ -104,6 +110,13 @@ pub(crate) fn ic_set_hit(obj: &mut JsObject, shape_id: u32, slot_index: u32, pro if shape_id == 0 { return false; } + if proto_depth == 0 { + if obj.shape_id() == shape_id && slot_index < obj.prop_vec_len() as u32 { + obj.set_prop_at(slot_index, value); + return true; + } + return false; + } let target = resolve_proto_target_raw(obj as *const JsObject, proto_depth); if target.is_null() { return false; diff --git a/crates/oxide_vm/src/vm_props.rs b/crates/oxide_vm/src/vm_props.rs index f2c532b..0115ec4 100644 --- a/crates/oxide_vm/src/vm_props.rs +++ b/crates/oxide_vm/src/vm_props.rs @@ -238,9 +238,17 @@ impl Vm { /// Perform ordinary_get and write back IC with proto chain depth. fn proto_chain_ic_get(&mut self, obj: &JsObject, prop_name_si: u32, receiver: JsValue) -> Result { let resolved = self.ordinary_get(obj, prop_name_si, receiver)?; - let mut cursor: *mut JsObject = obj as *const JsObject as *mut JsObject; - let mut depth = 0u8; - loop { + // Fast path: own property (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); + } + return Ok(resolved); + } + // Walk proto chain for inherited properties. + let mut cursor = obj.proto().as_js_object_ptr(); + let mut depth = 1u8; + while !cursor.is_null() { 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) {