Browse Source

Fix length/index in `32bit` architectures (#2196)

This PR fixes the length/index types from `usize` to `u64`, because in JavaScript the length can be from `0` to `2^53 - 1` it cannot be represented in a `usize`. On `64-bit` architectures this is fine because it is already a unsigned 64bit number and these changes essentially do nothing. But on 32bit architectures this was causing the length to be truncated giving an unexpected result. 

fixes/closes #2182 

It changes the following:
- Make length a `u64` to be able to represent all possible length values
- Change `JsValue::to_length()` t return `u64`
- Change `JsValue::to_index()` t return `u64`
pull/2201/head
Halid Odat 2 years ago
parent
commit
efff9d6269
  1. 2
      boa_engine/src/builtins/array/array_iterator.rs
  2. 56
      boa_engine/src/builtins/array/mod.rs
  3. 33
      boa_engine/src/builtins/array_buffer/mod.rs
  4. 2
      boa_engine/src/builtins/array_buffer/tests.rs
  5. 4
      boa_engine/src/builtins/dataview/mod.rs
  6. 31
      boa_engine/src/builtins/regexp/mod.rs
  7. 20
      boa_engine/src/builtins/string/mod.rs
  8. 2
      boa_engine/src/builtins/string/string_iterator.rs
  9. 24
      boa_engine/src/builtins/typed_array/integer_indexed_object.rs
  10. 30
      boa_engine/src/builtins/typed_array/mod.rs
  11. 22
      boa_engine/src/object/internal_methods/integer_indexed.rs
  12. 2
      boa_engine/src/object/jsarray.rs
  13. 4
      boa_engine/src/object/jsarraybuffer.rs
  14. 4
      boa_engine/src/object/operations.rs
  15. 4
      boa_engine/src/tests.rs
  16. 8
      boa_engine/src/value/mod.rs
  17. 2
      boa_engine/src/value/serde_json.rs

2
boa_engine/src/builtins/array/array_iterator.rs

@ -17,7 +17,7 @@ use boa_profiler::Profiler;
#[derive(Debug, Clone, Finalize, Trace)] #[derive(Debug, Clone, Finalize, Trace)]
pub struct ArrayIterator { pub struct ArrayIterator {
array: JsObject, array: JsObject,
next_index: usize, next_index: u64,
kind: PropertyNameKind, kind: PropertyNameKind,
done: bool, done: bool,
} }

56
boa_engine/src/builtins/array/mod.rs

@ -192,7 +192,7 @@ impl Array {
debug_assert!(number_of_args >= 2); debug_assert!(number_of_args >= 2);
// b. Let array be ? ArrayCreate(numberOfArgs, proto). // b. Let array be ? ArrayCreate(numberOfArgs, proto).
let array = Self::array_create(number_of_args, Some(prototype), context)?; let array = Self::array_create(number_of_args as u64, Some(prototype), context)?;
// c. Let k be 0. // c. Let k be 0.
// d. Repeat, while k < numberOfArgs, // d. Repeat, while k < numberOfArgs,
for (i, item) in args.iter().cloned().enumerate() { for (i, item) in args.iter().cloned().enumerate() {
@ -217,12 +217,12 @@ impl Array {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-arraycreate /// [spec]: https://tc39.es/ecma262/#sec-arraycreate
pub(crate) fn array_create( pub(crate) fn array_create(
length: usize, length: u64,
prototype: Option<JsObject>, prototype: Option<JsObject>,
context: &mut Context, context: &mut Context,
) -> JsResult<JsObject> { ) -> JsResult<JsObject> {
// 1. If length > 2^32 - 1, throw a RangeError exception. // 1. If length > 2^32 - 1, throw a RangeError exception.
if length > 2usize.pow(32) - 1 { if length > 2u64.pow(32) - 1 {
return context.throw_range_error("array exceeded max size"); return context.throw_range_error("array exceeded max size");
} }
// 7. Return A. // 7. Return A.
@ -334,7 +334,7 @@ impl Array {
/// see: <https://tc39.es/ecma262/#sec-arrayspeciescreate> /// see: <https://tc39.es/ecma262/#sec-arrayspeciescreate>
pub(crate) fn array_species_create( pub(crate) fn array_species_create(
original_array: &JsObject, original_array: &JsObject,
length: usize, length: u64,
context: &mut Context, context: &mut Context,
) -> JsResult<JsObject> { ) -> JsResult<JsObject> {
// 1. Let isArray be ? IsArray(originalArray). // 1. Let isArray be ? IsArray(originalArray).
@ -573,7 +573,7 @@ impl Array {
// a. Let A be ? ArrayCreate(len). // a. Let A be ? ArrayCreate(len).
let a = match this.as_constructor() { let a = match this.as_constructor() {
Some(constructor) => constructor.construct(&[len.into()], None, context)?, Some(constructor) => constructor.construct(&[len.into()], None, context)?,
_ => Self::array_create(len, None, context)?, _ => Self::array_create(len as u64, None, context)?,
}; };
// 6. Let k be 0. // 6. Let k be 0.
@ -667,7 +667,7 @@ impl Array {
// ii. Let len be ? LengthOfArrayLike(E). // ii. Let len be ? LengthOfArrayLike(E).
let len = item.length_of_array_like(context)?; let len = item.length_of_array_like(context)?;
// iii. If n + len > 2^53 - 1, throw a TypeError exception. // iii. If n + len > 2^53 - 1, throw a TypeError exception.
if n + len > Number::MAX_SAFE_INTEGER as usize { if n + len > Number::MAX_SAFE_INTEGER as u64 {
return context.throw_type_error( return context.throw_type_error(
"length + number of arguments exceeds the max safe integer limit", "length + number of arguments exceeds the max safe integer limit",
); );
@ -693,7 +693,7 @@ impl Array {
else { else {
// i. NOTE: E is added as a single item rather than spread. // i. NOTE: E is added as a single item rather than spread.
// ii. If n ≥ 2^53 - 1, throw a TypeError exception. // ii. If n ≥ 2^53 - 1, throw a TypeError exception.
if n >= Number::MAX_SAFE_INTEGER as usize { if n >= Number::MAX_SAFE_INTEGER as u64 {
return context.throw_type_error("length exceeds the max safe integer limit"); return context.throw_type_error("length exceeds the max safe integer limit");
} }
// iii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), E). // iii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), E).
@ -729,7 +729,7 @@ impl Array {
// 1. Let O be ? ToObject(this value). // 1. Let O be ? ToObject(this value).
let o = this.to_object(context)?; let o = this.to_object(context)?;
// 2. Let len be ? LengthOfArrayLike(O). // 2. Let len be ? LengthOfArrayLike(O).
let mut len = o.length_of_array_like(context)? as u64; let mut len = o.length_of_array_like(context)?;
// 3. Let argCount be the number of elements in items. // 3. Let argCount be the number of elements in items.
let arg_count = args.len() as u64; let arg_count = args.len() as u64;
// 4. If len + argCount > 2^53 - 1, throw a TypeError exception. // 4. If len + argCount > 2^53 - 1, throw a TypeError exception.
@ -1078,7 +1078,7 @@ impl Array {
// 1. Let O be ? ToObject(this value). // 1. Let O be ? ToObject(this value).
let o = this.to_object(context)?; let o = this.to_object(context)?;
// 2. Let len be ? LengthOfArrayLike(O). // 2. Let len be ? LengthOfArrayLike(O).
let len = o.length_of_array_like(context)? as u64; let len = o.length_of_array_like(context)?;
// 3. Let argCount be the number of elements in items. // 3. Let argCount be the number of elements in items.
let arg_count = args.len() as u64; let arg_count = args.len() as u64;
// 4. If argCount > 0, then // 4. If argCount > 0, then
@ -1640,7 +1640,7 @@ impl Array {
Self::flatten_into_array( Self::flatten_into_array(
&a, &a,
&o, &o,
source_len as u64, source_len,
0, 0,
depth_num, depth_num,
None, None,
@ -1687,7 +1687,7 @@ impl Array {
Self::flatten_into_array( Self::flatten_into_array(
&a, &a,
&o, &o,
source_len as u64, source_len,
0, 0,
1, 1,
Some(mapper_function), Some(mapper_function),
@ -1781,7 +1781,7 @@ impl Array {
target_index = Self::flatten_into_array( target_index = Self::flatten_into_array(
target, target,
element, element,
element_len as u64, element_len,
target_index, target_index,
new_depth, new_depth,
None, None,
@ -2037,7 +2037,7 @@ impl Array {
// 9. Else, // 9. Else,
} else { } else {
// 9a. Let insertCount be the number of elements in items. // 9a. Let insertCount be the number of elements in items.
items.len() items.len() as u64
}; };
let actual_delete_count = if start.is_none() { let actual_delete_count = if start.is_none() {
// 7b. Let actualDeleteCount be 0. // 7b. Let actualDeleteCount be 0.
@ -2056,16 +2056,14 @@ impl Array {
// c. Let actualDeleteCount be the result of clamping dc between 0 and len - actualStart. // c. Let actualDeleteCount be the result of clamping dc between 0 and len - actualStart.
let max = len - actual_start; let max = len - actual_start;
match dc { match dc {
IntegerOrInfinity::Integer(i) => { IntegerOrInfinity::Integer(i) => u64::try_from(i).unwrap_or_default().clamp(0, max),
usize::try_from(i).unwrap_or_default().clamp(0, max)
}
IntegerOrInfinity::PositiveInfinity => max, IntegerOrInfinity::PositiveInfinity => max,
IntegerOrInfinity::NegativeInfinity => 0, IntegerOrInfinity::NegativeInfinity => 0,
} }
}; };
// 10. If len + insertCount - actualDeleteCount > 2^53 - 1, throw a TypeError exception. // 10. If len + insertCount - actualDeleteCount > 2^53 - 1, throw a TypeError exception.
if len + insert_count - actual_delete_count > Number::MAX_SAFE_INTEGER as usize { if len + insert_count - actual_delete_count > Number::MAX_SAFE_INTEGER as u64 {
return context.throw_type_error("Target splice exceeded max safe integer value"); return context.throw_type_error("Target splice exceeded max safe integer value");
} }
@ -2091,7 +2089,7 @@ impl Array {
arr.set("length", actual_delete_count, true, context)?; arr.set("length", actual_delete_count, true, context)?;
// 15. Let itemCount be the number of elements in items. // 15. Let itemCount be the number of elements in items.
let item_count = items.len(); let item_count = items.len() as u64;
match item_count.cmp(&actual_delete_count) { match item_count.cmp(&actual_delete_count) {
// 16. If itemCount < actualDeleteCount, then // 16. If itemCount < actualDeleteCount, then
@ -2164,7 +2162,7 @@ impl Array {
for (k, item) in items for (k, item) in items
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, val)| (i + actual_start, val)) .map(|(i, val)| (i as u64 + actual_start, val))
{ {
// a. Perform ? Set(O, ! ToString(𝔽(k)), E, true). // a. Perform ? Set(O, ! ToString(𝔽(k)), E, true).
o.set(k, item, true, context)?; o.set(k, item, true, context)?;
@ -2381,7 +2379,7 @@ impl Array {
let length = obj.length_of_array_like(context)?; let length = obj.length_of_array_like(context)?;
// 4. Let items be a new empty List. // 4. Let items be a new empty List.
let mut items = Vec::with_capacity(length); let mut items = Vec::with_capacity(length as usize);
// 5. Let k be 0. // 5. Let k be 0.
// 6. Repeat, while k < len, // 6. Repeat, while k < len,
@ -2399,7 +2397,7 @@ impl Array {
} }
// 7. Let itemCount be the number of elements in items. // 7. Let itemCount be the number of elements in items.
let item_count = items.len(); let item_count = items.len() as u64;
// 8. Sort items using an implementation-defined sequence of calls to SortCompare. // 8. Sort items using an implementation-defined sequence of calls to SortCompare.
// If any such call returns an abrupt completion, stop before performing any further // If any such call returns an abrupt completion, stop before performing any further
@ -2792,8 +2790,8 @@ impl Array {
pub(super) fn get_relative_start( pub(super) fn get_relative_start(
context: &mut Context, context: &mut Context,
arg: Option<&JsValue>, arg: Option<&JsValue>,
len: usize, len: u64,
) -> JsResult<usize> { ) -> JsResult<u64> {
// 1. Let relativeStart be ? ToIntegerOrInfinity(start). // 1. Let relativeStart be ? ToIntegerOrInfinity(start).
let relative_start = arg let relative_start = arg
.cloned() .cloned()
@ -2803,10 +2801,10 @@ impl Array {
// 2. If relativeStart is -∞, let k be 0. // 2. If relativeStart is -∞, let k be 0.
IntegerOrInfinity::NegativeInfinity => Ok(0), IntegerOrInfinity::NegativeInfinity => Ok(0),
// 3. Else if relativeStart < 0, let k be max(len + relativeStart, 0). // 3. Else if relativeStart < 0, let k be max(len + relativeStart, 0).
IntegerOrInfinity::Integer(i) if i < 0 => Ok(max(len as i64 + i, 0) as usize), IntegerOrInfinity::Integer(i) if i < 0 => Ok(max(len as i64 + i, 0) as u64),
// Both `as` casts are safe as both variables are non-negative // Both `as` casts are safe as both variables are non-negative
// 4. Else, let k be min(relativeStart, len). // 4. Else, let k be min(relativeStart, len).
IntegerOrInfinity::Integer(i) => Ok(min(i, len as i64) as usize), IntegerOrInfinity::Integer(i) => Ok(min(i, len as i64) as u64),
// Special case - positive infinity. `len` is always smaller than +inf, thus from (4) // Special case - positive infinity. `len` is always smaller than +inf, thus from (4)
IntegerOrInfinity::PositiveInfinity => Ok(len), IntegerOrInfinity::PositiveInfinity => Ok(len),
@ -2817,8 +2815,8 @@ impl Array {
pub(super) fn get_relative_end( pub(super) fn get_relative_end(
context: &mut Context, context: &mut Context,
arg: Option<&JsValue>, arg: Option<&JsValue>,
len: usize, len: u64,
) -> JsResult<usize> { ) -> JsResult<u64> {
let default_value = JsValue::undefined(); let default_value = JsValue::undefined();
let value = arg.unwrap_or(&default_value); let value = arg.unwrap_or(&default_value);
// 1. If end is undefined, let relativeEnd be len [and return it] // 1. If end is undefined, let relativeEnd be len [and return it]
@ -2831,10 +2829,10 @@ impl Array {
// 2. If relativeEnd is -∞, let final be 0. // 2. If relativeEnd is -∞, let final be 0.
IntegerOrInfinity::NegativeInfinity => Ok(0), IntegerOrInfinity::NegativeInfinity => Ok(0),
// 3. Else if relativeEnd < 0, let final be max(len + relativeEnd, 0). // 3. Else if relativeEnd < 0, let final be max(len + relativeEnd, 0).
IntegerOrInfinity::Integer(i) if i < 0 => Ok(max(len as i64 + i, 0) as usize), IntegerOrInfinity::Integer(i) if i < 0 => Ok(max(len as i64 + i, 0) as u64),
// 4. Else, let final be min(relativeEnd, len). // 4. Else, let final be min(relativeEnd, len).
// Both `as` casts are safe as both variables are non-negative // Both `as` casts are safe as both variables are non-negative
IntegerOrInfinity::Integer(i) => Ok(min(i, len as i64) as usize), IntegerOrInfinity::Integer(i) => Ok(min(i, len as i64) as u64),
// Special case - positive infinity. `len` is always smaller than +inf, thus from (4) // Special case - positive infinity. `len` is always smaller than +inf, thus from (4)
IntegerOrInfinity::PositiveInfinity => Ok(len), IntegerOrInfinity::PositiveInfinity => Ok(len),

33
boa_engine/src/builtins/array_buffer/mod.rs

@ -21,12 +21,12 @@ use tap::{Conv, Pipe};
#[derive(Debug, Clone, Trace, Finalize)] #[derive(Debug, Clone, Trace, Finalize)]
pub struct ArrayBuffer { pub struct ArrayBuffer {
pub array_buffer_data: Option<Vec<u8>>, pub array_buffer_data: Option<Vec<u8>>,
pub array_buffer_byte_length: usize, pub array_buffer_byte_length: u64,
pub array_buffer_detach_key: JsValue, pub array_buffer_detach_key: JsValue,
} }
impl ArrayBuffer { impl ArrayBuffer {
pub(crate) fn array_buffer_byte_length(&self) -> usize { pub(crate) fn array_buffer_byte_length(&self) -> u64 {
self.array_buffer_byte_length self.array_buffer_byte_length
} }
} }
@ -235,7 +235,7 @@ impl ArrayBuffer {
}; };
// 14. Let newLen be max(final - first, 0). // 14. Let newLen be max(final - first, 0).
let new_len = std::cmp::max(r#final - first, 0) as usize; let new_len = std::cmp::max(r#final - first, 0) as u64;
// 15. Let ctor be ? SpeciesConstructor(O, %ArrayBuffer%). // 15. Let ctor be ? SpeciesConstructor(O, %ArrayBuffer%).
let ctor = obj.species_constructor(StandardConstructors::array_buffer, context)?; let ctor = obj.species_constructor(StandardConstructors::array_buffer, context)?;
@ -299,7 +299,7 @@ impl ArrayBuffer {
.expect("ArrayBuffer cannot be detached here"); .expect("ArrayBuffer cannot be detached here");
// 26. Perform CopyDataBlockBytes(toBuf, 0, fromBuf, first, newLen). // 26. Perform CopyDataBlockBytes(toBuf, 0, fromBuf, first, newLen).
copy_data_block_bytes(to_buf, 0, from_buf, first as usize, new_len); copy_data_block_bytes(to_buf, 0, from_buf, first as usize, new_len as usize);
} }
// 27. Return new. // 27. Return new.
@ -314,7 +314,7 @@ impl ArrayBuffer {
/// [spec]: https://tc39.es/ecma262/#sec-allocatearraybuffer /// [spec]: https://tc39.es/ecma262/#sec-allocatearraybuffer
pub(crate) fn allocate( pub(crate) fn allocate(
constructor: &JsValue, constructor: &JsValue,
byte_length: usize, byte_length: u64,
context: &mut Context, context: &mut Context,
) -> JsResult<JsObject> { ) -> JsResult<JsObject> {
// 1. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%ArrayBuffer.prototype%", « [[ArrayBufferData]], [[ArrayBufferByteLength]], [[ArrayBufferDetachKey]] »). // 1. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%ArrayBuffer.prototype%", « [[ArrayBufferData]], [[ArrayBufferByteLength]], [[ArrayBufferDetachKey]] »).
@ -361,8 +361,8 @@ impl ArrayBuffer {
/// [spec]: https://tc39.es/ecma262/#sec-clonearraybuffer /// [spec]: https://tc39.es/ecma262/#sec-clonearraybuffer
pub(crate) fn clone_array_buffer( pub(crate) fn clone_array_buffer(
&self, &self,
src_byte_offset: usize, src_byte_offset: u64,
src_length: usize, src_length: u64,
clone_constructor: &JsValue, clone_constructor: &JsValue,
context: &mut Context, context: &mut Context,
) -> JsResult<JsObject> { ) -> JsResult<JsObject> {
@ -392,8 +392,8 @@ impl ArrayBuffer {
.expect("ArrayBuffer cannot me detached here"), .expect("ArrayBuffer cannot me detached here"),
0, 0,
src_block, src_block,
src_byte_offset, src_byte_offset as usize,
src_length, src_length as usize,
); );
} }
@ -568,7 +568,7 @@ impl ArrayBuffer {
/// [spec]: https://tc39.es/ecma262/#sec-getvaluefrombuffer /// [spec]: https://tc39.es/ecma262/#sec-getvaluefrombuffer
pub(crate) fn get_value_from_buffer( pub(crate) fn get_value_from_buffer(
&self, &self,
byte_index: usize, byte_index: u64,
t: TypedArrayKind, t: TypedArrayKind,
_is_typed_array: bool, _is_typed_array: bool,
_order: SharedMemoryOrder, _order: SharedMemoryOrder,
@ -583,13 +583,14 @@ impl ArrayBuffer {
.expect("ArrayBuffer cannot be detached here"); .expect("ArrayBuffer cannot be detached here");
// 4. Let elementSize be the Element Size value specified in Table 73 for Element Type type. // 4. Let elementSize be the Element Size value specified in Table 73 for Element Type type.
let element_size = t.element_size(); let element_size = t.element_size() as usize;
// TODO: Shared Array Buffer // TODO: Shared Array Buffer
// 5. If IsSharedArrayBuffer(arrayBuffer) is true, then // 5. If IsSharedArrayBuffer(arrayBuffer) is true, then
// 6. Else, let rawValue be a List whose elements are bytes from block at indices byteIndex (inclusive) through byteIndex + elementSize (exclusive). // 6. Else, let rawValue be a List whose elements are bytes from block at indices byteIndex (inclusive) through byteIndex + elementSize (exclusive).
// 7. Assert: The number of elements in rawValue is elementSize. // 7. Assert: The number of elements in rawValue is elementSize.
let byte_index = byte_index as usize;
let raw_value = &block[byte_index..byte_index + element_size]; let raw_value = &block[byte_index..byte_index + element_size];
// TODO: Agent Record [[LittleEndian]] filed // TODO: Agent Record [[LittleEndian]] filed
@ -700,7 +701,7 @@ impl ArrayBuffer {
/// [spec]: https://tc39.es/ecma262/#sec-setvalueinbuffer /// [spec]: https://tc39.es/ecma262/#sec-setvalueinbuffer
pub(crate) fn set_value_in_buffer( pub(crate) fn set_value_in_buffer(
&mut self, &mut self,
byte_index: usize, byte_index: u64,
t: TypedArrayKind, t: TypedArrayKind,
value: &JsValue, value: &JsValue,
_order: SharedMemoryOrder, _order: SharedMemoryOrder,
@ -730,7 +731,7 @@ impl ArrayBuffer {
// 9. Else, store the individual bytes of rawBytes into block, starting at block[byteIndex]. // 9. Else, store the individual bytes of rawBytes into block, starting at block[byteIndex].
for (i, raw_byte) in raw_bytes.iter().enumerate() { for (i, raw_byte) in raw_bytes.iter().enumerate() {
block[byte_index + i] = *raw_byte; block[byte_index as usize + i] = *raw_byte;
} }
// 10. Return NormalCompletion(undefined). // 10. Return NormalCompletion(undefined).
@ -744,16 +745,16 @@ impl ArrayBuffer {
/// integer). For more information, check the [spec][spec]. /// integer). For more information, check the [spec][spec].
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-createbytedatablock /// [spec]: https://tc39.es/ecma262/#sec-createbytedatablock
pub fn create_byte_data_block(size: usize, context: &mut Context) -> JsResult<Vec<u8>> { pub fn create_byte_data_block(size: u64, context: &mut Context) -> JsResult<Vec<u8>> {
// 1. Let db be a new Data Block value consisting of size bytes. If it is impossible to // 1. Let db be a new Data Block value consisting of size bytes. If it is impossible to
// create such a Data Block, throw a RangeError exception. // create such a Data Block, throw a RangeError exception.
let mut data_block = Vec::new(); let mut data_block = Vec::new();
data_block.try_reserve(size).map_err(|e| { data_block.try_reserve(size as usize).map_err(|e| {
context.construct_range_error(format!("couldn't allocate the data block: {e}")) context.construct_range_error(format!("couldn't allocate the data block: {e}"))
})?; })?;
// 2. Set all of the bytes of db to 0. // 2. Set all of the bytes of db to 0.
data_block.resize(size, 0); data_block.resize(size as usize, 0);
// 3. Return db. // 3. Return db.
Ok(data_block) Ok(data_block)

2
boa_engine/src/builtins/array_buffer/tests.rs

@ -11,5 +11,5 @@ fn ut_sunny_day_create_byte_data_block() {
fn ut_rainy_day_create_byte_data_block() { fn ut_rainy_day_create_byte_data_block() {
let mut context = Context::default(); let mut context = Context::default();
assert!(create_byte_data_block(usize::MAX, &mut context).is_err()); assert!(create_byte_data_block(u64::MAX, &mut context).is_err());
} }

4
boa_engine/src/builtins/dataview/mod.rs

@ -16,8 +16,8 @@ use tap::{Conv, Pipe};
#[derive(Debug, Clone, Trace, Finalize)] #[derive(Debug, Clone, Trace, Finalize)]
pub struct DataView { pub struct DataView {
viewed_array_buffer: JsObject, viewed_array_buffer: JsObject,
byte_length: usize, byte_length: u64,
byte_offset: usize, byte_offset: u64,
} }
impl BuiltIn for DataView { impl BuiltIn for DataView {

31
boa_engine/src/builtins/regexp/mod.rs

@ -812,7 +812,7 @@ impl RegExp {
// 2. Assert: Type(S) is String. // 2. Assert: Type(S) is String.
// 3. Let length be the number of code units in S. // 3. Let length be the number of code units in S.
let length = input.encode_utf16().count(); let length = input.encode_utf16().count() as u64;
// 4. Let lastIndex be ℝ(? ToLength(? Get(R, "lastIndex"))). // 4. Let lastIndex be ℝ(? ToLength(? Get(R, "lastIndex"))).
let mut last_index = this.get("lastIndex", context)?.to_length(context)?; let mut last_index = this.get("lastIndex", context)?.to_length(context)?;
@ -855,7 +855,10 @@ impl RegExp {
// b. Let r be matcher(S, lastIndex). // b. Let r be matcher(S, lastIndex).
// Check if last_index is a valid utf8 index into input. // Check if last_index is a valid utf8 index into input.
let last_byte_index = match String::from_utf16( let last_byte_index = match String::from_utf16(
&input.encode_utf16().take(last_index).collect::<Vec<u16>>(), &input
.encode_utf16()
.take(last_index as usize)
.collect::<Vec<u16>>(),
) { ) {
Ok(s) => s.len(), Ok(s) => s.len(),
Err(_) => { Err(_) => {
@ -884,7 +887,7 @@ impl RegExp {
Some(m) => { Some(m) => {
// c. If r is failure, then // c. If r is failure, then
#[allow(clippy::if_not_else)] #[allow(clippy::if_not_else)]
if m.start() != last_index { if m.start() as u64 != last_index {
// i. If sticky is true, then // i. If sticky is true, then
if sticky { if sticky {
// 1. Perform ? Set(R, "lastIndex", +0𝔽, true). // 1. Perform ? Set(R, "lastIndex", +0𝔽, true).
@ -925,9 +928,9 @@ impl RegExp {
} }
// 16. Let n be the number of elements in r's captures List. (This is the same value as 22.2.2.1's NcapturingParens.) // 16. Let n be the number of elements in r's captures List. (This is the same value as 22.2.2.1's NcapturingParens.)
let n = match_value.captures.len(); let n = match_value.captures.len() as u64;
// 17. Assert: n < 23^2 - 1. // 17. Assert: n < 23^2 - 1.
debug_assert!(n < 23usize.pow(2) - 1); debug_assert!(n < 23u64.pow(2) - 1);
// 18. Let A be ! ArrayCreate(n + 1). // 18. Let A be ! ArrayCreate(n + 1).
// 19. Assert: The mathematical value of A's "length" property is n + 1. // 19. Assert: The mathematical value of A's "length" property is n + 1.
@ -990,7 +993,7 @@ impl RegExp {
// 27. For each integer i such that i ≥ 1 and i ≤ n, in ascending order, do // 27. For each integer i such that i ≥ 1 and i ≤ n, in ascending order, do
for i in 1..=n { for i in 1..=n {
// a. Let captureI be ith element of r's captures List. // a. Let captureI be ith element of r's captures List.
let capture = match_value.group(i); let capture = match_value.group(i as usize);
let captured_value = match capture { let captured_value = match capture {
// b. If captureI is undefined, let capturedValue be undefined. // b. If captureI is undefined, let capturedValue be undefined.
@ -1597,7 +1600,7 @@ impl RegExp {
} }
// 15. Let size be the length of S. // 15. Let size be the length of S.
let size = arg_str.encode_utf16().count(); let size = arg_str.encode_utf16().count() as u64;
// 16. If size is 0, then // 16. If size is 0, then
if size == 0 { if size == 0 {
@ -1648,8 +1651,8 @@ impl RegExp {
let arg_str_substring = String::from_utf16_lossy( let arg_str_substring = String::from_utf16_lossy(
&arg_str &arg_str
.encode_utf16() .encode_utf16()
.skip(p) .skip(p as usize)
.take(q - p) .take((q - p) as usize)
.collect::<Vec<u16>>(), .collect::<Vec<u16>>(),
); );
@ -1709,8 +1712,8 @@ impl RegExp {
let arg_str_substring = String::from_utf16_lossy( let arg_str_substring = String::from_utf16_lossy(
&arg_str &arg_str
.encode_utf16() .encode_utf16()
.skip(p) .skip(p as usize)
.take(size - p) .take((size - p) as usize)
.collect::<Vec<u16>>(), .collect::<Vec<u16>>(),
); );
@ -1729,7 +1732,7 @@ impl RegExp {
/// - [ECMAScript reference][spec] /// - [ECMAScript reference][spec]
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-advancestringindex /// [spec]: https://tc39.es/ecma262/#sec-advancestringindex
fn advance_string_index(s: &JsString, index: usize, unicode: bool) -> usize { fn advance_string_index(s: &JsString, index: u64, unicode: bool) -> u64 {
// Regress only works with utf8, so this function differs from the spec. // Regress only works with utf8, so this function differs from the spec.
// 1. Assert: index ≤ 2^53 - 1. // 1. Assert: index ≤ 2^53 - 1.
@ -1740,7 +1743,7 @@ fn advance_string_index(s: &JsString, index: usize, unicode: bool) -> usize {
} }
// 3. Let length be the number of code units in S. // 3. Let length be the number of code units in S.
let length = s.encode_utf16().count(); let length = s.encode_utf16().count() as u64;
// 4. If index + 1 ≥ length, return index + 1. // 4. If index + 1 ≥ length, return index + 1.
if index + 1 > length { if index + 1 > length {
@ -1750,5 +1753,5 @@ fn advance_string_index(s: &JsString, index: usize, unicode: bool) -> usize {
// 5. Let cp be ! CodePointAt(S, index). // 5. Let cp be ! CodePointAt(S, index).
let (_, offset, _) = crate::builtins::string::code_point_at(s, index); let (_, offset, _) = crate::builtins::string::code_point_at(s, index);
index + offset as usize index + u64::from(offset)
} }

20
boa_engine/src/builtins/string/mod.rs

@ -40,12 +40,12 @@ pub(crate) enum Placement {
End, End,
} }
pub(crate) fn code_point_at(string: &JsString, position: usize) -> (u32, u8, bool) { pub(crate) fn code_point_at(string: &JsString, position: u64) -> (u32, u8, bool) {
let mut encoded = string.encode_utf16(); let mut encoded = string.encode_utf16();
let size = encoded.clone().count(); let size = encoded.clone().count() as u64;
let first = encoded let first = encoded
.nth(position) .nth(position as usize)
.expect("The callers of this function must've already checked bounds."); .expect("The callers of this function must've already checked bounds.");
if !is_leading_surrogate(first) && !is_trailing_surrogate(first) { if !is_leading_surrogate(first) && !is_trailing_surrogate(first) {
return (u32::from(first), 1, false); return (u32::from(first), 1, false);
@ -309,7 +309,7 @@ impl String {
let substitutions = args.get(1..).unwrap_or_default(); let substitutions = args.get(1..).unwrap_or_default();
// 1. Let numberOfSubstitutions be the number of elements in substitutions. // 1. Let numberOfSubstitutions be the number of elements in substitutions.
let number_of_substitutions = substitutions.len(); let number_of_substitutions = substitutions.len() as u64;
// 2. Let cooked be ? ToObject(template). // 2. Let cooked be ? ToObject(template).
let cooked = args.get_or_undefined(0).to_object(context)?; let cooked = args.get_or_undefined(0).to_object(context)?;
@ -351,7 +351,7 @@ impl String {
// e. If nextIndex < numberOfSubstitutions, let next be substitutions[nextIndex]. // e. If nextIndex < numberOfSubstitutions, let next be substitutions[nextIndex].
let next = if next_index < number_of_substitutions { let next = if next_index < number_of_substitutions {
substitutions.get_or_undefined(next_index).clone() substitutions.get_or_undefined(next_index as usize).clone()
// f. Else, let next be the empty String. // f. Else, let next be the empty String.
} else { } else {
@ -544,7 +544,7 @@ impl String {
IntegerOrInfinity::Integer(position) if (0..size).contains(&position) => { IntegerOrInfinity::Integer(position) if (0..size).contains(&position) => {
// 6. Let cp be ! CodePointAt(S, position). // 6. Let cp be ! CodePointAt(S, position).
// 7. Return 𝔽(cp.[[CodePoint]]). // 7. Return 𝔽(cp.[[CodePoint]]).
Ok(code_point_at(&string, position as usize).0.into()) Ok(code_point_at(&string, position as u64).0.into())
} }
// 5. If position < 0 or position ≥ size, return undefined. // 5. If position < 0 or position ≥ size, return undefined.
_ => Ok(JsValue::undefined()), _ => Ok(JsValue::undefined()),
@ -1408,7 +1408,7 @@ impl String {
let int_max_length = max_length.to_length(context)?; let int_max_length = max_length.to_length(context)?;
// 3. Let stringLength be the length of S. // 3. Let stringLength be the length of S.
let string_length = string.encode_utf16().count(); let string_length = string.encode_utf16().count() as u64;
// 4. If intMaxLength ≤ stringLength, return S. // 4. If intMaxLength ≤ stringLength, return S.
if int_max_length <= string_length { if int_max_length <= string_length {
@ -1430,7 +1430,7 @@ impl String {
// 8. Let fillLen be intMaxLength - stringLength. // 8. Let fillLen be intMaxLength - stringLength.
let fill_len = int_max_length - string_length; let fill_len = int_max_length - string_length;
let filler_len = filler.encode_utf16().count(); let filler_len = filler.encode_utf16().count() as u64;
// 9. Let truncatedStringFiller be the String value consisting of repeated // 9. Let truncatedStringFiller be the String value consisting of repeated
// concatenations of filler truncated to length fillLen. // concatenations of filler truncated to length fillLen.
@ -1445,9 +1445,9 @@ impl String {
}; };
let truncated_string_filler = filler let truncated_string_filler = filler
.repeat(repetitions) .repeat(repetitions as usize)
.encode_utf16() .encode_utf16()
.take(fill_len) .take(fill_len as usize)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let truncated_string_filler = let truncated_string_filler =
std::string::String::from_utf16_lossy(truncated_string_filler.as_slice()); std::string::String::from_utf16_lossy(truncated_string_filler.as_slice());

2
boa_engine/src/builtins/string/string_iterator.rs

@ -61,7 +61,7 @@ impl StringIterator {
context, context,
)); ));
} }
let (_, code_unit_count, _) = code_point_at(&native_string, position as usize); let (_, code_unit_count, _) = code_point_at(&native_string, position as u64);
string_iterator.next_index += i32::from(code_unit_count); string_iterator.next_index += i32::from(code_unit_count);
let result_string = crate::builtins::string::String::substring( let result_string = crate::builtins::string::String::substring(
&string_iterator.string, &string_iterator.string,

24
boa_engine/src/builtins/typed_array/integer_indexed_object.rs

@ -32,18 +32,18 @@ unsafe impl Trace for ContentType {
pub struct IntegerIndexed { pub struct IntegerIndexed {
viewed_array_buffer: Option<JsObject>, viewed_array_buffer: Option<JsObject>,
typed_array_name: TypedArrayKind, typed_array_name: TypedArrayKind,
byte_offset: usize, byte_offset: u64,
byte_length: usize, byte_length: u64,
array_length: usize, array_length: u64,
} }
impl IntegerIndexed { impl IntegerIndexed {
pub(crate) fn new( pub(crate) fn new(
viewed_array_buffer: Option<JsObject>, viewed_array_buffer: Option<JsObject>,
typed_array_name: TypedArrayKind, typed_array_name: TypedArrayKind,
byte_offset: usize, byte_offset: u64,
byte_length: usize, byte_length: u64,
array_length: usize, array_length: u64,
) -> Self { ) -> Self {
Self { Self {
viewed_array_buffer, viewed_array_buffer,
@ -105,12 +105,12 @@ impl IntegerIndexed {
} }
/// Get the integer indexed object's byte offset. /// Get the integer indexed object's byte offset.
pub(crate) fn byte_offset(&self) -> usize { pub(crate) fn byte_offset(&self) -> u64 {
self.byte_offset self.byte_offset
} }
/// Set the integer indexed object's byte offset. /// Set the integer indexed object's byte offset.
pub(crate) fn set_byte_offset(&mut self, byte_offset: usize) { pub(crate) fn set_byte_offset(&mut self, byte_offset: u64) {
self.byte_offset = byte_offset; self.byte_offset = byte_offset;
} }
@ -130,22 +130,22 @@ impl IntegerIndexed {
} }
/// Get the integer indexed object's byte length. /// Get the integer indexed object's byte length.
pub fn byte_length(&self) -> usize { pub fn byte_length(&self) -> u64 {
self.byte_length self.byte_length
} }
/// Set the integer indexed object's byte length. /// Set the integer indexed object's byte length.
pub(crate) fn set_byte_length(&mut self, byte_length: usize) { pub(crate) fn set_byte_length(&mut self, byte_length: u64) {
self.byte_length = byte_length; self.byte_length = byte_length;
} }
/// Get the integer indexed object's array length. /// Get the integer indexed object's array length.
pub fn array_length(&self) -> usize { pub fn array_length(&self) -> u64 {
self.array_length self.array_length
} }
/// Set the integer indexed object's array length. /// Set the integer indexed object's array length.
pub(crate) fn set_array_length(&mut self, array_length: usize) { pub(crate) fn set_array_length(&mut self, array_length: u64) {
self.array_length = array_length; self.array_length = array_length;
} }
} }

30
boa_engine/src/builtins/typed_array/mod.rs

@ -819,7 +819,7 @@ impl TypedArray {
while count_bytes > 0 { while count_bytes > 0 {
// i. Let value be GetValueFromBuffer(buffer, fromByteIndex, Uint8, true, Unordered). // i. Let value be GetValueFromBuffer(buffer, fromByteIndex, Uint8, true, Unordered).
let value = buffer.get_value_from_buffer( let value = buffer.get_value_from_buffer(
from_byte_index as usize, from_byte_index as u64,
TypedArrayKind::Uint8, TypedArrayKind::Uint8,
true, true,
SharedMemoryOrder::Unordered, SharedMemoryOrder::Unordered,
@ -828,7 +828,7 @@ impl TypedArray {
// ii. Perform SetValueInBuffer(buffer, toByteIndex, Uint8, value, true, Unordered). // ii. Perform SetValueInBuffer(buffer, toByteIndex, Uint8, value, true, Unordered).
buffer.set_value_in_buffer( buffer.set_value_in_buffer(
to_byte_index as usize, to_byte_index as u64,
TypedArrayKind::Uint8, TypedArrayKind::Uint8,
&value, &value,
SharedMemoryOrder::Unordered, SharedMemoryOrder::Unordered,
@ -2061,7 +2061,7 @@ impl TypedArray {
// 15. If targetOffset is +∞, throw a RangeError exception. // 15. If targetOffset is +∞, throw a RangeError exception.
let target_offset = match target_offset { let target_offset = match target_offset {
IntegerOrInfinity::Integer(i) if i >= 0 => i as usize, IntegerOrInfinity::Integer(i) if i >= 0 => i as u64,
IntegerOrInfinity::PositiveInfinity => { IntegerOrInfinity::PositiveInfinity => {
return context.throw_range_error("Target offset cannot be Infinity"); return context.throw_range_error("Target offset cannot be Infinity");
} }
@ -2254,7 +2254,7 @@ impl TypedArray {
IntegerOrInfinity::PositiveInfinity => { IntegerOrInfinity::PositiveInfinity => {
return context.throw_range_error("Target offset cannot be Infinity") return context.throw_range_error("Target offset cannot be Infinity")
} }
IntegerOrInfinity::Integer(i) if i >= 0 => i as usize, IntegerOrInfinity::Integer(i) if i >= 0 => i as u64,
_ => unreachable!(), _ => unreachable!(),
}; };
@ -2378,7 +2378,7 @@ impl TypedArray {
}; };
// 12. Let count be max(final - k, 0). // 12. Let count be max(final - k, 0).
let count = std::cmp::max(r#final - k, 0) as usize; let count = std::cmp::max(r#final - k, 0) as u64;
// 13. Let A be ? TypedArraySpeciesCreate(O, « 𝔽(count) »). // 13. Let A be ? TypedArraySpeciesCreate(O, « 𝔽(count) »).
let a = Self::species_create(obj, o.typed_array_name(), &[count.into()], context)?; let a = Self::species_create(obj, o.typed_array_name(), &[count.into()], context)?;
@ -2449,7 +2449,7 @@ impl TypedArray {
let mut target_byte_index = a_array.byte_offset(); let mut target_byte_index = a_array.byte_offset();
// vii. Let srcByteIndex be (k × elementSize) + srcByteOffset. // vii. Let srcByteIndex be (k × elementSize) + srcByteOffset.
let mut src_byte_index = k as usize * element_size + src_byte_offset; let mut src_byte_index = k as u64 * element_size + src_byte_offset;
// viii. Let limit be targetByteIndex + count × elementSize. // viii. Let limit be targetByteIndex + count × elementSize.
let limit = target_byte_index + count * element_size; let limit = target_byte_index + count * element_size;
@ -2601,7 +2601,7 @@ impl TypedArray {
}; };
// 4. Let items be a new empty List. // 4. Let items be a new empty List.
let mut items = Vec::with_capacity(len); let mut items = Vec::with_capacity(len as usize);
// 5. Let k be 0. // 5. Let k be 0.
// 6. Repeat, while k < len, // 6. Repeat, while k < len,
@ -2754,7 +2754,7 @@ impl TypedArray {
} }
// 11. Repeat, while j < len, // 11. Repeat, while j < len,
for j in item_count..len { for j in item_count..(len as usize) {
// a. Perform ? DeletePropertyOrThrow(obj, ! ToString(𝔽(j))). // a. Perform ? DeletePropertyOrThrow(obj, ! ToString(𝔽(j))).
obj.delete_property_or_throw(j, context)?; obj.delete_property_or_throw(j, context)?;
// b. Set j to j + 1. // b. Set j to j + 1.
@ -2834,7 +2834,7 @@ impl TypedArray {
let src_byte_offset = o.byte_offset(); let src_byte_offset = o.byte_offset();
// 18. Let beginByteOffset be srcByteOffset + beginIndex × elementSize. // 18. Let beginByteOffset be srcByteOffset + beginIndex × elementSize.
let begin_byte_offset = src_byte_offset + begin_index as usize * element_size; let begin_byte_offset = src_byte_offset + begin_index as u64 * element_size;
// 19. Let argumentsList be « buffer, 𝔽(beginByteOffset), 𝔽(newLength) ». // 19. Let argumentsList be « buffer, 𝔽(beginByteOffset), 𝔽(newLength) ».
// 20. Return ? TypedArraySpeciesCreate(O, argumentsList). // 20. Return ? TypedArraySpeciesCreate(O, argumentsList).
@ -2997,7 +2997,7 @@ impl TypedArray {
/// <https://tc39.es/ecma262/#sec-allocatetypedarraybuffer> /// <https://tc39.es/ecma262/#sec-allocatetypedarraybuffer>
fn allocate_buffer( fn allocate_buffer(
indexed: &mut IntegerIndexed, indexed: &mut IntegerIndexed,
length: usize, length: u64,
context: &mut Context, context: &mut Context,
) -> JsResult<()> { ) -> JsResult<()> {
// 1. Assert: O.[[ViewedArrayBuffer]] is undefined. // 1. Assert: O.[[ViewedArrayBuffer]] is undefined.
@ -3042,7 +3042,7 @@ impl TypedArray {
context: &mut Context, context: &mut Context,
) -> JsResult<()> { ) -> JsResult<()> {
// 1. Let len be the number of elements in values. // 1. Let len be the number of elements in values.
let len = values.len(); let len = values.len() as u64;
{ {
let mut o = o.borrow_mut(); let mut o = o.borrow_mut();
let o_inner = o.as_typed_array_mut().expect("expected a TypedArray"); let o_inner = o.as_typed_array_mut().expect("expected a TypedArray");
@ -3080,7 +3080,7 @@ impl TypedArray {
constructor_name: TypedArrayKind, constructor_name: TypedArrayKind,
new_target: &JsValue, new_target: &JsValue,
default_proto: P, default_proto: P,
length: Option<usize>, length: Option<u64>,
context: &mut Context, context: &mut Context,
) -> JsResult<JsObject> ) -> JsResult<JsObject>
where where
@ -3310,14 +3310,14 @@ impl TypedArray {
} }
// b. Let newByteLength be bufferByteLength - offset. // b. Let newByteLength be bufferByteLength - offset.
let new_byte_length = buffer_byte_length as isize - offset as isize; let new_byte_length = buffer_byte_length as i64 - offset as i64;
// c. If newByteLength < 0, throw a RangeError exception. // c. If newByteLength < 0, throw a RangeError exception.
if new_byte_length < 0 { if new_byte_length < 0 {
return context.throw_range_error("Invalid length for typed array"); return context.throw_range_error("Invalid length for typed array");
} }
new_byte_length as usize new_byte_length as u64
// 9. Else, // 9. Else,
} else { } else {
// 5. If length is not undefined, then // 5. If length is not undefined, then
@ -3413,7 +3413,7 @@ impl TypedArrayKind {
/// ///
/// [spec]: https://tc39.es/ecma262/#table-the-typedarray-constructors /// [spec]: https://tc39.es/ecma262/#table-the-typedarray-constructors
#[inline] #[inline]
pub(crate) const fn element_size(self) -> usize { pub(crate) const fn element_size(self) -> u64 {
match self { match self {
Self::Int8 | Self::Uint8 | Self::Uint8Clamped => 1, Self::Int8 | Self::Uint8 | Self::Uint8Clamped => 1,
Self::Int16 | Self::Uint16 => 2, Self::Int16 | Self::Uint16 => 2,

22
boa_engine/src/object/internal_methods/integer_indexed.rs

@ -44,14 +44,16 @@ pub(crate) fn integer_indexed_exotic_get_own_property(
// i. Let value be ! IntegerIndexedElementGet(O, numericIndex). // i. Let value be ! IntegerIndexedElementGet(O, numericIndex).
// ii. If value is undefined, return undefined. // ii. If value is undefined, return undefined.
// iii. Return the PropertyDescriptor { [[Value]]: value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true }. // iii. Return the PropertyDescriptor { [[Value]]: value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true }.
Ok(integer_indexed_element_get(obj, *index as usize).map(|v| { Ok(
integer_indexed_element_get(obj, u64::from(*index)).map(|v| {
PropertyDescriptor::builder() PropertyDescriptor::builder()
.value(v) .value(v)
.writable(true) .writable(true)
.enumerable(true) .enumerable(true)
.configurable(true) .configurable(true)
.build() .build()
})) }),
)
} else { } else {
// 2. Return OrdinaryGetOwnProperty(O, P). // 2. Return OrdinaryGetOwnProperty(O, P).
super::ordinary_get_own_property(obj, key, context) super::ordinary_get_own_property(obj, key, context)
@ -74,7 +76,7 @@ pub(crate) fn integer_indexed_exotic_has_property(
// a. Let numericIndex be ! CanonicalNumericIndexString(P). // a. Let numericIndex be ! CanonicalNumericIndexString(P).
if let PropertyKey::Index(index) = key { if let PropertyKey::Index(index) = key {
// b. If numericIndex is not undefined, return ! IsValidIntegerIndex(O, numericIndex). // b. If numericIndex is not undefined, return ! IsValidIntegerIndex(O, numericIndex).
Ok(is_valid_integer_index(obj, *index as usize)) Ok(is_valid_integer_index(obj, u64::from(*index)))
} else { } else {
// 2. Return ? OrdinaryHasProperty(O, P). // 2. Return ? OrdinaryHasProperty(O, P).
super::ordinary_has_property(obj, key, context) super::ordinary_has_property(obj, key, context)
@ -103,7 +105,7 @@ pub(crate) fn integer_indexed_exotic_define_own_property(
// iii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]] is false, return false. // iii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]] is false, return false.
// v. If Desc has a [[Writable]] field and if Desc.[[Writable]] is false, return false. // v. If Desc has a [[Writable]] field and if Desc.[[Writable]] is false, return false.
// iv. If ! IsAccessorDescriptor(Desc) is true, return false. // iv. If ! IsAccessorDescriptor(Desc) is true, return false.
if !is_valid_integer_index(obj, index as usize) if !is_valid_integer_index(obj, u64::from(index))
|| !desc || !desc
.configurable() .configurable()
.or_else(|| desc.enumerable()) .or_else(|| desc.enumerable())
@ -145,7 +147,7 @@ pub(crate) fn integer_indexed_exotic_get(
// b. If numericIndex is not undefined, then // b. If numericIndex is not undefined, then
if let PropertyKey::Index(index) = key { if let PropertyKey::Index(index) = key {
// i. Return ! IntegerIndexedElementGet(O, numericIndex). // i. Return ! IntegerIndexedElementGet(O, numericIndex).
Ok(integer_indexed_element_get(obj, *index as usize).unwrap_or_default()) Ok(integer_indexed_element_get(obj, u64::from(*index)).unwrap_or_default())
} else { } else {
// 2. Return ? OrdinaryGet(O, P, Receiver). // 2. Return ? OrdinaryGet(O, P, Receiver).
super::ordinary_get(obj, key, receiver, context) super::ordinary_get(obj, key, receiver, context)
@ -198,7 +200,7 @@ pub(crate) fn integer_indexed_exotic_delete(
// b. If numericIndex is not undefined, then // b. If numericIndex is not undefined, then
if let PropertyKey::Index(index) = key { if let PropertyKey::Index(index) = key {
// i. If ! IsValidIntegerIndex(O, numericIndex) is false, return true; else return false. // i. If ! IsValidIntegerIndex(O, numericIndex) is false, return true; else return false.
Ok(!is_valid_integer_index(obj, *index as usize)) Ok(!is_valid_integer_index(obj, u64::from(*index)))
} else { } else {
// 2. Return ? OrdinaryDelete(O, P). // 2. Return ? OrdinaryDelete(O, P).
super::ordinary_delete(obj, key, context) super::ordinary_delete(obj, key, context)
@ -263,7 +265,7 @@ pub(crate) fn integer_indexed_exotic_own_property_keys(
/// - [ECMAScript reference][spec] /// - [ECMAScript reference][spec]
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-isvalidintegerindex /// [spec]: https://tc39.es/ecma262/#sec-isvalidintegerindex
pub(crate) fn is_valid_integer_index(obj: &JsObject, index: usize) -> bool { pub(crate) fn is_valid_integer_index(obj: &JsObject, index: u64) -> bool {
let obj = obj.borrow(); let obj = obj.borrow();
let inner = obj.as_typed_array().expect( let inner = obj.as_typed_array().expect(
"integer indexed exotic method should only be callable from integer indexed objects", "integer indexed exotic method should only be callable from integer indexed objects",
@ -282,7 +284,7 @@ pub(crate) fn is_valid_integer_index(obj: &JsObject, index: usize) -> bool {
/// - [ECMAScript reference][spec] /// - [ECMAScript reference][spec]
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-integerindexedelementget /// [spec]: https://tc39.es/ecma262/#sec-integerindexedelementget
fn integer_indexed_element_get(obj: &JsObject, index: usize) -> Option<JsValue> { fn integer_indexed_element_get(obj: &JsObject, index: u64) -> Option<JsValue> {
// 1. If ! IsValidIntegerIndex(O, index) is false, return undefined. // 1. If ! IsValidIntegerIndex(O, index) is false, return undefined.
if !is_valid_integer_index(obj, index) { if !is_valid_integer_index(obj, index) {
return None; return None;
@ -349,7 +351,7 @@ fn integer_indexed_element_set(
}; };
// 3. If ! IsValidIntegerIndex(O, index) is true, then // 3. If ! IsValidIntegerIndex(O, index) is true, then
if is_valid_integer_index(obj, index) { if is_valid_integer_index(obj, index as u64) {
// a. Let offset be O.[[ByteOffset]]. // a. Let offset be O.[[ByteOffset]].
let offset = inner.byte_offset(); let offset = inner.byte_offset();
@ -361,7 +363,7 @@ fn integer_indexed_element_set(
let size = elem_type.element_size(); let size = elem_type.element_size();
// d. Let indexedPosition be (ℝ(index) × elementSize) + offset. // d. Let indexedPosition be (ℝ(index) × elementSize) + offset.
let indexed_position = (index * size) + offset; let indexed_position = (index as u64 * size) + offset;
let buffer_obj = inner let buffer_obj = inner
.viewed_array_buffer() .viewed_array_buffer()

2
boa_engine/src/object/jsarray.rs

@ -50,7 +50,7 @@ impl JsArray {
/// ///
/// Same a `array.length` in JavaScript. /// Same a `array.length` in JavaScript.
#[inline] #[inline]
pub fn length(&self, context: &mut Context) -> JsResult<usize> { pub fn length(&self, context: &mut Context) -> JsResult<u64> {
self.inner.length_of_array_like(context) self.inner.length_of_array_like(context)
} }

4
boa_engine/src/object/jsarraybuffer.rs

@ -26,7 +26,7 @@ impl JsArrayBuffer {
.array_buffer() .array_buffer()
.constructor() .constructor()
.into(), .into(),
byte_length, byte_length as u64,
context, context,
)?; )?;
@ -68,7 +68,7 @@ impl JsArrayBuffer {
// 4. Set obj.[[ArrayBufferByteLength]] to byteLength. // 4. Set obj.[[ArrayBufferByteLength]] to byteLength.
obj.borrow_mut().data = ObjectData::array_buffer(ArrayBuffer { obj.borrow_mut().data = ObjectData::array_buffer(ArrayBuffer {
array_buffer_data: Some(block), array_buffer_data: Some(block),
array_buffer_byte_length: byte_length, array_buffer_byte_length: byte_length as u64,
array_buffer_detach_key: JsValue::Undefined, array_buffer_detach_key: JsValue::Undefined,
}); });

4
boa_engine/src/object/operations.rs

@ -457,7 +457,7 @@ impl JsObject {
} }
#[inline] #[inline]
pub(crate) fn length_of_array_like(&self, context: &mut Context) -> JsResult<usize> { pub(crate) fn length_of_array_like(&self, context: &mut Context) -> JsResult<u64> {
// 1. Assert: Type(obj) is Object. // 1. Assert: Type(obj) is Object.
// 2. Return ℝ(? ToLength(? Get(obj, "length"))). // 2. Return ℝ(? ToLength(? Get(obj, "length"))).
self.get("length", context)?.to_length(context) self.get("length", context)?.to_length(context)
@ -735,7 +735,7 @@ impl JsValue {
let len = obj.length_of_array_like(context)?; let len = obj.length_of_array_like(context)?;
// 4. Let list be a new empty List. // 4. Let list be a new empty List.
let mut list = Vec::with_capacity(len); let mut list = Vec::with_capacity(len as usize);
// 5. Let index be 0. // 5. Let index be 0.
// 6. Repeat, while index < len, // 6. Repeat, while index < len,

4
boa_engine/src/tests.rs

@ -1066,7 +1066,7 @@ fn to_length() {
); );
assert_eq!( assert_eq!(
JsValue::new(f64::INFINITY).to_length(&mut context).unwrap(), JsValue::new(f64::INFINITY).to_length(&mut context).unwrap(),
Number::MAX_SAFE_INTEGER as usize Number::MAX_SAFE_INTEGER as u64
); );
assert_eq!(JsValue::new(0.0).to_length(&mut context).unwrap(), 0); assert_eq!(JsValue::new(0.0).to_length(&mut context).unwrap(), 0);
assert_eq!(JsValue::new(-0.0).to_length(&mut context).unwrap(), 0); assert_eq!(JsValue::new(-0.0).to_length(&mut context).unwrap(), 0);
@ -1075,7 +1075,7 @@ fn to_length() {
assert_eq!( assert_eq!(
JsValue::new(100000000000.0) JsValue::new(100000000000.0)
.to_length(&mut context) .to_length(&mut context)
.unwrap() as u64, .unwrap(),
100000000000 100000000000
); );
assert_eq!( assert_eq!(

8
boa_engine/src/value/mod.rs

@ -786,7 +786,7 @@ impl JsValue {
/// Converts a value to a non-negative integer if it is a valid integer index value. /// Converts a value to a non-negative integer if it is a valid integer index value.
/// ///
/// See: <https://tc39.es/ecma262/#sec-toindex> /// See: <https://tc39.es/ecma262/#sec-toindex>
pub fn to_index(&self, context: &mut Context) -> JsResult<usize> { pub fn to_index(&self, context: &mut Context) -> JsResult<u64> {
// 1. If value is undefined, then // 1. If value is undefined, then
if self.is_undefined() { if self.is_undefined() {
// a. Return 0. // a. Return 0.
@ -809,19 +809,19 @@ impl JsValue {
debug_assert!(0 <= clamped && clamped <= Number::MAX_SAFE_INTEGER as i64); debug_assert!(0 <= clamped && clamped <= Number::MAX_SAFE_INTEGER as i64);
// e. Return integer. // e. Return integer.
Ok(clamped as usize) Ok(clamped as u64)
} }
/// Converts argument to an integer suitable for use as the length of an array-like object. /// Converts argument to an integer suitable for use as the length of an array-like object.
/// ///
/// See: <https://tc39.es/ecma262/#sec-tolength> /// See: <https://tc39.es/ecma262/#sec-tolength>
pub fn to_length(&self, context: &mut Context) -> JsResult<usize> { pub fn to_length(&self, context: &mut Context) -> JsResult<u64> {
// 1. Let len be ? ToInteger(argument). // 1. Let len be ? ToInteger(argument).
// 2. If len ≤ +0, return +0. // 2. If len ≤ +0, return +0.
// 3. Return min(len, 2^53 - 1). // 3. Return min(len, 2^53 - 1).
Ok(self Ok(self
.to_integer_or_infinity(context)? .to_integer_or_infinity(context)?
.clamp_finite(0, Number::MAX_SAFE_INTEGER as i64) as usize) .clamp_finite(0, Number::MAX_SAFE_INTEGER as i64) as u64)
} }
/// Abstract operation `ToIntegerOrInfinity ( argument )` /// Abstract operation `ToIntegerOrInfinity ( argument )`

2
boa_engine/src/value/serde_json.rs

@ -115,7 +115,7 @@ impl JsValue {
Self::Object(obj) => { Self::Object(obj) => {
if obj.is_array() { if obj.is_array() {
let len = obj.length_of_array_like(context)?; let len = obj.length_of_array_like(context)?;
let mut arr = Vec::with_capacity(len); let mut arr = Vec::with_capacity(len as usize);
let obj = obj.borrow(); let obj = obj.borrow();

Loading…
Cancel
Save