1use crate::PropertyKey;
5use crate::bytecode::{self, CodeStore, CodeUnit, CodeUnitId, ValidateError};
6use crate::heap::atom::KeyKind;
7use crate::heap::gc::{Handle, HeapLimits};
8use crate::heap::object::ObjectKind;
9use crate::heap::{Heap, HeapError};
10use crate::value::{ObjectId, ScopeId, StringId, SymbolId, Value};
11use crate::vm::regexp::RegExpStore;
12use crate::vm::{Cx, ErrorKind, Output, Services, Throw, VmStack};
13
14macro_rules! intrinsics {
15 ($($(#[$doc:meta])* $name:ident,)*) => {
16 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
19 #[repr(u8)]
20 pub enum Intrinsic {
21 $($(#[$doc])* $name,)*
22 }
23
24 impl Intrinsic {
25 pub const ALL: &'static [Intrinsic] = &[$(Intrinsic::$name,)*];
26 pub const COUNT: usize = Intrinsic::ALL.len();
27 }
28 };
29}
30
31intrinsics! {
32 ObjectPrototype,
33 FunctionPrototype,
34 ArrayPrototype,
35 StringPrototype,
36 RegExpPrototype,
37 NumberPrototype,
38 BooleanPrototype,
39 SymbolPrototype,
40 BigIntPrototype,
41 DatePrototype,
42 ErrorPrototype,
43 EvalErrorPrototype,
44 RangeErrorPrototype,
45 ReferenceErrorPrototype,
46 SyntaxErrorPrototype,
47 TypeErrorPrototype,
48 InternalErrorPrototype,
49 UriErrorPrototype,
50 AggregateErrorPrototype,
51 OutOfMemoryError,
54 ThrowTypeError,
56 Object,
57 Function,
58 Array,
59 String,
60 Number,
61 Boolean,
62 Symbol,
63 BigInt,
64 RegExp,
65 Date,
66 Promise,
67 Proxy,
68 Eval,
69 IteratorPrototype,
70 AsyncIteratorPrototype,
71 ArrayIteratorPrototype,
72 StringIteratorPrototype,
73 MapIteratorPrototype,
74 SetIteratorPrototype,
75 RegExpStringIteratorPrototype,
76 IteratorHelperPrototype,
77 Iterator,
78 WrapForValidIteratorPrototype,
79 AsyncFromSyncIteratorPrototype,
80 GeneratorFunctionPrototype,
82 GeneratorPrototype,
84 AsyncFunctionPrototype,
85 AsyncGeneratorFunctionPrototype,
86 AsyncGeneratorPrototype,
87 GeneratorFunction,
88 AsyncFunction,
89 AsyncGeneratorFunction,
90 PromisePrototype,
91 MapPrototype,
92 SetPrototype,
93 WeakMapPrototype,
94 WeakSetPrototype,
95 WeakRefPrototype,
96 FinalizationRegistryPrototype,
97 ArrayBufferPrototype,
98 SharedArrayBufferPrototype,
99 DataViewPrototype,
100 TypedArray,
101 TypedArrayPrototype,
102 Int8ArrayPrototype,
103 Uint8ArrayPrototype,
104 Uint8ClampedArrayPrototype,
105 Int16ArrayPrototype,
106 Uint16ArrayPrototype,
107 Int32ArrayPrototype,
108 Uint32ArrayPrototype,
109 Float16ArrayPrototype,
110 Float32ArrayPrototype,
111 Float64ArrayPrototype,
112 BigInt64ArrayPrototype,
113 BigUint64ArrayPrototype,
114 Int8Array,
115 Uint8Array,
116 Uint8ClampedArray,
117 Int16Array,
118 Uint16Array,
119 Int32Array,
120 Uint32Array,
121 Float16Array,
122 Float32Array,
123 Float64Array,
124 BigInt64Array,
125 BigUint64Array,
126 ArrayBuffer,
127 ArrayValues,
129 GlobalLexical,
131}
132
133macro_rules! names {
134 ($($field:ident: $text:expr,)*) => {
135 #[derive(Clone, Copy, Debug)]
139 pub(crate) struct Names {
140 $(pub $field: StringId,)*
141 }
142
143 impl Names {
144 fn new(heap: &mut Heap) -> Result<Names, HeapError> {
145 Ok(Names {
146 $($field: heap.intern($text)?,)*
147 })
148 }
149 }
150 };
151}
152
153names! {
154 length: "length",
155 callee: "callee",
156 caller: "caller",
157 arguments: "arguments",
158 last_index: "lastIndex",
159 index: "index",
160 indices: "indices",
161 input: "input",
162 groups: "groups",
163 prototype: "prototype",
164 constructor: "constructor",
165 message: "message",
166 name: "name",
167 cause: "cause",
168 stack: "stack",
169 file_name: "fileName",
170 line_number: "lineNumber",
171 column_number: "columnNumber",
172 errors: "errors",
173 value_of: "valueOf",
174 to_string: "toString",
175 to_json: "toJSON",
176 undefined: "undefined",
177 null: "null",
178 true_: "true",
179 false_: "false",
180 object: "object",
181 boolean: "boolean",
182 number: "number",
183 string: "string",
184 symbol: "symbol",
185 function: "function",
186 bigint: "bigint",
187 empty: "",
188 value: "value",
189 writable: "writable",
190 enumerable: "enumerable",
191 configurable: "configurable",
192 get: "get",
193 set: "set",
194 next: "next",
195 done: "done",
196 return_: "return",
197 throw: "throw",
198 then: "then",
199 proto: "__proto__",
200 raw: "raw",
201 join: "join",
202 default: "default",
203 flags: "flags",
204 source: "source",
205 exec: "exec",
206 size: "size",
207 iterator_tag: "Iterator",
208 resolve: "resolve",
209 reject: "reject",
210 promise: "promise",
211 status: "status",
212 reason: "reason",
213 fulfilled: "fulfilled",
214 rejected: "rejected",
215}
216
217impl Names {
218 #[inline]
219 pub fn key(id: StringId) -> PropertyKey {
220 PropertyKey::atom(id)
221 }
222}
223
224macro_rules! well_known {
225 ($($field:ident: $text:expr,)*) => {
226 #[derive(Clone, Copy, Debug)]
228 pub(crate) struct WellKnown {
229 $(pub $field: SymbolId,)*
230 }
231
232 impl WellKnown {
233 fn new(heap: &mut Heap) -> Result<WellKnown, HeapError> {
234 Ok(WellKnown {
235 $($field: {
236 let description = heap.intern($text)?;
237 let symbol = heap.alloc_symbol(Some(description), false)?;
238 heap.add_fixed_root(Value::symbol(symbol));
239 symbol
240 },)*
241 })
242 }
243
244 pub fn all(&self) -> Vec<(&'static str, SymbolId)> {
246 vec![$((&$text["Symbol.".len()..], self.$field),)*]
247 }
248 }
249 };
250}
251
252well_known! {
253 async_iterator: "Symbol.asyncIterator",
254 has_instance: "Symbol.hasInstance",
255 is_concat_spreadable: "Symbol.isConcatSpreadable",
256 iterator: "Symbol.iterator",
257 match_: "Symbol.match",
258 match_all: "Symbol.matchAll",
259 replace: "Symbol.replace",
260 search: "Symbol.search",
261 species: "Symbol.species",
262 split: "Symbol.split",
263 to_primitive: "Symbol.toPrimitive",
264 to_string_tag: "Symbol.toStringTag",
265 unscopables: "Symbol.unscopables",
266}
267
268impl WellKnown {
269 #[inline]
270 pub fn key(id: SymbolId) -> PropertyKey {
271 PropertyKey::symbol(id)
272 }
273}
274
275pub struct Realm {
277 global: ObjectId,
278 intrinsics: [std::cell::Cell<ObjectId>; Intrinsic::COUNT],
281 pub(crate) names: Names,
282 pub(crate) symbols: WellKnown,
283 pub(crate) brand: SymbolId,
285 pub(crate) regexp_flags: std::cell::Cell<Option<crate::builtins::RegExpFlagCache>>,
288 pub(crate) regexp_instance_shape: std::cell::Cell<Option<(crate::value::ShapeId, u32)>>,
291}
292
293impl Realm {
294 #[inline]
295 pub fn global(&self) -> ObjectId {
296 self.global
297 }
298
299 #[inline]
300 pub fn intrinsic(&self, intrinsic: Intrinsic) -> ObjectId {
301 self.intrinsics[intrinsic as usize].get()
302 }
303
304 pub(crate) fn record_intrinsic(&self, intrinsic: Intrinsic, object: ObjectId) {
306 self.intrinsics[intrinsic as usize].set(object);
307 }
308}
309
310pub struct Runtime {
311 pub(crate) heap: Heap,
312 pub(crate) code: CodeStore,
315 pub(crate) realm: Realm,
316 pub(crate) host: Services,
317}
318
319#[derive(Clone, Copy, Debug, PartialEq)]
322pub struct RuntimeOptions {
323 pub heap: HeapLimits,
325 pub min_heap: usize,
327 pub growth: f64,
330 pub stack_limit: u32,
333 pub native_stack_budget: usize,
335 pub native_depth_limit: u32,
339}
340
341impl Default for RuntimeOptions {
342 fn default() -> Self {
343 RuntimeOptions {
344 heap: HeapLimits::default(),
345 min_heap: crate::heap::gc::DEFAULT_MIN_HEAP,
346 growth: 2.0,
347 stack_limit: crate::vm::DEFAULT_STACK_LIMIT,
348 native_stack_budget: crate::vm::NATIVE_STACK_BUDGET,
349 native_depth_limit: u32::MAX,
350 }
351 }
352}
353
354impl From<HeapLimits> for RuntimeOptions {
355 fn from(heap: HeapLimits) -> Self {
356 RuntimeOptions {
357 heap,
358 ..RuntimeOptions::default()
359 }
360 }
361}
362
363#[derive(Clone, Debug, Default, PartialEq, Eq)]
365pub struct ThrownSummary {
366 pub name: Option<String>,
367 pub message: Option<String>,
368 pub stack: Option<String>,
369}
370
371impl Runtime {
372 pub fn new(options: impl Into<RuntimeOptions>) -> Result<Runtime, HeapError> {
373 let options = options.into();
374 let mut heap = Heap::new(options.heap);
375 let reserved = heap.bytes();
376 heap.gc
377 .configure(options.min_heap, options.growth, reserved);
378 heap.vm.limit = options.stack_limit;
379 heap.vm.native_budget = options.native_stack_budget;
380 heap.vm.native_depth = options.native_depth_limit;
381 let root = |heap: &mut Heap, object: ObjectId| {
382 heap.add_fixed_root(Value::object(object));
383 object
384 };
385 let object_prototype = heap.alloc_object(ObjectKind::Ordinary, None, 4)?;
386 let object_prototype = root(&mut heap, object_prototype);
387 let function_prototype = heap.alloc_native_function(
390 Some(object_prototype),
391 crate::builtins::Native::FunctionPrototype.index(),
392 )?;
393 let function_prototype = root(&mut heap, function_prototype);
394 let array_prototype = heap.alloc_array(Some(object_prototype), 0)?;
396 let array_prototype = root(&mut heap, array_prototype);
397 let string_prototype =
398 heap.alloc_object(ObjectKind::Ordinary, Some(object_prototype), 4)?;
399 let string_prototype = root(&mut heap, string_prototype);
400 let regexp_prototype =
401 heap.alloc_object(ObjectKind::Ordinary, Some(object_prototype), 4)?;
402 let regexp_prototype = root(&mut heap, regexp_prototype);
403 let number_prototype = heap.alloc_internal(
407 ObjectKind::NumberWrapper,
408 crate::heap::object::InternalTag::None,
409 Some(object_prototype),
410 4,
411 &[Value::int32(0)],
412 Default::default(),
413 0,
414 )?;
415 let number_prototype = root(&mut heap, number_prototype);
416 let boolean_prototype = heap.alloc_internal(
417 ObjectKind::BooleanWrapper,
418 crate::heap::object::InternalTag::None,
419 Some(object_prototype),
420 4,
421 &[Value::FALSE],
422 Default::default(),
423 0,
424 )?;
425 let boolean_prototype = root(&mut heap, boolean_prototype);
426 let global = heap.alloc_object(ObjectKind::GlobalObject, Some(object_prototype), 16)?;
427 let global = root(&mut heap, global);
428 let lexical = heap.alloc_object(ObjectKind::GlobalObject, None, 16)?;
431 let lexical = root(&mut heap, lexical);
432 let names = Names::new(&mut heap)?;
433 let symbols = WellKnown::new(&mut heap)?;
434 let brand = heap.alloc_symbol(None, true)?;
435 heap.add_fixed_root(Value::symbol(brand));
436 let mut intrinsics = [object_prototype; Intrinsic::COUNT];
437 intrinsics[Intrinsic::FunctionPrototype as usize] = function_prototype;
438 intrinsics[Intrinsic::ArrayPrototype as usize] = array_prototype;
439 intrinsics[Intrinsic::StringPrototype as usize] = string_prototype;
440 intrinsics[Intrinsic::RegExpPrototype as usize] = regexp_prototype;
441 intrinsics[Intrinsic::NumberPrototype as usize] = number_prototype;
442 intrinsics[Intrinsic::BooleanPrototype as usize] = boolean_prototype;
443 intrinsics[Intrinsic::GlobalLexical as usize] = lexical;
444 let error_prototype = heap.alloc_object(ObjectKind::Ordinary, Some(object_prototype), 4)?;
445 intrinsics[Intrinsic::ErrorPrototype as usize] = root(&mut heap, error_prototype);
446 for kind in ErrorKind::ALL {
447 if kind != ErrorKind::Error {
448 let prototype =
449 heap.alloc_object(ObjectKind::Ordinary, Some(error_prototype), 4)?;
450 intrinsics[kind.prototype() as usize] = root(&mut heap, prototype);
451 }
452 }
453 let realm = Realm {
454 global,
455 intrinsics: intrinsics.map(std::cell::Cell::new),
456 names,
457 symbols,
458 brand,
459 regexp_flags: std::cell::Cell::new(None),
460 regexp_instance_shape: std::cell::Cell::new(None),
461 };
462 let mut runtime = Runtime {
463 heap,
464 code: CodeStore::default(),
465 realm,
466 host: Services::default(),
467 };
468 let out_of_memory = crate::builtins::install(&mut runtime.cx())?;
469 runtime.set_intrinsic(Intrinsic::OutOfMemoryError, out_of_memory);
470 runtime.heap.set_atom_mode(crate::heap::AtomMode::Weak);
473 Ok(runtime)
474 }
475
476 fn installing<T>(&mut self, install: impl FnOnce(&mut Cx<'_>) -> T) -> T {
479 self.native_cx().installing(install)
480 }
481
482 #[inline]
484 pub(crate) fn cx(&mut self) -> Cx<'_> {
485 Cx {
486 heap: &mut self.heap,
487 static_code: &self.code,
488 realm: &self.realm,
489 host: &mut self.host,
490 }
491 }
492
493 pub(crate) fn set_intrinsic(&mut self, intrinsic: Intrinsic, object: ObjectId) {
494 self.heap.add_fixed_root(Value::object(object));
495 self.realm.record_intrinsic(intrinsic, object);
496 }
497
498 pub fn regexps(&self) -> &RegExpStore {
499 &self.heap.regexps
500 }
501
502 pub fn realm(&self) -> &Realm {
503 &self.realm
504 }
505
506 pub fn host(&mut self) -> &mut Services {
507 &mut self.host
508 }
509
510 pub fn set_can_block(&mut self, can_block: bool) {
513 self.host.can_block = can_block;
514 }
515
516 pub fn set_host(&mut self, mut hooks: Box<dyn crate::host::Host>) {
519 let seed = hooks.random_seed();
520 self.host.seed_random(seed);
521 self.host.hooks = hooks;
522 }
523
524 pub fn set_track_rejections(&mut self, track: bool) {
528 self.host.track_rejections = track;
529 if !track {
530 self.heap.rejections.clear();
531 }
532 }
533
534 pub fn unhandled_rejections(&self) -> &[Value] {
536 &self.heap.rejections
537 }
538
539 pub fn clear_unhandled_rejections(&mut self) {
540 self.heap.rejections.clear();
541 }
542
543 pub fn capture_output(&mut self) {
545 self.host.output = Output::Capture(String::new());
546 }
547
548 pub fn take_output(&mut self) -> String {
550 match &mut self.host.output {
551 Output::Capture(text) => std::mem::take(text),
552 Output::Stdout => String::new(),
553 }
554 }
555
556 pub fn install_test262_host(&mut self) -> Result<(), HeapError> {
558 self.installing(crate::builtins::test262::install)
559 }
560
561 pub fn install_print(&mut self) -> Result<(), HeapError> {
563 self.installing(crate::builtins::install_print)
564 }
565
566 pub fn install_std(&mut self) -> Result<(), HeapError> {
569 self.native_cx().install_std()
570 }
571
572 pub fn install_qjs_helpers(&mut self, script_args: Option<&[String]>) -> Result<(), HeapError> {
575 self.native_cx().install_qjs_helpers(script_args)
576 }
577
578 pub fn install_script_args(&mut self, args: &[String]) -> Result<(), HeapError> {
580 self.installing(|cx| crate::builtins::install_script_args(cx, args))
581 }
582
583 pub fn run_script(&mut self, script: ObjectId) -> Result<Value, Throw> {
586 self.native_cx().run_script(script)
587 }
588
589 pub fn run_jobs(&mut self) -> Result<(), Throw> {
592 crate::vm::jobs::run_jobs(&mut self.cx())
593 }
594
595 pub fn run_pending_job(&mut self) -> Result<bool, Throw> {
598 crate::vm::jobs::run_one_job(&mut self.cx())
599 }
600
601 pub fn clear_kept_objects(&mut self) {
603 self.heap.kept.clear();
604 }
605
606 pub fn has_pending_jobs(&self) -> bool {
608 !self.heap.jobs.is_empty()
609 }
610
611 pub fn call(&mut self, function: Value, this: Value, args: &[Value]) -> Result<Value, Throw> {
614 self.native_cx().call(function, this, args)
615 }
616
617 pub fn display(&mut self, value: Value) -> Result<String, Throw> {
620 crate::vm::ops::display(&mut self.cx(), value)
621 }
622
623 pub fn vm_stack(&self) -> &VmStack {
625 &self.heap.vm
626 }
627
628 pub fn set_stack_limit(&mut self, registers: u32) {
629 self.heap.vm.limit = registers;
630 }
631
632 pub fn set_native_stack_budget(&mut self, bytes: usize) {
636 self.heap.vm.native_budget = bytes;
637 }
638
639 #[inline]
640 pub fn heap(&self) -> &Heap {
641 &self.heap
642 }
643
644 #[inline]
645 pub fn heap_mut(&mut self) -> &mut Heap {
646 &mut self.heap
647 }
648
649 #[inline]
650 pub fn code(&self) -> &CodeStore {
651 &self.code
652 }
653
654 #[inline]
656 pub fn units(&self) -> crate::bytecode::Units<'_> {
657 crate::bytecode::Units {
658 code: &self.code,
659 dynamic: &self.heap.code,
660 }
661 }
662
663 #[inline]
666 pub fn heap_and_code(&mut self) -> (&mut Heap, &CodeStore) {
667 (&mut self.heap, &self.code)
668 }
669
670 pub fn publish(&mut self, unit: CodeUnit) -> Result<CodeUnitId, ValidateError> {
673 self.compiler().publish(unit)
674 }
675
676 pub fn instantiate(
681 &mut self,
682 root: CodeUnitId,
683 constants: &[&[Value]],
684 ) -> Result<ObjectId, HeapError> {
685 self.compiler().instantiate(root, constants)
686 }
687
688 pub fn compiler(&mut self) -> crate::vm::compile::Compiler<'_> {
692 crate::vm::compile::Compiler::owned(&mut self.heap, &mut self.code, &self.realm)
693 }
694
695 pub fn transient_compiler(&mut self) -> crate::vm::compile::Compiler<'_> {
699 crate::vm::compile::Compiler::new(&mut self.heap, &self.code, &self.realm)
700 }
701
702 pub fn set_compiler(&mut self, compile: crate::vm::compile::CompileFn) {
705 self.host.compile = Some(compile);
706 }
707
708 pub fn ic_report(&self, worst: usize) -> Option<String> {
713 use std::fmt::Write;
714
715 use crate::vm::ic::IcKind;
716 let ics = self.heap.ics();
717 let stats = ics.stats()?;
718 let mut out = String::new();
719 let _ = writeln!(
720 out,
721 "{:<10}{:>14}{:>14}{:>14}{:>14}{:>9}",
722 "ic", "mono hits", "poly hits", "fills", "unfilled", "hit %"
723 );
724 let kinds = [IcKind::Get, IcKind::Set, IcKind::Global, IcKind::Construct];
725 for kind in kinds {
726 let k = kind as usize;
727 let hits = stats.mono_hits[k] + stats.poly_hits[k];
728 let total = hits + stats.fills[k] + stats.unfilled[k];
729 let rate = if total == 0 {
730 0.0
731 } else {
732 100.0 * hits as f64 / total as f64
733 };
734 let _ = writeln!(
735 out,
736 "{:<10}{:>14}{:>14}{:>14}{:>14}{:>8.2}%",
737 kind.name(),
738 stats.mono_hits[k],
739 stats.poly_hits[k],
740 stats.fills[k],
741 stats.unfilled[k],
742 rate
743 );
744 }
745 let (mono, poly, mega) = ics.site_states();
746 let _ = writeln!(
747 out,
748 "sites: {} entries, {mono} monomorphic, {poly} polymorphic, {mega} megamorphic",
749 ics.len()
750 );
751 let _ = writeln!(
752 out,
753 "iteration: {} pristine arrays, {} through the protocol",
754 stats.iter_pristine, stats.iter_generic
755 );
756 let mut sites = Vec::new();
757 for (id, unit) in self.units().all() {
758 for (pc, insn) in unit.code.iter().enumerate() {
759 if let Some(site) = insn.site() {
760 let entry = (unit.ic_base + site) as usize;
761 let misses = stats.site_misses[entry];
762 if misses > 0 {
763 sites.push((misses, id, pc, *insn));
764 }
765 }
766 }
767 }
768 sites.sort_by_key(|&(misses, id, pc, _)| (std::cmp::Reverse(misses), id, pc));
769 for &(misses, id, pc, insn) in sites.iter().take(worst) {
770 let unit = self.units().get(id);
771 let name = if unit.debug.name.is_empty() {
772 "<anonymous>"
773 } else {
774 &unit.debug.name
775 };
776 let key = match insn.op {
777 crate::bytecode::Opcode::New => String::new(),
778 _ => crate::vm::property::key_text(&self.heap, insn.key()),
779 };
780 let _ = writeln!(
781 out,
782 " {misses:>10} misses {name} @{pc} {} {key}",
783 insn.op.name()
784 );
785 }
786 Some(out)
787 }
788
789 pub fn disassemble(&self, unit: CodeUnitId) -> String {
791 let heap = &self.heap;
792 bytecode::disassemble(&self.units().get(unit), &mut |key| match key.kind() {
793 KeyKind::String(id) => format!(".{}", heap.string_text(id)),
794 _ => bytecode::disasm::key_placeholder(key),
795 })
796 }
797
798 pub fn global_object(&self) -> ObjectId {
799 self.realm.global
800 }
801
802 pub fn intrinsic(&self, intrinsic: Intrinsic) -> ObjectId {
803 self.realm.intrinsic(intrinsic)
804 }
805
806 pub fn template_object(
809 &mut self,
810 cooked: &[Value],
811 raw: &[Value],
812 ) -> Result<ObjectId, HeapError> {
813 self.compiler().template_object(cooked, raw)
814 }
815
816 pub fn new_object(&mut self) -> Result<ObjectId, HeapError> {
818 self.native_cx().new_object()
819 }
820
821 pub fn new_array(&mut self, capacity: u32) -> Result<ObjectId, HeapError> {
822 let prototype = self.intrinsic(Intrinsic::ArrayPrototype);
823 self.heap.alloc_array(Some(prototype), capacity)
824 }
825
826 pub fn new_function(&mut self, scope: Option<ScopeId>) -> Result<ObjectId, HeapError> {
827 let prototype = self.intrinsic(Intrinsic::FunctionPrototype);
828 self.heap.alloc_function(Some(prototype), scope)
829 }
830
831 pub fn new_scope(&mut self, parent: Option<ScopeId>, slots: u32) -> Result<ScopeId, HeapError> {
832 self.heap.alloc_scope(parent, slots)
833 }
834
835 pub fn thrown_summary(&mut self, value: Value) -> Option<ThrownSummary> {
842 let object = value.as_object()?;
843 let heap = &mut self.heap;
844 let (Ok(name), Ok(message), Ok(constructor)) = (
845 heap.intern("name"),
846 heap.intern("message"),
847 heap.intern("constructor"),
848 ) else {
849 return Some(ThrownSummary::default());
850 };
851 let heap = &self.heap;
852 let names = &self.realm.names;
853 let own = |object: ObjectId, key: StringId| {
854 crate::vm::property::own(heap, names, object, Names::key(key))
855 };
856 let own_string = |object: ObjectId, key: StringId| match own(object, key) {
857 Some(crate::vm::property::Found::Data(value)) => {
858 Some(value.as_string().map(|id| heap.string_text(id)))
859 }
860 Some(_) => Some(None),
861 None => None,
862 };
863 let named = |found: Option<Option<String>>| match found {
865 Some(Some(name)) if !name.is_empty() => Some(Some(name)),
866 Some(_) => Some(None),
867 None => None,
868 };
869 let error_name = named(own_string(object, name))
870 .or_else(|| {
871 let prototype = heap.prototype_of(object)?;
872 named(own_string(prototype, name)).or_else(|| {
873 let Some(crate::vm::property::Found::Data(function)) =
874 own(prototype, constructor)
875 else {
876 return Some(None);
877 };
878 let function = function.as_object()?;
879 Some(
880 own_string(function, name)
881 .flatten()
882 .filter(|name| !name.is_empty() && name != "Object"),
883 )
884 })
885 })
886 .flatten();
887 Some(ThrownSummary {
888 name: error_name,
889 message: own_string(object, message).flatten(),
890 stack: own_string(object, self.realm.names.stack).flatten(),
891 })
892 }
893
894 pub fn memory_report(&self) -> crate::heap::report::MemoryReport {
897 let mut report = self.heap.report();
898 let code = &mut report.code;
899 code.static_units = self.code.len();
900 for (_, unit) in self.units().all() {
901 code.units += 1;
902 code.instructions += unit.code.len();
903 code.instruction_bytes += std::mem::size_of_val(&*unit.code);
904 code.position_bytes += std::mem::size_of_val(&*unit.debug.positions);
905 code.source_bytes += unit.source.as_ref().map_or(0, |source| source.len());
906 }
907 report
908 }
909
910 pub fn hold(&mut self, value: Value) -> Handle {
912 self.native_cx().hold(value)
913 }
914
915 pub fn held(&self, handle: Handle) -> Value {
916 self.heap.handles_ref().get(handle)
917 }
918
919 pub fn release(&mut self, handle: Handle) {
920 self.native_cx().release(handle);
921 }
922}