use super::arena::{Arena, Record};
use super::values::Range;
use crate::value::{ShapeId, Value};
pub const NONE: u32 = u32::MAX;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum ObjectKind {
Ordinary,
Array,
Function,
Scope,
GlobalObject,
Arguments,
RegExp,
ForInIterator,
Native,
StringWrapper,
NumberWrapper,
BooleanWrapper,
SymbolWrapper,
BigIntWrapper,
Date,
BoundFunction,
Proxy,
TypedArray,
ModuleNamespace,
Builtin,
Free,
}
impl ObjectKind {
#[inline]
pub const fn has_internal(self) -> bool {
matches!(
self,
ObjectKind::StringWrapper
| ObjectKind::NumberWrapper
| ObjectKind::BooleanWrapper
| ObjectKind::SymbolWrapper
| ObjectKind::BigIntWrapper
| ObjectKind::Date
| ObjectKind::BoundFunction
| ObjectKind::Proxy
| ObjectKind::TypedArray
| ObjectKind::ModuleNamespace
| ObjectKind::Builtin
)
}
#[inline]
pub const fn has_elements(self) -> bool {
matches!(
self,
ObjectKind::Ordinary
| ObjectKind::Array
| ObjectKind::Function
| ObjectKind::Arguments
| ObjectKind::RegExp
| ObjectKind::NumberWrapper
| ObjectKind::BooleanWrapper
| ObjectKind::SymbolWrapper
| ObjectKind::BigIntWrapper
| ObjectKind::Date
| ObjectKind::BoundFunction
| ObjectKind::Builtin
| ObjectKind::GlobalObject
)
}
#[inline]
pub const fn is_exotic(self) -> bool {
matches!(
self,
ObjectKind::StringWrapper
| ObjectKind::Proxy
| ObjectKind::TypedArray
| ObjectKind::ModuleNamespace
)
}
}
pub mod flags {
pub const EXTENSIBLE: u8 = 1 << 0;
pub const USED_AS_PROTOTYPE: u8 = 1 << 1;
pub const CALLABLE: u8 = 1 << 2;
pub const CONSTRUCTOR: u8 = 1 << 3;
pub const DICTIONARY: u8 = 1 << 4;
pub const ERROR: u8 = 1 << 5;
pub const SPARSE: u8 = 1 << 6;
pub const LENGTH_READONLY: u8 = 1 << 7;
}
#[derive(Clone, Copy, Debug)]
pub struct ObjectHeader {
pub shape: ShapeId,
pub slots_start: u32,
pub elements_start: u32,
pub payload: u32,
pub slots_log: u8,
pub elements_log: u8,
pub kind: ObjectKind,
pub flags: u8,
}
const _: () = assert!(size_of::<ObjectHeader>() <= 24);
impl ObjectHeader {
pub fn new(
kind: ObjectKind,
shape: ShapeId,
slots: Range,
elements: Range,
payload: u32,
flags: u8,
) -> Self {
ObjectHeader {
shape,
slots_start: slots.start,
elements_start: elements.start,
payload,
slots_log: slots.exponent(),
elements_log: elements.log(),
kind,
flags,
}
}
#[inline]
pub fn slots(&self) -> Range {
Range::from_exponent(self.slots_start, self.slots_log)
}
#[inline]
pub fn set_slots(&mut self, range: Range) {
debug_assert!(range.len == 0 || range.len.is_power_of_two());
self.slots_start = range.start;
self.slots_log = range.exponent();
}
#[inline]
pub fn elements(&self) -> Range {
Range::from_log(self.elements_start, self.elements_log)
}
#[inline]
pub fn set_elements(&mut self, range: Range) {
self.elements_start = range.start;
self.elements_log = range.log();
}
#[inline]
pub fn has(&self, flag: u8) -> bool {
self.flags & flag != 0
}
}
impl Record for ObjectHeader {
fn vacant() -> Self {
ObjectHeader::new(
ObjectKind::Free,
ShapeId(NONE),
Range::EMPTY,
Range::EMPTY,
NONE,
0,
)
}
}
#[derive(Clone, Copy, Debug)]
pub struct FunctionRecord {
pub scope: u32,
pub bytecode: u32,
pub native: u32,
pub home_object: u32,
pub fields: u32,
}
impl Record for FunctionRecord {
fn vacant() -> Self {
FunctionRecord {
scope: NONE,
bytecode: NONE,
native: NONE,
home_object: NONE,
fields: NONE,
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct FunctionBytecode {
pub unit: u32,
pub constants: Range,
pub constant_count: u32,
pub children: Range,
pub child_count: u32,
}
impl Record for FunctionBytecode {
fn vacant() -> Self {
FunctionBytecode {
unit: NONE,
constants: Range::EMPTY,
constant_count: 0,
children: Range::EMPTY,
child_count: 0,
}
}
}
#[derive(Debug)]
pub struct Internal {
pub tag: InternalTag,
pub slots: Vec<Value>,
pub data: InternalData,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum InternalTag {
None,
ArrayIterator,
StringIterator,
MapIterator,
SetIterator,
RegExpStringIterator,
IteratorHelper,
WrapForValidIterator,
AsyncFromSyncIterator,
Promise,
PromiseReaction,
Map,
Set,
WeakMap,
WeakSet,
WeakRef,
FinalizationRegistry,
Generator,
AsyncGenerator,
AsyncFunction,
ArrayBuffer,
SharedArrayBuffer,
TypedArray,
DataView,
ModuleNamespace,
NativeData,
HtmlDda,
RawJson,
Module,
Iterator,
HostData,
}
#[derive(Debug, Default)]
pub enum InternalData {
#[default]
None,
Bytes(Vec<u8>),
Frame(SavedFrame),
Table(Box<super::table::Table>),
Cursor(std::rc::Rc<std::cell::Cell<u32>>),
Buffer(Box<super::buffer::Buffer>),
View(super::buffer::View),
Module(Box<crate::vm::module::ModuleData>),
Exports(Box<[super::atom::PropertyKey]>),
HostFn(crate::vm::native::HostBody),
HostData(std::rc::Rc<dyn std::any::Any>),
}
pub const FRAME_SLOTS: usize = 2;
#[derive(Clone, Copy, Debug)]
pub struct SavedFrame {
pub unit: u32,
pub bytecode: u32,
pub pc: u32,
pub argc: u32,
pub state: u8,
}
impl Record for Internal {
fn vacant() -> Self {
Internal {
tag: InternalTag::None,
slots: Vec::new(),
data: InternalData::None,
}
}
}
impl Internal {
pub fn owned_bytes(&self) -> usize {
self.slots.capacity() * size_of::<Value>()
+ match &self.data {
InternalData::None
| InternalData::Frame(_)
| InternalData::Cursor(_)
| InternalData::View(_)
| InternalData::Module(_)
| InternalData::HostFn(_)
| InternalData::HostData(_) => 0,
InternalData::Exports(keys) => keys.len() * 8,
InternalData::Buffer(buffer) => buffer.owned_bytes(),
InternalData::Bytes(bytes) => bytes.capacity(),
InternalData::Table(table) => table.owned_bytes(),
}
}
}
#[derive(Default)]
pub struct PayloadArenas {
pub functions: Arena<FunctionRecord>,
pub bytecode: Arena<FunctionBytecode>,
pub internals: Arena<Internal>,
}