use std::any::Any;
use std::rc::Rc;
use crate::bytecode::CodeStore;
use crate::heap::atom::{KeyKind, PropertyKey};
use crate::heap::object::{InternalData, InternalTag, flags};
use crate::heap::string::StringRepr;
use crate::runtime::{Realm, Runtime, WellKnown};
use crate::value::{Kind, ObjectId, Value};
use crate::vm::native::{HostBody, HostFn};
use crate::vm::object::Descriptor;
use crate::vm::{Cx, ErrorKind, Services, Throw, ops};
use crate::{Heap, HeapError, ObjectKind};
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct PropertyDescriptor {
pub value: Option<Value>,
pub get: Option<Value>,
pub set: Option<Value>,
pub writable: Option<bool>,
pub enumerable: Option<bool>,
pub configurable: Option<bool>,
}
impl PropertyDescriptor {
pub fn is_accessor(&self) -> bool {
self.get.is_some() || self.set.is_some()
}
fn to_internal(self) -> Descriptor {
Descriptor {
value: self.value,
get: self.get,
set: self.set,
writable: self.writable,
enumerable: self.enumerable,
configurable: self.configurable,
}
}
fn from_internal(descriptor: Descriptor) -> Self {
PropertyDescriptor {
value: descriptor.value,
get: descriptor.get,
set: descriptor.set,
writable: descriptor.writable,
enumerable: descriptor.enumerable,
configurable: descriptor.configurable,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum KeyName {
Index(u32),
String(Vec<u16>),
Symbol(Value),
}
pub struct NativeCx<'a> {
pub(crate) heap: &'a mut Heap,
code: CodeView<'a>,
pub(crate) realm: &'a Realm,
pub(crate) host: &'a mut Services,
}
enum CodeView<'a> {
Owned(&'a mut CodeStore),
Shared(&'a CodeStore),
}
impl Runtime {
#[inline]
pub fn native_cx(&mut self) -> NativeCx<'_> {
NativeCx {
heap: &mut self.heap,
code: CodeView::Owned(&mut self.code),
realm: &self.realm,
host: &mut self.host,
}
}
}
pub(crate) fn host_function(
heap: &mut Heap,
realm: &Realm,
name: &str,
length: u32,
constructor: bool,
data: &[Value],
body: Rc<HostFn>,
) -> Result<ObjectId, HeapError> {
let record = heap.alloc_internal(
ObjectKind::Builtin,
InternalTag::NativeData,
None,
0,
data,
InternalData::HostFn(HostBody(body)),
0,
)?;
let mark = heap.roots().mark();
heap.roots().push(Value::object(record));
let result = (|| {
let native = if constructor {
crate::builtins::Native::HostConstructor
} else {
crate::builtins::Native::HostFunction
};
let prototype = realm.intrinsic(crate::Intrinsic::FunctionPrototype);
let function = heap.alloc_native_closure(Some(prototype), native.index(), Some(record))?;
heap.roots().push(Value::object(function));
if constructor {
heap.set_object_flag(function, flags::CONSTRUCTOR);
}
let name = heap.alloc_string(name)?;
crate::builtins::define_name_length(
heap,
&realm.names,
function,
Value::string(name),
length,
)?;
Ok(function)
})();
heap.roots().truncate(mark);
result
}
pub(crate) fn host_object(
heap: &mut Heap,
prototype: Option<ObjectId>,
data: Rc<dyn Any>,
) -> Result<ObjectId, HeapError> {
heap.alloc_internal(
ObjectKind::Builtin,
InternalTag::HostData,
prototype,
4,
&[],
InternalData::HostData(data),
0,
)
}
impl<'a> NativeCx<'a> {
pub fn reborrow(&mut self) -> NativeCx<'_> {
NativeCx {
heap: self.heap,
code: match &mut self.code {
CodeView::Owned(code) => CodeView::Owned(code),
CodeView::Shared(code) => CodeView::Shared(code),
},
realm: self.realm,
host: self.host,
}
}
pub(crate) fn from_cx<'b>(cx: &'b mut Cx<'_>) -> NativeCx<'b> {
NativeCx {
heap: cx.heap,
code: CodeView::Shared(cx.static_code),
realm: cx.realm,
host: cx.host,
}
}
#[inline]
pub(crate) fn cx(&mut self) -> Cx<'_> {
let static_code: &CodeStore = match &self.code {
CodeView::Owned(code) => code,
CodeView::Shared(code) => code,
};
Cx {
heap: self.heap,
static_code,
realm: self.realm,
host: self.host,
}
}
pub fn compiler(&mut self, transient: bool) -> crate::vm::compile::Compiler<'_> {
match &mut self.code {
CodeView::Owned(code) => {
if transient {
crate::vm::compile::Compiler::new(self.heap, code, self.realm)
} else {
crate::vm::compile::Compiler::owned(self.heap, code, self.realm)
}
}
CodeView::Shared(code) => {
crate::vm::compile::Compiler::new(self.heap, code, self.realm)
}
}
}
pub fn owns_code(&self) -> bool {
matches!(self.code, CodeView::Owned(_))
}
#[inline]
pub fn heap(&self) -> &Heap {
self.heap
}
#[inline]
pub fn heap_mut(&mut self) -> &mut Heap {
self.heap
}
#[inline]
pub fn realm(&self) -> &'a Realm {
self.realm
}
pub fn interrupt_flag(&self) -> std::sync::Arc<std::sync::atomic::AtomicBool> {
std::sync::Arc::clone(&self.host.interrupt)
}
pub fn is_interrupted(&self) -> bool {
self.heap.vm.interrupted
}
pub fn clear_interrupted(&mut self) {
self.heap.vm.interrupted = false;
self.heap.vm.poll = crate::vm::INTERRUPT_INTERVAL;
}
pub(crate) fn installing<T>(&mut self, install: impl FnOnce(&mut Cx<'_>) -> T) -> T {
let mode = self.heap.set_atom_mode(crate::heap::AtomMode::Pin);
let result = install(&mut self.cx());
self.heap.set_atom_mode(mode);
result
}
pub fn install_std(&mut self) -> Result<(), HeapError> {
self.installing(crate::builtins::install_std)
}
pub fn install_qjs_helpers(&mut self, script_args: Option<&[String]>) -> Result<(), HeapError> {
self.installing(|cx| crate::builtins::install_qjs_helpers(cx, script_args))
}
pub fn set_native_stack_budget(&mut self, bytes: usize) {
self.heap.vm.native_budget = bytes;
}
}
impl NativeCx<'_> {
pub fn call(&mut self, function: Value, this: Value, args: &[Value]) -> Result<Value, Throw> {
crate::vm::call(&mut self.cx(), function, this, args)
}
pub fn run_script(&mut self, script: ObjectId) -> Result<Value, Throw> {
let global = Value::object(self.realm.global());
self.call(Value::object(script), global, &[])
}
pub fn hold(&mut self, value: Value) -> crate::Handle {
self.heap.handles().create(value)
}
pub fn held(&self, handle: crate::Handle) -> Value {
self.heap.handles_ref().get(handle)
}
pub fn release(&mut self, handle: crate::Handle) {
self.heap.handles().release(handle);
}
pub fn global_object(&self) -> ObjectId {
self.realm.global()
}
pub fn intrinsic(&self, intrinsic: crate::Intrinsic) -> ObjectId {
self.realm.intrinsic(intrinsic)
}
pub fn new_object(&mut self) -> Result<ObjectId, HeapError> {
let prototype = self.intrinsic(crate::Intrinsic::ObjectPrototype);
self.heap
.alloc_object(ObjectKind::Ordinary, Some(prototype), 4)
}
pub fn new_host_function(
&mut self,
name: &str,
length: u32,
constructor: bool,
data: &[Value],
body: Rc<HostFn>,
) -> Result<ObjectId, HeapError> {
host_function(self.heap, self.realm, name, length, constructor, data, body)
}
pub fn new_host_object(
&mut self,
prototype: Option<ObjectId>,
data: Rc<dyn Any>,
) -> Result<ObjectId, HeapError> {
host_object(self.heap, prototype, data)
}
pub fn host_data(&self, object: ObjectId) -> Option<Rc<dyn Any>> {
if self.heap.internal_tag(object) != InternalTag::HostData {
return None;
}
match &self.heap.internal(object).data {
InternalData::HostData(data) => Some(Rc::clone(data)),
_ => None,
}
}
pub fn key_from_units(&mut self, units: &[u16]) -> Result<PropertyKey, HeapError> {
self.heap.property_key_units(units)
}
pub fn key_from_symbol(&self, symbol: Value) -> Option<PropertyKey> {
symbol.as_symbol().map(PropertyKey::symbol)
}
pub fn to_property_key(&mut self, value: Value) -> Result<PropertyKey, Throw> {
ops::to_property_key(&mut self.cx(), value)
}
pub fn key_name(&self, key: PropertyKey) -> KeyName {
match key.kind() {
KeyKind::Index(index) => KeyName::Index(index),
KeyKind::String(id) => KeyName::String(self.heap.string(id).repr().units().collect()),
KeyKind::Symbol(id) => KeyName::Symbol(Value::symbol(id)),
}
}
pub fn get(
&mut self,
object: ObjectId,
key: PropertyKey,
receiver: Value,
) -> Result<Value, Throw> {
crate::vm::object::get(&mut self.cx(), object, key, receiver)
}
pub fn set(
&mut self,
object: ObjectId,
key: PropertyKey,
value: Value,
receiver: Value,
) -> Result<bool, Throw> {
crate::vm::object::set(&mut self.cx(), object, key, value, receiver)
}
pub fn get_own_property(
&mut self,
object: ObjectId,
key: PropertyKey,
) -> Result<Option<PropertyDescriptor>, Throw> {
Ok(
crate::vm::object::get_own_property(&mut self.cx(), object, key)?
.map(PropertyDescriptor::from_internal),
)
}
pub fn define_own_property(
&mut self,
object: ObjectId,
key: PropertyKey,
descriptor: &PropertyDescriptor,
) -> Result<bool, Throw> {
crate::vm::object::define_own_property(
&mut self.cx(),
object,
key,
&descriptor.to_internal(),
)
}
pub fn delete_property(&mut self, object: ObjectId, key: PropertyKey) -> Result<bool, Throw> {
crate::vm::object::delete(&mut self.cx(), object, key)
}
pub fn has_property(&mut self, object: ObjectId, key: PropertyKey) -> Result<bool, Throw> {
crate::vm::object::has_property(&mut self.cx(), object, key)
}
pub fn has_own_property(&mut self, object: ObjectId, key: PropertyKey) -> Result<bool, Throw> {
crate::vm::object::has_own_property(&mut self.cx(), object, key)
}
pub fn own_property_keys(&mut self, object: ObjectId) -> Result<Vec<PropertyKey>, Throw> {
crate::vm::object::own_property_keys(&mut self.cx(), object)
}
pub fn get_prototype_of(&mut self, object: ObjectId) -> Result<Option<ObjectId>, Throw> {
Ok(crate::vm::object::get_prototype_of(&mut self.cx(), object)?.as_object())
}
pub fn set_prototype_of(
&mut self,
object: ObjectId,
prototype: Option<ObjectId>,
) -> Result<bool, Throw> {
let prototype = prototype.map_or(Value::NULL, Value::object);
crate::vm::object::set_prototype_of(&mut self.cx(), object, prototype)
}
pub fn prevent_extensions(&mut self, object: ObjectId) -> Result<bool, Throw> {
crate::vm::object::prevent_extensions(&mut self.cx(), object)
}
pub fn construct(
&mut self,
function: Value,
args: &[Value],
new_target: Value,
) -> Result<Value, Throw> {
crate::vm::construct(&mut self.cx(), function, args, new_target)
}
pub fn is_callable(&self, value: Value) -> bool {
ops::is_callable(self.heap, value)
}
pub fn is_constructor(&self, value: Value) -> bool {
value
.as_object()
.is_some_and(|object| self.heap.header(object).has(flags::CONSTRUCTOR))
}
pub fn is_array(&mut self, value: Value) -> Result<bool, Throw> {
crate::vm::object::is_array(&mut self.cx(), value)
}
pub fn is_error(&self, value: Value) -> bool {
value
.as_object()
.is_some_and(|object| self.heap.header(object).has(flags::ERROR))
}
pub fn is_promise(&mut self, value: Value) -> bool {
crate::vm::jobs::is_promise(&self.cx(), value)
}
pub fn object_kind(&self, object: ObjectId) -> ObjectKind {
self.heap.object_kind(object)
}
pub fn new_object_with_prototype(
&mut self,
prototype: Option<ObjectId>,
) -> Result<ObjectId, HeapError> {
self.heap.alloc_object(ObjectKind::Ordinary, prototype, 4)
}
pub fn new_array_from(&mut self, values: &[Value]) -> Result<ObjectId, Throw> {
let mut cx = self.cx();
let length = u32::try_from(values.len()).unwrap_or(u32::MAX);
let prototype = cx.realm.intrinsic(crate::Intrinsic::ArrayPrototype);
let array = cx
.heap
.alloc_array(Some(prototype), length)
.map_err(|error| crate::vm::error::heap_error(&cx, error))?;
let mark = cx.heap.roots().mark();
cx.heap.roots().push(Value::object(array));
let mut result = Ok(array);
for (index, &value) in values.iter().enumerate() {
let key = crate::vm::object::index_key(&mut cx, index as u32);
if let Err(error) = key.and_then(|key| {
crate::vm::object::create_data_property_or_throw(&mut cx, array, key, value)
}) {
result = Err(error);
break;
}
}
cx.heap.roots().truncate(mark);
result
}
pub fn new_error(&mut self, kind: ErrorKind, message: &str) -> Result<Value, HeapError> {
let message = self.heap.alloc_string(message)?;
crate::vm::error::new_error(&mut self.cx(), kind, Value::string(message))
}
pub fn new_located_error(
&mut self,
kind: ErrorKind,
message: &str,
file: &str,
line: u32,
column: u32,
) -> Result<Value, HeapError> {
let message = self.heap.alloc_string(message)?;
let location = crate::vm::error::Location { file, line, column };
crate::vm::error::new_error_at(
&mut self.cx(),
kind,
Value::string(message),
Some(location),
0,
)
}
pub fn new_promise_capability(&mut self) -> Result<(ObjectId, ObjectId, ObjectId), Throw> {
let mut cx = self.cx();
let prototype = cx.realm.intrinsic(crate::Intrinsic::PromisePrototype);
let promise = crate::vm::jobs::new_promise(&mut cx, prototype)?;
let mark = cx.heap.roots().mark();
cx.heap.roots().push(Value::object(promise));
let functions = crate::vm::jobs::resolving_functions(&mut cx, promise);
cx.heap.roots().truncate(mark);
let (resolve, reject) = functions?;
Ok((promise, resolve, reject))
}
pub fn new_promise(&mut self) -> Result<ObjectId, Throw> {
let prototype = self.realm.intrinsic(crate::Intrinsic::PromisePrototype);
crate::vm::jobs::new_promise(&mut self.cx(), prototype)
}
pub fn new_array_buffer(&mut self, len: usize) -> Result<ObjectId, Throw> {
let mut cx = self.cx();
let mark = cx.heap.roots().mark();
let buffer = crate::builtins::new_array_buffer(&mut cx, len);
cx.heap.roots().truncate(mark);
buffer
}
fn buffer(&self, object: ObjectId) -> Option<&crate::heap::buffer::Buffer> {
match self.heap.internal_tag(object) {
InternalTag::ArrayBuffer | InternalTag::SharedArrayBuffer => {
Some(crate::vm::typed::buffer(self.heap, object))
}
_ => None,
}
}
pub fn array_buffer_len(&self, object: ObjectId) -> Option<usize> {
self.buffer(object)
.filter(|buffer| !buffer.detached)
.map(crate::heap::buffer::Buffer::len)
}
fn buffer_range(&mut self, object: ObjectId, offset: usize, len: usize) -> Result<(), Throw> {
let Some(buffer) = self.buffer(object) else {
return Err(crate::vm::error::type_error(
&mut self.cx(),
"not an ArrayBuffer",
));
};
if buffer.detached {
return Err(crate::vm::error::type_error(
&mut self.cx(),
"ArrayBuffer is detached",
));
}
if offset.checked_add(len).is_none_or(|end| end > buffer.len()) {
return Err(crate::vm::error::range_error(
&mut self.cx(),
"out of bound",
));
}
Ok(())
}
pub fn array_buffer_read(
&mut self,
object: ObjectId,
offset: usize,
out: &mut [u8],
) -> Result<(), Throw> {
self.buffer_range(object, offset, out.len())?;
crate::vm::typed::buffer(self.heap, object).read(offset, out);
Ok(())
}
pub fn array_buffer_write(
&mut self,
object: ObjectId,
offset: usize,
data: &[u8],
) -> Result<(), Throw> {
self.buffer_range(object, offset, data.len())?;
crate::vm::typed::buffer_mut(self.heap, object).write(offset, data);
Ok(())
}
pub fn array_buffer_bytes(&self, object: ObjectId) -> Option<&[u8]> {
self.buffer(object)
.filter(|buffer| !buffer.detached)
.and_then(crate::heap::buffer::Buffer::owned_slice)
}
pub fn typed_array_view(
&self,
object: ObjectId,
) -> Option<(
crate::heap::buffer::ElementKind,
ObjectId,
usize,
Option<usize>,
)> {
if self.heap.internal_tag(object) != InternalTag::TypedArray {
return None;
}
let (view, buffer) = crate::vm::typed::view(self.heap, object);
Some((
view.kind,
buffer,
view.byte_offset,
crate::vm::typed::length(self.heap, object),
))
}
pub fn detach_array_buffer(&mut self, value: Value) -> Result<(), Throw> {
let is_buffer = value.as_object().is_some_and(|object| {
self.heap.internal_tag(object) == crate::heap::object::InternalTag::ArrayBuffer
});
if is_buffer {
crate::builtins::detach_buffer(&mut self.cx(), value)?;
}
Ok(())
}
pub fn new_string(&mut self, text: &str) -> Result<Value, HeapError> {
self.heap.alloc_string(text).map(Value::string)
}
pub fn new_string_units(&mut self, units: &[u16]) -> Result<Value, HeapError> {
self.heap.alloc_string_units(units).map(Value::string)
}
pub fn new_string_repr(&mut self, repr: StringRepr) -> Result<Value, HeapError> {
self.heap.alloc_string_repr(repr).map(Value::string)
}
pub fn string_repr(&self, value: Value) -> Option<&StringRepr> {
value.as_string().map(|id| self.heap.string(id).repr())
}
pub fn string_lossy(&self, value: Value) -> Option<String> {
value.as_string().map(|id| self.heap.string_text(id))
}
pub fn new_bigint(&mut self, decimal: &str) -> Option<Result<Value, HeapError>> {
let big = crate::vm::bigint::Big::parse(decimal)?;
Some(
self.heap
.alloc_bigint(big.negative, &big.limbs)
.map(Value::bigint),
)
}
pub fn bigint_decimal(&self, value: Value) -> Option<String> {
value.as_bigint()?;
Some(ops::big(self.heap, value).to_string_radix10())
}
pub fn new_symbol(&mut self, description: Option<&[u16]>) -> Result<Value, HeapError> {
let description = match description {
Some(units) => Some(self.heap.alloc_string_units(units)?),
None => None,
};
self.heap
.alloc_symbol(description, false)
.map(Value::symbol)
}
pub fn symbol_description(&self, value: Value) -> Option<Vec<u16>> {
let record = self.heap.symbol(value.as_symbol()?);
(record.description != crate::heap::object::NONE).then(|| {
self.heap
.string(crate::value::StringId(record.description))
.repr()
.units()
.collect()
})
}
pub fn well_known_symbol(&self, name: &str) -> Option<Value> {
self.realm
.symbols
.all()
.into_iter()
.find(|&(candidate, _)| candidate == name)
.map(|(_, id)| Value::symbol(id))
}
pub fn well_known_symbol_key(&self, name: &str) -> Option<PropertyKey> {
self.well_known_symbol(name)
.and_then(|symbol| symbol.as_symbol())
.map(WellKnown::key)
}
pub fn to_string(&mut self, value: Value) -> Result<Value, Throw> {
ops::to_string(&mut self.cx(), value)
}
pub fn to_number(&mut self, value: Value) -> Result<f64, Throw> {
ops::to_number(&mut self.cx(), value)
}
pub fn to_boolean(&self, value: Value) -> bool {
ops::to_boolean(self.heap, value)
}
pub fn to_object(&mut self, value: Value) -> Result<ObjectId, Throw> {
crate::vm::object::to_object(&mut self.cx(), value)
}
pub fn strict_equals(&self, x: Value, y: Value) -> bool {
ops::strict_eq(self.heap, x, y)
}
pub fn loose_equals(&mut self, x: Value, y: Value) -> Result<bool, Throw> {
ops::loose_eq(&mut self.cx(), x, y)
}
pub fn same_value(&mut self, x: Value, y: Value) -> bool {
crate::vm::object::same_value(&self.cx(), x, y)
}
pub fn same_value_zero(&self, x: Value, y: Value) -> bool {
ops::same_value_zero_heap(self.heap, x, y)
}
pub fn type_of(&mut self, value: Value) -> String {
let cx = self.cx();
let text = ops::type_of(&cx, value);
self.heap
.string_text(text.as_string().expect("a typeof atom"))
}
pub fn kind_of(&self, value: Value) -> Kind {
value.kind()
}
pub fn run_gc(&mut self) {
self.heap.collect();
}
}
impl Runtime {
pub fn key_from_units(&mut self, units: &[u16]) -> Result<PropertyKey, HeapError> {
self.native_cx().key_from_units(units)
}
pub fn key_from_symbol(&self, symbol: Value) -> Option<PropertyKey> {
symbol.as_symbol().map(PropertyKey::symbol)
}
pub fn to_property_key(&mut self, value: Value) -> Result<PropertyKey, Throw> {
self.native_cx().to_property_key(value)
}
pub fn key_name(&self, key: PropertyKey) -> KeyName {
match key.kind() {
KeyKind::Index(index) => KeyName::Index(index),
KeyKind::String(id) => KeyName::String(self.heap.string(id).repr().units().collect()),
KeyKind::Symbol(id) => KeyName::Symbol(Value::symbol(id)),
}
}
pub fn get(
&mut self,
object: ObjectId,
key: PropertyKey,
receiver: Value,
) -> Result<Value, Throw> {
self.native_cx().get(object, key, receiver)
}
pub fn set(
&mut self,
object: ObjectId,
key: PropertyKey,
value: Value,
receiver: Value,
) -> Result<bool, Throw> {
self.native_cx().set(object, key, value, receiver)
}
pub fn get_own_property(
&mut self,
object: ObjectId,
key: PropertyKey,
) -> Result<Option<PropertyDescriptor>, Throw> {
self.native_cx().get_own_property(object, key)
}
pub fn define_own_property(
&mut self,
object: ObjectId,
key: PropertyKey,
descriptor: &PropertyDescriptor,
) -> Result<bool, Throw> {
self.native_cx()
.define_own_property(object, key, descriptor)
}
pub fn delete_property(&mut self, object: ObjectId, key: PropertyKey) -> Result<bool, Throw> {
self.native_cx().delete_property(object, key)
}
pub fn has_property(&mut self, object: ObjectId, key: PropertyKey) -> Result<bool, Throw> {
self.native_cx().has_property(object, key)
}
pub fn has_own_property(&mut self, object: ObjectId, key: PropertyKey) -> Result<bool, Throw> {
self.native_cx().has_own_property(object, key)
}
pub fn own_property_keys(&mut self, object: ObjectId) -> Result<Vec<PropertyKey>, Throw> {
self.native_cx().own_property_keys(object)
}
pub fn get_prototype_of(&mut self, object: ObjectId) -> Result<Option<ObjectId>, Throw> {
self.native_cx().get_prototype_of(object)
}
pub fn set_prototype_of(
&mut self,
object: ObjectId,
prototype: Option<ObjectId>,
) -> Result<bool, Throw> {
self.native_cx().set_prototype_of(object, prototype)
}
pub fn prevent_extensions(&mut self, object: ObjectId) -> Result<bool, Throw> {
self.native_cx().prevent_extensions(object)
}
pub fn construct(
&mut self,
function: Value,
args: &[Value],
new_target: Value,
) -> Result<Value, Throw> {
self.native_cx().construct(function, args, new_target)
}
pub fn is_callable(&self, value: Value) -> bool {
ops::is_callable(&self.heap, value)
}
pub fn is_constructor(&self, value: Value) -> bool {
value
.as_object()
.is_some_and(|object| self.heap.header(object).has(flags::CONSTRUCTOR))
}
pub fn is_array(&mut self, value: Value) -> Result<bool, Throw> {
self.native_cx().is_array(value)
}
pub fn is_error(&self, value: Value) -> bool {
value
.as_object()
.is_some_and(|object| self.heap.header(object).has(flags::ERROR))
}
pub fn is_promise(&mut self, value: Value) -> bool {
self.native_cx().is_promise(value)
}
pub fn object_kind(&self, object: ObjectId) -> ObjectKind {
self.heap.object_kind(object)
}
pub fn new_object_with_prototype(
&mut self,
prototype: Option<ObjectId>,
) -> Result<ObjectId, HeapError> {
self.native_cx().new_object_with_prototype(prototype)
}
pub fn new_array_from(&mut self, values: &[Value]) -> Result<ObjectId, Throw> {
self.native_cx().new_array_from(values)
}
pub fn new_error(&mut self, kind: ErrorKind, message: &str) -> Result<Value, HeapError> {
self.native_cx().new_error(kind, message)
}
pub fn new_located_error(
&mut self,
kind: ErrorKind,
message: &str,
file: &str,
line: u32,
column: u32,
) -> Result<Value, HeapError> {
self.native_cx()
.new_located_error(kind, message, file, line, column)
}
pub fn new_promise(&mut self) -> Result<ObjectId, Throw> {
self.native_cx().new_promise()
}
pub fn detach_array_buffer(&mut self, value: Value) -> Result<(), Throw> {
self.native_cx().detach_array_buffer(value)
}
pub fn new_string(&mut self, text: &str) -> Result<Value, HeapError> {
self.native_cx().new_string(text)
}
pub fn new_string_units(&mut self, units: &[u16]) -> Result<Value, HeapError> {
self.native_cx().new_string_units(units)
}
pub fn new_string_repr(&mut self, repr: StringRepr) -> Result<Value, HeapError> {
self.native_cx().new_string_repr(repr)
}
pub fn string_repr(&self, value: Value) -> Option<&StringRepr> {
value.as_string().map(|id| self.heap.string(id).repr())
}
pub fn string_lossy(&self, value: Value) -> Option<String> {
value.as_string().map(|id| self.heap.string_text(id))
}
pub fn new_bigint(&mut self, decimal: &str) -> Option<Result<Value, HeapError>> {
self.native_cx().new_bigint(decimal)
}
pub fn bigint_decimal(&self, value: Value) -> Option<String> {
value.as_bigint()?;
Some(ops::big(&self.heap, value).to_string_radix10())
}
pub fn new_symbol(&mut self, description: Option<&[u16]>) -> Result<Value, HeapError> {
self.native_cx().new_symbol(description)
}
pub fn symbol_description(&self, value: Value) -> Option<Vec<u16>> {
let record = self.heap.symbol(value.as_symbol()?);
(record.description != crate::heap::object::NONE).then(|| {
self.heap
.string(crate::value::StringId(record.description))
.repr()
.units()
.collect()
})
}
pub fn well_known_symbol(&self, name: &str) -> Option<Value> {
self.realm
.symbols
.all()
.into_iter()
.find(|&(candidate, _)| candidate == name)
.map(|(_, id)| Value::symbol(id))
}
pub fn well_known_symbol_key(&self, name: &str) -> Option<PropertyKey> {
self.well_known_symbol(name)
.and_then(|symbol| symbol.as_symbol())
.map(WellKnown::key)
}
pub fn to_string(&mut self, value: Value) -> Result<Value, Throw> {
self.native_cx().to_string(value)
}
pub fn to_number(&mut self, value: Value) -> Result<f64, Throw> {
self.native_cx().to_number(value)
}
pub fn to_boolean(&self, value: Value) -> bool {
ops::to_boolean(&self.heap, value)
}
pub fn to_object(&mut self, value: Value) -> Result<ObjectId, Throw> {
self.native_cx().to_object(value)
}
pub fn strict_equals(&self, x: Value, y: Value) -> bool {
ops::strict_eq(&self.heap, x, y)
}
pub fn loose_equals(&mut self, x: Value, y: Value) -> Result<bool, Throw> {
self.native_cx().loose_equals(x, y)
}
pub fn same_value(&mut self, x: Value, y: Value) -> bool {
self.native_cx().same_value(x, y)
}
pub fn same_value_zero(&self, x: Value, y: Value) -> bool {
ops::same_value_zero_heap(&self.heap, x, y)
}
pub fn type_of(&mut self, value: Value) -> String {
self.native_cx().type_of(value)
}
pub fn kind_of(&self, value: Value) -> Kind {
value.kind()
}
pub fn run_gc(&mut self) {
self.native_cx().run_gc()
}
}