mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 10:41:11 +08:00
feat: TypedArray 第一批解锁(%TypedArray% 构造器、原型访问器、of/from、bind 绑参、harness)
This commit is contained in:
@@ -1,11 +1,60 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::bind_constructor;
|
||||
use crate::bindings::{apply_binding_table, configure_native_constructor};
|
||||
use crate::bindings::{apply_binding_table, bind_accessor_getter, configure_native_constructor};
|
||||
use oxide_kernel::kernel::{KernelCore, KernelSession};
|
||||
use oxide_types::object::{JsObject, PropAttributes};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
/// 把 `%TypedArray%` 抽象构造器的 native 实现配置为恒抛 TypeError(不可 new/不可调用),
|
||||
/// 设置 `length` 属性为 0,并挂载静态 `of`/`from`(具体构造器经原型链继承)。
|
||||
fn bind_typed_array_abstract_ctor(core: &Arc<KernelCore>, session: &KernelSession) {
|
||||
let ctor_ptr = session.builtin_world().typed_array_constructor.as_ptr() as *mut JsObject;
|
||||
let ctor = unsafe { &mut *ctor_ptr };
|
||||
configure_native_constructor(
|
||||
ctor,
|
||||
oxide_builtins::typed_array::typed_array_abstract_constructor::<crate::vm::Vm> as *const (),
|
||||
0,
|
||||
);
|
||||
let length_si = core.perm_interner().intern("length").0;
|
||||
let length_shape = core.shape_forge().make_shape(ctor.shape_id(), length_si);
|
||||
ctor.set_shape_id(length_shape);
|
||||
ctor.ensure_hash_props().push(JsValue::int(0));
|
||||
let pos = ctor.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
|
||||
ctor.set_data_meta(pos, PropAttributes::new(false, false, true));
|
||||
|
||||
let sf = core.perm_interner().as_ref();
|
||||
let sh = core.shape_forge().as_ref();
|
||||
let world = session.builtin_world();
|
||||
let ctor_ptr = world.typed_array_constructor.as_ptr() as *mut JsObject;
|
||||
let ctor = unsafe { &mut *ctor_ptr };
|
||||
// SAFETY: of/from 是转成 *const () 的 NativeFn 函数项指针。
|
||||
let _ = world.bind_method(
|
||||
ctor,
|
||||
sh,
|
||||
sf,
|
||||
"of",
|
||||
unsafe {
|
||||
oxide_types::object::NativeFnPtr::from_raw(
|
||||
oxide_builtins::typed_array::typed_array_of::<crate::vm::Vm> as *const (),
|
||||
)
|
||||
},
|
||||
0,
|
||||
);
|
||||
let _ = world.bind_method(
|
||||
ctor,
|
||||
sh,
|
||||
sf,
|
||||
"from",
|
||||
unsafe {
|
||||
oxide_types::object::NativeFnPtr::from_raw(
|
||||
oxide_builtins::typed_array::typed_array_from::<crate::vm::Vm> as *const (),
|
||||
)
|
||||
},
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
/// 给构造器与对应原型设置 `BYTES_PER_ELEMENT`(只读、不可枚举、不可配置)。
|
||||
///
|
||||
/// # 步骤
|
||||
@@ -34,8 +83,11 @@ fn set_bypes_per_element(core: &Arc<KernelCore>, ctor_ptr: *mut JsObject, proto_
|
||||
macro_rules! bind_typed_array_constructor {
|
||||
($core:expr, $global:expr, $name:literal, $ctor_ptr:expr, $proto_ptr:expr, $bpe:expr, $ctor_fn:path) => {{
|
||||
let ctor = unsafe { &mut *$ctor_ptr };
|
||||
configure_native_constructor(ctor, ($ctor_fn as fn(&mut $crate::vm::Vm, &[u8]) -> oxide_runtime_api::NativeResult) as *const (), 1);
|
||||
bind_constructor!($core, $global, $name, $ctor_ptr, $ctor_fn, 1, hash: true);
|
||||
configure_native_constructor(ctor, ($ctor_fn as fn(&mut $crate::vm::Vm, &[u8]) -> oxide_runtime_api::NativeResult) as *const (), 3);
|
||||
bind_constructor!($core, $global, $name, $ctor_ptr, $ctor_fn, 3, hash: true);
|
||||
// Function.length 描述符:不可写、不可枚举、可配置。
|
||||
let len_pos = ctor.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
|
||||
ctor.set_data_meta(len_pos, PropAttributes::new(false, false, true));
|
||||
set_bypes_per_element($core, $ctor_ptr, $proto_ptr, $bpe);
|
||||
}};
|
||||
}
|
||||
@@ -58,14 +110,49 @@ pub fn bind_typed_array(core: &Arc<KernelCore>, session: &KernelSession, global:
|
||||
oxide_builtins::typed_array::typed_array_subarray::<crate::vm::Vm> as *const (),
|
||||
2,
|
||||
),
|
||||
(
|
||||
"toString",
|
||||
oxide_builtins::typed_array::typed_array_to_string::<crate::vm::Vm> as *const (),
|
||||
0,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
// 原型访问器:视图属性(buffer/byteOffset/byteLength/length)读内部数据槽,
|
||||
// @@toStringTag 返回具体类型名,供 Object.prototype.toString 区分类型。
|
||||
bind_accessor_getter(
|
||||
core,
|
||||
session,
|
||||
shared_proto,
|
||||
"buffer",
|
||||
oxide_builtins::typed_array::typed_array_buffer_getter::<crate::vm::Vm> as *const (),
|
||||
);
|
||||
bind_accessor_getter(
|
||||
core,
|
||||
session,
|
||||
shared_proto,
|
||||
"byteOffset",
|
||||
oxide_builtins::typed_array::typed_array_byte_offset_getter::<crate::vm::Vm> as *const (),
|
||||
);
|
||||
bind_accessor_getter(
|
||||
core,
|
||||
session,
|
||||
shared_proto,
|
||||
"byteLength",
|
||||
oxide_builtins::typed_array::typed_array_byte_length_getter::<crate::vm::Vm> as *const (),
|
||||
);
|
||||
bind_accessor_getter(
|
||||
core,
|
||||
session,
|
||||
shared_proto,
|
||||
"length",
|
||||
oxide_builtins::typed_array::typed_array_length_getter::<crate::vm::Vm> as *const (),
|
||||
);
|
||||
bind_accessor_getter(
|
||||
core,
|
||||
session,
|
||||
shared_proto,
|
||||
"@@toStringTag",
|
||||
oxide_builtins::typed_array::typed_array_to_string_tag_getter::<crate::vm::Vm> as *const (),
|
||||
);
|
||||
|
||||
bind_typed_array_abstract_ctor(core, session);
|
||||
|
||||
bind_typed_array_constructor!(
|
||||
core,
|
||||
global,
|
||||
|
||||
@@ -502,7 +502,7 @@ pub fn bind_global_builtin_slots(core: &Arc<KernelCore>, session: &KernelSession
|
||||
oxide_builtins::typed_array::biguint64array_constructor::<crate::vm::Vm> as *const (),
|
||||
),
|
||||
] {
|
||||
configure_existing_ctor(ctor, native_fn, 1);
|
||||
configure_existing_ctor(ctor, native_fn, 3);
|
||||
bind_existing_global(core, global, name, JsValue::from_js_object(ctor.as_ptr() as *mut JsObject));
|
||||
}
|
||||
|
||||
|
||||
@@ -323,7 +323,10 @@ impl Vm {
|
||||
return Err(self.error_message_text("TypeError", "Symbol.toPrimitive is not a function"));
|
||||
}
|
||||
let hint_val = self.new_string(if prefer_string { "string" } else { "number" });
|
||||
let result = self.call_function_sync(exotic, value, &[hint_val])?;
|
||||
let result = match self.call_function_sync(exotic, value, &[hint_val]) {
|
||||
Ok(r) => r,
|
||||
Err(err) => return self.raise_call_error(&err),
|
||||
};
|
||||
if result.is_object() {
|
||||
return Err(self.error_message_text("TypeError", "Cannot convert object to primitive value"));
|
||||
}
|
||||
@@ -351,7 +354,10 @@ impl Vm {
|
||||
return Ok(JsValue::undefined());
|
||||
}
|
||||
|
||||
let result = self.call_function_sync(method, value, &[])?;
|
||||
let result = match self.call_function_sync(method, value, &[]) {
|
||||
Ok(r) => r,
|
||||
Err(err) => return self.raise_call_error(&err),
|
||||
};
|
||||
if !result.is_object() {
|
||||
return Ok(result);
|
||||
}
|
||||
@@ -360,6 +366,28 @@ impl Vm {
|
||||
Err(self.error_message_text("TypeError", "Cannot convert object to primitive value"))
|
||||
}
|
||||
|
||||
/// 把 `call_function_sync` 返回的调用错误恢复为原始异常值并走异常展开,
|
||||
/// 使外围 try/catch 可捕获(native 函数抛错时原值存于 `last_uncaught_value`)。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// 仅在主 dispatch(`native_call_depth == 0`)下展开——此时 try_stack 只含当前
|
||||
/// 字节码的处理器,展开后 pc/regs[0] 不会被中途的原生调用栈覆盖。原生 builtin
|
||||
/// 内部(depth > 0)必须传播错误,由其调用边界(dispatch_native_call)转换。
|
||||
pub(crate) fn raise_call_error(&mut self, err: &str) -> Result<JsValue, String> {
|
||||
if self.native_call_depth == 0 {
|
||||
let exc = self
|
||||
.last_uncaught_value
|
||||
.take()
|
||||
.unwrap_or_else(|| oxide_builtins::error::create_error(self, err));
|
||||
let kind = self.thrown_error_kind(exc);
|
||||
self.exception_value = Some(exc);
|
||||
self.pending_error_kind = Some(kind);
|
||||
self.unwind()?;
|
||||
return Ok(JsValue::undefined());
|
||||
}
|
||||
Err(err.to_string())
|
||||
}
|
||||
|
||||
pub(crate) fn coerce_number_bounded(&mut self, value: JsValue) -> Result<f64, String> {
|
||||
let primitive = self.coerce_primitive_bounded(value, false)?;
|
||||
Ok(coercion::to_number(primitive))
|
||||
|
||||
@@ -108,7 +108,10 @@ impl Vm {
|
||||
}
|
||||
|
||||
if getter_obj.native_fn().is_some() {
|
||||
let result = self.call_function_sync(getter, receiver, &[])?;
|
||||
let result = match self.call_function_sync(getter, receiver, &[]) {
|
||||
Ok(v) => v,
|
||||
Err(err) => self.raise_call_error(&err)?,
|
||||
};
|
||||
self.regs[target_reg as usize] = result;
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user