mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 19:21:11 +08:00
fix: 修复全局边界安全与内存稳定性问题
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||||
use oxide_types::object::JsObject;
|
||||
use oxide_types::object::{JsObject, MAX_DENSE_PROPS};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
use crate::coercion;
|
||||
@@ -40,8 +40,20 @@ fn get_this_array_ref(val: JsValue) -> Result<*mut JsObject, JsValue> {
|
||||
|
||||
fn create_new_array(vm: &mut Vm, n: usize) -> *mut JsObject {
|
||||
let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
|
||||
vm.epoch()
|
||||
.alloc(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto), n, vm.epoch().bump()))
|
||||
vm.alloc_object(JsObject::new_array(
|
||||
EMPTY_SHAPE_ID,
|
||||
JsValue::from_js_object(proto),
|
||||
n.min(MAX_DENSE_PROPS),
|
||||
vm.epoch().bump(),
|
||||
))
|
||||
}
|
||||
|
||||
fn array_length_arg(vm: &mut Vm, value: JsValue) -> Result<usize, JsValue> {
|
||||
let n = coercion::to_number(value, vm.kernel_core().string_forge().as_ref());
|
||||
if !n.is_finite() || n < 0.0 || n.fract() != 0.0 || n > MAX_DENSE_PROPS as f64 {
|
||||
return Err(crate::builtins::error::create_range_error(vm, "Invalid array length"));
|
||||
}
|
||||
Ok(n as usize)
|
||||
}
|
||||
|
||||
fn invoke_native_callback(vm: &mut Vm, callback_val: JsValue, this_val: JsValue, cb_args: &[JsValue]) -> NativeResult {
|
||||
@@ -92,26 +104,18 @@ pub fn array_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
|
||||
if args.len() == 2 {
|
||||
let val = vm.reg(args[1]);
|
||||
if val.is_int() {
|
||||
let n = val.as_int().max(0) as usize;
|
||||
let arr = vm
|
||||
.epoch()
|
||||
.alloc(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, n, vm.epoch().bump()));
|
||||
return NativeResult::Ok(JsValue::from_js_object(arr));
|
||||
}
|
||||
if val.is_double() {
|
||||
let n = val.as_double() as usize;
|
||||
let arr = vm
|
||||
.epoch()
|
||||
.alloc(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, n, vm.epoch().bump()));
|
||||
if val.is_int() || val.is_double() {
|
||||
let n = match array_length_arg(vm, val) {
|
||||
Ok(n) => n,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
};
|
||||
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, n, vm.epoch().bump()));
|
||||
return NativeResult::Ok(JsValue::from_js_object(arr));
|
||||
}
|
||||
}
|
||||
|
||||
let n_elems = if args.len() > 1 { args.len() - 1 } else { 0 };
|
||||
let arr = vm
|
||||
.epoch()
|
||||
.alloc(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, n_elems, vm.epoch().bump()));
|
||||
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, n_elems, vm.epoch().bump()));
|
||||
for i in 0..n_elems {
|
||||
unsafe {
|
||||
(*arr).set_prop_at(i, vm.reg(args[1 + i]));
|
||||
@@ -373,22 +377,34 @@ pub fn array_flat(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let arr = unsafe { &*arr_ptr };
|
||||
let n = arr.prop_count() as usize;
|
||||
let depth = if args.len() > 1 {
|
||||
(coercion::to_number(vm.reg(args[1]), vm.kernel_core().string_forge().as_ref()) as i32).max(1) as usize
|
||||
let n = coercion::to_number(vm.reg(args[1]), vm.kernel_core().string_forge().as_ref());
|
||||
if !n.is_finite() {
|
||||
vm.kernel_core.config.max_call_depth
|
||||
} else {
|
||||
(n as i32).max(1) as usize
|
||||
}
|
||||
} else {
|
||||
1
|
||||
};
|
||||
}
|
||||
.min(vm.kernel_core.config.max_call_depth);
|
||||
|
||||
fn flatten(items: &[JsValue], remaining_depth: usize) -> Vec<JsValue> {
|
||||
fn flatten(items: &[JsValue], remaining_depth: usize, seen: &mut Vec<*mut JsObject>) -> Vec<JsValue> {
|
||||
let mut out = Vec::new();
|
||||
for &v in items {
|
||||
if remaining_depth > 0 && v.is_object() {
|
||||
let ptr = v.as_js_object_ptr();
|
||||
if !ptr.is_null() {
|
||||
if seen.iter().any(|seen_ptr| std::ptr::eq(*seen_ptr, ptr)) {
|
||||
out.push(v);
|
||||
continue;
|
||||
}
|
||||
let o = unsafe { &*ptr };
|
||||
if o.is_array() {
|
||||
seen.push(ptr);
|
||||
let on = o.prop_count() as usize;
|
||||
let sub: Vec<JsValue> = (0..on).map(|i| o.get_prop_at(i)).collect();
|
||||
let flat = flatten(&sub, remaining_depth - 1);
|
||||
let flat = flatten(&sub, remaining_depth - 1, seen);
|
||||
seen.pop();
|
||||
out.extend(flat);
|
||||
continue;
|
||||
}
|
||||
@@ -400,7 +416,8 @@ pub fn array_flat(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
let all: Vec<JsValue> = (0..n).map(|i| arr.get_prop_at(i)).collect();
|
||||
let flat = flatten(&all, depth);
|
||||
let mut seen = vec![arr_ptr];
|
||||
let flat = flatten(&all, depth, &mut seen);
|
||||
let new_arr = create_new_array(vm, flat.len());
|
||||
unsafe {
|
||||
for (i, val) in flat.iter().enumerate() {
|
||||
|
||||
@@ -66,7 +66,25 @@ pub(crate) fn new_array_buffer(vm: &mut Vm, data: Vec<u8>) -> *mut JsObject {
|
||||
JsValue::int(len as i32),
|
||||
PropAttributes::new(false, false, false),
|
||||
);
|
||||
vm.epoch().alloc(obj)
|
||||
vm.alloc_object(obj)
|
||||
}
|
||||
|
||||
pub(crate) fn drop_array_buffer_native(obj: &mut JsObject) -> u64 {
|
||||
if !obj.is_array_buffer_obj() {
|
||||
return 0;
|
||||
}
|
||||
let Some(ptr) = obj.native_fn() else {
|
||||
return 0;
|
||||
};
|
||||
let data_ptr = ptr.as_ptr() as *mut Vec<u8>;
|
||||
if data_ptr.is_null() {
|
||||
return 0;
|
||||
}
|
||||
// SAFETY: ArrayBuffer stores `Box<Vec<u8>>` in native_fn.
|
||||
let data = unsafe { Box::from_raw(data_ptr) };
|
||||
let bytes = std::mem::size_of::<Vec<u8>>() + data.capacity();
|
||||
obj.set_native_fn(None);
|
||||
bytes as u64
|
||||
}
|
||||
|
||||
pub(crate) fn array_buffer_data_ptr(vm: &mut Vm, this_val: JsValue) -> Result<*mut Vec<u8>, JsValue> {
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::native::NativeResult;
|
||||
use crate::vm::Vm;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct DataViewData {
|
||||
pub(crate) struct DataViewData {
|
||||
buffer: JsValue,
|
||||
byte_offset: usize,
|
||||
byte_length: usize,
|
||||
@@ -177,7 +177,72 @@ pub fn data_view_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
JsValue::int(byte_length as i32),
|
||||
PropAttributes::new(false, false, false),
|
||||
);
|
||||
NativeResult::Ok(JsValue::from_js_object(vm.epoch().alloc(obj)))
|
||||
NativeResult::Ok(JsValue::from_js_object(vm.alloc_object(obj)))
|
||||
}
|
||||
|
||||
fn data_view_data_ptr(obj: &JsObject) -> Option<*mut DataViewData> {
|
||||
if !obj.is_data_view_obj() {
|
||||
return None;
|
||||
}
|
||||
obj.native_fn().map(|ptr| ptr.as_ptr() as *mut DataViewData)
|
||||
}
|
||||
|
||||
pub(crate) fn data_view_native_edges(obj: &JsObject) -> Vec<JsValue> {
|
||||
let Some(ptr) = data_view_data_ptr(obj) else {
|
||||
return Vec::new();
|
||||
};
|
||||
if ptr.is_null() {
|
||||
return Vec::new();
|
||||
}
|
||||
let data = unsafe { *ptr };
|
||||
if data.buffer.is_object() {
|
||||
vec![data.buffer]
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn clone_data_view_native_with_rewrite<F>(old_obj: &JsObject, new_obj: &mut JsObject, mut rewrite: F)
|
||||
where
|
||||
F: FnMut(JsValue) -> JsValue,
|
||||
{
|
||||
let Some(ptr) = data_view_data_ptr(old_obj) else {
|
||||
return;
|
||||
};
|
||||
if ptr.is_null() {
|
||||
return;
|
||||
}
|
||||
let mut data = unsafe { *ptr };
|
||||
data.buffer = rewrite(data.buffer);
|
||||
let cloned = Box::into_raw(Box::new(data));
|
||||
new_obj.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(cloned as *const ()) }));
|
||||
}
|
||||
|
||||
pub(crate) fn rewrite_data_view_native<F>(obj: &mut JsObject, mut rewrite: F)
|
||||
where
|
||||
F: FnMut(JsValue) -> JsValue,
|
||||
{
|
||||
let Some(ptr) = data_view_data_ptr(obj) else {
|
||||
return;
|
||||
};
|
||||
if ptr.is_null() {
|
||||
return;
|
||||
}
|
||||
unsafe {
|
||||
(*ptr).buffer = rewrite((*ptr).buffer);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn drop_data_view_native(obj: &mut JsObject) -> u64 {
|
||||
let Some(ptr) = data_view_data_ptr(obj) else {
|
||||
return 0;
|
||||
};
|
||||
if ptr.is_null() {
|
||||
return 0;
|
||||
}
|
||||
unsafe { drop(Box::from_raw(ptr)) };
|
||||
obj.set_native_fn(None);
|
||||
std::mem::size_of::<DataViewData>() as u64
|
||||
}
|
||||
|
||||
pub fn data_view_get_int8(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
|
||||
@@ -201,7 +201,7 @@ pub fn date_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
obj.type_tag = JsObject::OBJ_TYPE_DATE;
|
||||
obj.set_prop_at(0, JsValue::float(timestamp));
|
||||
|
||||
let ptr = vm.epoch().alloc(obj);
|
||||
let ptr = vm.alloc_object(obj);
|
||||
NativeResult::Ok(JsValue::from_js_object(ptr))
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ pub fn function_bind(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
let bound_this = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
|
||||
let wrapper = vm.epoch().alloc(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
|
||||
let wrapper = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
|
||||
unsafe {
|
||||
(*wrapper).set_function(true);
|
||||
// SAFETY: bind_dispatcher is a NativeFn fn-item; valid to store as NativeFnPtr.
|
||||
|
||||
@@ -156,7 +156,7 @@ fn make_native_function(vm: &mut Vm, name: &str, native_fn: *const (), arg_count
|
||||
// SAFETY: native_fn is provided from a NativeFn fn item.
|
||||
func.set_native_fn(Some(unsafe { oxide_types::object::NativeFnPtr::from_raw(native_fn) }));
|
||||
func.set_native_arg_count(arg_count);
|
||||
let func = vm.epoch().alloc(func);
|
||||
let func = vm.alloc_object(func);
|
||||
let name_si = vm.kernel_core().string_forge().intern("name").0;
|
||||
let value = vm.intern(name);
|
||||
let func_ref = unsafe { &mut *func };
|
||||
|
||||
@@ -48,7 +48,7 @@ fn value_to_jsvalue(vm: &mut Vm, val: &serde_json::Value) -> JsValue {
|
||||
serde_json::Value::Array(arr) => {
|
||||
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
|
||||
let n = arr.len();
|
||||
let array_obj = vm.epoch().alloc(JsObject::new_array(
|
||||
let array_obj = vm.alloc_object(JsObject::new_array(
|
||||
EMPTY_SHAPE_ID,
|
||||
JsValue::from_js_object(array_proto),
|
||||
n,
|
||||
@@ -72,7 +72,7 @@ fn value_to_jsvalue(vm: &mut Vm, val: &serde_json::Value) -> JsValue {
|
||||
obj.set_shape_id(new_shape);
|
||||
obj.ensure_hash_props().push(jsv);
|
||||
}
|
||||
let obj_ptr = vm.epoch().alloc(obj);
|
||||
let obj_ptr = vm.alloc_object(obj);
|
||||
JsValue::from_js_object(obj_ptr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ fn alloc_map(vm: &mut Vm) -> *mut JsObject {
|
||||
obj.set_map(true);
|
||||
let inner = new_map_inner();
|
||||
obj.set_native_data(inner as *mut u8);
|
||||
vm.epoch().alloc(obj)
|
||||
vm.alloc_object(obj)
|
||||
}
|
||||
|
||||
pub(crate) fn map_native_edges(obj: &JsObject) -> Vec<JsValue> {
|
||||
|
||||
@@ -39,7 +39,7 @@ pub(crate) fn walk_own_keys(vm: &Vm, obj: &JsObject) -> Vec<(u32, u32)> {
|
||||
}
|
||||
|
||||
pub fn object_constructor(vm: &mut Vm, _args: &[u8]) -> NativeResult {
|
||||
let obj = vm.epoch().alloc(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
|
||||
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
|
||||
NativeResult::Ok(JsValue::from_js_object(obj))
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ pub fn object_keys(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
|
||||
let n = key_names.len();
|
||||
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
|
||||
let arr = vm.epoch().alloc(JsObject::new_array(
|
||||
let arr = vm.alloc_object(JsObject::new_array(
|
||||
EMPTY_SHAPE_ID,
|
||||
JsValue::from_js_object(array_proto),
|
||||
n,
|
||||
@@ -94,7 +94,7 @@ pub fn object_create(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
if !proto_val.is_null() && !proto_val.is_object() {
|
||||
return NativeResult::Ok(JsValue::undefined());
|
||||
}
|
||||
let obj = vm.epoch().alloc(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
|
||||
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
|
||||
NativeResult::Ok(JsValue::from_js_object(obj))
|
||||
}
|
||||
|
||||
@@ -412,7 +412,7 @@ pub fn object_get_own_property_names(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
|
||||
let n = key_names.len();
|
||||
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
|
||||
let arr = vm.epoch().alloc(JsObject::new_array(
|
||||
let arr = vm.alloc_object(JsObject::new_array(
|
||||
EMPTY_SHAPE_ID,
|
||||
JsValue::from_js_object(array_proto),
|
||||
n,
|
||||
@@ -450,7 +450,7 @@ pub fn object_from_entries(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
if !entries.is_object() {
|
||||
return NativeResult::Ok(JsValue::null());
|
||||
}
|
||||
let obj_ptr = vm.epoch().alloc(JsObject::new_empty(
|
||||
let obj_ptr = vm.alloc_object(JsObject::new_empty(
|
||||
EMPTY_SHAPE_ID,
|
||||
JsValue::from_js_object(vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject),
|
||||
));
|
||||
@@ -517,7 +517,7 @@ pub fn object_entries(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let keys = walk_own_keys(vm, obj);
|
||||
let n = keys.len();
|
||||
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
|
||||
let arr = vm.epoch().alloc(JsObject::new_array(
|
||||
let arr = vm.alloc_object(JsObject::new_array(
|
||||
EMPTY_SHAPE_ID,
|
||||
JsValue::from_js_object(array_proto),
|
||||
n,
|
||||
@@ -527,7 +527,7 @@ pub fn object_entries(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let key_str = vm.kernel_core().string_forge().lookup(*si).unwrap_or_default();
|
||||
let key_val = vm.intern(&key_str);
|
||||
let val = obj.get_prop_at(*offset);
|
||||
let pair = vm.epoch().alloc(JsObject::new_array(
|
||||
let pair = vm.alloc_object(JsObject::new_array(
|
||||
EMPTY_SHAPE_ID,
|
||||
JsValue::from_js_object(array_proto),
|
||||
2,
|
||||
@@ -552,7 +552,7 @@ pub fn object_values(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let keys = walk_own_keys(vm, obj);
|
||||
let n = keys.len();
|
||||
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
|
||||
let arr = vm.epoch().alloc(JsObject::new_array(
|
||||
let arr = vm.alloc_object(JsObject::new_array(
|
||||
EMPTY_SHAPE_ID,
|
||||
JsValue::from_js_object(array_proto),
|
||||
n,
|
||||
|
||||
@@ -221,7 +221,7 @@ fn own_field(vm: &Vm, obj: &JsObject, prop_si: u32) -> Option<JsValue> {
|
||||
|
||||
fn make_string_array(vm: &mut Vm, parts: &[String]) -> JsValue {
|
||||
let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
|
||||
let arr = vm.epoch().alloc(JsObject::new_array(
|
||||
let arr = vm.alloc_object(JsObject::new_array(
|
||||
EMPTY_SHAPE_ID,
|
||||
JsValue::from_js_object(proto),
|
||||
parts.len(),
|
||||
|
||||
@@ -103,7 +103,7 @@ pub fn regexp_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
// SAFETY: re_ptr is a Box<regex::Regex> pointer stored by the constructor via
|
||||
// NativeFnPtr::from_raw(re_ptr as *const ()). RegExp objects repurpose the native_fn
|
||||
// field to hold the compiled Regex — not a NativeFn pointer. Valid for the object's
|
||||
// lifetime because the Box is never freed (intentional leak tied to epoch).
|
||||
// lifetime; VM reset drops the Box through `drop_regexp_native`.
|
||||
obj.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(re_ptr as *const ()) }));
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -123,10 +123,26 @@ pub fn regexp_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
set_prop(&mut obj, "unicode", JsValue::bool(false), vm);
|
||||
obj.type_tag = JsObject::OBJ_TYPE_REGEXP;
|
||||
|
||||
let obj_ptr = vm.epoch().alloc(obj);
|
||||
let obj_ptr = vm.alloc_object(obj);
|
||||
NativeResult::Ok(JsValue::from_js_object(obj_ptr))
|
||||
}
|
||||
|
||||
pub(crate) fn drop_regexp_native(obj: &mut JsObject) -> u64 {
|
||||
if !obj.is_regexp_obj() {
|
||||
return 0;
|
||||
}
|
||||
let Some(ptr) = obj.native_fn() else {
|
||||
return 0;
|
||||
};
|
||||
let regex_ptr = ptr.as_ptr() as *mut regex::Regex;
|
||||
if regex_ptr.is_null() {
|
||||
return 0;
|
||||
}
|
||||
unsafe { drop(Box::from_raw(regex_ptr)) };
|
||||
obj.set_native_fn(None);
|
||||
std::mem::size_of::<regex::Regex>() as u64
|
||||
}
|
||||
|
||||
pub fn regexp_test(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let re_ptr = match get_regexp_ptr(vm, args) {
|
||||
Ok(ptr) => ptr,
|
||||
@@ -231,7 +247,7 @@ pub fn regexp_exec(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
set_prop_at(re_ptr, 0, JsValue::int(m.end() as i32));
|
||||
}
|
||||
|
||||
let obj_ptr = vm.epoch().alloc(match_obj);
|
||||
let obj_ptr = vm.alloc_object(match_obj);
|
||||
NativeResult::Ok(JsValue::from_js_object(obj_ptr))
|
||||
} else {
|
||||
if is_global {
|
||||
|
||||
@@ -105,7 +105,7 @@ fn alloc_set(vm: &mut Vm) -> *mut JsObject {
|
||||
obj.set_set(true);
|
||||
let inner = new_set_inner();
|
||||
obj.set_native_data(inner as *mut u8);
|
||||
vm.epoch().alloc(obj)
|
||||
vm.alloc_object(obj)
|
||||
}
|
||||
|
||||
pub(crate) fn set_native_edges(obj: &JsObject) -> Vec<JsValue> {
|
||||
|
||||
@@ -288,6 +288,9 @@ pub fn string_pad_start(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
} else {
|
||||
s_len
|
||||
};
|
||||
if target > 10000 {
|
||||
return NativeResult::Err(crate::builtins::error::create_range_error(vm, "Invalid string length"));
|
||||
}
|
||||
let pad = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { " ".to_string() };
|
||||
if s_len >= target || pad.is_empty() {
|
||||
return NativeResult::Ok(vm.intern(&s));
|
||||
@@ -308,6 +311,9 @@ pub fn string_pad_end(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
} else {
|
||||
s_len
|
||||
};
|
||||
if target > 10000 {
|
||||
return NativeResult::Err(crate::builtins::error::create_range_error(vm, "Invalid string length"));
|
||||
}
|
||||
let pad = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { " ".to_string() };
|
||||
if s_len >= target || pad.is_empty() {
|
||||
return NativeResult::Ok(vm.intern(&s));
|
||||
|
||||
@@ -117,7 +117,72 @@ fn create_typed_array(
|
||||
JsValue::int(length as i32),
|
||||
PropAttributes::new(false, false, false),
|
||||
);
|
||||
vm.epoch().alloc(obj)
|
||||
vm.alloc_object(obj)
|
||||
}
|
||||
|
||||
fn typed_array_data_ptr(obj: &JsObject) -> Option<*mut TypedArrayData> {
|
||||
if !obj.is_typed_array_obj() {
|
||||
return None;
|
||||
}
|
||||
obj.native_fn().map(|ptr| ptr.as_ptr() as *mut TypedArrayData)
|
||||
}
|
||||
|
||||
pub(crate) fn typed_array_native_edges(obj: &JsObject) -> Vec<JsValue> {
|
||||
let Some(ptr) = typed_array_data_ptr(obj) else {
|
||||
return Vec::new();
|
||||
};
|
||||
if ptr.is_null() {
|
||||
return Vec::new();
|
||||
}
|
||||
let data = unsafe { *ptr };
|
||||
if data.buffer.is_object() {
|
||||
vec![data.buffer]
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn clone_typed_array_native_with_rewrite<F>(old_obj: &JsObject, new_obj: &mut JsObject, mut rewrite: F)
|
||||
where
|
||||
F: FnMut(JsValue) -> JsValue,
|
||||
{
|
||||
let Some(ptr) = typed_array_data_ptr(old_obj) else {
|
||||
return;
|
||||
};
|
||||
if ptr.is_null() {
|
||||
return;
|
||||
}
|
||||
let mut data = unsafe { *ptr };
|
||||
data.buffer = rewrite(data.buffer);
|
||||
let cloned = Box::into_raw(Box::new(data));
|
||||
new_obj.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(cloned as *const ()) }));
|
||||
}
|
||||
|
||||
pub(crate) fn rewrite_typed_array_native<F>(obj: &mut JsObject, mut rewrite: F)
|
||||
where
|
||||
F: FnMut(JsValue) -> JsValue,
|
||||
{
|
||||
let Some(ptr) = typed_array_data_ptr(obj) else {
|
||||
return;
|
||||
};
|
||||
if ptr.is_null() {
|
||||
return;
|
||||
}
|
||||
unsafe {
|
||||
(*ptr).buffer = rewrite((*ptr).buffer);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn drop_typed_array_native(obj: &mut JsObject) -> u64 {
|
||||
let Some(ptr) = typed_array_data_ptr(obj) else {
|
||||
return 0;
|
||||
};
|
||||
if ptr.is_null() {
|
||||
return 0;
|
||||
}
|
||||
unsafe { drop(Box::from_raw(ptr)) };
|
||||
obj.set_native_fn(None);
|
||||
std::mem::size_of::<TypedArrayData>() as u64
|
||||
}
|
||||
|
||||
pub(crate) fn get_typed_array_data(vm: &mut Vm, this_val: JsValue) -> Result<TypedArrayData, JsValue> {
|
||||
|
||||
Reference in New Issue
Block a user