Skip to content

Commit

Permalink
feat(ecmascript): Implement some ArrayBuffer abstract operations
Browse files Browse the repository at this point in the history
  • Loading branch information
aapoalas committed Oct 29, 2023
1 parent fe58e9a commit 94aa0b5
Show file tree
Hide file tree
Showing 8 changed files with 541 additions and 28 deletions.
477 changes: 477 additions & 0 deletions nova_vm/src/ecmascript/builtins/array_buffer.rs

Large diffs are not rendered by default.

28 changes: 25 additions & 3 deletions nova_vm/src/ecmascript/builtins/array_buffer/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ use crate::{ecmascript::types::DataBlock, heap::indexes::ObjectIndex};
#[derive(Debug)]
pub(crate) enum InternalBuffer {
Detached,
Growable(DataBlock),
Static(DataBlock),
// Shared(SharedDataBlockIndex)
FixedLength(DataBlock),
Resizable(DataBlock),
// TODO: Implement SharedDataBlock
SharedFixedLength(()),
SharedResizableLength(()),
}

#[derive(Debug)]
Expand All @@ -14,3 +16,23 @@ pub struct ArrayBufferHeapData {
pub(super) buffer: InternalBuffer,
// detach_key
}

impl ArrayBufferHeapData {
pub(crate) fn new_resizable(db: DataBlock) -> Self {
Self {
object_index: None,
buffer: InternalBuffer::Resizable(db),
}
}

pub(crate) fn new_fixed_length(db: DataBlock) -> Self {
Self {
object_index: None,
buffer: InternalBuffer::FixedLength(db),
}
}

pub(crate) fn is_detached_buffer(&self) -> bool {
matches!(self.buffer, InternalBuffer::Detached)
}
}
18 changes: 18 additions & 0 deletions nova_vm/src/ecmascript/execution/realm/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ pub struct Intrinsics {
array: FunctionIndex,
/// %Array.prototype%
array_prototype: ObjectIndex,
/// %ArrayBuffer%
array_buffer: FunctionIndex,
/// %ArrayBuffer.prototype%
array_buffer_prototype: ObjectIndex,
/// %BigInt%
big_int: FunctionIndex,
/// %BigInt.prototype%
Expand Down Expand Up @@ -92,6 +96,8 @@ impl Default for Intrinsics {
fn default() -> Self {
let array = BuiltinObjectIndexes::ArrayConstructorIndex.into();
let array_prototype = BuiltinObjectIndexes::ArrayPrototypeIndex.into();
let array_buffer = BuiltinObjectIndexes::ArrayBufferConstructorIndex.into();
let array_buffer_prototype = BuiltinObjectIndexes::ArrayBufferPrototypeIndex.into();
let big_int = BuiltinObjectIndexes::BigintConstructorIndex.into();
let big_int_prototype = BuiltinObjectIndexes::BigintPrototypeIndex.into();
let boolean = BuiltinObjectIndexes::BooleanConstructorIndex.into();
Expand Down Expand Up @@ -148,6 +154,8 @@ impl Default for Intrinsics {
Self {
array,
array_prototype,
array_buffer,
array_buffer_prototype,
big_int,
big_int_prototype,
boolean,
Expand Down Expand Up @@ -198,6 +206,16 @@ impl Intrinsics {
Object::Object(self.array_prototype)
}

/// %ArrayBuffer%
pub const fn array_buffer(&self) -> Function {
Function(self.array_buffer)
}

/// %ArrayBuffer.prototype%
pub const fn array_buffer_prototype(&self) -> Object {
Object::Object(self.array_buffer_prototype)
}

/// %BigInt%
pub const fn big_int(&self) -> Function {
Function(self.big_int)
Expand Down
2 changes: 1 addition & 1 deletion nova_vm/src/ecmascript/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ pub(crate) use language::{
BigIntHeapData, FunctionHeapData, NumberHeapData, ObjectHeapData, StringHeapData,
};
pub use language::{Function, InternalMethods, Number, Object, PropertyKey, String, Value};
pub(crate) use spec::DataBlock;
pub use spec::{Base, PropertyDescriptor, Reference, ReferencedName};
pub(crate) use spec::{DataBlock};

#[derive(Debug)]
pub struct Symbol;
8 changes: 8 additions & 0 deletions nova_vm/src/ecmascript/types/language/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,14 @@ impl Number {
}
}

pub fn into_i64(self, agent: &Agent) -> i64 {
match self {
Number::Number(n) => *agent.heap.get(n) as i64,
Number::Integer(n) => Into::<i64>::into(n),
Number::Float(n) => n as i64,
}
}

/// A minimal version of ObjectIs when you know the arguments are numbers.
pub fn is(self, agent: &mut Agent, y: Self) -> bool {
// TODO: Add in spec from Object.is pertaining to numbers.
Expand Down
2 changes: 1 addition & 1 deletion nova_vm/src/ecmascript/types/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ mod data_block;
mod property_descriptor;
mod reference;

pub(crate) use data_block::DataBlock;
pub(crate) use data_block::{DataBlock};
pub use property_descriptor::PropertyDescriptor;
pub use reference::{Base, Reference, ReferencedName};
29 changes: 8 additions & 21 deletions nova_vm/src/ecmascript/types/spec/data_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
use std::{
alloc::{alloc_zeroed, handle_alloc_error, Layout},
ptr::{read_unaligned, write_bytes, write_unaligned, NonNull},
sync::atomic::AtomicU8,
};

use crate::ecmascript::execution::{agent::JsError, JsResult};
use crate::ecmascript::execution::{agent::JsError, Agent, JsResult};

/// # Data Block
///
Expand All @@ -28,10 +27,7 @@ pub(crate) struct DataBlock {
}

mod private {
use std::sync::atomic::AtomicU8;

pub trait Sealed {}
impl Sealed for AtomicU8 {}
impl Sealed for u8 {}
impl Sealed for i8 {}
impl Sealed for u16 {}
Expand All @@ -57,11 +53,6 @@ impl Viewable for i64 {}
impl Viewable for f32 {}
impl Viewable for f64 {}

pub trait Copyable: private::Sealed {}

impl Copyable for u8 {}
impl Copyable for AtomicU8 {}

impl DataBlock {
fn new(len: u32) -> Self {
let ptr = if len == 0 {
Expand Down Expand Up @@ -232,19 +223,17 @@ impl DataBlock {
///
/// The abstract operation CreateByteDataBlock takes argument size (a non-negative integer)
/// and returns either a normal completion containing a Data Block or a throw completion.
///
/// TODO: size parameter should be Integer
pub fn create_byte_data_block(size: usize) -> JsResult<Self> {
pub fn create_byte_data_block(_agent: &Agent, size: u64) -> JsResult<Self> {
// 1. If size > 2**53 - 1, throw a RangeError exception.
if size > usize::pow(2, 53) - 1 {
if size > u64::pow(2, 53) - 1 {
// TODO: throw a RangeError exception
Err(JsError {})
} else
// 2. 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.
if let Ok(size) = u32::try_from(size) {
// 3. Set all of the bytes of db to 0.
// 4. Return db.
Ok(Self::new(size as u32))
Ok(Self::new(size))
} else {
// TODO: throw a RangeError exception
Err(JsError {})
Expand All @@ -255,17 +244,15 @@ impl DataBlock {
///
/// The abstract operation CreateSharedByteDataBlock takes argument size (a non-negative integer)
/// and returns either a normal completion containing a Shared Data Block or a throw completion.
///
/// TODO: size parameter should be Integer
pub fn create_shared_byte_data_block(size: usize) -> JsResult<Self> {
pub fn create_shared_byte_data_block(size: u64) -> JsResult<Self> {
// 1. Let db be a new Shared Data Block value consisting of size bytes. If it is impossible to create such a Shared Data Block, throw a RangeError exception.
if let Ok(size) = u32::try_from(size) {
// 2. Let execution be the [[CandidateExecution]] field of the surrounding agent's Agent Record.
// 3. Let eventsRecord be the Agent Events Record of execution.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
// 4. Let zero be « 0 ».
// 5. For each index i of db, do
// a. Append WriteSharedMemory { [[Order]]: INIT, [[NoTear]]: true, [[Block]]: db, [[ByteIndex]]: i, [[ElementSize]]: 1, [[Payload]]: zero } to eventsRecord.[[EventList]].
Ok(Self::new(size as u32))
Ok(Self::new(size))
} else {
Err(JsError {})
}
Expand All @@ -277,7 +264,7 @@ impl DataBlock {
/// The abstract operation CopyDataBlockBytes takes arguments toBlock (a Data Block or a Shared
/// Data Block), toIndex (a non-negative integer), fromBlock (a Data Block or a Shared Data Block),
/// fromIndex (a non-negative integer), and count (a non-negative integer) and returns UNUSED.
pub fn copy_data_block_bytes<T: Copyable>(
pub fn copy_data_block_bytes(
&mut self,
to_index: u32,
from_block: &Self,
Expand Down Expand Up @@ -348,7 +335,7 @@ impl DataBlock {
}

#[test]
fn new_backing_store() {
fn new_data_block() {
let db = DataBlock::new(0);
assert_eq!(db.len(), 0);
assert_eq!(db.capacity(), 0);
Expand Down
5 changes: 3 additions & 2 deletions nova_vm/src/heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,12 @@ macro_rules! impl_heap_data {
};
}

impl_heap_data!(arrays, ArrayHeapData, ArrayHeapData);
impl_heap_data!(array_buffers, ArrayBufferHeapData, ArrayBufferHeapData);
impl_heap_data!(functions, FunctionHeapData, FunctionHeapData);
impl_heap_data!(numbers, NumberHeapData, f64, data);
impl_heap_data!(objects, ObjectHeapData, ObjectHeapData);
impl_heap_data!(strings, StringHeapData, Wtf8Buf, data);
impl_heap_data!(functions, FunctionHeapData, FunctionHeapData);
impl_heap_data!(arrays, ArrayHeapData, ArrayHeapData);

impl CreateHeapData<&str, String> for Heap<'_, '_> {
fn create(&mut self, data: &str) -> String {
Expand Down

0 comments on commit 94aa0b5

Please sign in to comment.