mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 修复数组长度与槽位索引截断问题
This commit is contained in:
@@ -167,7 +167,7 @@ fn format_object(string_forge: &StringForge, shape_forge: &ShapeForge, obj: &JsO
|
||||
break;
|
||||
}
|
||||
}
|
||||
let mut pos: u8 = 0;
|
||||
let mut pos: u32 = 0;
|
||||
for id in shape_ids.iter().rev() {
|
||||
if let Some(shape) = shape_forge.get_shape(*id) {
|
||||
if shape.property_name != 0 {
|
||||
@@ -190,7 +190,7 @@ fn format_array(string_forge: &StringForge, shape_forge: &ShapeForge, obj: &JsOb
|
||||
let len = obj.prop_vec_len();
|
||||
let mut items = Vec::new();
|
||||
for i in 0..len {
|
||||
let val = obj.get_prop_at(i as u8);
|
||||
let val = obj.get_prop_at(i);
|
||||
items.push(format_js_value(string_forge, shape_forge, val));
|
||||
}
|
||||
format!("[{}]", items.join(", "))
|
||||
|
||||
@@ -318,19 +318,8 @@ impl Compiler {
|
||||
self.count_expression(expr, ctx);
|
||||
}
|
||||
}
|
||||
// CALL_NATIVE: 1 opcode + 1 ext word; CALL(0x40): 1 opcode
|
||||
let is_builtin = match &call.callee {
|
||||
Expression::Identifier(ident) => ctx.is_builtin(ident.name.as_str()),
|
||||
Expression::StaticMemberExpression(m) => {
|
||||
if let Expression::Identifier(ident) = &m.object {
|
||||
ctx.is_builtin(ident.name.as_str())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
ctx.projected_pc += if is_builtin { 2 } else { 1 };
|
||||
// CALL and CALL_NATIVE both carry 1 ext word for arg_count.
|
||||
ctx.projected_pc += 2;
|
||||
ctx.alloc_reg(); // result register
|
||||
ctx.projected_pc += 1; // LOAD_VAR result <- regs[0]
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ use crate::shape_forge::ShapeId;
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PropTemplate {
|
||||
pub shape_id: ShapeId,
|
||||
pub position: u8,
|
||||
pub prop_name: u32,
|
||||
pub position: u32,
|
||||
pub generation: u32,
|
||||
}
|
||||
|
||||
@@ -67,12 +68,14 @@ mod tests {
|
||||
let forge = PropForge::new();
|
||||
let t = PropTemplate {
|
||||
shape_id: 1,
|
||||
prop_name: 11,
|
||||
position: 3,
|
||||
generation: 10,
|
||||
};
|
||||
forge.upsert(1, t);
|
||||
let got = forge.get_template(1).unwrap();
|
||||
assert_eq!(got.shape_id, 1);
|
||||
assert_eq!(got.prop_name, 11);
|
||||
assert_eq!(got.position, 3);
|
||||
assert_eq!(got.generation, 10);
|
||||
}
|
||||
@@ -84,6 +87,7 @@ mod tests {
|
||||
1,
|
||||
PropTemplate {
|
||||
shape_id: 1,
|
||||
prop_name: 11,
|
||||
position: 3,
|
||||
generation: 10,
|
||||
},
|
||||
@@ -92,6 +96,7 @@ mod tests {
|
||||
1,
|
||||
PropTemplate {
|
||||
shape_id: 1,
|
||||
prop_name: 12,
|
||||
position: 7,
|
||||
generation: 5,
|
||||
},
|
||||
@@ -107,6 +112,7 @@ mod tests {
|
||||
1,
|
||||
PropTemplate {
|
||||
shape_id: 1,
|
||||
prop_name: 11,
|
||||
position: 3,
|
||||
generation: 5,
|
||||
},
|
||||
@@ -115,6 +121,7 @@ mod tests {
|
||||
1,
|
||||
PropTemplate {
|
||||
shape_id: 1,
|
||||
prop_name: 12,
|
||||
position: 7,
|
||||
generation: 10,
|
||||
},
|
||||
|
||||
@@ -46,8 +46,8 @@ impl ShapeForge {
|
||||
((parent_id as u64) << 32) | (prop_name as u64)
|
||||
}
|
||||
|
||||
fn compute_depth(shape_id: ShapeId, shapes: &[Option<Arc<Shape>>]) -> u8 {
|
||||
let mut count = 0u8;
|
||||
fn compute_depth(shape_id: ShapeId, shapes: &[Option<Arc<Shape>>]) -> u32 {
|
||||
let mut count = 0u32;
|
||||
let mut cursor = Some(shape_id);
|
||||
while let Some(id) = cursor {
|
||||
match shapes.get((id - 1) as usize).and_then(|s| s.clone()) {
|
||||
@@ -94,10 +94,10 @@ impl ShapeForge {
|
||||
shapes.get((id - 1) as usize).and_then(|s| s.clone())
|
||||
}
|
||||
|
||||
pub fn lookup_position(&self, shape_id: ShapeId, prop_name: StringIndex) -> Option<u8> {
|
||||
pub fn lookup_position(&self, shape_id: ShapeId, prop_name: StringIndex) -> Option<u32> {
|
||||
let shapes = self.shapes.read().unwrap();
|
||||
let total_depth = Self::compute_depth(shape_id, &shapes);
|
||||
let mut step: u8 = 0;
|
||||
let mut step: u32 = 0;
|
||||
let mut cursor = Some(shape_id);
|
||||
while let Some(id) = cursor {
|
||||
match shapes.get((id - 1) as usize).and_then(|s| s.clone()) {
|
||||
@@ -131,9 +131,9 @@ impl ShapeForge {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn shape_prop_count(&self, shape_id: ShapeId) -> u8 {
|
||||
pub fn shape_prop_count(&self, shape_id: ShapeId) -> u32 {
|
||||
let shapes = self.shapes.read().unwrap();
|
||||
let mut count = 0u8;
|
||||
let mut count = 0u32;
|
||||
let mut cursor = Some(shape_id);
|
||||
while let Some(id) = cursor {
|
||||
match shapes.get((id - 1) as usize).and_then(|s| s.clone()) {
|
||||
|
||||
@@ -2,6 +2,41 @@ use crate::value::JsValue;
|
||||
|
||||
pub type ShapeId = u32;
|
||||
|
||||
pub trait PropIndex {
|
||||
fn to_u32(self) -> u32;
|
||||
}
|
||||
|
||||
impl PropIndex for u8 {
|
||||
fn to_u32(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl PropIndex for u16 {
|
||||
fn to_u32(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl PropIndex for u32 {
|
||||
fn to_u32(self) -> u32 {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl PropIndex for usize {
|
||||
fn to_u32(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl PropIndex for i32 {
|
||||
fn to_u32(self) -> u32 {
|
||||
debug_assert!(self >= 0, "property index must be non-negative");
|
||||
self.max(0) as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// Layout (56B):
|
||||
/// header: u32 bits
|
||||
/// [0:23] shape_id
|
||||
@@ -82,19 +117,19 @@ impl JsObject {
|
||||
|
||||
/// Returns property count from the hash_props vec length.
|
||||
/// Returns 0 if hash_props has not been allocated.
|
||||
pub fn prop_count(&self) -> u8 {
|
||||
pub fn prop_count(&self) -> u32 {
|
||||
if self.hash_props.is_null() {
|
||||
0
|
||||
} else {
|
||||
let vec = unsafe { &*(self.hash_props as *const Vec<Box<JsValue>>) };
|
||||
vec.len() as u8
|
||||
vec.len() as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the length of hash_props vec. Truncates or extends with undefined.
|
||||
pub fn set_prop_count(&mut self, count: u8) {
|
||||
pub fn set_prop_count(&mut self, count: impl PropIndex) {
|
||||
let vec = self.ensure_hash_props();
|
||||
let target = count as usize;
|
||||
let target = count.to_u32() as usize;
|
||||
if target < vec.len() {
|
||||
vec.truncate(target);
|
||||
} else {
|
||||
@@ -152,20 +187,20 @@ impl JsObject {
|
||||
|
||||
/// Get property value at position index in the vec.
|
||||
/// Returns JsValue::undefined() if hash_props not allocated or position out of bounds.
|
||||
pub fn get_prop_at(&self, position: u8) -> JsValue {
|
||||
pub fn get_prop_at(&self, position: impl PropIndex) -> JsValue {
|
||||
if self.hash_props.is_null() {
|
||||
return JsValue::undefined();
|
||||
}
|
||||
let vec = unsafe { &*(self.hash_props as *const Vec<Box<JsValue>>) };
|
||||
vec.get(position as usize)
|
||||
vec.get(position.to_u32() as usize)
|
||||
.map(|b| **b)
|
||||
.unwrap_or(JsValue::undefined())
|
||||
}
|
||||
|
||||
/// Set property value at position index. Vec auto-grows if needed.
|
||||
pub fn set_prop_at(&mut self, position: u8, val: JsValue) {
|
||||
pub fn set_prop_at(&mut self, position: impl PropIndex, val: JsValue) {
|
||||
let vec = self.ensure_hash_props();
|
||||
let pos = position as usize;
|
||||
let pos = position.to_u32() as usize;
|
||||
if pos < vec.len() {
|
||||
*vec[pos] = val;
|
||||
} else {
|
||||
@@ -177,21 +212,22 @@ impl JsObject {
|
||||
}
|
||||
|
||||
/// Push a value onto hash_props vec. Returns the index position.
|
||||
pub fn push_prop(&mut self, val: JsValue) -> u8 {
|
||||
pub fn push_prop(&mut self, val: JsValue) -> u32 {
|
||||
let vec = self.ensure_hash_props();
|
||||
let pos = vec.len();
|
||||
vec.push(Box::new(val));
|
||||
pos as u8
|
||||
pos as u32
|
||||
}
|
||||
|
||||
/// Get a stable pointer to the Box<JsValue> at position.
|
||||
/// Returns None if hash_props not allocated or position out of bounds.
|
||||
pub fn prop_ptr_at(&self, position: u8) -> Option<*const JsValue> {
|
||||
pub fn prop_ptr_at(&self, position: impl PropIndex) -> Option<*const JsValue> {
|
||||
if self.hash_props.is_null() {
|
||||
return None;
|
||||
}
|
||||
let vec = unsafe { &*(self.hash_props as *const Vec<Box<JsValue>>) };
|
||||
vec.get(position as usize).map(|b| &**b as *const JsValue)
|
||||
vec.get(position.to_u32() as usize)
|
||||
.map(|b| &**b as *const JsValue)
|
||||
}
|
||||
|
||||
/// Get the length of hash_props vec (returns 0 if not allocated).
|
||||
|
||||
@@ -71,8 +71,8 @@ impl ShapeStore {
|
||||
new_id
|
||||
}
|
||||
|
||||
fn lookup_position(&self, shape_id: ShapeId, prop_name: StringIndex) -> Option<u8> {
|
||||
let mut depth: u8 = 0;
|
||||
fn lookup_position(&self, shape_id: ShapeId, prop_name: StringIndex) -> Option<u32> {
|
||||
let mut depth: u32 = 0;
|
||||
let mut cursor = Some(shape_id);
|
||||
while let Some(id) = cursor {
|
||||
match self.get_shape(id) {
|
||||
@@ -86,7 +86,7 @@ impl ShapeStore {
|
||||
}
|
||||
}
|
||||
let total_depth = depth;
|
||||
let mut step: u8 = 0;
|
||||
let mut step: u32 = 0;
|
||||
cursor = Some(shape_id);
|
||||
while let Some(id) = cursor {
|
||||
match self.get_shape(id) {
|
||||
@@ -119,8 +119,8 @@ impl ShapeStore {
|
||||
false
|
||||
}
|
||||
|
||||
fn shape_prop_count(&self, shape_id: ShapeId) -> u8 {
|
||||
let mut count = 0u8;
|
||||
fn shape_prop_count(&self, shape_id: ShapeId) -> u32 {
|
||||
let mut count = 0u32;
|
||||
let mut cursor = Some(shape_id);
|
||||
while let Some(id) = cursor {
|
||||
match self.get_shape(id) {
|
||||
@@ -151,7 +151,7 @@ pub fn make_shape(parent_id: ShapeId, prop_name: StringIndex) -> ShapeId {
|
||||
store().lock().unwrap().make_shape(parent_id, prop_name)
|
||||
}
|
||||
|
||||
pub fn lookup_position(shape_id: ShapeId, prop_name: StringIndex) -> Option<u8> {
|
||||
pub fn lookup_position(shape_id: ShapeId, prop_name: StringIndex) -> Option<u32> {
|
||||
store().lock().unwrap().lookup_position(shape_id, prop_name)
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ pub fn has_property(shape_id: ShapeId, prop_name: StringIndex) -> bool {
|
||||
store().lock().unwrap().has_property(shape_id, prop_name)
|
||||
}
|
||||
|
||||
pub fn shape_prop_count(shape_id: ShapeId) -> u8 {
|
||||
pub fn shape_prop_count(shape_id: ShapeId) -> u32 {
|
||||
store().lock().unwrap().shape_prop_count(shape_id)
|
||||
}
|
||||
|
||||
|
||||
@@ -100,11 +100,11 @@ pub fn array_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
));
|
||||
for i in 0..n_elems {
|
||||
unsafe {
|
||||
(*arr).set_prop_at(i as u8, vm.reg(args[1 + i]));
|
||||
(*arr).set_prop_at(i, vm.reg(args[1 + i]));
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
(*arr).set_prop_count(n_elems as u8);
|
||||
(*arr).set_prop_count(n_elems);
|
||||
}
|
||||
Ok(JsValue::from_js_object(arr))
|
||||
}
|
||||
@@ -112,14 +112,13 @@ pub fn array_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
pub fn array_push(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
let mut len = arr.prop_count() as usize;
|
||||
let mut len = arr.prop_count();
|
||||
for &arg_reg in args.iter().skip(1) {
|
||||
let val = vm.reg(arg_reg);
|
||||
arr.set_prop_at(len as u8, val);
|
||||
arr.set_prop_at(len, val);
|
||||
len += 1;
|
||||
}
|
||||
let stored_len = (len as u8).min(31);
|
||||
arr.set_prop_count(stored_len);
|
||||
arr.set_prop_count(len);
|
||||
Ok(JsValue::int(len as i32))
|
||||
}
|
||||
|
||||
@@ -156,9 +155,9 @@ pub fn array_slice(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let new_arr = create_new_array(vm, count);
|
||||
unsafe {
|
||||
for i in 0..count {
|
||||
(*new_arr).set_prop_at(i as u8, arr.get_prop_at((start + i) as u8));
|
||||
(*new_arr).set_prop_at(i, arr.get_prop_at(start + i));
|
||||
}
|
||||
(*new_arr).set_prop_count(count.min(31) as u8);
|
||||
(*new_arr).set_prop_count(count);
|
||||
}
|
||||
Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
@@ -191,36 +190,36 @@ pub fn array_splice(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
|
||||
let mut removed: Vec<JsValue> = Vec::new();
|
||||
for i in 0..delete_count {
|
||||
removed.push(arr.get_prop_at((start + i) as u8));
|
||||
removed.push(arr.get_prop_at(start + i));
|
||||
}
|
||||
|
||||
if insert_count > delete_count {
|
||||
let shift = insert_count - delete_count;
|
||||
for i in (start + delete_count..n).rev() {
|
||||
let val = arr.get_prop_at(i as u8);
|
||||
arr.set_prop_at((i + shift) as u8, val);
|
||||
let val = arr.get_prop_at(i);
|
||||
arr.set_prop_at(i + shift, val);
|
||||
}
|
||||
} else if insert_count < delete_count {
|
||||
let shift = delete_count - insert_count;
|
||||
for i in start + delete_count..n {
|
||||
let val = arr.get_prop_at(i as u8);
|
||||
arr.set_prop_at((i - shift) as u8, val);
|
||||
let val = arr.get_prop_at(i);
|
||||
arr.set_prop_at(i - shift, val);
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..insert_count {
|
||||
arr.set_prop_at((start + i) as u8, vm.reg(args[3 + i]));
|
||||
arr.set_prop_at(start + i, vm.reg(args[3 + i]));
|
||||
}
|
||||
|
||||
let new_len = n + insert_count - delete_count;
|
||||
arr.set_prop_count(new_len.min(31) as u8);
|
||||
arr.set_prop_count(new_len);
|
||||
|
||||
let removed_arr = create_new_array(vm, removed.len());
|
||||
unsafe {
|
||||
for (i, val) in removed.iter().enumerate() {
|
||||
(*removed_arr).set_prop_at(i as u8, *val);
|
||||
(*removed_arr).set_prop_at(i, *val);
|
||||
}
|
||||
(*removed_arr).set_prop_count(removed.len().min(31) as u8);
|
||||
(*removed_arr).set_prop_count(removed.len());
|
||||
}
|
||||
Ok(JsValue::from_js_object(removed_arr))
|
||||
}
|
||||
@@ -231,7 +230,7 @@ pub fn array_concat(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let n = arr.prop_count() as usize;
|
||||
let mut all: Vec<JsValue> = Vec::new();
|
||||
for i in 0..n {
|
||||
all.push(arr.get_prop_at(i as u8));
|
||||
all.push(arr.get_prop_at(i));
|
||||
}
|
||||
for &arg_reg in args.iter().skip(1) {
|
||||
let val = vm.reg(arg_reg);
|
||||
@@ -242,7 +241,7 @@ pub fn array_concat(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
if o.is_array() {
|
||||
let on = o.prop_count() as usize;
|
||||
for i in 0..on {
|
||||
all.push(o.get_prop_at(i as u8));
|
||||
all.push(o.get_prop_at(i));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -253,9 +252,9 @@ pub fn array_concat(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let new_arr = create_new_array(vm, all.len());
|
||||
unsafe {
|
||||
for (i, val) in all.iter().enumerate() {
|
||||
(*new_arr).set_prop_at(i as u8, *val);
|
||||
(*new_arr).set_prop_at(i, *val);
|
||||
}
|
||||
(*new_arr).set_prop_count(all.len().min(31) as u8);
|
||||
(*new_arr).set_prop_count(all.len());
|
||||
}
|
||||
Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
@@ -272,7 +271,7 @@ pub fn array_join(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let sf = vm.kernel().string_forge().as_ref();
|
||||
let parts: Vec<String> = (0..n)
|
||||
.map(|i| {
|
||||
let v = arr.get_prop_at(i as u8);
|
||||
let v = arr.get_prop_at(i);
|
||||
if v.is_undefined() || v.is_null() {
|
||||
String::new()
|
||||
} else {
|
||||
@@ -294,7 +293,7 @@ pub fn array_index_of(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
let target = vm.reg(args[1]);
|
||||
for i in 0..n {
|
||||
if coercion::strict_equality(arr.get_prop_at(i as u8), target) {
|
||||
if coercion::strict_equality(arr.get_prop_at(i), target) {
|
||||
return Ok(JsValue::int(i as i32));
|
||||
}
|
||||
}
|
||||
@@ -310,7 +309,7 @@ pub fn array_includes(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
let target = vm.reg(args[1]);
|
||||
for i in 0..n {
|
||||
let elem = arr.get_prop_at(i as u8);
|
||||
let elem = arr.get_prop_at(i);
|
||||
if elem.is_double() && target.is_double() {
|
||||
let ea = elem.as_double();
|
||||
let ta = target.as_double();
|
||||
@@ -332,9 +331,9 @@ pub fn array_reverse(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let mut i = 0;
|
||||
let mut j = n.saturating_sub(1);
|
||||
while i < j {
|
||||
let tmp = arr.get_prop_at(i as u8);
|
||||
arr.set_prop_at(i as u8, arr.get_prop_at(j as u8));
|
||||
arr.set_prop_at(j as u8, tmp);
|
||||
let tmp = arr.get_prop_at(i);
|
||||
arr.set_prop_at(i, arr.get_prop_at(j));
|
||||
arr.set_prop_at(j, tmp);
|
||||
i += 1;
|
||||
j = j.saturating_sub(1);
|
||||
}
|
||||
@@ -361,7 +360,7 @@ pub fn array_flat(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let o = unsafe { &*ptr };
|
||||
if o.is_array() {
|
||||
let on = o.prop_count() as usize;
|
||||
let sub: Vec<JsValue> = (0..on).map(|i| o.get_prop_at(i as u8)).collect();
|
||||
let sub: Vec<JsValue> = (0..on).map(|i| o.get_prop_at(i)).collect();
|
||||
let flat = flatten(&sub, remaining_depth - 1);
|
||||
out.extend(flat);
|
||||
continue;
|
||||
@@ -373,14 +372,14 @@ pub fn array_flat(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
out
|
||||
}
|
||||
|
||||
let all: Vec<JsValue> = (0..n).map(|i| arr.get_prop_at(i as u8)).collect();
|
||||
let all: Vec<JsValue> = (0..n).map(|i| arr.get_prop_at(i)).collect();
|
||||
let flat = flatten(&all, depth);
|
||||
let new_arr = create_new_array(vm, flat.len());
|
||||
unsafe {
|
||||
for (i, val) in flat.iter().enumerate() {
|
||||
(*new_arr).set_prop_at(i as u8, *val);
|
||||
(*new_arr).set_prop_at(i, *val);
|
||||
}
|
||||
(*new_arr).set_prop_count(flat.len().min(31) as u8);
|
||||
(*new_arr).set_prop_count(flat.len());
|
||||
}
|
||||
Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
@@ -401,7 +400,7 @@ pub fn array_for_each(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
JsValue::undefined()
|
||||
};
|
||||
for i in 0..n {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i) };
|
||||
let _ = invoke_native_callback(
|
||||
vm,
|
||||
callback_val,
|
||||
@@ -429,7 +428,7 @@ pub fn array_map(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
};
|
||||
let new_arr = create_new_array(vm, n);
|
||||
for i in 0..n {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i) };
|
||||
match invoke_native_callback(
|
||||
vm,
|
||||
callback_val,
|
||||
@@ -437,13 +436,13 @@ pub fn array_map(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
&[elem, JsValue::int(i as i32), vm.reg(args[0])],
|
||||
) {
|
||||
Ok(mapped) => unsafe {
|
||||
(*new_arr).set_prop_at(i as u8, mapped);
|
||||
(*new_arr).set_prop_at(i, mapped);
|
||||
},
|
||||
Err(_) => return Err(JsValue::undefined()),
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
(*new_arr).set_prop_count(n.min(31) as u8);
|
||||
(*new_arr).set_prop_count(n);
|
||||
}
|
||||
Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
@@ -465,7 +464,7 @@ pub fn array_filter(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
};
|
||||
let mut kept: Vec<JsValue> = Vec::new();
|
||||
for i in 0..n {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i) };
|
||||
match invoke_native_callback(
|
||||
vm,
|
||||
callback_val,
|
||||
@@ -484,9 +483,9 @@ pub fn array_filter(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let new_arr = create_new_array(vm, kept.len());
|
||||
unsafe {
|
||||
for (i, val) in kept.iter().enumerate() {
|
||||
(*new_arr).set_prop_at(i as u8, *val);
|
||||
(*new_arr).set_prop_at(i, *val);
|
||||
}
|
||||
(*new_arr).set_prop_count(kept.len().min(31) as u8);
|
||||
(*new_arr).set_prop_count(kept.len());
|
||||
}
|
||||
Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
@@ -516,7 +515,7 @@ pub fn array_reduce(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
let this_val = JsValue::undefined();
|
||||
for i in start_idx..n {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i) };
|
||||
match invoke_native_callback(
|
||||
vm,
|
||||
callback_val,
|
||||
@@ -546,7 +545,7 @@ pub fn array_find(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
JsValue::undefined()
|
||||
};
|
||||
for i in 0..n {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i) };
|
||||
match invoke_native_callback(
|
||||
vm,
|
||||
callback_val,
|
||||
@@ -581,7 +580,7 @@ pub fn array_some(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
JsValue::undefined()
|
||||
};
|
||||
for i in 0..n {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i) };
|
||||
match invoke_native_callback(
|
||||
vm,
|
||||
callback_val,
|
||||
@@ -616,7 +615,7 @@ pub fn array_every(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
JsValue::undefined()
|
||||
};
|
||||
for i in 0..n {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i) };
|
||||
match invoke_native_callback(
|
||||
vm,
|
||||
callback_val,
|
||||
@@ -652,7 +651,7 @@ pub fn array_flat_map(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
};
|
||||
let mut flat: Vec<JsValue> = Vec::new();
|
||||
for i in 0..n {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i) };
|
||||
match invoke_native_callback(
|
||||
vm,
|
||||
callback_val,
|
||||
@@ -667,7 +666,7 @@ pub fn array_flat_map(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
if r.is_array() {
|
||||
let rn = r.prop_count() as usize;
|
||||
for j in 0..rn {
|
||||
flat.push(r.get_prop_at(j as u8));
|
||||
flat.push(r.get_prop_at(j));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -681,9 +680,9 @@ pub fn array_flat_map(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let new_arr = create_new_array(vm, flat.len());
|
||||
unsafe {
|
||||
for (i, val) in flat.iter().enumerate() {
|
||||
(*new_arr).set_prop_at(i as u8, *val);
|
||||
(*new_arr).set_prop_at(i, *val);
|
||||
}
|
||||
(*new_arr).set_prop_count(flat.len().min(31) as u8);
|
||||
(*new_arr).set_prop_count(flat.len());
|
||||
}
|
||||
Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
@@ -710,14 +709,14 @@ pub fn array_unshift(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let len = arr.prop_count();
|
||||
let n_items = args.len().saturating_sub(1);
|
||||
for i in (0..len as usize).rev() {
|
||||
let v = arr.get_prop_at(i as u8);
|
||||
arr.set_prop_at(i as u8 + n_items as u8, v);
|
||||
let v = arr.get_prop_at(i);
|
||||
arr.set_prop_at(i + n_items, v);
|
||||
}
|
||||
for (j, &arg_reg) in args.iter().skip(1).enumerate() {
|
||||
arr.set_prop_at(j as u8, vm.reg(arg_reg));
|
||||
arr.set_prop_at(j, vm.reg(arg_reg));
|
||||
}
|
||||
let new_len = (len as usize + n_items).min(31);
|
||||
arr.set_prop_count(new_len as u8);
|
||||
let new_len = len as usize + n_items;
|
||||
arr.set_prop_count(new_len);
|
||||
Ok(JsValue::int(new_len as i32))
|
||||
}
|
||||
|
||||
@@ -743,7 +742,7 @@ pub fn array_fill(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
len
|
||||
};
|
||||
for i in start..end {
|
||||
arr.set_prop_at(i as u8, value);
|
||||
arr.set_prop_at(i, value);
|
||||
}
|
||||
Ok(vm.reg(args[0]))
|
||||
}
|
||||
@@ -776,8 +775,8 @@ pub fn array_copy_within(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
if to >= len {
|
||||
break;
|
||||
}
|
||||
let v = arr.get_prop_at(from as u8);
|
||||
arr.set_prop_at(to as u8, v);
|
||||
let v = arr.get_prop_at(from);
|
||||
arr.set_prop_at(to, v);
|
||||
to += 1;
|
||||
}
|
||||
Ok(vm.reg(args[0]))
|
||||
@@ -798,7 +797,7 @@ pub fn array_at(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
if index < 0 || index >= len {
|
||||
return Ok(JsValue::undefined());
|
||||
}
|
||||
Ok(arr.get_prop_at(index as u8))
|
||||
Ok(arr.get_prop_at(index))
|
||||
}
|
||||
|
||||
pub fn array_last_index_of(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
@@ -811,7 +810,7 @@ pub fn array_last_index_of(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
JsValue::undefined()
|
||||
};
|
||||
for i in (0..len).rev() {
|
||||
if coercion::strict_equality(arr.get_prop_at(i as u8), search) {
|
||||
if coercion::strict_equality(arr.get_prop_at(i), search) {
|
||||
return Ok(JsValue::int(i));
|
||||
}
|
||||
}
|
||||
@@ -831,7 +830,7 @@ pub fn array_find_index(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
JsValue::undefined()
|
||||
};
|
||||
for i in 0..n {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i) };
|
||||
match invoke_native_callback(
|
||||
vm,
|
||||
callback_val,
|
||||
@@ -862,7 +861,7 @@ pub fn array_find_last(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
JsValue::undefined()
|
||||
};
|
||||
for i in (0..n).rev() {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i) };
|
||||
match invoke_native_callback(
|
||||
vm,
|
||||
callback_val,
|
||||
@@ -893,10 +892,10 @@ pub fn array_reduce_right(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
if n == 0 {
|
||||
return Err(JsValue::undefined());
|
||||
}
|
||||
(unsafe { (*arr_ptr).get_prop_at(n as u8 - 1) }, n as i32 - 2)
|
||||
(unsafe { (*arr_ptr).get_prop_at(n - 1) }, n as i32 - 2)
|
||||
};
|
||||
for i in (0..=start_idx).rev() {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i) };
|
||||
match invoke_native_callback(
|
||||
vm,
|
||||
callback_val,
|
||||
@@ -914,14 +913,14 @@ pub fn array_sort(vm: &mut Vm, _args: &[u8]) -> NativeResult {
|
||||
let arr_ptr = get_this_array_ref(vm.reg(_args[0]))?;
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
let len = arr.prop_count() as usize;
|
||||
let mut vals: Vec<JsValue> = (0..len).map(|i| arr.get_prop_at(i as u8)).collect();
|
||||
let mut vals: Vec<JsValue> = (0..len).map(|i| arr.get_prop_at(i)).collect();
|
||||
vals.sort_by(|a, b| {
|
||||
let sa = coercion::to_string(vm.kernel().string_forge().as_ref(), *a);
|
||||
let sb = coercion::to_string(vm.kernel().string_forge().as_ref(), *b);
|
||||
sa.cmp(&sb)
|
||||
});
|
||||
for (i, &v) in vals.iter().enumerate() {
|
||||
arr.set_prop_at(i as u8, v);
|
||||
arr.set_prop_at(i, v);
|
||||
}
|
||||
Ok(vm.reg(_args[0]))
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ fn value_to_jsvalue(vm: &mut Vm, val: &serde_json::Value) -> JsValue {
|
||||
for (i, v) in arr.iter().enumerate() {
|
||||
let jsv = value_to_jsvalue(vm, v);
|
||||
unsafe {
|
||||
(*array_obj).set_prop_at(i as u8, jsv);
|
||||
(*array_obj).set_prop_at(i, jsv);
|
||||
}
|
||||
}
|
||||
JsValue::from_js_object(array_obj)
|
||||
@@ -216,7 +216,7 @@ fn stringify_array(
|
||||
if i > 0 {
|
||||
out.push(',');
|
||||
}
|
||||
let val = obj.get_prop_at(i as u8);
|
||||
let val = obj.get_prop_at(i);
|
||||
let is_function = val.is_object() && {
|
||||
let ptr = val.as_js_object_ptr();
|
||||
if ptr.is_null() {
|
||||
|
||||
@@ -7,10 +7,10 @@ use crate::coercion;
|
||||
use crate::native::NativeResult;
|
||||
use crate::vm::Vm;
|
||||
|
||||
pub(crate) fn walk_own_keys(vm: &Vm, obj: &JsObject) -> Vec<(u32, u8)> {
|
||||
let mut keys: Vec<(u32, u8)> = Vec::new();
|
||||
pub(crate) fn walk_own_keys(vm: &Vm, obj: &JsObject) -> Vec<(u32, u32)> {
|
||||
let mut keys: Vec<(u32, u32)> = Vec::new();
|
||||
let shape_id = obj.shape_id();
|
||||
let mut pos: u8 = 0;
|
||||
let mut pos: u32 = 0;
|
||||
let mut shape_ids = Vec::new();
|
||||
let mut cursor = Some(shape_id);
|
||||
while let Some(id) = cursor {
|
||||
@@ -67,7 +67,7 @@ pub fn object_keys(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
.collect();
|
||||
}
|
||||
|
||||
let n = key_names.len().min(255);
|
||||
let n = key_names.len();
|
||||
let array_proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject;
|
||||
let arr = vm.epoch().alloc(JsObject::new_array(
|
||||
EMPTY_SHAPE_ID,
|
||||
@@ -75,12 +75,15 @@ pub fn object_keys(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
n,
|
||||
vm.epoch().bump(),
|
||||
));
|
||||
for k in key_names.iter().take(n) {
|
||||
for (i, k) in key_names.iter().enumerate() {
|
||||
let str_val = vm.intern(k);
|
||||
unsafe {
|
||||
(*arr).ensure_hash_props().push(Box::new(str_val));
|
||||
(*arr).set_prop_at(i, str_val);
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
(*arr).set_prop_count(n);
|
||||
}
|
||||
Ok(JsValue::from_js_object(arr))
|
||||
}
|
||||
|
||||
@@ -334,7 +337,7 @@ pub fn object_get_own_property_names(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
.collect()
|
||||
};
|
||||
|
||||
let n = key_names.len().min(255);
|
||||
let n = key_names.len();
|
||||
let array_proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject;
|
||||
let arr = vm.epoch().alloc(JsObject::new_array(
|
||||
EMPTY_SHAPE_ID,
|
||||
@@ -342,12 +345,15 @@ pub fn object_get_own_property_names(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
n,
|
||||
vm.epoch().bump(),
|
||||
));
|
||||
for k in key_names.iter().take(n) {
|
||||
for (i, k) in key_names.iter().enumerate() {
|
||||
let str_val = vm.intern(k);
|
||||
unsafe {
|
||||
(*arr).ensure_hash_props().push(Box::new(str_val));
|
||||
(*arr).set_prop_at(i, str_val);
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
(*arr).set_prop_count(n);
|
||||
}
|
||||
Ok(JsValue::from_js_object(arr))
|
||||
}
|
||||
|
||||
@@ -399,7 +405,7 @@ pub fn object_entries(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let obj_ptr = require_obj_arg(vm, args, "entries")?;
|
||||
let obj = unsafe { &*obj_ptr };
|
||||
let keys = walk_own_keys(vm, obj);
|
||||
let n = keys.len().min(255);
|
||||
let n = keys.len();
|
||||
let array_proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject;
|
||||
let arr = vm.epoch().alloc(JsObject::new_array(
|
||||
EMPTY_SHAPE_ID,
|
||||
@@ -407,7 +413,7 @@ pub fn object_entries(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
n,
|
||||
vm.epoch().bump(),
|
||||
));
|
||||
for (_i, (si, offset)) in keys.iter().enumerate().take(n) {
|
||||
for (i, (si, offset)) in keys.iter().enumerate() {
|
||||
let key_str = vm.kernel().string_forge().lookup(*si).unwrap_or_default();
|
||||
let key_val = vm.intern(&key_str);
|
||||
let val = obj.get_prop_at(*offset);
|
||||
@@ -421,11 +427,12 @@ pub fn object_entries(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
(*pair).set_prop_at(0, key_val);
|
||||
(*pair).set_prop_at(1, val);
|
||||
(*pair).set_prop_count(2);
|
||||
(*arr)
|
||||
.ensure_hash_props()
|
||||
.push(Box::new(JsValue::from_js_object(pair)));
|
||||
(*arr).set_prop_at(i, JsValue::from_js_object(pair));
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
(*arr).set_prop_count(n);
|
||||
}
|
||||
Ok(JsValue::from_js_object(arr))
|
||||
}
|
||||
|
||||
@@ -433,7 +440,7 @@ pub fn object_values(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let obj_ptr = require_obj_arg(vm, args, "values")?;
|
||||
let obj = unsafe { &*obj_ptr };
|
||||
let keys = walk_own_keys(vm, obj);
|
||||
let n = keys.len().min(255);
|
||||
let n = keys.len();
|
||||
let array_proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject;
|
||||
let arr = vm.epoch().alloc(JsObject::new_array(
|
||||
EMPTY_SHAPE_ID,
|
||||
@@ -441,14 +448,14 @@ pub fn object_values(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
n,
|
||||
vm.epoch().bump(),
|
||||
));
|
||||
for (i, (_si, offset)) in keys.iter().enumerate().take(n) {
|
||||
for (i, (_si, offset)) in keys.iter().enumerate() {
|
||||
let val = obj.get_prop_at(*offset);
|
||||
unsafe {
|
||||
(*arr).set_prop_at(i as u8, val);
|
||||
(*arr).set_prop_at(i, val);
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
(*arr).set_prop_count(n as u8);
|
||||
(*arr).set_prop_count(n);
|
||||
}
|
||||
Ok(JsValue::from_js_object(arr))
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ fn this_string(vm: &Vm, args: &[u8]) -> String {
|
||||
|
||||
fn make_string_array(vm: &mut Vm, parts: &[String]) -> JsValue {
|
||||
let proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject;
|
||||
let n = parts.len().min(31);
|
||||
let n = parts.len();
|
||||
let arr = vm.epoch().alloc(JsObject::new_array(
|
||||
EMPTY_SHAPE_ID,
|
||||
JsValue::from_js_object(proto),
|
||||
@@ -21,11 +21,11 @@ fn make_string_array(vm: &mut Vm, parts: &[String]) -> JsValue {
|
||||
vm.epoch().bump(),
|
||||
));
|
||||
unsafe {
|
||||
for (i, s) in parts.iter().enumerate().take(n) {
|
||||
for (i, s) in parts.iter().enumerate() {
|
||||
let sv = vm.intern(s);
|
||||
(*arr).set_prop_at(i as u8, sv);
|
||||
(*arr).set_prop_at(i, sv);
|
||||
}
|
||||
(*arr).set_prop_count(n as u8);
|
||||
(*arr).set_prop_count(n);
|
||||
}
|
||||
JsValue::from_js_object(arr)
|
||||
}
|
||||
|
||||
+43
-23
@@ -105,7 +105,11 @@ macro_rules! member_read_prop {
|
||||
if cached_shape_id != 0 && cached_shape_id == $obj.shape_id() && cached_ptr != 0 {
|
||||
unsafe { *(cached_ptr as *const JsValue) }
|
||||
} else if let Some(template) = $self.kernel.prop_forge().get_template($obj.shape_id()) {
|
||||
if let Some(ptr) = $self.template_prop_ptr($obj, &template) {
|
||||
if template.prop_name != $prop_name_si {
|
||||
$self
|
||||
.resolve_property($obj, $prop_name_si)
|
||||
.unwrap_or(JsValue::undefined())
|
||||
} else if let Some(ptr) = $self.template_prop_ptr($obj, &template) {
|
||||
$self.bytecode[$self.pc - 3] = $obj.shape_id() & 0x00FF_FFFF;
|
||||
$self.bytecode[$self.pc - 2] = ptr as u32;
|
||||
$self.bytecode[$self.pc - 1] = (ptr as u64 >> 32) as u32;
|
||||
@@ -116,15 +120,16 @@ macro_rules! member_read_prop {
|
||||
.unwrap_or(JsValue::undefined())
|
||||
}
|
||||
} else if let Some(val) = $self.resolve_property($obj, $prop_name_si) {
|
||||
let pos = $self
|
||||
if let Some(pos) = $self
|
||||
.kernel
|
||||
.shape_forge()
|
||||
.lookup_position($obj.shape_id(), $prop_name_si)
|
||||
.unwrap_or(0);
|
||||
if let Some(ptr) = $obj.prop_ptr_at(pos) {
|
||||
$self.bytecode[$self.pc - 3] = $obj.shape_id() & 0x00FF_FFFF;
|
||||
$self.bytecode[$self.pc - 2] = ptr as u32;
|
||||
$self.bytecode[$self.pc - 1] = (ptr as u64 >> 32) as u32;
|
||||
{
|
||||
if let Some(ptr) = $obj.prop_ptr_at(pos) {
|
||||
$self.bytecode[$self.pc - 3] = $obj.shape_id() & 0x00FF_FFFF;
|
||||
$self.bytecode[$self.pc - 2] = ptr as u32;
|
||||
$self.bytecode[$self.pc - 1] = (ptr as u64 >> 32) as u32;
|
||||
}
|
||||
}
|
||||
val
|
||||
} else {
|
||||
@@ -397,6 +402,10 @@ impl Vm {
|
||||
}
|
||||
|
||||
fn resolve_property(&self, obj: &JsObject, prop_name_si: u32) -> Option<JsValue> {
|
||||
let length_si = self.kernel.string_forge().intern("length").0;
|
||||
if obj.is_array() && prop_name_si == length_si {
|
||||
return Some(JsValue::int(obj.prop_count() as i32));
|
||||
}
|
||||
if let Some(pos) = self
|
||||
.kernel
|
||||
.shape_forge()
|
||||
@@ -459,6 +468,7 @@ impl Vm {
|
||||
new_shape_id,
|
||||
PropTemplate {
|
||||
shape_id: new_shape_id,
|
||||
prop_name: prop_name_si,
|
||||
position: new_pos,
|
||||
generation: obj.generation(),
|
||||
},
|
||||
@@ -1023,14 +1033,20 @@ impl Vm {
|
||||
} else if let Some(template) =
|
||||
self.kernel.prop_forge().get_template(obj.shape_id())
|
||||
{
|
||||
let pos = template.position as usize;
|
||||
if let Some(vec) = obj.hash_props_vec() {
|
||||
if pos < vec.len() {
|
||||
let ptr = &*vec[pos] as *const JsValue;
|
||||
self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF;
|
||||
self.bytecode[self.pc - 2] = ptr as u32;
|
||||
self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32;
|
||||
self.regs[a] = unsafe { *(ptr) };
|
||||
if template.prop_name == prop_name_si {
|
||||
let pos = template.position as usize;
|
||||
if let Some(vec) = obj.hash_props_vec() {
|
||||
if pos < vec.len() {
|
||||
let ptr = &*vec[pos] as *const JsValue;
|
||||
self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF;
|
||||
self.bytecode[self.pc - 2] = ptr as u32;
|
||||
self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32;
|
||||
self.regs[a] = unsafe { *(ptr) };
|
||||
} else {
|
||||
self.regs[a] = self
|
||||
.resolve_property(obj, prop_name_si)
|
||||
.unwrap_or(JsValue::undefined());
|
||||
}
|
||||
} else {
|
||||
self.regs[a] = self
|
||||
.resolve_property(obj, prop_name_si)
|
||||
@@ -1042,15 +1058,16 @@ impl Vm {
|
||||
.unwrap_or(JsValue::undefined());
|
||||
}
|
||||
} else if let Some(val) = self.resolve_property(obj, prop_name_si) {
|
||||
let pos = self
|
||||
if let Some(pos) = self
|
||||
.kernel
|
||||
.shape_forge()
|
||||
.lookup_position(obj.shape_id(), prop_name_si)
|
||||
.unwrap_or(0);
|
||||
if let Some(ptr) = obj.prop_ptr_at(pos) {
|
||||
self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF;
|
||||
self.bytecode[self.pc - 2] = ptr as u32;
|
||||
self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32;
|
||||
{
|
||||
if let Some(ptr) = obj.prop_ptr_at(pos) {
|
||||
self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF;
|
||||
self.bytecode[self.pc - 2] = ptr as u32;
|
||||
self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32;
|
||||
}
|
||||
}
|
||||
self.regs[a] = val;
|
||||
} else {
|
||||
@@ -1105,6 +1122,7 @@ impl Vm {
|
||||
new_shape_id,
|
||||
PropTemplate {
|
||||
shape_id: new_shape_id,
|
||||
prop_name: prop_name_si,
|
||||
position: new_pos,
|
||||
generation: obj.generation(),
|
||||
},
|
||||
@@ -1221,9 +1239,9 @@ impl Vm {
|
||||
if obj_ptr.is_null() {
|
||||
throw_err!(self, TypeError, "SET_ELEM on non-object");
|
||||
}
|
||||
let idx = self.regs[a].as_int() as usize;
|
||||
let idx = self.regs[a].as_int().max(0) as u32;
|
||||
let obj = unsafe { &mut *obj_ptr };
|
||||
obj.set_prop_at(idx as u8, self.regs[b]);
|
||||
obj.set_prop_at(idx, self.regs[b]);
|
||||
}
|
||||
|
||||
OpCode::COMPOUND_ADD => {
|
||||
@@ -1507,6 +1525,7 @@ impl Vm {
|
||||
new_shape_id,
|
||||
PropTemplate {
|
||||
shape_id: new_shape_id,
|
||||
prop_name: prop_name_si,
|
||||
position: new_pos,
|
||||
generation: obj.generation(),
|
||||
},
|
||||
@@ -1557,6 +1576,7 @@ impl Vm {
|
||||
new_shape_id,
|
||||
PropTemplate {
|
||||
shape_id: new_shape_id,
|
||||
prop_name: prop_name_si,
|
||||
position: new_pos,
|
||||
generation: obj.generation(),
|
||||
},
|
||||
|
||||
@@ -38,6 +38,21 @@ fn array_push_returns_true_length_beyond_31() {
|
||||
assert_eq!(result.as_int(), 32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_length_tracks_more_than_31_elements() {
|
||||
let result = eval("var a=[]; for (var i=0;i<40;i=i+1) a.push(i); a.length").unwrap();
|
||||
assert_eq!(result.as_int(), 40);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_push_preserves_slots_beyond_255() {
|
||||
let result = eval("var a=[]; for (var i=0;i<257;i=i+1) a.push(i); a").unwrap();
|
||||
let obj = unsafe { &*result.as_js_object_ptr() };
|
||||
assert_eq!(obj.prop_count(), 257);
|
||||
let tail = obj.get_prop_at(256);
|
||||
assert_eq!(tail.as_double(), 256.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_pop_returns_last() {
|
||||
let result = eval("[1,2,3].pop()").unwrap();
|
||||
|
||||
@@ -16,11 +16,15 @@ fn eval(source: &str) -> Result<oxide_types::value::JsValue, String> {
|
||||
fn object_keys_empty() {
|
||||
let result = eval("Object.keys({})").unwrap();
|
||||
assert!(result.is_object());
|
||||
let obj = unsafe { &*result.as_js_object_ptr() };
|
||||
assert_eq!(obj.prop_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn object_keys_has_own_property() {
|
||||
eval("Object.keys({a:1})").unwrap();
|
||||
let result = eval("Object.keys({a:1,b:2})").unwrap();
|
||||
let obj = unsafe { &*result.as_js_object_ptr() };
|
||||
assert_eq!(obj.prop_count(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -68,10 +72,14 @@ fn object_has_own_true() {
|
||||
fn object_entries_returns_array() {
|
||||
let result = eval("Object.entries({a:1,b:2})").unwrap();
|
||||
assert!(result.is_object());
|
||||
let obj = unsafe { &*result.as_js_object_ptr() };
|
||||
assert_eq!(obj.prop_count(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn object_values_returns_array() {
|
||||
let result = eval("Object.values({a:1,b:2})").unwrap();
|
||||
assert!(result.is_object());
|
||||
let obj = unsafe { &*result.as_js_object_ptr() };
|
||||
assert_eq!(obj.prop_count(), 2);
|
||||
}
|
||||
|
||||
@@ -227,6 +227,9 @@ fn string_split_with_regexp() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "'a,b,c'.split(/,/)").unwrap();
|
||||
assert!(result.is_object());
|
||||
let obj = unsafe { &*result.as_js_object_ptr() };
|
||||
assert_eq!(obj.prop_count(), 3);
|
||||
assert_eq!(to_str(&vm, obj.get_prop_at(1)), "b");
|
||||
}
|
||||
|
||||
// --- toString ---
|
||||
|
||||
@@ -143,6 +143,10 @@ fn string_split_comma() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "'a,b,c'.split(',')").unwrap();
|
||||
assert!(result.is_object());
|
||||
let obj = unsafe { &*result.as_js_object_ptr() };
|
||||
assert_eq!(obj.prop_count(), 3);
|
||||
assert_eq!(to_str(&vm, obj.get_prop_at(0)), "a");
|
||||
assert_eq!(to_str(&vm, obj.get_prop_at(2)), "c");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -27,13 +27,7 @@ fn json_parse_object() {
|
||||
let result = eval(&mut vm, "JSON.parse('{\"a\":1,\"b\":2}')").unwrap();
|
||||
assert!(result.is_object());
|
||||
let obj = unsafe { &*result.as_js_object_ptr() };
|
||||
let mut count = 0;
|
||||
for i in 0..obj.prop_vec_len() {
|
||||
if !obj.get_prop_at(i as u8).is_undefined() {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
assert_eq!(count, 2);
|
||||
assert_eq!(obj.prop_count(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -43,7 +37,8 @@ fn json_parse_array() {
|
||||
assert!(result.is_object());
|
||||
let obj = unsafe { &*result.as_js_object_ptr() };
|
||||
assert!(obj.is_array());
|
||||
assert_eq!(obj.prop_vec_len(), 3);
|
||||
assert_eq!(obj.prop_count(), 3);
|
||||
assert_eq!(obj.get_prop_at(2).as_double(), 3.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user