Browse Source

Added fallible allocation to data blocks (#1728)

This Pull Request uses the new fallible allocation API in Rust 1.57 to follow the JavaScript specification for data blocks: https://tc39.es/ecma262/#sec-createbytedatablock

It changes the following:

- Creating a new DataBlock for an ArrayBuffer will no longer fail with an arbitrary byte length, it will now actually call the allocator and try to reserve the needed space, and fail if it can't.
- Added sunny and rainy day unit tests that check if the API works as expected.
- Bumped the minimum Rust version to Rust 1.57 for the Boa crate.
- Removed the unused `DataBlock` implementation in IntegerIndexedObjects.
pull/1730/head
Iban Eguia 3 years ago
parent
commit
0724a7832b
  1. 2
      boa/Cargo.toml
  2. 30
      boa/src/builtins/array_buffer/mod.rs
  3. 15
      boa/src/builtins/array_buffer/tests.rs
  4. 37
      boa/src/builtins/typed_array/integer_indexed_object.rs

2
boa/Cargo.toml

@ -9,7 +9,7 @@ categories = ["parser-implementations", "wasm"]
license = "Unlicense/MIT" license = "Unlicense/MIT"
exclude = ["../.vscode/*", "../Dockerfile", "../Makefile", "../.editorConfig"] exclude = ["../.vscode/*", "../Dockerfile", "../Makefile", "../.editorConfig"]
edition = "2021" edition = "2021"
rust-version = "1.56" rust-version = "1.57"
[features] [features]
profiler = ["measureme"] profiler = ["measureme"]

30
boa/src/builtins/array_buffer/mod.rs

@ -1,3 +1,6 @@
#[cfg(test)]
mod tests;
use crate::{ use crate::{
builtins::{typed_array::TypedArrayName, BuiltIn, JsArgs}, builtins::{typed_array::TypedArrayName, BuiltIn, JsArgs},
context::StandardObjects, context::StandardObjects,
@ -313,11 +316,7 @@ impl ArrayBuffer {
obj.set_prototype(prototype.into()); obj.set_prototype(prototype.into());
// 2. Let block be ? CreateByteDataBlock(byteLength). // 2. Let block be ? CreateByteDataBlock(byteLength).
// TODO: for now just a arbitrary limit to not OOM. let block = create_byte_data_block(byte_length, context)?;
if byte_length > 8589934592 {
return Err(context.construct_range_error("ArrayBuffer allocation failed"));
}
let block = vec![0; byte_length];
// 3. Set obj.[[ArrayBufferData]] to block. // 3. Set obj.[[ArrayBufferData]] to block.
// 4. Set obj.[[ArrayBufferByteLength]] to byteLength. // 4. Set obj.[[ArrayBufferByteLength]] to byteLength.
@ -733,6 +732,27 @@ impl ArrayBuffer {
} }
} }
/// `CreateByteDataBlock ( size )` abstract operation.
///
/// The abstract operation `CreateByteDataBlock` takes argument `size` (a non-negative
/// integer). For more information, check the [spec][spec].
///
/// [spec]: https://tc39.es/ecma262/#sec-createbytedatablock
pub fn create_byte_data_block(size: usize, context: &mut Context) -> JsResult<Vec<u8>> {
// 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.
let mut data_block = Vec::new();
data_block.try_reserve(size).map_err(|e| {
context.construct_range_error(format!("couldn't allocate the data block: {}", e))
})?;
// 2. Set all of the bytes of db to 0.
data_block.resize(size, 0);
// 3. Return db.
Ok(data_block)
}
/// `6.2.8.3 CopyDataBlockBytes ( toBlock, toIndex, fromBlock, fromIndex, count )` /// `6.2.8.3 CopyDataBlockBytes ( toBlock, toIndex, fromBlock, fromIndex, count )`
/// ///
/// More information: /// More information:

15
boa/src/builtins/array_buffer/tests.rs

@ -0,0 +1,15 @@
use super::*;
#[test]
fn ut_sunnyy_day_create_byte_data_block() {
let mut context = Context::new();
assert!(create_byte_data_block(100, &mut context).is_ok())
}
#[test]
fn ut_rainy_day_create_byte_data_block() {
let mut context = Context::new();
assert!(create_byte_data_block(usize::MAX, &mut context).is_err())
}

37
boa/src/builtins/typed_array/integer_indexed_object.rs

@ -12,7 +12,7 @@ use crate::{
builtins::typed_array::TypedArrayName, builtins::typed_array::TypedArrayName,
gc::{empty_trace, Finalize, Trace}, gc::{empty_trace, Finalize, Trace},
object::{JsObject, ObjectData}, object::{JsObject, ObjectData},
Context, JsResult, Context,
}; };
/// Type of the array content. /// Type of the array content.
@ -147,38 +147,3 @@ impl IntegerIndexed {
self.array_length = array_length; self.array_length = array_length;
} }
} }
/// A Data Block
///
/// The Data Block specification type is used to describe a distinct and mutable sequence of
/// byte-sized (8 bit) numeric values. A byte value is an integer value in the range `0` through
/// `255`, inclusive. A Data Block value is created with a fixed number of bytes that each have
/// the initial value `0`.
///
/// For more information, check the [spec][spec].
///
/// [spec]: https://tc39.es/ecma262/#sec-data-blocks
#[derive(Debug, Clone, Default, Trace, Finalize)]
pub struct DataBlock {
inner: Vec<u8>,
}
impl DataBlock {
/// `CreateByteDataBlock ( size )` abstract operation.
///
/// The abstract operation `CreateByteDataBlock` takes argument `size` (a non-negative
/// integer). For more information, check the [spec][spec].
///
/// [spec]: https://tc39.es/ecma262/#sec-createbytedatablock
pub fn create_byte_data_block(size: usize) -> JsResult<Self> {
// 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.
// 2. Set all of the bytes of db to 0.
// 3. Return db.
// TODO: waiting on <https://github.com/rust-lang/rust/issues/48043> for having fallible
// allocation.
Ok(Self {
inner: vec![0u8; size],
})
}
}

Loading…
Cancel
Save