fix: 修复数组长度与槽位索引截断问题

This commit is contained in:
爱特每羊队
2026-06-08 22:55:52 +08:00
parent 22cbccdf6c
commit e57e140bef
16 changed files with 242 additions and 159 deletions
+2 -2
View File
@@ -167,7 +167,7 @@ fn format_object(string_forge: &StringForge, shape_forge: &ShapeForge, obj: &JsO
break; break;
} }
} }
let mut pos: u8 = 0; let mut pos: u32 = 0;
for id in shape_ids.iter().rev() { for id in shape_ids.iter().rev() {
if let Some(shape) = shape_forge.get_shape(*id) { if let Some(shape) = shape_forge.get_shape(*id) {
if shape.property_name != 0 { 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 len = obj.prop_vec_len();
let mut items = Vec::new(); let mut items = Vec::new();
for i in 0..len { 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)); items.push(format_js_value(string_forge, shape_forge, val));
} }
format!("[{}]", items.join(", ")) format!("[{}]", items.join(", "))
+2 -13
View File
@@ -318,19 +318,8 @@ impl Compiler {
self.count_expression(expr, ctx); self.count_expression(expr, ctx);
} }
} }
// CALL_NATIVE: 1 opcode + 1 ext word; CALL(0x40): 1 opcode // CALL and CALL_NATIVE both carry 1 ext word for arg_count.
let is_builtin = match &call.callee { ctx.projected_pc += 2;
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 };
ctx.alloc_reg(); // result register ctx.alloc_reg(); // result register
ctx.projected_pc += 1; // LOAD_VAR result <- regs[0] ctx.projected_pc += 1; // LOAD_VAR result <- regs[0]
} }
+8 -1
View File
@@ -7,7 +7,8 @@ use crate::shape_forge::ShapeId;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PropTemplate { pub struct PropTemplate {
pub shape_id: ShapeId, pub shape_id: ShapeId,
pub position: u8, pub prop_name: u32,
pub position: u32,
pub generation: u32, pub generation: u32,
} }
@@ -67,12 +68,14 @@ mod tests {
let forge = PropForge::new(); let forge = PropForge::new();
let t = PropTemplate { let t = PropTemplate {
shape_id: 1, shape_id: 1,
prop_name: 11,
position: 3, position: 3,
generation: 10, generation: 10,
}; };
forge.upsert(1, t); forge.upsert(1, t);
let got = forge.get_template(1).unwrap(); let got = forge.get_template(1).unwrap();
assert_eq!(got.shape_id, 1); assert_eq!(got.shape_id, 1);
assert_eq!(got.prop_name, 11);
assert_eq!(got.position, 3); assert_eq!(got.position, 3);
assert_eq!(got.generation, 10); assert_eq!(got.generation, 10);
} }
@@ -84,6 +87,7 @@ mod tests {
1, 1,
PropTemplate { PropTemplate {
shape_id: 1, shape_id: 1,
prop_name: 11,
position: 3, position: 3,
generation: 10, generation: 10,
}, },
@@ -92,6 +96,7 @@ mod tests {
1, 1,
PropTemplate { PropTemplate {
shape_id: 1, shape_id: 1,
prop_name: 12,
position: 7, position: 7,
generation: 5, generation: 5,
}, },
@@ -107,6 +112,7 @@ mod tests {
1, 1,
PropTemplate { PropTemplate {
shape_id: 1, shape_id: 1,
prop_name: 11,
position: 3, position: 3,
generation: 5, generation: 5,
}, },
@@ -115,6 +121,7 @@ mod tests {
1, 1,
PropTemplate { PropTemplate {
shape_id: 1, shape_id: 1,
prop_name: 12,
position: 7, position: 7,
generation: 10, generation: 10,
}, },
+6 -6
View File
@@ -46,8 +46,8 @@ impl ShapeForge {
((parent_id as u64) << 32) | (prop_name as u64) ((parent_id as u64) << 32) | (prop_name as u64)
} }
fn compute_depth(shape_id: ShapeId, shapes: &[Option<Arc<Shape>>]) -> u8 { fn compute_depth(shape_id: ShapeId, shapes: &[Option<Arc<Shape>>]) -> u32 {
let mut count = 0u8; let mut count = 0u32;
let mut cursor = Some(shape_id); let mut cursor = Some(shape_id);
while let Some(id) = cursor { while let Some(id) = cursor {
match shapes.get((id - 1) as usize).and_then(|s| s.clone()) { 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()) 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 shapes = self.shapes.read().unwrap();
let total_depth = Self::compute_depth(shape_id, &shapes); 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); let mut cursor = Some(shape_id);
while let Some(id) = cursor { while let Some(id) = cursor {
match shapes.get((id - 1) as usize).and_then(|s| s.clone()) { match shapes.get((id - 1) as usize).and_then(|s| s.clone()) {
@@ -131,9 +131,9 @@ impl ShapeForge {
false 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 shapes = self.shapes.read().unwrap();
let mut count = 0u8; let mut count = 0u32;
let mut cursor = Some(shape_id); let mut cursor = Some(shape_id);
while let Some(id) = cursor { while let Some(id) = cursor {
match shapes.get((id - 1) as usize).and_then(|s| s.clone()) { match shapes.get((id - 1) as usize).and_then(|s| s.clone()) {
+48 -12
View File
@@ -2,6 +2,41 @@ use crate::value::JsValue;
pub type ShapeId = u32; 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): /// Layout (56B):
/// header: u32 bits /// header: u32 bits
/// [0:23] shape_id /// [0:23] shape_id
@@ -82,19 +117,19 @@ impl JsObject {
/// Returns property count from the hash_props vec length. /// Returns property count from the hash_props vec length.
/// Returns 0 if hash_props has not been allocated. /// 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() { if self.hash_props.is_null() {
0 0
} else { } else {
let vec = unsafe { &*(self.hash_props as *const Vec<Box<JsValue>>) }; 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. /// 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 vec = self.ensure_hash_props();
let target = count as usize; let target = count.to_u32() as usize;
if target < vec.len() { if target < vec.len() {
vec.truncate(target); vec.truncate(target);
} else { } else {
@@ -152,20 +187,20 @@ impl JsObject {
/// Get property value at position index in the vec. /// Get property value at position index in the vec.
/// Returns JsValue::undefined() if hash_props not allocated or position out of bounds. /// 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() { if self.hash_props.is_null() {
return JsValue::undefined(); return JsValue::undefined();
} }
let vec = unsafe { &*(self.hash_props as *const Vec<Box<JsValue>>) }; 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) .map(|b| **b)
.unwrap_or(JsValue::undefined()) .unwrap_or(JsValue::undefined())
} }
/// Set property value at position index. Vec auto-grows if needed. /// 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 vec = self.ensure_hash_props();
let pos = position as usize; let pos = position.to_u32() as usize;
if pos < vec.len() { if pos < vec.len() {
*vec[pos] = val; *vec[pos] = val;
} else { } else {
@@ -177,21 +212,22 @@ impl JsObject {
} }
/// Push a value onto hash_props vec. Returns the index position. /// 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 vec = self.ensure_hash_props();
let pos = vec.len(); let pos = vec.len();
vec.push(Box::new(val)); vec.push(Box::new(val));
pos as u8 pos as u32
} }
/// Get a stable pointer to the Box<JsValue> at position. /// Get a stable pointer to the Box<JsValue> at position.
/// Returns None if hash_props not allocated or position out of bounds. /// 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() { if self.hash_props.is_null() {
return None; return None;
} }
let vec = unsafe { &*(self.hash_props as *const Vec<Box<JsValue>>) }; 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). /// Get the length of hash_props vec (returns 0 if not allocated).
+7 -7
View File
@@ -71,8 +71,8 @@ impl ShapeStore {
new_id new_id
} }
fn lookup_position(&self, shape_id: ShapeId, prop_name: StringIndex) -> Option<u8> { fn lookup_position(&self, shape_id: ShapeId, prop_name: StringIndex) -> Option<u32> {
let mut depth: u8 = 0; let mut depth: u32 = 0;
let mut cursor = Some(shape_id); let mut cursor = Some(shape_id);
while let Some(id) = cursor { while let Some(id) = cursor {
match self.get_shape(id) { match self.get_shape(id) {
@@ -86,7 +86,7 @@ impl ShapeStore {
} }
} }
let total_depth = depth; let total_depth = depth;
let mut step: u8 = 0; let mut step: u32 = 0;
cursor = Some(shape_id); cursor = Some(shape_id);
while let Some(id) = cursor { while let Some(id) = cursor {
match self.get_shape(id) { match self.get_shape(id) {
@@ -119,8 +119,8 @@ impl ShapeStore {
false false
} }
fn shape_prop_count(&self, shape_id: ShapeId) -> u8 { fn shape_prop_count(&self, shape_id: ShapeId) -> u32 {
let mut count = 0u8; let mut count = 0u32;
let mut cursor = Some(shape_id); let mut cursor = Some(shape_id);
while let Some(id) = cursor { while let Some(id) = cursor {
match self.get_shape(id) { 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) 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) 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) 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) store().lock().unwrap().shape_prop_count(shape_id)
} }
+61 -62
View File
@@ -100,11 +100,11 @@ pub fn array_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
)); ));
for i in 0..n_elems { for i in 0..n_elems {
unsafe { unsafe {
(*arr).set_prop_at(i as u8, vm.reg(args[1 + i])); (*arr).set_prop_at(i, vm.reg(args[1 + i]));
} }
} }
unsafe { unsafe {
(*arr).set_prop_count(n_elems as u8); (*arr).set_prop_count(n_elems);
} }
Ok(JsValue::from_js_object(arr)) 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 { pub fn array_push(vm: &mut Vm, args: &[u8]) -> NativeResult {
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?; let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
let arr = unsafe { &mut *arr_ptr }; 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) { for &arg_reg in args.iter().skip(1) {
let val = vm.reg(arg_reg); let val = vm.reg(arg_reg);
arr.set_prop_at(len as u8, val); arr.set_prop_at(len, val);
len += 1; len += 1;
} }
let stored_len = (len as u8).min(31); arr.set_prop_count(len);
arr.set_prop_count(stored_len);
Ok(JsValue::int(len as i32)) 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); let new_arr = create_new_array(vm, count);
unsafe { unsafe {
for i in 0..count { 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)) 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(); let mut removed: Vec<JsValue> = Vec::new();
for i in 0..delete_count { 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 { if insert_count > delete_count {
let shift = insert_count - delete_count; let shift = insert_count - delete_count;
for i in (start + delete_count..n).rev() { for i in (start + delete_count..n).rev() {
let val = arr.get_prop_at(i as u8); let val = arr.get_prop_at(i);
arr.set_prop_at((i + shift) as u8, val); arr.set_prop_at(i + shift, val);
} }
} else if insert_count < delete_count { } else if insert_count < delete_count {
let shift = delete_count - insert_count; let shift = delete_count - insert_count;
for i in start + delete_count..n { for i in start + delete_count..n {
let val = arr.get_prop_at(i as u8); let val = arr.get_prop_at(i);
arr.set_prop_at((i - shift) as u8, val); arr.set_prop_at(i - shift, val);
} }
} }
for i in 0..insert_count { 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; 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()); let removed_arr = create_new_array(vm, removed.len());
unsafe { unsafe {
for (i, val) in removed.iter().enumerate() { 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)) 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 n = arr.prop_count() as usize;
let mut all: Vec<JsValue> = Vec::new(); let mut all: Vec<JsValue> = Vec::new();
for i in 0..n { 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) { for &arg_reg in args.iter().skip(1) {
let val = vm.reg(arg_reg); let val = vm.reg(arg_reg);
@@ -242,7 +241,7 @@ pub fn array_concat(vm: &mut Vm, args: &[u8]) -> NativeResult {
if o.is_array() { if o.is_array() {
let on = o.prop_count() as usize; let on = o.prop_count() as usize;
for i in 0..on { for i in 0..on {
all.push(o.get_prop_at(i as u8)); all.push(o.get_prop_at(i));
} }
continue; continue;
} }
@@ -253,9 +252,9 @@ pub fn array_concat(vm: &mut Vm, args: &[u8]) -> NativeResult {
let new_arr = create_new_array(vm, all.len()); let new_arr = create_new_array(vm, all.len());
unsafe { unsafe {
for (i, val) in all.iter().enumerate() { 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)) 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 sf = vm.kernel().string_forge().as_ref();
let parts: Vec<String> = (0..n) let parts: Vec<String> = (0..n)
.map(|i| { .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() { if v.is_undefined() || v.is_null() {
String::new() String::new()
} else { } else {
@@ -294,7 +293,7 @@ pub fn array_index_of(vm: &mut Vm, args: &[u8]) -> NativeResult {
} }
let target = vm.reg(args[1]); let target = vm.reg(args[1]);
for i in 0..n { 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)); 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]); let target = vm.reg(args[1]);
for i in 0..n { 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() { if elem.is_double() && target.is_double() {
let ea = elem.as_double(); let ea = elem.as_double();
let ta = target.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 i = 0;
let mut j = n.saturating_sub(1); let mut j = n.saturating_sub(1);
while i < j { while i < j {
let tmp = arr.get_prop_at(i as u8); let tmp = arr.get_prop_at(i);
arr.set_prop_at(i as u8, arr.get_prop_at(j as u8)); arr.set_prop_at(i, arr.get_prop_at(j));
arr.set_prop_at(j as u8, tmp); arr.set_prop_at(j, tmp);
i += 1; i += 1;
j = j.saturating_sub(1); j = j.saturating_sub(1);
} }
@@ -361,7 +360,7 @@ pub fn array_flat(vm: &mut Vm, args: &[u8]) -> NativeResult {
let o = unsafe { &*ptr }; let o = unsafe { &*ptr };
if o.is_array() { if o.is_array() {
let on = o.prop_count() as usize; 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); let flat = flatten(&sub, remaining_depth - 1);
out.extend(flat); out.extend(flat);
continue; continue;
@@ -373,14 +372,14 @@ pub fn array_flat(vm: &mut Vm, args: &[u8]) -> NativeResult {
out 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 flat = flatten(&all, depth);
let new_arr = create_new_array(vm, flat.len()); let new_arr = create_new_array(vm, flat.len());
unsafe { unsafe {
for (i, val) in flat.iter().enumerate() { 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)) Ok(JsValue::from_js_object(new_arr))
} }
@@ -401,7 +400,7 @@ pub fn array_for_each(vm: &mut Vm, args: &[u8]) -> NativeResult {
JsValue::undefined() JsValue::undefined()
}; };
for i in 0..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) };
let _ = invoke_native_callback( let _ = invoke_native_callback(
vm, vm,
callback_val, callback_val,
@@ -429,7 +428,7 @@ pub fn array_map(vm: &mut Vm, args: &[u8]) -> NativeResult {
}; };
let new_arr = create_new_array(vm, n); let new_arr = create_new_array(vm, n);
for i in 0..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( match invoke_native_callback(
vm, vm,
callback_val, 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])], &[elem, JsValue::int(i as i32), vm.reg(args[0])],
) { ) {
Ok(mapped) => unsafe { Ok(mapped) => unsafe {
(*new_arr).set_prop_at(i as u8, mapped); (*new_arr).set_prop_at(i, mapped);
}, },
Err(_) => return Err(JsValue::undefined()), Err(_) => return Err(JsValue::undefined()),
} }
} }
unsafe { unsafe {
(*new_arr).set_prop_count(n.min(31) as u8); (*new_arr).set_prop_count(n);
} }
Ok(JsValue::from_js_object(new_arr)) 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(); let mut kept: Vec<JsValue> = Vec::new();
for i in 0..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( match invoke_native_callback(
vm, vm,
callback_val, 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()); let new_arr = create_new_array(vm, kept.len());
unsafe { unsafe {
for (i, val) in kept.iter().enumerate() { 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)) 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(); let this_val = JsValue::undefined();
for i in start_idx..n { 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( match invoke_native_callback(
vm, vm,
callback_val, callback_val,
@@ -546,7 +545,7 @@ pub fn array_find(vm: &mut Vm, args: &[u8]) -> NativeResult {
JsValue::undefined() JsValue::undefined()
}; };
for i in 0..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( match invoke_native_callback(
vm, vm,
callback_val, callback_val,
@@ -581,7 +580,7 @@ pub fn array_some(vm: &mut Vm, args: &[u8]) -> NativeResult {
JsValue::undefined() JsValue::undefined()
}; };
for i in 0..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( match invoke_native_callback(
vm, vm,
callback_val, callback_val,
@@ -616,7 +615,7 @@ pub fn array_every(vm: &mut Vm, args: &[u8]) -> NativeResult {
JsValue::undefined() JsValue::undefined()
}; };
for i in 0..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( match invoke_native_callback(
vm, vm,
callback_val, callback_val,
@@ -652,7 +651,7 @@ pub fn array_flat_map(vm: &mut Vm, args: &[u8]) -> NativeResult {
}; };
let mut flat: Vec<JsValue> = Vec::new(); let mut flat: Vec<JsValue> = Vec::new();
for i in 0..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( match invoke_native_callback(
vm, vm,
callback_val, callback_val,
@@ -667,7 +666,7 @@ pub fn array_flat_map(vm: &mut Vm, args: &[u8]) -> NativeResult {
if r.is_array() { if r.is_array() {
let rn = r.prop_count() as usize; let rn = r.prop_count() as usize;
for j in 0..rn { for j in 0..rn {
flat.push(r.get_prop_at(j as u8)); flat.push(r.get_prop_at(j));
} }
continue; 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()); let new_arr = create_new_array(vm, flat.len());
unsafe { unsafe {
for (i, val) in flat.iter().enumerate() { 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)) 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 len = arr.prop_count();
let n_items = args.len().saturating_sub(1); let n_items = args.len().saturating_sub(1);
for i in (0..len as usize).rev() { for i in (0..len as usize).rev() {
let v = arr.get_prop_at(i as u8); let v = arr.get_prop_at(i);
arr.set_prop_at(i as u8 + n_items as u8, v); arr.set_prop_at(i + n_items, v);
} }
for (j, &arg_reg) in args.iter().skip(1).enumerate() { 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); let new_len = len as usize + n_items;
arr.set_prop_count(new_len as u8); arr.set_prop_count(new_len);
Ok(JsValue::int(new_len as i32)) Ok(JsValue::int(new_len as i32))
} }
@@ -743,7 +742,7 @@ pub fn array_fill(vm: &mut Vm, args: &[u8]) -> NativeResult {
len len
}; };
for i in start..end { for i in start..end {
arr.set_prop_at(i as u8, value); arr.set_prop_at(i, value);
} }
Ok(vm.reg(args[0])) Ok(vm.reg(args[0]))
} }
@@ -776,8 +775,8 @@ pub fn array_copy_within(vm: &mut Vm, args: &[u8]) -> NativeResult {
if to >= len { if to >= len {
break; break;
} }
let v = arr.get_prop_at(from as u8); let v = arr.get_prop_at(from);
arr.set_prop_at(to as u8, v); arr.set_prop_at(to, v);
to += 1; to += 1;
} }
Ok(vm.reg(args[0])) Ok(vm.reg(args[0]))
@@ -798,7 +797,7 @@ pub fn array_at(vm: &mut Vm, args: &[u8]) -> NativeResult {
if index < 0 || index >= len { if index < 0 || index >= len {
return Ok(JsValue::undefined()); 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 { 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() JsValue::undefined()
}; };
for i in (0..len).rev() { 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)); return Ok(JsValue::int(i));
} }
} }
@@ -831,7 +830,7 @@ pub fn array_find_index(vm: &mut Vm, args: &[u8]) -> NativeResult {
JsValue::undefined() JsValue::undefined()
}; };
for i in 0..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( match invoke_native_callback(
vm, vm,
callback_val, callback_val,
@@ -862,7 +861,7 @@ pub fn array_find_last(vm: &mut Vm, args: &[u8]) -> NativeResult {
JsValue::undefined() JsValue::undefined()
}; };
for i in (0..n).rev() { 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( match invoke_native_callback(
vm, vm,
callback_val, callback_val,
@@ -893,10 +892,10 @@ pub fn array_reduce_right(vm: &mut Vm, args: &[u8]) -> NativeResult {
if n == 0 { if n == 0 {
return Err(JsValue::undefined()); 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() { 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( match invoke_native_callback(
vm, vm,
callback_val, 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_ptr = get_this_array_ref(vm.reg(_args[0]))?;
let arr = unsafe { &mut *arr_ptr }; let arr = unsafe { &mut *arr_ptr };
let len = arr.prop_count() as usize; 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| { vals.sort_by(|a, b| {
let sa = coercion::to_string(vm.kernel().string_forge().as_ref(), *a); let sa = coercion::to_string(vm.kernel().string_forge().as_ref(), *a);
let sb = coercion::to_string(vm.kernel().string_forge().as_ref(), *b); let sb = coercion::to_string(vm.kernel().string_forge().as_ref(), *b);
sa.cmp(&sb) sa.cmp(&sb)
}); });
for (i, &v) in vals.iter().enumerate() { 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])) Ok(vm.reg(_args[0]))
} }
+2 -2
View File
@@ -58,7 +58,7 @@ fn value_to_jsvalue(vm: &mut Vm, val: &serde_json::Value) -> JsValue {
for (i, v) in arr.iter().enumerate() { for (i, v) in arr.iter().enumerate() {
let jsv = value_to_jsvalue(vm, v); let jsv = value_to_jsvalue(vm, v);
unsafe { unsafe {
(*array_obj).set_prop_at(i as u8, jsv); (*array_obj).set_prop_at(i, jsv);
} }
} }
JsValue::from_js_object(array_obj) JsValue::from_js_object(array_obj)
@@ -216,7 +216,7 @@ fn stringify_array(
if i > 0 { if i > 0 {
out.push(','); 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 is_function = val.is_object() && {
let ptr = val.as_js_object_ptr(); let ptr = val.as_js_object_ptr();
if ptr.is_null() { if ptr.is_null() {
+25 -18
View File
@@ -7,10 +7,10 @@ use crate::coercion;
use crate::native::NativeResult; use crate::native::NativeResult;
use crate::vm::Vm; use crate::vm::Vm;
pub(crate) fn walk_own_keys(vm: &Vm, obj: &JsObject) -> Vec<(u32, u8)> { pub(crate) fn walk_own_keys(vm: &Vm, obj: &JsObject) -> Vec<(u32, u32)> {
let mut keys: Vec<(u32, u8)> = Vec::new(); let mut keys: Vec<(u32, u32)> = Vec::new();
let shape_id = obj.shape_id(); let shape_id = obj.shape_id();
let mut pos: u8 = 0; let mut pos: u32 = 0;
let mut shape_ids = Vec::new(); let mut shape_ids = Vec::new();
let mut cursor = Some(shape_id); let mut cursor = Some(shape_id);
while let Some(id) = cursor { while let Some(id) = cursor {
@@ -67,7 +67,7 @@ pub fn object_keys(vm: &mut Vm, args: &[u8]) -> NativeResult {
.collect(); .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 array_proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.epoch().alloc(JsObject::new_array( let arr = vm.epoch().alloc(JsObject::new_array(
EMPTY_SHAPE_ID, EMPTY_SHAPE_ID,
@@ -75,12 +75,15 @@ pub fn object_keys(vm: &mut Vm, args: &[u8]) -> NativeResult {
n, n,
vm.epoch().bump(), 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); let str_val = vm.intern(k);
unsafe { 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)) Ok(JsValue::from_js_object(arr))
} }
@@ -334,7 +337,7 @@ pub fn object_get_own_property_names(vm: &mut Vm, args: &[u8]) -> NativeResult {
.collect() .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 array_proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.epoch().alloc(JsObject::new_array( let arr = vm.epoch().alloc(JsObject::new_array(
EMPTY_SHAPE_ID, EMPTY_SHAPE_ID,
@@ -342,12 +345,15 @@ pub fn object_get_own_property_names(vm: &mut Vm, args: &[u8]) -> NativeResult {
n, n,
vm.epoch().bump(), 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); let str_val = vm.intern(k);
unsafe { 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)) 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_ptr = require_obj_arg(vm, args, "entries")?;
let obj = unsafe { &*obj_ptr }; let obj = unsafe { &*obj_ptr };
let keys = walk_own_keys(vm, obj); 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 array_proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.epoch().alloc(JsObject::new_array( let arr = vm.epoch().alloc(JsObject::new_array(
EMPTY_SHAPE_ID, EMPTY_SHAPE_ID,
@@ -407,7 +413,7 @@ pub fn object_entries(vm: &mut Vm, args: &[u8]) -> NativeResult {
n, n,
vm.epoch().bump(), 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_str = vm.kernel().string_forge().lookup(*si).unwrap_or_default();
let key_val = vm.intern(&key_str); let key_val = vm.intern(&key_str);
let val = obj.get_prop_at(*offset); 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(0, key_val);
(*pair).set_prop_at(1, val); (*pair).set_prop_at(1, val);
(*pair).set_prop_count(2); (*pair).set_prop_count(2);
(*arr) (*arr).set_prop_at(i, JsValue::from_js_object(pair));
.ensure_hash_props()
.push(Box::new(JsValue::from_js_object(pair)));
} }
} }
unsafe {
(*arr).set_prop_count(n);
}
Ok(JsValue::from_js_object(arr)) 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_ptr = require_obj_arg(vm, args, "values")?;
let obj = unsafe { &*obj_ptr }; let obj = unsafe { &*obj_ptr };
let keys = walk_own_keys(vm, obj); 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 array_proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.epoch().alloc(JsObject::new_array( let arr = vm.epoch().alloc(JsObject::new_array(
EMPTY_SHAPE_ID, EMPTY_SHAPE_ID,
@@ -441,14 +448,14 @@ pub fn object_values(vm: &mut Vm, args: &[u8]) -> NativeResult {
n, n,
vm.epoch().bump(), 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); let val = obj.get_prop_at(*offset);
unsafe { unsafe {
(*arr).set_prop_at(i as u8, val); (*arr).set_prop_at(i, val);
} }
} }
unsafe { unsafe {
(*arr).set_prop_count(n as u8); (*arr).set_prop_count(n);
} }
Ok(JsValue::from_js_object(arr)) Ok(JsValue::from_js_object(arr))
} }
+4 -4
View File
@@ -13,7 +13,7 @@ fn this_string(vm: &Vm, args: &[u8]) -> String {
fn make_string_array(vm: &mut Vm, parts: &[String]) -> JsValue { fn make_string_array(vm: &mut Vm, parts: &[String]) -> JsValue {
let proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject; 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( let arr = vm.epoch().alloc(JsObject::new_array(
EMPTY_SHAPE_ID, EMPTY_SHAPE_ID,
JsValue::from_js_object(proto), JsValue::from_js_object(proto),
@@ -21,11 +21,11 @@ fn make_string_array(vm: &mut Vm, parts: &[String]) -> JsValue {
vm.epoch().bump(), vm.epoch().bump(),
)); ));
unsafe { unsafe {
for (i, s) in parts.iter().enumerate().take(n) { for (i, s) in parts.iter().enumerate() {
let sv = vm.intern(s); 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) JsValue::from_js_object(arr)
} }
+43 -23
View File
@@ -105,7 +105,11 @@ macro_rules! member_read_prop {
if cached_shape_id != 0 && cached_shape_id == $obj.shape_id() && cached_ptr != 0 { if cached_shape_id != 0 && cached_shape_id == $obj.shape_id() && cached_ptr != 0 {
unsafe { *(cached_ptr as *const JsValue) } unsafe { *(cached_ptr as *const JsValue) }
} else if let Some(template) = $self.kernel.prop_forge().get_template($obj.shape_id()) { } 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 - 3] = $obj.shape_id() & 0x00FF_FFFF;
$self.bytecode[$self.pc - 2] = ptr as u32; $self.bytecode[$self.pc - 2] = ptr as u32;
$self.bytecode[$self.pc - 1] = (ptr as u64 >> 32) 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()) .unwrap_or(JsValue::undefined())
} }
} else if let Some(val) = $self.resolve_property($obj, $prop_name_si) { } else if let Some(val) = $self.resolve_property($obj, $prop_name_si) {
let pos = $self if let Some(pos) = $self
.kernel .kernel
.shape_forge() .shape_forge()
.lookup_position($obj.shape_id(), $prop_name_si) .lookup_position($obj.shape_id(), $prop_name_si)
.unwrap_or(0); {
if let Some(ptr) = $obj.prop_ptr_at(pos) { if let Some(ptr) = $obj.prop_ptr_at(pos) {
$self.bytecode[$self.pc - 3] = $obj.shape_id() & 0x00FF_FFFF; $self.bytecode[$self.pc - 3] = $obj.shape_id() & 0x00FF_FFFF;
$self.bytecode[$self.pc - 2] = ptr as u32; $self.bytecode[$self.pc - 2] = ptr as u32;
$self.bytecode[$self.pc - 1] = (ptr as u64 >> 32) as u32; $self.bytecode[$self.pc - 1] = (ptr as u64 >> 32) as u32;
}
} }
val val
} else { } else {
@@ -397,6 +402,10 @@ impl Vm {
} }
fn resolve_property(&self, obj: &JsObject, prop_name_si: u32) -> Option<JsValue> { 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 if let Some(pos) = self
.kernel .kernel
.shape_forge() .shape_forge()
@@ -459,6 +468,7 @@ impl Vm {
new_shape_id, new_shape_id,
PropTemplate { PropTemplate {
shape_id: new_shape_id, shape_id: new_shape_id,
prop_name: prop_name_si,
position: new_pos, position: new_pos,
generation: obj.generation(), generation: obj.generation(),
}, },
@@ -1023,14 +1033,20 @@ impl Vm {
} else if let Some(template) = } else if let Some(template) =
self.kernel.prop_forge().get_template(obj.shape_id()) self.kernel.prop_forge().get_template(obj.shape_id())
{ {
let pos = template.position as usize; if template.prop_name == prop_name_si {
if let Some(vec) = obj.hash_props_vec() { let pos = template.position as usize;
if pos < vec.len() { if let Some(vec) = obj.hash_props_vec() {
let ptr = &*vec[pos] as *const JsValue; if pos < vec.len() {
self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; let ptr = &*vec[pos] as *const JsValue;
self.bytecode[self.pc - 2] = ptr as u32; self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF;
self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; self.bytecode[self.pc - 2] = ptr as u32;
self.regs[a] = unsafe { *(ptr) }; 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 { } else {
self.regs[a] = self self.regs[a] = self
.resolve_property(obj, prop_name_si) .resolve_property(obj, prop_name_si)
@@ -1042,15 +1058,16 @@ impl Vm {
.unwrap_or(JsValue::undefined()); .unwrap_or(JsValue::undefined());
} }
} else if let Some(val) = self.resolve_property(obj, prop_name_si) { } else if let Some(val) = self.resolve_property(obj, prop_name_si) {
let pos = self if let Some(pos) = self
.kernel .kernel
.shape_forge() .shape_forge()
.lookup_position(obj.shape_id(), prop_name_si) .lookup_position(obj.shape_id(), prop_name_si)
.unwrap_or(0); {
if let Some(ptr) = obj.prop_ptr_at(pos) { if let Some(ptr) = obj.prop_ptr_at(pos) {
self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF; self.bytecode[self.pc - 3] = obj.shape_id() & 0x00FF_FFFF;
self.bytecode[self.pc - 2] = ptr as u32; self.bytecode[self.pc - 2] = ptr as u32;
self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32; self.bytecode[self.pc - 1] = (ptr as u64 >> 32) as u32;
}
} }
self.regs[a] = val; self.regs[a] = val;
} else { } else {
@@ -1105,6 +1122,7 @@ impl Vm {
new_shape_id, new_shape_id,
PropTemplate { PropTemplate {
shape_id: new_shape_id, shape_id: new_shape_id,
prop_name: prop_name_si,
position: new_pos, position: new_pos,
generation: obj.generation(), generation: obj.generation(),
}, },
@@ -1221,9 +1239,9 @@ impl Vm {
if obj_ptr.is_null() { if obj_ptr.is_null() {
throw_err!(self, TypeError, "SET_ELEM on non-object"); 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 }; 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 => { OpCode::COMPOUND_ADD => {
@@ -1507,6 +1525,7 @@ impl Vm {
new_shape_id, new_shape_id,
PropTemplate { PropTemplate {
shape_id: new_shape_id, shape_id: new_shape_id,
prop_name: prop_name_si,
position: new_pos, position: new_pos,
generation: obj.generation(), generation: obj.generation(),
}, },
@@ -1557,6 +1576,7 @@ impl Vm {
new_shape_id, new_shape_id,
PropTemplate { PropTemplate {
shape_id: new_shape_id, shape_id: new_shape_id,
prop_name: prop_name_si,
position: new_pos, position: new_pos,
generation: obj.generation(), generation: obj.generation(),
}, },
@@ -38,6 +38,21 @@ fn array_push_returns_true_length_beyond_31() {
assert_eq!(result.as_int(), 32); 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] #[test]
fn array_pop_returns_last() { fn array_pop_returns_last() {
let result = eval("[1,2,3].pop()").unwrap(); 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() { fn object_keys_empty() {
let result = eval("Object.keys({})").unwrap(); let result = eval("Object.keys({})").unwrap();
assert!(result.is_object()); assert!(result.is_object());
let obj = unsafe { &*result.as_js_object_ptr() };
assert_eq!(obj.prop_count(), 0);
} }
#[test] #[test]
fn object_keys_has_own_property() { 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] #[test]
@@ -68,10 +72,14 @@ fn object_has_own_true() {
fn object_entries_returns_array() { fn object_entries_returns_array() {
let result = eval("Object.entries({a:1,b:2})").unwrap(); let result = eval("Object.entries({a:1,b:2})").unwrap();
assert!(result.is_object()); assert!(result.is_object());
let obj = unsafe { &*result.as_js_object_ptr() };
assert_eq!(obj.prop_count(), 2);
} }
#[test] #[test]
fn object_values_returns_array() { fn object_values_returns_array() {
let result = eval("Object.values({a:1,b:2})").unwrap(); let result = eval("Object.values({a:1,b:2})").unwrap();
assert!(result.is_object()); 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 mut vm = Vm::new();
let result = eval(&mut vm, "'a,b,c'.split(/,/)").unwrap(); let result = eval(&mut vm, "'a,b,c'.split(/,/)").unwrap();
assert!(result.is_object()); 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 --- // --- toString ---
@@ -143,6 +143,10 @@ fn string_split_comma() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let result = eval(&mut vm, "'a,b,c'.split(',')").unwrap(); let result = eval(&mut vm, "'a,b,c'.split(',')").unwrap();
assert!(result.is_object()); 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] #[test]
+3 -8
View File
@@ -27,13 +27,7 @@ fn json_parse_object() {
let result = eval(&mut vm, "JSON.parse('{\"a\":1,\"b\":2}')").unwrap(); let result = eval(&mut vm, "JSON.parse('{\"a\":1,\"b\":2}')").unwrap();
assert!(result.is_object()); assert!(result.is_object());
let obj = unsafe { &*result.as_js_object_ptr() }; let obj = unsafe { &*result.as_js_object_ptr() };
let mut count = 0; assert_eq!(obj.prop_count(), 2);
for i in 0..obj.prop_vec_len() {
if !obj.get_prop_at(i as u8).is_undefined() {
count += 1;
}
}
assert_eq!(count, 2);
} }
#[test] #[test]
@@ -43,7 +37,8 @@ fn json_parse_array() {
assert!(result.is_object()); assert!(result.is_object());
let obj = unsafe { &*result.as_js_object_ptr() }; let obj = unsafe { &*result.as_js_object_ptr() };
assert!(obj.is_array()); 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] #[test]