fix(vm): 数组元素访问器属性触发 getter 并透传异常
This commit is contained in:
@@ -91,8 +91,10 @@ pub fn iterator_wrapper_next<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
|||||||
_ => return NativeResult::Err(crate::error::create_type_error(vm, "Iterator wrapper has no inner iterator")),
|
_ => 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) {
|
match next_array_like(vm, wrapper, inner, index_si) {
|
||||||
return NativeResult::Ok(result);
|
Ok(Some(result)) => return NativeResult::Ok(result),
|
||||||
|
Ok(None) => {}
|
||||||
|
Err(original) => return NativeResult::Err(original),
|
||||||
}
|
}
|
||||||
|
|
||||||
if inner.is_object() {
|
if inner.is_object() {
|
||||||
@@ -158,16 +160,29 @@ fn get_iterator<H: VmHost>(vm: &mut H, value: JsValue) -> Result<JsValue, JsValu
|
|||||||
Err(crate::error::create_type_error(vm, "value is not iterable"))
|
Err(crate::error::create_type_error(vm, "value is not iterable"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_array_like<H: VmHost>(vm: &mut H, wrapper: &mut JsObject, inner: JsValue, index_si: u32) -> Option<JsValue> {
|
fn next_array_like<H: VmHost>(
|
||||||
|
vm: &mut H, wrapper: &mut JsObject, inner: JsValue, index_si: u32,
|
||||||
|
) -> Result<Option<JsValue>, JsValue> {
|
||||||
if is_array_value(inner) {
|
if is_array_value(inner) {
|
||||||
let index = current_index(vm, wrapper, index_si);
|
let index = current_index(vm, wrapper, index_si);
|
||||||
let arr = unsafe { &*inner.as_js_object_ptr() };
|
let arr = unsafe { &*inner.as_js_object_ptr() };
|
||||||
if index < arr.prop_count() as usize {
|
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));
|
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() {
|
if inner.is_string() {
|
||||||
@@ -177,20 +192,20 @@ fn next_array_like<H: VmHost>(vm: &mut H, wrapper: &mut JsObject, inner: JsValue
|
|||||||
if let Some(ch) = chars.nth(index) {
|
if let Some(ch) = chars.nth(index) {
|
||||||
vm.set_or_create_prop_value(wrapper, index_si, JsValue::int((index + 1) as i32));
|
vm.set_or_create_prop_value(wrapper, index_si, JsValue::int((index + 1) as i32));
|
||||||
let value = vm.new_string(&ch.to_string());
|
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 产出值。
|
// for-of 循环默认迭代:Map 产出 [key, value] 对,Set 产出值。
|
||||||
if is_map_value(inner) {
|
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) {
|
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<H: VmHost>(vm: &mut H, wrapper: &JsObject, index_si: u32) -> usize {
|
fn current_index<H: VmHost>(vm: &mut H, wrapper: &JsObject, index_si: u32) -> usize {
|
||||||
|
|||||||
@@ -31,6 +31,24 @@ impl Vm {
|
|||||||
if obj.is_array() {
|
if obj.is_array() {
|
||||||
if let Some(index) = self.array_index_from_property_key(prop_name_si) {
|
if let Some(index) = self.array_index_from_property_key(prop_name_si) {
|
||||||
if index < obj.prop_vec_len() as u32 {
|
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));
|
return Ok(obj.get_prop_at(index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user