1use std::any::Any;
14use std::rc::Rc;
15
16use crate::bytecode::CodeStore;
17use crate::heap::atom::{KeyKind, PropertyKey};
18use crate::heap::object::{InternalData, InternalTag, flags};
19use crate::heap::string::StringRepr;
20use crate::runtime::{Realm, Runtime, WellKnown};
21use crate::value::{Kind, ObjectId, Value};
22use crate::vm::native::{HostBody, HostFn};
23use crate::vm::object::Descriptor;
24use crate::vm::{Cx, ErrorKind, Services, Throw, ops};
25use crate::{Heap, HeapError, ObjectKind};
26
27#[derive(Clone, Copy, Debug, Default, PartialEq)]
30pub struct PropertyDescriptor {
31 pub value: Option<Value>,
32 pub get: Option<Value>,
33 pub set: Option<Value>,
34 pub writable: Option<bool>,
35 pub enumerable: Option<bool>,
36 pub configurable: Option<bool>,
37}
38
39impl PropertyDescriptor {
40 pub fn is_accessor(&self) -> bool {
41 self.get.is_some() || self.set.is_some()
42 }
43
44 fn to_internal(self) -> Descriptor {
45 Descriptor {
46 value: self.value,
47 get: self.get,
48 set: self.set,
49 writable: self.writable,
50 enumerable: self.enumerable,
51 configurable: self.configurable,
52 }
53 }
54
55 fn from_internal(descriptor: Descriptor) -> Self {
56 PropertyDescriptor {
57 value: descriptor.value,
58 get: descriptor.get,
59 set: descriptor.set,
60 writable: descriptor.writable,
61 enumerable: descriptor.enumerable,
62 configurable: descriptor.configurable,
63 }
64 }
65}
66
67#[derive(Clone, Debug, PartialEq, Eq)]
69pub enum KeyName {
70 Index(u32),
71 String(Vec<u16>),
72 Symbol(Value),
75}
76
77pub struct NativeCx<'a> {
81 pub(crate) heap: &'a mut Heap,
82 code: CodeView<'a>,
83 pub(crate) realm: &'a Realm,
84 pub(crate) host: &'a mut Services,
85}
86
87enum CodeView<'a> {
90 Owned(&'a mut CodeStore),
91 Shared(&'a CodeStore),
92}
93
94impl Runtime {
95 #[inline]
97 pub fn native_cx(&mut self) -> NativeCx<'_> {
98 NativeCx {
99 heap: &mut self.heap,
100 code: CodeView::Owned(&mut self.code),
101 realm: &self.realm,
102 host: &mut self.host,
103 }
104 }
105}
106
107pub(crate) fn host_function(
110 heap: &mut Heap,
111 realm: &Realm,
112 name: &str,
113 length: u32,
114 constructor: bool,
115 data: &[Value],
116 body: Rc<HostFn>,
117) -> Result<ObjectId, HeapError> {
118 let record = heap.alloc_internal(
119 ObjectKind::Builtin,
120 InternalTag::NativeData,
121 None,
122 0,
123 data,
124 InternalData::HostFn(HostBody(body)),
125 0,
126 )?;
127 let mark = heap.roots().mark();
128 heap.roots().push(Value::object(record));
129 let result = (|| {
130 let native = if constructor {
131 crate::builtins::Native::HostConstructor
132 } else {
133 crate::builtins::Native::HostFunction
134 };
135 let prototype = realm.intrinsic(crate::Intrinsic::FunctionPrototype);
136 let function = heap.alloc_native_closure(Some(prototype), native.index(), Some(record))?;
137 heap.roots().push(Value::object(function));
138 if constructor {
139 heap.set_object_flag(function, flags::CONSTRUCTOR);
140 }
141 let name = heap.alloc_string(name)?;
142 crate::builtins::define_name_length(
143 heap,
144 &realm.names,
145 function,
146 Value::string(name),
147 length,
148 )?;
149 Ok(function)
150 })();
151 heap.roots().truncate(mark);
152 result
153}
154
155pub(crate) fn host_object(
157 heap: &mut Heap,
158 prototype: Option<ObjectId>,
159 data: Rc<dyn Any>,
160) -> Result<ObjectId, HeapError> {
161 heap.alloc_internal(
162 ObjectKind::Builtin,
163 InternalTag::HostData,
164 prototype,
165 4,
166 &[],
167 InternalData::HostData(data),
168 0,
169 )
170}
171
172impl<'a> NativeCx<'a> {
173 pub fn reborrow(&mut self) -> NativeCx<'_> {
175 NativeCx {
176 heap: self.heap,
177 code: match &mut self.code {
178 CodeView::Owned(code) => CodeView::Owned(code),
179 CodeView::Shared(code) => CodeView::Shared(code),
180 },
181 realm: self.realm,
182 host: self.host,
183 }
184 }
185
186 pub(crate) fn from_cx<'b>(cx: &'b mut Cx<'_>) -> NativeCx<'b> {
188 NativeCx {
189 heap: cx.heap,
190 code: CodeView::Shared(cx.static_code),
191 realm: cx.realm,
192 host: cx.host,
193 }
194 }
195
196 #[inline]
198 pub(crate) fn cx(&mut self) -> Cx<'_> {
199 let static_code: &CodeStore = match &self.code {
200 CodeView::Owned(code) => code,
201 CodeView::Shared(code) => code,
202 };
203 Cx {
204 heap: self.heap,
205 static_code,
206 realm: self.realm,
207 host: self.host,
208 }
209 }
210
211 pub fn compiler(&mut self, transient: bool) -> crate::vm::compile::Compiler<'_> {
217 match &mut self.code {
218 CodeView::Owned(code) => {
219 if transient {
220 crate::vm::compile::Compiler::new(self.heap, code, self.realm)
221 } else {
222 crate::vm::compile::Compiler::owned(self.heap, code, self.realm)
223 }
224 }
225 CodeView::Shared(code) => {
226 crate::vm::compile::Compiler::new(self.heap, code, self.realm)
227 }
228 }
229 }
230
231 pub fn owns_code(&self) -> bool {
234 matches!(self.code, CodeView::Owned(_))
235 }
236
237 #[inline]
238 pub fn heap(&self) -> &Heap {
239 self.heap
240 }
241
242 #[inline]
243 pub fn heap_mut(&mut self) -> &mut Heap {
244 self.heap
245 }
246
247 #[inline]
248 pub fn realm(&self) -> &'a Realm {
249 self.realm
250 }
251
252 pub fn interrupt_flag(&self) -> std::sync::Arc<std::sync::atomic::AtomicBool> {
254 std::sync::Arc::clone(&self.host.interrupt)
255 }
256
257 pub fn is_interrupted(&self) -> bool {
259 self.heap.vm.interrupted
260 }
261
262 pub fn clear_interrupted(&mut self) {
265 self.heap.vm.interrupted = false;
266 self.heap.vm.poll = crate::vm::INTERRUPT_INTERVAL;
267 }
268
269 pub(crate) fn installing<T>(&mut self, install: impl FnOnce(&mut Cx<'_>) -> T) -> T {
272 let mode = self.heap.set_atom_mode(crate::heap::AtomMode::Pin);
273 let result = install(&mut self.cx());
274 self.heap.set_atom_mode(mode);
275 result
276 }
277
278 pub fn install_std(&mut self) -> Result<(), HeapError> {
280 self.installing(crate::builtins::install_std)
281 }
282
283 pub fn install_qjs_helpers(&mut self, script_args: Option<&[String]>) -> Result<(), HeapError> {
285 self.installing(|cx| crate::builtins::install_qjs_helpers(cx, script_args))
286 }
287
288 pub fn set_native_stack_budget(&mut self, bytes: usize) {
290 self.heap.vm.native_budget = bytes;
291 }
292}
293
294impl NativeCx<'_> {
295 pub fn call(&mut self, function: Value, this: Value, args: &[Value]) -> Result<Value, Throw> {
300 crate::vm::call(&mut self.cx(), function, this, args)
301 }
302
303 pub fn run_script(&mut self, script: ObjectId) -> Result<Value, Throw> {
305 let global = Value::object(self.realm.global());
306 self.call(Value::object(script), global, &[])
307 }
308
309 pub fn hold(&mut self, value: Value) -> crate::Handle {
311 self.heap.handles().create(value)
312 }
313
314 pub fn held(&self, handle: crate::Handle) -> Value {
315 self.heap.handles_ref().get(handle)
316 }
317
318 pub fn release(&mut self, handle: crate::Handle) {
319 self.heap.handles().release(handle);
320 }
321
322 pub fn global_object(&self) -> ObjectId {
323 self.realm.global()
324 }
325
326 pub fn intrinsic(&self, intrinsic: crate::Intrinsic) -> ObjectId {
327 self.realm.intrinsic(intrinsic)
328 }
329
330 pub fn new_object(&mut self) -> Result<ObjectId, HeapError> {
332 let prototype = self.intrinsic(crate::Intrinsic::ObjectPrototype);
333 self.heap
334 .alloc_object(ObjectKind::Ordinary, Some(prototype), 4)
335 }
336
337 pub fn new_host_function(
346 &mut self,
347 name: &str,
348 length: u32,
349 constructor: bool,
350 data: &[Value],
351 body: Rc<HostFn>,
352 ) -> Result<ObjectId, HeapError> {
353 host_function(self.heap, self.realm, name, length, constructor, data, body)
354 }
355
356 pub fn new_host_object(
360 &mut self,
361 prototype: Option<ObjectId>,
362 data: Rc<dyn Any>,
363 ) -> Result<ObjectId, HeapError> {
364 host_object(self.heap, prototype, data)
365 }
366
367 pub fn host_data(&self, object: ObjectId) -> Option<Rc<dyn Any>> {
370 if self.heap.internal_tag(object) != InternalTag::HostData {
371 return None;
372 }
373 match &self.heap.internal(object).data {
374 InternalData::HostData(data) => Some(Rc::clone(data)),
375 _ => None,
376 }
377 }
378
379 pub fn key_from_units(&mut self, units: &[u16]) -> Result<PropertyKey, HeapError> {
384 self.heap.property_key_units(units)
385 }
386
387 pub fn key_from_symbol(&self, symbol: Value) -> Option<PropertyKey> {
389 symbol.as_symbol().map(PropertyKey::symbol)
390 }
391
392 pub fn to_property_key(&mut self, value: Value) -> Result<PropertyKey, Throw> {
394 ops::to_property_key(&mut self.cx(), value)
395 }
396
397 pub fn key_name(&self, key: PropertyKey) -> KeyName {
398 match key.kind() {
399 KeyKind::Index(index) => KeyName::Index(index),
400 KeyKind::String(id) => KeyName::String(self.heap.string(id).repr().units().collect()),
401 KeyKind::Symbol(id) => KeyName::Symbol(Value::symbol(id)),
402 }
403 }
404
405 pub fn get(
409 &mut self,
410 object: ObjectId,
411 key: PropertyKey,
412 receiver: Value,
413 ) -> Result<Value, Throw> {
414 crate::vm::object::get(&mut self.cx(), object, key, receiver)
415 }
416
417 pub fn set(
419 &mut self,
420 object: ObjectId,
421 key: PropertyKey,
422 value: Value,
423 receiver: Value,
424 ) -> Result<bool, Throw> {
425 crate::vm::object::set(&mut self.cx(), object, key, value, receiver)
426 }
427
428 pub fn get_own_property(
430 &mut self,
431 object: ObjectId,
432 key: PropertyKey,
433 ) -> Result<Option<PropertyDescriptor>, Throw> {
434 Ok(
435 crate::vm::object::get_own_property(&mut self.cx(), object, key)?
436 .map(PropertyDescriptor::from_internal),
437 )
438 }
439
440 pub fn define_own_property(
442 &mut self,
443 object: ObjectId,
444 key: PropertyKey,
445 descriptor: &PropertyDescriptor,
446 ) -> Result<bool, Throw> {
447 crate::vm::object::define_own_property(
448 &mut self.cx(),
449 object,
450 key,
451 &descriptor.to_internal(),
452 )
453 }
454
455 pub fn delete_property(&mut self, object: ObjectId, key: PropertyKey) -> Result<bool, Throw> {
457 crate::vm::object::delete(&mut self.cx(), object, key)
458 }
459
460 pub fn has_property(&mut self, object: ObjectId, key: PropertyKey) -> Result<bool, Throw> {
462 crate::vm::object::has_property(&mut self.cx(), object, key)
463 }
464
465 pub fn has_own_property(&mut self, object: ObjectId, key: PropertyKey) -> Result<bool, Throw> {
467 crate::vm::object::has_own_property(&mut self.cx(), object, key)
468 }
469
470 pub fn own_property_keys(&mut self, object: ObjectId) -> Result<Vec<PropertyKey>, Throw> {
472 crate::vm::object::own_property_keys(&mut self.cx(), object)
473 }
474
475 pub fn get_prototype_of(&mut self, object: ObjectId) -> Result<Option<ObjectId>, Throw> {
477 Ok(crate::vm::object::get_prototype_of(&mut self.cx(), object)?.as_object())
478 }
479
480 pub fn set_prototype_of(
482 &mut self,
483 object: ObjectId,
484 prototype: Option<ObjectId>,
485 ) -> Result<bool, Throw> {
486 let prototype = prototype.map_or(Value::NULL, Value::object);
487 crate::vm::object::set_prototype_of(&mut self.cx(), object, prototype)
488 }
489
490 pub fn prevent_extensions(&mut self, object: ObjectId) -> Result<bool, Throw> {
492 crate::vm::object::prevent_extensions(&mut self.cx(), object)
493 }
494
495 pub fn construct(
498 &mut self,
499 function: Value,
500 args: &[Value],
501 new_target: Value,
502 ) -> Result<Value, Throw> {
503 crate::vm::construct(&mut self.cx(), function, args, new_target)
504 }
505
506 pub fn is_callable(&self, value: Value) -> bool {
508 ops::is_callable(self.heap, value)
509 }
510
511 pub fn is_constructor(&self, value: Value) -> bool {
513 value
514 .as_object()
515 .is_some_and(|object| self.heap.header(object).has(flags::CONSTRUCTOR))
516 }
517
518 pub fn is_array(&mut self, value: Value) -> Result<bool, Throw> {
520 crate::vm::object::is_array(&mut self.cx(), value)
521 }
522
523 pub fn is_error(&self, value: Value) -> bool {
525 value
526 .as_object()
527 .is_some_and(|object| self.heap.header(object).has(flags::ERROR))
528 }
529
530 pub fn is_promise(&mut self, value: Value) -> bool {
532 crate::vm::jobs::is_promise(&self.cx(), value)
533 }
534
535 pub fn object_kind(&self, object: ObjectId) -> ObjectKind {
536 self.heap.object_kind(object)
537 }
538
539 pub fn new_object_with_prototype(
541 &mut self,
542 prototype: Option<ObjectId>,
543 ) -> Result<ObjectId, HeapError> {
544 self.heap.alloc_object(ObjectKind::Ordinary, prototype, 4)
545 }
546
547 pub fn new_array_from(&mut self, values: &[Value]) -> Result<ObjectId, Throw> {
549 let mut cx = self.cx();
550 let length = u32::try_from(values.len()).unwrap_or(u32::MAX);
551 let prototype = cx.realm.intrinsic(crate::Intrinsic::ArrayPrototype);
552 let array = cx
553 .heap
554 .alloc_array(Some(prototype), length)
555 .map_err(|error| crate::vm::error::heap_error(&cx, error))?;
556 let mark = cx.heap.roots().mark();
557 cx.heap.roots().push(Value::object(array));
558 let mut result = Ok(array);
559 for (index, &value) in values.iter().enumerate() {
560 let key = crate::vm::object::index_key(&mut cx, index as u32);
561 if let Err(error) = key.and_then(|key| {
562 crate::vm::object::create_data_property_or_throw(&mut cx, array, key, value)
563 }) {
564 result = Err(error);
565 break;
566 }
567 }
568 cx.heap.roots().truncate(mark);
569 result
570 }
571
572 pub fn new_error(&mut self, kind: ErrorKind, message: &str) -> Result<Value, HeapError> {
575 let message = self.heap.alloc_string(message)?;
576 crate::vm::error::new_error(&mut self.cx(), kind, Value::string(message))
577 }
578
579 pub fn new_located_error(
583 &mut self,
584 kind: ErrorKind,
585 message: &str,
586 file: &str,
587 line: u32,
588 column: u32,
589 ) -> Result<Value, HeapError> {
590 let message = self.heap.alloc_string(message)?;
591 let location = crate::vm::error::Location { file, line, column };
592 crate::vm::error::new_error_at(
593 &mut self.cx(),
594 kind,
595 Value::string(message),
596 Some(location),
597 0,
598 )
599 }
600
601 pub fn new_promise_capability(&mut self) -> Result<(ObjectId, ObjectId, ObjectId), Throw> {
604 let mut cx = self.cx();
605 let prototype = cx.realm.intrinsic(crate::Intrinsic::PromisePrototype);
606 let promise = crate::vm::jobs::new_promise(&mut cx, prototype)?;
607 let mark = cx.heap.roots().mark();
608 cx.heap.roots().push(Value::object(promise));
609 let functions = crate::vm::jobs::resolving_functions(&mut cx, promise);
610 cx.heap.roots().truncate(mark);
611 let (resolve, reject) = functions?;
612 Ok((promise, resolve, reject))
613 }
614
615 pub fn new_promise(&mut self) -> Result<ObjectId, Throw> {
617 let prototype = self.realm.intrinsic(crate::Intrinsic::PromisePrototype);
618 crate::vm::jobs::new_promise(&mut self.cx(), prototype)
619 }
620
621 pub fn new_array_buffer(&mut self, len: usize) -> Result<ObjectId, Throw> {
626 let mut cx = self.cx();
627 let mark = cx.heap.roots().mark();
628 let buffer = crate::builtins::new_array_buffer(&mut cx, len);
629 cx.heap.roots().truncate(mark);
630 buffer
631 }
632
633 fn buffer(&self, object: ObjectId) -> Option<&crate::heap::buffer::Buffer> {
635 match self.heap.internal_tag(object) {
636 InternalTag::ArrayBuffer | InternalTag::SharedArrayBuffer => {
637 Some(crate::vm::typed::buffer(self.heap, object))
638 }
639 _ => None,
640 }
641 }
642
643 pub fn array_buffer_len(&self, object: ObjectId) -> Option<usize> {
646 self.buffer(object)
647 .filter(|buffer| !buffer.detached)
648 .map(crate::heap::buffer::Buffer::len)
649 }
650
651 fn buffer_range(&mut self, object: ObjectId, offset: usize, len: usize) -> Result<(), Throw> {
654 let Some(buffer) = self.buffer(object) else {
655 return Err(crate::vm::error::type_error(
656 &mut self.cx(),
657 "not an ArrayBuffer",
658 ));
659 };
660 if buffer.detached {
661 return Err(crate::vm::error::type_error(
662 &mut self.cx(),
663 "ArrayBuffer is detached",
664 ));
665 }
666 if offset.checked_add(len).is_none_or(|end| end > buffer.len()) {
667 return Err(crate::vm::error::range_error(
668 &mut self.cx(),
669 "out of bound",
670 ));
671 }
672 Ok(())
673 }
674
675 pub fn array_buffer_read(
678 &mut self,
679 object: ObjectId,
680 offset: usize,
681 out: &mut [u8],
682 ) -> Result<(), Throw> {
683 self.buffer_range(object, offset, out.len())?;
684 crate::vm::typed::buffer(self.heap, object).read(offset, out);
685 Ok(())
686 }
687
688 pub fn array_buffer_write(
690 &mut self,
691 object: ObjectId,
692 offset: usize,
693 data: &[u8],
694 ) -> Result<(), Throw> {
695 self.buffer_range(object, offset, data.len())?;
696 crate::vm::typed::buffer_mut(self.heap, object).write(offset, data);
697 Ok(())
698 }
699
700 pub fn array_buffer_bytes(&self, object: ObjectId) -> Option<&[u8]> {
703 self.buffer(object)
704 .filter(|buffer| !buffer.detached)
705 .and_then(crate::heap::buffer::Buffer::owned_slice)
706 }
707
708 pub fn typed_array_view(
712 &self,
713 object: ObjectId,
714 ) -> Option<(
715 crate::heap::buffer::ElementKind,
716 ObjectId,
717 usize,
718 Option<usize>,
719 )> {
720 if self.heap.internal_tag(object) != InternalTag::TypedArray {
721 return None;
722 }
723 let (view, buffer) = crate::vm::typed::view(self.heap, object);
724 Some((
725 view.kind,
726 buffer,
727 view.byte_offset,
728 crate::vm::typed::length(self.heap, object),
729 ))
730 }
731
732 pub fn detach_array_buffer(&mut self, value: Value) -> Result<(), Throw> {
735 let is_buffer = value.as_object().is_some_and(|object| {
736 self.heap.internal_tag(object) == crate::heap::object::InternalTag::ArrayBuffer
737 });
738 if is_buffer {
739 crate::builtins::detach_buffer(&mut self.cx(), value)?;
740 }
741 Ok(())
742 }
743
744 pub fn new_string(&mut self, text: &str) -> Result<Value, HeapError> {
747 self.heap.alloc_string(text).map(Value::string)
748 }
749
750 pub fn new_string_units(&mut self, units: &[u16]) -> Result<Value, HeapError> {
751 self.heap.alloc_string_units(units).map(Value::string)
752 }
753
754 pub fn new_string_repr(&mut self, repr: StringRepr) -> Result<Value, HeapError> {
757 self.heap.alloc_string_repr(repr).map(Value::string)
758 }
759
760 pub fn string_repr(&self, value: Value) -> Option<&StringRepr> {
762 value.as_string().map(|id| self.heap.string(id).repr())
763 }
764
765 pub fn string_lossy(&self, value: Value) -> Option<String> {
767 value.as_string().map(|id| self.heap.string_text(id))
768 }
769
770 pub fn new_bigint(&mut self, decimal: &str) -> Option<Result<Value, HeapError>> {
773 let big = crate::vm::bigint::Big::parse(decimal)?;
774 Some(
775 self.heap
776 .alloc_bigint(big.negative, &big.limbs)
777 .map(Value::bigint),
778 )
779 }
780
781 pub fn bigint_decimal(&self, value: Value) -> Option<String> {
783 value.as_bigint()?;
784 Some(ops::big(self.heap, value).to_string_radix10())
785 }
786
787 pub fn new_symbol(&mut self, description: Option<&[u16]>) -> Result<Value, HeapError> {
789 let description = match description {
790 Some(units) => Some(self.heap.alloc_string_units(units)?),
791 None => None,
792 };
793 self.heap
794 .alloc_symbol(description, false)
795 .map(Value::symbol)
796 }
797
798 pub fn symbol_description(&self, value: Value) -> Option<Vec<u16>> {
801 let record = self.heap.symbol(value.as_symbol()?);
802 (record.description != crate::heap::object::NONE).then(|| {
803 self.heap
804 .string(crate::value::StringId(record.description))
805 .repr()
806 .units()
807 .collect()
808 })
809 }
810
811 pub fn well_known_symbol(&self, name: &str) -> Option<Value> {
813 self.realm
814 .symbols
815 .all()
816 .into_iter()
817 .find(|&(candidate, _)| candidate == name)
818 .map(|(_, id)| Value::symbol(id))
819 }
820
821 pub fn well_known_symbol_key(&self, name: &str) -> Option<PropertyKey> {
822 self.well_known_symbol(name)
823 .and_then(|symbol| symbol.as_symbol())
824 .map(WellKnown::key)
825 }
826
827 pub fn to_string(&mut self, value: Value) -> Result<Value, Throw> {
831 ops::to_string(&mut self.cx(), value)
832 }
833
834 pub fn to_number(&mut self, value: Value) -> Result<f64, Throw> {
836 ops::to_number(&mut self.cx(), value)
837 }
838
839 pub fn to_boolean(&self, value: Value) -> bool {
841 ops::to_boolean(self.heap, value)
842 }
843
844 pub fn to_object(&mut self, value: Value) -> Result<ObjectId, Throw> {
846 crate::vm::object::to_object(&mut self.cx(), value)
847 }
848
849 pub fn strict_equals(&self, x: Value, y: Value) -> bool {
851 ops::strict_eq(self.heap, x, y)
852 }
853
854 pub fn loose_equals(&mut self, x: Value, y: Value) -> Result<bool, Throw> {
856 ops::loose_eq(&mut self.cx(), x, y)
857 }
858
859 pub fn same_value(&mut self, x: Value, y: Value) -> bool {
861 crate::vm::object::same_value(&self.cx(), x, y)
862 }
863
864 pub fn same_value_zero(&self, x: Value, y: Value) -> bool {
866 ops::same_value_zero_heap(self.heap, x, y)
867 }
868
869 pub fn type_of(&mut self, value: Value) -> String {
871 let cx = self.cx();
872 let text = ops::type_of(&cx, value);
873 self.heap
874 .string_text(text.as_string().expect("a typeof atom"))
875 }
876
877 pub fn kind_of(&self, value: Value) -> Kind {
879 value.kind()
880 }
881
882 pub fn run_gc(&mut self) {
887 self.heap.collect();
888 }
889}
890
891impl Runtime {
892 pub fn key_from_units(&mut self, units: &[u16]) -> Result<PropertyKey, HeapError> {
896 self.native_cx().key_from_units(units)
897 }
898
899 pub fn key_from_symbol(&self, symbol: Value) -> Option<PropertyKey> {
901 symbol.as_symbol().map(PropertyKey::symbol)
902 }
903
904 pub fn to_property_key(&mut self, value: Value) -> Result<PropertyKey, Throw> {
906 self.native_cx().to_property_key(value)
907 }
908
909 pub fn key_name(&self, key: PropertyKey) -> KeyName {
910 match key.kind() {
911 KeyKind::Index(index) => KeyName::Index(index),
912 KeyKind::String(id) => KeyName::String(self.heap.string(id).repr().units().collect()),
913 KeyKind::Symbol(id) => KeyName::Symbol(Value::symbol(id)),
914 }
915 }
916
917 pub fn get(
921 &mut self,
922 object: ObjectId,
923 key: PropertyKey,
924 receiver: Value,
925 ) -> Result<Value, Throw> {
926 self.native_cx().get(object, key, receiver)
927 }
928
929 pub fn set(
931 &mut self,
932 object: ObjectId,
933 key: PropertyKey,
934 value: Value,
935 receiver: Value,
936 ) -> Result<bool, Throw> {
937 self.native_cx().set(object, key, value, receiver)
938 }
939
940 pub fn get_own_property(
942 &mut self,
943 object: ObjectId,
944 key: PropertyKey,
945 ) -> Result<Option<PropertyDescriptor>, Throw> {
946 self.native_cx().get_own_property(object, key)
947 }
948
949 pub fn define_own_property(
951 &mut self,
952 object: ObjectId,
953 key: PropertyKey,
954 descriptor: &PropertyDescriptor,
955 ) -> Result<bool, Throw> {
956 self.native_cx()
957 .define_own_property(object, key, descriptor)
958 }
959
960 pub fn delete_property(&mut self, object: ObjectId, key: PropertyKey) -> Result<bool, Throw> {
962 self.native_cx().delete_property(object, key)
963 }
964
965 pub fn has_property(&mut self, object: ObjectId, key: PropertyKey) -> Result<bool, Throw> {
967 self.native_cx().has_property(object, key)
968 }
969
970 pub fn has_own_property(&mut self, object: ObjectId, key: PropertyKey) -> Result<bool, Throw> {
972 self.native_cx().has_own_property(object, key)
973 }
974
975 pub fn own_property_keys(&mut self, object: ObjectId) -> Result<Vec<PropertyKey>, Throw> {
977 self.native_cx().own_property_keys(object)
978 }
979
980 pub fn get_prototype_of(&mut self, object: ObjectId) -> Result<Option<ObjectId>, Throw> {
982 self.native_cx().get_prototype_of(object)
983 }
984
985 pub fn set_prototype_of(
987 &mut self,
988 object: ObjectId,
989 prototype: Option<ObjectId>,
990 ) -> Result<bool, Throw> {
991 self.native_cx().set_prototype_of(object, prototype)
992 }
993
994 pub fn prevent_extensions(&mut self, object: ObjectId) -> Result<bool, Throw> {
996 self.native_cx().prevent_extensions(object)
997 }
998
999 pub fn construct(
1001 &mut self,
1002 function: Value,
1003 args: &[Value],
1004 new_target: Value,
1005 ) -> Result<Value, Throw> {
1006 self.native_cx().construct(function, args, new_target)
1007 }
1008
1009 pub fn is_callable(&self, value: Value) -> bool {
1011 ops::is_callable(&self.heap, value)
1012 }
1013
1014 pub fn is_constructor(&self, value: Value) -> bool {
1016 value
1017 .as_object()
1018 .is_some_and(|object| self.heap.header(object).has(flags::CONSTRUCTOR))
1019 }
1020
1021 pub fn is_array(&mut self, value: Value) -> Result<bool, Throw> {
1023 self.native_cx().is_array(value)
1024 }
1025
1026 pub fn is_error(&self, value: Value) -> bool {
1028 value
1029 .as_object()
1030 .is_some_and(|object| self.heap.header(object).has(flags::ERROR))
1031 }
1032
1033 pub fn is_promise(&mut self, value: Value) -> bool {
1035 self.native_cx().is_promise(value)
1036 }
1037
1038 pub fn object_kind(&self, object: ObjectId) -> ObjectKind {
1039 self.heap.object_kind(object)
1040 }
1041
1042 pub fn new_object_with_prototype(
1044 &mut self,
1045 prototype: Option<ObjectId>,
1046 ) -> Result<ObjectId, HeapError> {
1047 self.native_cx().new_object_with_prototype(prototype)
1048 }
1049
1050 pub fn new_array_from(&mut self, values: &[Value]) -> Result<ObjectId, Throw> {
1052 self.native_cx().new_array_from(values)
1053 }
1054
1055 pub fn new_error(&mut self, kind: ErrorKind, message: &str) -> Result<Value, HeapError> {
1057 self.native_cx().new_error(kind, message)
1058 }
1059
1060 pub fn new_located_error(
1062 &mut self,
1063 kind: ErrorKind,
1064 message: &str,
1065 file: &str,
1066 line: u32,
1067 column: u32,
1068 ) -> Result<Value, HeapError> {
1069 self.native_cx()
1070 .new_located_error(kind, message, file, line, column)
1071 }
1072
1073 pub fn new_promise(&mut self) -> Result<ObjectId, Throw> {
1075 self.native_cx().new_promise()
1076 }
1077
1078 pub fn detach_array_buffer(&mut self, value: Value) -> Result<(), Throw> {
1080 self.native_cx().detach_array_buffer(value)
1081 }
1082
1083 pub fn new_string(&mut self, text: &str) -> Result<Value, HeapError> {
1087 self.native_cx().new_string(text)
1088 }
1089
1090 pub fn new_string_units(&mut self, units: &[u16]) -> Result<Value, HeapError> {
1092 self.native_cx().new_string_units(units)
1093 }
1094
1095 pub fn new_string_repr(&mut self, repr: StringRepr) -> Result<Value, HeapError> {
1097 self.native_cx().new_string_repr(repr)
1098 }
1099
1100 pub fn string_repr(&self, value: Value) -> Option<&StringRepr> {
1102 value.as_string().map(|id| self.heap.string(id).repr())
1103 }
1104
1105 pub fn string_lossy(&self, value: Value) -> Option<String> {
1107 value.as_string().map(|id| self.heap.string_text(id))
1108 }
1109
1110 pub fn new_bigint(&mut self, decimal: &str) -> Option<Result<Value, HeapError>> {
1112 self.native_cx().new_bigint(decimal)
1113 }
1114
1115 pub fn bigint_decimal(&self, value: Value) -> Option<String> {
1117 value.as_bigint()?;
1118 Some(ops::big(&self.heap, value).to_string_radix10())
1119 }
1120
1121 pub fn new_symbol(&mut self, description: Option<&[u16]>) -> Result<Value, HeapError> {
1123 self.native_cx().new_symbol(description)
1124 }
1125
1126 pub fn symbol_description(&self, value: Value) -> Option<Vec<u16>> {
1129 let record = self.heap.symbol(value.as_symbol()?);
1130 (record.description != crate::heap::object::NONE).then(|| {
1131 self.heap
1132 .string(crate::value::StringId(record.description))
1133 .repr()
1134 .units()
1135 .collect()
1136 })
1137 }
1138
1139 pub fn well_known_symbol(&self, name: &str) -> Option<Value> {
1141 self.realm
1142 .symbols
1143 .all()
1144 .into_iter()
1145 .find(|&(candidate, _)| candidate == name)
1146 .map(|(_, id)| Value::symbol(id))
1147 }
1148
1149 pub fn well_known_symbol_key(&self, name: &str) -> Option<PropertyKey> {
1150 self.well_known_symbol(name)
1151 .and_then(|symbol| symbol.as_symbol())
1152 .map(WellKnown::key)
1153 }
1154
1155 pub fn to_string(&mut self, value: Value) -> Result<Value, Throw> {
1159 self.native_cx().to_string(value)
1160 }
1161
1162 pub fn to_number(&mut self, value: Value) -> Result<f64, Throw> {
1164 self.native_cx().to_number(value)
1165 }
1166
1167 pub fn to_boolean(&self, value: Value) -> bool {
1169 ops::to_boolean(&self.heap, value)
1170 }
1171
1172 pub fn to_object(&mut self, value: Value) -> Result<ObjectId, Throw> {
1174 self.native_cx().to_object(value)
1175 }
1176
1177 pub fn strict_equals(&self, x: Value, y: Value) -> bool {
1179 ops::strict_eq(&self.heap, x, y)
1180 }
1181
1182 pub fn loose_equals(&mut self, x: Value, y: Value) -> Result<bool, Throw> {
1184 self.native_cx().loose_equals(x, y)
1185 }
1186
1187 pub fn same_value(&mut self, x: Value, y: Value) -> bool {
1189 self.native_cx().same_value(x, y)
1190 }
1191
1192 pub fn same_value_zero(&self, x: Value, y: Value) -> bool {
1194 ops::same_value_zero_heap(&self.heap, x, y)
1195 }
1196
1197 pub fn type_of(&mut self, value: Value) -> String {
1199 self.native_cx().type_of(value)
1200 }
1201
1202 pub fn kind_of(&self, value: Value) -> Kind {
1204 value.kind()
1205 }
1206
1207 pub fn run_gc(&mut self) {
1211 self.native_cx().run_gc()
1212 }
1213}