From fe623bacec6edf510135b1287097ae14f8ffbf18 Mon Sep 17 00:00:00 2001 From: Andrew DiZenzo Date: Thu, 4 Jun 2026 03:24:12 +0000 Subject: [PATCH] fix(runtime): bind inherited prototype accessors --- .../src/object/class_registry.rs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/crates/perry-runtime/src/object/class_registry.rs b/crates/perry-runtime/src/object/class_registry.rs index bea798421..85e734a00 100644 --- a/crates/perry-runtime/src/object/class_registry.rs +++ b/crates/perry-runtime/src/object/class_registry.rs @@ -418,6 +418,31 @@ pub(crate) unsafe fn resolve_proto_chain_field_with_receiver( resolve_proto_chain_field_inner(class_id, key, Some(receiver)) } +unsafe fn inherited_proto_accessor_value( + proto_obj: *mut ObjectHeader, + key: *const crate::StringHeader, + receiver: f64, +) -> Option { + if key.is_null() || !ACCESSORS_IN_USE.with(|c| c.get()) { + return None; + } + let key_ptr = (key as *const u8).add(std::mem::size_of::()); + let key_len = (*key).byte_len as usize; + let name = std::str::from_utf8(std::slice::from_raw_parts(key_ptr, key_len)).ok()?; + let acc = get_accessor_descriptor(proto_obj as usize, name)?; + if acc.get == 0 { + return Some(JSValue::undefined()); + } + let closure = (acc.get & crate::value::POINTER_MASK) as *const crate::closure::ClosureHeader; + if closure.is_null() { + return Some(JSValue::undefined()); + } + let previous_this = js_implicit_this_set(receiver); + let value = crate::closure::js_closure_call0(closure); + js_implicit_this_set(previous_this); + Some(JSValue::from_bits(value.to_bits())) +} + unsafe fn resolve_proto_chain_field_inner( class_id: u32, key: *const crate::StringHeader, @@ -428,6 +453,11 @@ unsafe fn resolve_proto_chain_field_inner( while depth < 32 { let proto_obj = class_prototype_object(cid); if !proto_obj.is_null() { + if let Some(receiver) = receiver { + if let Some(value) = inherited_proto_accessor_value(proto_obj, key, receiver) { + return Some(value); + } + } let field_val = if let Some(receiver) = receiver { let previous_this = js_implicit_this_set(receiver); let value = js_object_get_field_by_name(proto_obj as *const _, key);