fix: 修复数组长度与槽位索引截断问题
This commit is contained in:
@@ -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(", "))
|
||||||
|
|||||||
@@ -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]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
@@ -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).
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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]))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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]
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
Reference in New Issue
Block a user