diff --git a/crates/oxide_builtins/src/iterator.rs b/crates/oxide_builtins/src/iterator.rs index 5a207f86..07a9902d 100644 --- a/crates/oxide_builtins/src/iterator.rs +++ b/crates/oxide_builtins/src/iterator.rs @@ -91,8 +91,10 @@ pub fn iterator_wrapper_next(vm: &mut H, args: &[u8]) -> NativeResult _ => return NativeResult::Err(crate::error::create_type_error(vm, "Iterator wrapper has no inner iterator")), }; - if let Some(result) = next_array_like(vm, wrapper, inner, index_si) { - return NativeResult::Ok(result); + match next_array_like(vm, wrapper, inner, index_si) { + Ok(Some(result)) => return NativeResult::Ok(result), + Ok(None) => {} + Err(original) => return NativeResult::Err(original), } if inner.is_object() { @@ -158,16 +160,29 @@ fn get_iterator(vm: &mut H, value: JsValue) -> Result(vm: &mut H, wrapper: &mut JsObject, inner: JsValue, index_si: u32) -> Option { +fn next_array_like( + vm: &mut H, wrapper: &mut JsObject, inner: JsValue, index_si: u32, +) -> Result, JsValue> { if is_array_value(inner) { let index = current_index(vm, wrapper, index_si); let arr = unsafe { &*inner.as_js_object_ptr() }; if index < arr.prop_count() as usize { - let value = arr.get_prop_at(index); + // 数组元素读取走 GetValue:普通数据属性返回槽值,访问器属性 + // (defineProperty getter)触发 getter 并透传异常。 + let key_si = vm.kernel_core().perm_interner().intern(&index.to_string()).0; + let value = match vm.ordinary_get(arr, key_si, inner) { + Ok(v) => v, + Err(err) => { + let exc = vm + .take_uncaught_value() + .unwrap_or_else(|| crate::error::create_error(vm, &err)); + return Err(exc); + } + }; vm.set_or_create_prop_value(wrapper, index_si, JsValue::int((index + 1) as i32)); - return Some(make_iter_result(vm, value, false)); + return Ok(Some(make_iter_result(vm, value, false))); } - return Some(make_iter_result(vm, JsValue::undefined(), true)); + return Ok(Some(make_iter_result(vm, JsValue::undefined(), true))); } if inner.is_string() { @@ -177,20 +192,20 @@ fn next_array_like(vm: &mut H, wrapper: &mut JsObject, inner: JsValue if let Some(ch) = chars.nth(index) { vm.set_or_create_prop_value(wrapper, index_si, JsValue::int((index + 1) as i32)); let value = vm.new_string(&ch.to_string()); - return Some(make_iter_result(vm, value, false)); + return Ok(Some(make_iter_result(vm, value, false))); } - return Some(make_iter_result(vm, JsValue::undefined(), true)); + return Ok(Some(make_iter_result(vm, JsValue::undefined(), true))); } // for-of 循环默认迭代:Map 产出 [key, value] 对,Set 产出值。 if is_map_value(inner) { - return Some(map_set_step(vm, wrapper, inner, index_si, MapSetMode::MapEntries)); + return Ok(Some(map_set_step(vm, wrapper, inner, index_si, MapSetMode::MapEntries))); } if is_set_value(inner) { - return Some(map_set_step(vm, wrapper, inner, index_si, MapSetMode::SetValues)); + return Ok(Some(map_set_step(vm, wrapper, inner, index_si, MapSetMode::SetValues))); } - None + Ok(None) } fn current_index(vm: &mut H, wrapper: &JsObject, index_si: u32) -> usize { diff --git a/crates/oxide_vm/src/vm_props.rs b/crates/oxide_vm/src/vm_props.rs index 83750f6d..be30fb26 100644 --- a/crates/oxide_vm/src/vm_props.rs +++ b/crates/oxide_vm/src/vm_props.rs @@ -31,6 +31,24 @@ impl Vm { if obj.is_array() { if let Some(index) = self.array_index_from_property_key(prop_name_si) { if index < obj.prop_vec_len() as u32 { + // 数组元素为访问器属性(defineProperty getter)时须触发 + // getter,而非直接读数据槽。 + if let Some(meta) = obj.prop_meta_at(index) { + if meta.is_accessor { + return if meta.get.is_undefined() { + Ok(JsValue::undefined()) + } else if let Some(tr) = target_reg { + let getter = meta.get; + let pushed = self.push_bytecode_getter_frame(getter, receiver, tr)?; + if pushed { + return Ok(JsValue::undefined()); + } + Ok(self.regs[tr as usize]) + } else { + self.call_function_sync(meta.get, receiver, &[]) + }; + } + } return Ok(obj.get_prop_at(index)); } }