Skip to main content

pipa/runtime/
context.rs

1use super::atom::{Atom, AtomTable};
2use super::event_loop::EventLoop;
3use super::extension::MacroTaskExtension;
4use super::runtime::JSRuntime;
5use crate::builtins;
6use crate::builtins::promise::{Microtask, MicrotaskQueue};
7use crate::compiler::codegen::OptLevel;
8use crate::host::HostFunction;
9use crate::object::JSObject;
10use crate::object::ShapeCache;
11use crate::util::FxHashMap;
12use crate::value::JSValue;
13
14#[allow(non_snake_case)]
15pub struct CommonAtoms {
16    pub length: Atom,
17    pub prototype: Atom,
18    pub constructor: Atom,
19    pub call: Atom,
20    pub apply: Atom,
21    pub bind: Atom,
22    pub to_string: Atom,
23    pub value_of: Atom,
24    pub push: Atom,
25    pub pop: Atom,
26    pub shift: Atom,
27    pub unshift: Atom,
28    pub slice: Atom,
29    pub splice: Atom,
30    pub join: Atom,
31    pub map: Atom,
32    pub for_each: Atom,
33    pub filter: Atom,
34    pub reduce: Atom,
35    pub index_of: Atom,
36    pub last_index_of: Atom,
37    pub includes: Atom,
38    pub concat: Atom,
39    pub reverse: Atom,
40    pub sort: Atom,
41    pub flat: Atom,
42    pub flat_map: Atom,
43    pub find: Atom,
44    pub find_index: Atom,
45    pub every: Atom,
46    pub some: Atom,
47    pub fill: Atom,
48    pub keys: Atom,
49    pub values: Atom,
50    pub entries: Atom,
51    pub has_own_property: Atom,
52    pub is_prototype_of: Atom,
53    pub property_is_enumerable: Atom,
54    pub to_locale_string: Atom,
55    pub split: Atom,
56    pub replace: Atom,
57    pub match_atom: Atom,
58    pub search: Atom,
59    pub test: Atom,
60    pub exec: Atom,
61    pub then: Atom,
62    pub catch: Atom,
63    pub finally: Atom,
64    pub message: Atom,
65    pub name: Atom,
66    pub stack: Atom,
67    pub __proto__: Atom,
68    pub __super__: Atom,
69    pub __boundFn: Atom,
70    pub __boundArgs: Atom,
71    pub __boundThis: Atom,
72    pub __value__: Atom,
73    pub __dateValue__: Atom,
74    pub __pattern__: Atom,
75    pub __flags__: Atom,
76    pub source: Atom,
77    pub global: Atom,
78    pub ignore_case: Atom,
79    pub multiline: Atom,
80    pub sticky: Atom,
81    pub unicode: Atom,
82    pub undefined: Atom,
83    pub null: Atom,
84    pub object: Atom,
85    pub function: Atom,
86    pub number: Atom,
87    pub string: Atom,
88    pub boolean: Atom,
89    pub symbol: Atom,
90    pub bigint: Atom,
91    pub math: Atom,
92    pub json: Atom,
93    pub array: Atom,
94    pub regexp: Atom,
95    pub error: Atom,
96    pub date: Atom,
97    pub promise: Atom,
98    pub map_ctor: Atom,
99    pub set_ctor: Atom,
100    pub weak_map_ctor: Atom,
101    pub weak_set_ctor: Atom,
102    pub proxy: Atom,
103    pub reflect: Atom,
104    pub console: Atom,
105    pub index: Atom,
106    pub input: Atom,
107    pub empty: Atom,
108    pub n0: Atom,
109    pub n1: Atom,
110
111    pub typeof_undefined: Atom,
112    pub typeof_object: Atom,
113    pub typeof_boolean: Atom,
114    pub typeof_number: Atom,
115    pub typeof_bigint: Atom,
116    pub typeof_symbol: Atom,
117    pub typeof_string: Atom,
118    pub typeof_function: Atom,
119
120    pub dot_all: Atom,
121    pub last_index: Atom,
122    pub callee: Atom,
123    pub default_: Atom,
124    pub url: Atom,
125    pub __promise_state__: Atom,
126    pub __promise_result__: Atom,
127    pub __done__: Atom,
128    pub __iter_arr__: Atom,
129    pub __iter_idx__: Atom,
130}
131
132impl CommonAtoms {
133    pub fn new(tbl: &mut AtomTable) -> Self {
134        CommonAtoms {
135            length: tbl.intern("length"),
136            prototype: tbl.intern("prototype"),
137            constructor: tbl.intern("constructor"),
138            call: tbl.intern("call"),
139            apply: tbl.intern("apply"),
140            bind: tbl.intern("bind"),
141            to_string: tbl.intern("toString"),
142            value_of: tbl.intern("valueOf"),
143            push: tbl.intern("push"),
144            pop: tbl.intern("pop"),
145            shift: tbl.intern("shift"),
146            unshift: tbl.intern("unshift"),
147            slice: tbl.intern("slice"),
148            splice: tbl.intern("splice"),
149            join: tbl.intern("join"),
150            map: tbl.intern("map"),
151            for_each: tbl.intern("forEach"),
152            filter: tbl.intern("filter"),
153            reduce: tbl.intern("reduce"),
154            index_of: tbl.intern("indexOf"),
155            last_index_of: tbl.intern("lastIndexOf"),
156            includes: tbl.intern("includes"),
157            concat: tbl.intern("concat"),
158            reverse: tbl.intern("reverse"),
159            sort: tbl.intern("sort"),
160            flat: tbl.intern("flat"),
161            flat_map: tbl.intern("flatMap"),
162            find: tbl.intern("find"),
163            find_index: tbl.intern("findIndex"),
164            every: tbl.intern("every"),
165            some: tbl.intern("some"),
166            fill: tbl.intern("fill"),
167            keys: tbl.intern("keys"),
168            values: tbl.intern("values"),
169            entries: tbl.intern("entries"),
170            has_own_property: tbl.intern("hasOwnProperty"),
171            is_prototype_of: tbl.intern("isPrototypeOf"),
172            property_is_enumerable: tbl.intern("propertyIsEnumerable"),
173            to_locale_string: tbl.intern("toLocaleString"),
174            split: tbl.intern("split"),
175            replace: tbl.intern("replace"),
176            match_atom: tbl.intern("match"),
177            search: tbl.intern("search"),
178            test: tbl.intern("test"),
179            exec: tbl.intern("exec"),
180            then: tbl.intern("then"),
181            catch: tbl.intern("catch"),
182            finally: tbl.intern("finally"),
183            message: tbl.intern("message"),
184            name: tbl.intern("name"),
185            stack: tbl.intern("stack"),
186            __proto__: tbl.intern("__proto__"),
187            __super__: tbl.intern("__super__"),
188            __boundFn: tbl.intern("__boundFn"),
189            __boundArgs: tbl.intern("__boundArgs"),
190            __boundThis: tbl.intern("__boundThis"),
191            __value__: tbl.intern("__value__"),
192            __dateValue__: tbl.intern("__dateValue__"),
193            __pattern__: tbl.intern("__pattern__"),
194            __flags__: tbl.intern("__flags__"),
195            source: tbl.intern("source"),
196            global: tbl.intern("global"),
197            ignore_case: tbl.intern("ignoreCase"),
198            multiline: tbl.intern("multiline"),
199            sticky: tbl.intern("sticky"),
200            unicode: tbl.intern("unicode"),
201            undefined: tbl.intern("undefined"),
202            null: tbl.intern("null"),
203            object: tbl.intern("Object"),
204            function: tbl.intern("Function"),
205            number: tbl.intern("Number"),
206            string: tbl.intern("String"),
207            boolean: tbl.intern("Boolean"),
208            symbol: tbl.intern("Symbol"),
209            bigint: tbl.intern("BigInt"),
210            math: tbl.intern("Math"),
211            json: tbl.intern("JSON"),
212            array: tbl.intern("Array"),
213            regexp: tbl.intern("RegExp"),
214            error: tbl.intern("Error"),
215            date: tbl.intern("Date"),
216            promise: tbl.intern("Promise"),
217            map_ctor: tbl.intern("Map"),
218            set_ctor: tbl.intern("Set"),
219            weak_map_ctor: tbl.intern("WeakMap"),
220            weak_set_ctor: tbl.intern("WeakSet"),
221            proxy: tbl.intern("Proxy"),
222            reflect: tbl.intern("Reflect"),
223            console: tbl.intern("console"),
224            index: tbl.intern("index"),
225            input: tbl.intern("input"),
226            empty: tbl.intern(""),
227            n0: tbl.intern("0"),
228            n1: tbl.intern("1"),
229            typeof_undefined: tbl.intern("undefined"),
230            typeof_object: tbl.intern("object"),
231            typeof_boolean: tbl.intern("boolean"),
232            typeof_number: tbl.intern("number"),
233            typeof_bigint: tbl.intern("bigint"),
234            typeof_symbol: tbl.intern("symbol"),
235            typeof_string: tbl.intern("string"),
236            typeof_function: tbl.intern("function"),
237            dot_all: tbl.intern("dotAll"),
238            last_index: tbl.intern("lastIndex"),
239            callee: tbl.intern("callee"),
240            default_: tbl.intern("default"),
241            url: tbl.intern("url"),
242            __promise_state__: tbl.intern("__promise_state__"),
243            __promise_result__: tbl.intern("__promise_result__"),
244            __done__: tbl.intern("__done__"),
245            __iter_arr__: tbl.intern("__iter_arr__"),
246            __iter_idx__: tbl.intern("__iter_idx__"),
247        }
248    }
249}
250
251pub struct JSContext {
252    runtime: *mut JSRuntime,
253    global_object: JSValue,
254    interrupt_counter: i32,
255    builtin_functions: FxHashMap<String, HostFunction>,
256
257    string_prototype: Option<usize>,
258    number_prototype: Option<usize>,
259    array_prototype: Option<usize>,
260    regexp_prototype: Option<usize>,
261    object_prototype: Option<usize>,
262    function_prototype: Option<usize>,
263    map_prototype: Option<usize>,
264    set_prototype: Option<usize>,
265    weakmap_prototype: Option<usize>,
266    weakset_prototype: Option<usize>,
267    error_prototype: Option<usize>,
268    type_error_prototype: Option<usize>,
269    reference_error_prototype: Option<usize>,
270    syntax_error_prototype: Option<usize>,
271    range_error_prototype: Option<usize>,
272    symbol_prototype: Option<usize>,
273    weakref_prototype: Option<usize>,
274    finalization_registry_prototype: Option<usize>,
275    pub finalization_registries: std::cell::RefCell<Vec<usize>>,
276    generator_prototype: Option<usize>,
277    async_generator_prototype: Option<usize>,
278    promise_prototype: Option<usize>,
279
280    register_vm_ptr: Option<usize>,
281    compiler_opt_level: OptLevel,
282
283    pub pending_exception: Option<JSValue>,
284
285    pending_callback: Option<PendingCallback>,
286
287    microtask_queue: MicrotaskQueue,
288
289    current_module_specifier: Option<String>,
290    import_meta_object: Option<usize>,
291
292    event_loop: EventLoop,
293
294    running_event_loop: Option<*mut EventLoop>,
295
296    shape_cache: ShapeCache,
297
298    pub common_atoms: CommonAtoms,
299
300    cached_int_atoms: [Atom; 100],
301
302    args_length_shape: Option<std::ptr::NonNull<crate::object::shape::Shape>>,
303}
304
305#[derive(Clone)]
306pub struct PendingCallback {
307    pub func: JSValue,
308
309    pub args: Vec<JSValue>,
310
311    pub is_method_call: bool,
312}
313
314impl JSContext {
315    const INTERRUPT_THRESHOLD: i32 = 1000;
316
317    pub fn new(runtime: &mut JSRuntime) -> Self {
318        let global = JSObject::new_global();
319        let global_ptr = Box::into_raw(Box::new(global)) as usize;
320        runtime.gc_heap_mut().track(global_ptr);
321        let global_value = JSValue::new_object(global_ptr);
322
323        let mut ctx = JSContext {
324            runtime: runtime as *mut JSRuntime,
325            global_object: global_value,
326            interrupt_counter: Self::INTERRUPT_THRESHOLD,
327            builtin_functions: FxHashMap::default(),
328            string_prototype: None,
329            number_prototype: None,
330            array_prototype: None,
331            regexp_prototype: None,
332            object_prototype: None,
333            function_prototype: None,
334            map_prototype: None,
335            set_prototype: None,
336            weakmap_prototype: None,
337            weakset_prototype: None,
338            error_prototype: None,
339            type_error_prototype: None,
340            reference_error_prototype: None,
341            syntax_error_prototype: None,
342            range_error_prototype: None,
343            symbol_prototype: None,
344            weakref_prototype: None,
345            finalization_registry_prototype: None,
346            finalization_registries: std::cell::RefCell::new(Vec::new()),
347            generator_prototype: None,
348            async_generator_prototype: None,
349            promise_prototype: None,
350            register_vm_ptr: None,
351            compiler_opt_level: OptLevel::default(),
352            pending_exception: None,
353            pending_callback: None,
354            microtask_queue: MicrotaskQueue::new(),
355            current_module_specifier: None,
356            import_meta_object: None,
357            event_loop: EventLoop::new(),
358            running_event_loop: None,
359            shape_cache: ShapeCache::new(),
360            common_atoms: CommonAtoms::new(runtime.atom_table_mut()),
361            cached_int_atoms: {
362                let mut arr = [Atom::empty(); 100];
363                for i in 0..100 {
364                    arr[i] = runtime.atom_table_mut().intern(&i.to_string());
365                }
366                arr
367            },
368            args_length_shape: None,
369        };
370
371        builtins::init_globals(&mut ctx);
372
373        ctx
374    }
375
376    #[inline(always)]
377    pub fn check_interrupt(&mut self) -> Result<(), String> {
378        self.interrupt_counter -= 1;
379        if self.interrupt_counter <= 0 {
380            self.interrupt_counter = Self::INTERRUPT_THRESHOLD;
381            if self.runtime_mut().is_interrupted() {
382                return Err("interrupted".to_string());
383            }
384        }
385        Ok(())
386    }
387
388    #[inline(always)]
389    pub fn reset_interrupt_counter(&mut self) {
390        self.interrupt_counter = 0;
391    }
392
393    pub fn runtime(&self) -> &JSRuntime {
394        unsafe { &*self.runtime }
395    }
396
397    pub fn runtime_mut(&mut self) -> &mut JSRuntime {
398        unsafe { &mut *self.runtime }
399    }
400
401    pub fn atom_table(&self) -> &AtomTable {
402        self.runtime().atom_table()
403    }
404
405    pub fn atom_table_mut(&mut self) -> &mut AtomTable {
406        self.runtime_mut().atom_table_mut()
407    }
408
409    pub fn shape_cache(&self) -> &ShapeCache {
410        &self.shape_cache
411    }
412
413    pub fn shape_cache_mut(&mut self) -> &mut ShapeCache {
414        &mut self.shape_cache
415    }
416
417    #[inline]
418    pub fn get_or_create_args_length_shape(
419        &mut self,
420    ) -> std::ptr::NonNull<crate::object::shape::Shape> {
421        if let Some(s) = self.args_length_shape {
422            return s;
423        }
424        let root = self.shape_cache.root_shape();
425        let s = self.shape_cache.transition(root, self.common_atoms.length);
426        self.args_length_shape = Some(s);
427        s
428    }
429
430    pub fn global(&self) -> JSValue {
431        self.global_object
432    }
433
434    pub fn set_global(&mut self, value: JSValue) {
435        self.global_object = value;
436    }
437
438    pub fn intern(&mut self, s: &str) -> Atom {
439        self.atom_table_mut().intern(s)
440    }
441
442    #[inline]
443    pub fn intern_concat(&mut self, a: &str, b: &str) -> Atom {
444        self.atom_table_mut().intern_concat(a, b)
445    }
446
447    #[inline]
448    pub fn intern_concat_atoms(&mut self, a: Atom, b: Atom) -> Atom {
449        self.atom_table_mut().intern_concat_atoms(a, b)
450    }
451
452    #[inline]
453    pub fn int_atom(&self, n: usize) -> Atom {
454        if n < 100 {
455            unsafe { *self.cached_int_atoms.get_unchecked(n) }
456        } else {
457            self.common_atoms.empty
458        }
459    }
460
461    #[inline]
462    pub fn int_atom_mut(&mut self, n: usize) -> Atom {
463        if n < 100 {
464            unsafe { *self.cached_int_atoms.get_unchecked(n) }
465        } else {
466            self.atom_table_mut().intern(&n.to_string())
467        }
468    }
469
470    pub fn intern_fast(&mut self, s: &str) -> Atom {
471        self.atom_table_mut().intern_fast(s)
472    }
473
474    pub fn lookup_atom(&self, s: &str) -> Option<Atom> {
475        self.atom_table().lookup(s)
476    }
477
478    pub fn get_atom_str(&self, atom: Atom) -> &str {
479        self.atom_table().get(atom)
480    }
481
482    #[inline]
483    pub fn string_char_count(&self, atom: Atom) -> usize {
484        self.atom_table().char_count(atom)
485    }
486
487    #[inline]
488    pub fn string_char_code_at(&self, atom: Atom, index: usize) -> Option<u32> {
489        self.atom_table().char_code_at(atom, index)
490    }
491
492    pub fn mark_symbol_atom(&mut self, atom: Atom) {
493        self.atom_table_mut().mark_symbol_atom(atom.index());
494    }
495
496    pub fn is_symbol_atom(&self, atom: Atom) -> bool {
497        self.atom_table().is_symbol_atom(atom.index())
498    }
499
500    pub fn register_builtin(&mut self, name: &str, func: HostFunction) {
501        self.builtin_functions.insert(name.to_string(), func);
502    }
503
504    pub fn register_global_builtin(&mut self, name: &'static str, arity: u32, func: crate::host::HostFunc) {
505        self.register_builtin(name, HostFunction::new(name, arity, func));
506        let mut f = crate::object::function::JSFunction::new_builtin(self.intern(name), arity);
507        f.set_builtin_marker(self, name);
508        let ptr = Box::into_raw(Box::new(f)) as usize;
509        self.runtime_mut().gc_heap_mut().track_function(ptr);
510        self.global()
511            .as_object_mut()
512            .set(self.intern(name), crate::value::JSValue::new_function(ptr));
513    }
514
515    pub fn call_builtin(&mut self, name: &str, args: &[JSValue]) -> JSValue {
516        let func = self.builtin_functions.get(name).cloned();
517        if let Some(f) = func {
518            f.call(self, args)
519        } else {
520            JSValue::undefined()
521        }
522    }
523
524    pub fn get_builtin_func(&self, name: &str) -> Option<crate::host::func::HostFunc> {
525        self.builtin_functions.get(name).map(|f| f.func)
526    }
527
528    pub fn call_builtin_direct(
529        &mut self,
530        func: crate::host::func::HostFunc,
531        args: &[JSValue],
532    ) -> JSValue {
533        func(self, args)
534    }
535
536    pub fn set_string_prototype(&mut self, ptr: usize) {
537        self.string_prototype = Some(ptr);
538    }
539
540    pub fn set_number_prototype(&mut self, ptr: usize) {
541        self.number_prototype = Some(ptr);
542    }
543
544    pub fn set_array_prototype(&mut self, ptr: usize) {
545        self.array_prototype = Some(ptr);
546    }
547
548    pub fn set_regexp_prototype(&mut self, ptr: usize) {
549        self.regexp_prototype = Some(ptr);
550    }
551
552    pub fn set_object_prototype(&mut self, ptr: usize) {
553        self.object_prototype = Some(ptr);
554    }
555
556    pub fn set_function_prototype(&mut self, ptr: usize) {
557        self.function_prototype = Some(ptr);
558    }
559
560    pub fn set_map_prototype(&mut self, ptr: usize) {
561        self.map_prototype = Some(ptr);
562    }
563
564    pub fn set_set_prototype(&mut self, ptr: usize) {
565        self.set_prototype = Some(ptr);
566    }
567
568    pub fn get_string_prototype(&self) -> Option<*mut JSObject> {
569        self.string_prototype.map(|p| p as *mut JSObject)
570    }
571
572    pub fn get_number_prototype(&self) -> Option<*mut JSObject> {
573        self.number_prototype.map(|p| p as *mut JSObject)
574    }
575
576    pub fn get_array_prototype(&self) -> Option<*mut JSObject> {
577        self.array_prototype.map(|p| p as *mut JSObject)
578    }
579
580    pub fn get_regexp_prototype(&self) -> Option<*mut JSObject> {
581        self.regexp_prototype.map(|p| p as *mut JSObject)
582    }
583
584    pub fn get_object_prototype(&self) -> Option<*mut JSObject> {
585        self.object_prototype.map(|p| p as *mut JSObject)
586    }
587
588    pub fn get_function_prototype(&self) -> Option<*mut JSObject> {
589        self.function_prototype.map(|p| p as *mut JSObject)
590    }
591
592    pub fn get_map_prototype(&self) -> Option<*mut JSObject> {
593        self.map_prototype.map(|p| p as *mut JSObject)
594    }
595
596    pub fn get_set_prototype(&self) -> Option<*mut JSObject> {
597        self.set_prototype.map(|p| p as *mut JSObject)
598    }
599
600    pub fn set_weakmap_prototype(&mut self, ptr: usize) {
601        self.weakmap_prototype = Some(ptr);
602    }
603
604    pub fn get_weakmap_prototype(&self) -> Option<*mut JSObject> {
605        self.weakmap_prototype.map(|p| p as *mut JSObject)
606    }
607
608    pub fn set_weakset_prototype(&mut self, ptr: usize) {
609        self.weakset_prototype = Some(ptr);
610    }
611
612    pub fn get_weakset_prototype(&self) -> Option<*mut JSObject> {
613        self.weakset_prototype.map(|p| p as *mut JSObject)
614    }
615
616    pub fn set_error_prototype(&mut self, ptr: usize) {
617        self.error_prototype = Some(ptr);
618    }
619
620    pub fn get_error_prototype(&self) -> Option<*mut JSObject> {
621        self.error_prototype.map(|p| p as *mut JSObject)
622    }
623
624    pub fn set_type_error_prototype(&mut self, ptr: usize) {
625        self.type_error_prototype = Some(ptr);
626    }
627
628    pub fn get_type_error_prototype(&self) -> Option<*mut JSObject> {
629        self.type_error_prototype.map(|p| p as *mut JSObject)
630    }
631
632    pub fn set_reference_error_prototype(&mut self, ptr: usize) {
633        self.reference_error_prototype = Some(ptr);
634    }
635
636    pub fn get_reference_error_prototype(&self) -> Option<*mut JSObject> {
637        self.reference_error_prototype.map(|p| p as *mut JSObject)
638    }
639
640    pub fn set_range_error_prototype(&mut self, ptr: usize) {
641        self.range_error_prototype = Some(ptr);
642    }
643
644    pub fn get_range_error_prototype(&self) -> Option<*mut JSObject> {
645        self.range_error_prototype.map(|p| p as *mut JSObject)
646    }
647
648    pub fn set_syntax_error_prototype(&mut self, ptr: usize) {
649        self.syntax_error_prototype = Some(ptr);
650    }
651
652    pub fn get_syntax_error_prototype(&self) -> Option<*mut JSObject> {
653        self.syntax_error_prototype.map(|p| p as *mut JSObject)
654    }
655
656    pub fn set_symbol_prototype(&mut self, ptr: usize) {
657        self.symbol_prototype = Some(ptr);
658    }
659
660    pub fn get_symbol_prototype(&self) -> Option<*mut JSObject> {
661        self.symbol_prototype.map(|p| p as *mut JSObject)
662    }
663
664    pub fn set_weakref_prototype(&mut self, ptr: usize) {
665        self.weakref_prototype = Some(ptr);
666    }
667
668    pub fn get_weakref_prototype(&self) -> Option<*mut JSObject> {
669        self.weakref_prototype.map(|p| p as *mut JSObject)
670    }
671
672    pub fn set_finalization_registry_prototype(&mut self, ptr: usize) {
673        self.finalization_registry_prototype = Some(ptr);
674    }
675
676    pub fn get_finalization_registry_prototype(&self) -> Option<*mut JSObject> {
677        self.finalization_registry_prototype
678            .map(|p| p as *mut JSObject)
679    }
680
681    pub fn set_generator_prototype(&mut self, ptr: usize) {
682        self.generator_prototype = Some(ptr);
683    }
684
685    pub fn get_generator_prototype(&self) -> Option<*mut JSObject> {
686        self.generator_prototype.map(|p| p as *mut JSObject)
687    }
688
689    pub fn set_async_generator_prototype(&mut self, ptr: usize) {
690        self.async_generator_prototype = Some(ptr);
691    }
692
693    pub fn get_async_generator_prototype(&self) -> Option<*mut JSObject> {
694        self.async_generator_prototype.map(|p| p as *mut JSObject)
695    }
696
697    pub fn set_promise_prototype(&mut self, ptr: usize) {
698        self.promise_prototype = Some(ptr);
699    }
700
701    pub fn get_promise_prototype(&self) -> Option<*mut JSObject> {
702        self.promise_prototype.map(|p| p as *mut JSObject)
703    }
704
705    pub fn set_register_vm_ptr(&mut self, ptr: Option<usize>) {
706        self.register_vm_ptr = ptr;
707    }
708
709    pub fn get_register_vm_ptr(&self) -> Option<usize> {
710        self.register_vm_ptr
711    }
712
713    pub fn add_extension(&mut self, ext: Box<dyn MacroTaskExtension>) {
714        self.event_loop_mut().extensions.push(ext);
715    }
716
717    pub fn set_compiler_opt_level(&mut self, opt_level: OptLevel) {
718        self.compiler_opt_level = opt_level;
719    }
720
721    pub fn get_compiler_opt_level(&self) -> OptLevel {
722        self.compiler_opt_level
723    }
724
725    pub fn set_pending_callback(&mut self, callback: PendingCallback) {
726        self.pending_callback = Some(callback);
727    }
728
729    pub fn take_pending_callback(&mut self) -> Option<PendingCallback> {
730        self.pending_callback.take()
731    }
732
733    pub fn has_pending_callback(&self) -> bool {
734        self.pending_callback.is_some()
735    }
736
737    pub fn microtask_enqueue(&mut self, task: Microtask) {
738        self.microtask_queue.enqueue(task);
739    }
740
741    pub fn microtask_is_empty(&self) -> bool {
742        self.microtask_queue.is_empty()
743    }
744
745    pub fn microtask_dequeue(&mut self) -> Option<Microtask> {
746        self.microtask_queue.dequeue()
747    }
748
749    pub fn set_current_module(&mut self, specifier: Option<String>) {
750        self.current_module_specifier = specifier;
751    }
752
753    pub fn get_current_module(&self) -> Option<&str> {
754        self.current_module_specifier.as_deref()
755    }
756
757    pub fn set_import_meta(&mut self, ptr: Option<usize>) {
758        self.import_meta_object = ptr;
759    }
760
761    pub fn get_import_meta(&self) -> Option<usize> {
762        self.import_meta_object
763    }
764
765    pub fn event_loop(&self) -> &EventLoop {
766        &self.event_loop
767    }
768
769    pub fn event_loop_mut(&mut self) -> &mut EventLoop {
770        if let Some(ptr) = self.running_event_loop {
771            unsafe { &mut *ptr }
772        } else {
773            &mut self.event_loop
774        }
775    }
776
777    pub fn run_event_loop(&mut self) -> Result<super::event_loop::EventLoopResult, String> {
778        let mut event_loop = std::mem::take(&mut self.event_loop);
779
780        self.running_event_loop = Some(&mut event_loop as *mut EventLoop);
781        let result = event_loop.run_until_complete(self, None);
782        self.running_event_loop = None;
783        self.event_loop = event_loop;
784        result
785    }
786
787    pub fn run_event_loop_with_timeout(
788        &mut self,
789        timeout_ms: u64,
790    ) -> Result<super::event_loop::EventLoopResult, String> {
791        let mut event_loop = std::mem::take(&mut self.event_loop);
792
793        self.running_event_loop = Some(&mut event_loop as *mut EventLoop);
794        let result = event_loop.run_until_complete(self, Some(timeout_ms));
795        self.running_event_loop = None;
796        self.event_loop = event_loop;
797        result
798    }
799}