boa/
context.rs

1//! Javascript context.
2
3use crate::{
4    builtins::{
5        self,
6        function::{Function, FunctionFlags, NativeFunction},
7        iterable::IteratorPrototypes,
8    },
9    class::{Class, ClassBuilder},
10    exec::Interpreter,
11    object::{FunctionBuilder, JsObject, Object, PROTOTYPE},
12    property::{Attribute, PropertyDescriptor, PropertyKey},
13    realm::Realm,
14    syntax::{
15        ast::{
16            node::{
17                statement_list::RcStatementList, Call, FormalParameter, Identifier, New,
18                StatementList,
19            },
20            Const, Node,
21        },
22        Parser,
23    },
24    BoaProfiler, Executable, JsResult, JsString, JsValue,
25};
26
27#[cfg(feature = "console")]
28use crate::builtins::console::Console;
29
30#[cfg(feature = "vm")]
31use crate::vm::Vm;
32
33/// Store a builtin constructor (such as `Object`) and its corresponding prototype.
34#[derive(Debug, Clone)]
35pub struct StandardConstructor {
36    pub(crate) constructor: JsObject,
37    pub(crate) prototype: JsObject,
38}
39
40impl Default for StandardConstructor {
41    fn default() -> Self {
42        Self {
43            constructor: JsObject::new(Object::default()),
44            prototype: JsObject::new(Object::default()),
45        }
46    }
47}
48
49impl StandardConstructor {
50    /// Build a constructor with a defined prototype.
51    fn with_prototype(prototype: Object) -> Self {
52        Self {
53            constructor: JsObject::new(Object::default()),
54            prototype: JsObject::new(prototype),
55        }
56    }
57
58    /// Return the constructor object.
59    ///
60    /// This is the same as `Object`, `Array`, etc.
61    #[inline]
62    pub fn constructor(&self) -> JsObject {
63        self.constructor.clone()
64    }
65
66    /// Return the prototype of the constructor object.
67    ///
68    /// This is the same as `Object.prototype`, `Array.prototype`, etc
69    #[inline]
70    pub fn prototype(&self) -> JsObject {
71        self.prototype.clone()
72    }
73}
74
75/// Cached core standard objects.
76#[derive(Debug, Clone)]
77pub struct StandardObjects {
78    object: StandardConstructor,
79    function: StandardConstructor,
80    array: StandardConstructor,
81    bigint: StandardConstructor,
82    number: StandardConstructor,
83    boolean: StandardConstructor,
84    string: StandardConstructor,
85    regexp: StandardConstructor,
86    symbol: StandardConstructor,
87    error: StandardConstructor,
88    type_error: StandardConstructor,
89    referece_error: StandardConstructor,
90    range_error: StandardConstructor,
91    syntax_error: StandardConstructor,
92    eval_error: StandardConstructor,
93    uri_error: StandardConstructor,
94    map: StandardConstructor,
95    set: StandardConstructor,
96}
97
98impl Default for StandardObjects {
99    fn default() -> Self {
100        Self {
101            object: StandardConstructor::default(),
102            function: StandardConstructor::default(),
103            array: StandardConstructor::default(),
104            bigint: StandardConstructor::default(),
105            number: StandardConstructor::with_prototype(Object::number(0.0)),
106            boolean: StandardConstructor::with_prototype(Object::boolean(false)),
107            string: StandardConstructor::with_prototype(Object::string("")),
108            regexp: StandardConstructor::default(),
109            symbol: StandardConstructor::default(),
110            error: StandardConstructor::default(),
111            type_error: StandardConstructor::default(),
112            referece_error: StandardConstructor::default(),
113            range_error: StandardConstructor::default(),
114            syntax_error: StandardConstructor::default(),
115            eval_error: StandardConstructor::default(),
116            uri_error: StandardConstructor::default(),
117            map: StandardConstructor::default(),
118            set: StandardConstructor::default(),
119        }
120    }
121}
122
123impl StandardObjects {
124    #[inline]
125    pub fn object_object(&self) -> &StandardConstructor {
126        &self.object
127    }
128
129    #[inline]
130    pub fn function_object(&self) -> &StandardConstructor {
131        &self.function
132    }
133
134    #[inline]
135    pub fn array_object(&self) -> &StandardConstructor {
136        &self.array
137    }
138
139    #[inline]
140    pub fn bigint_object(&self) -> &StandardConstructor {
141        &self.bigint
142    }
143
144    #[inline]
145    pub fn number_object(&self) -> &StandardConstructor {
146        &self.number
147    }
148
149    #[inline]
150    pub fn boolean_object(&self) -> &StandardConstructor {
151        &self.boolean
152    }
153
154    #[inline]
155    pub fn string_object(&self) -> &StandardConstructor {
156        &self.string
157    }
158
159    #[inline]
160    pub fn regexp_object(&self) -> &StandardConstructor {
161        &self.regexp
162    }
163
164    #[inline]
165    pub fn symbol_object(&self) -> &StandardConstructor {
166        &self.symbol
167    }
168
169    #[inline]
170    pub fn error_object(&self) -> &StandardConstructor {
171        &self.error
172    }
173
174    #[inline]
175    pub fn reference_error_object(&self) -> &StandardConstructor {
176        &self.referece_error
177    }
178
179    #[inline]
180    pub fn type_error_object(&self) -> &StandardConstructor {
181        &self.type_error
182    }
183
184    #[inline]
185    pub fn range_error_object(&self) -> &StandardConstructor {
186        &self.range_error
187    }
188
189    #[inline]
190    pub fn syntax_error_object(&self) -> &StandardConstructor {
191        &self.syntax_error
192    }
193
194    #[inline]
195    pub fn eval_error_object(&self) -> &StandardConstructor {
196        &self.eval_error
197    }
198
199    #[inline]
200    pub fn uri_error_object(&self) -> &StandardConstructor {
201        &self.uri_error
202    }
203
204    #[inline]
205    pub fn map_object(&self) -> &StandardConstructor {
206        &self.map
207    }
208
209    #[inline]
210    pub fn set_object(&self) -> &StandardConstructor {
211        &self.set
212    }
213}
214
215/// Internal representation of the strict mode types.
216#[derive(Debug, Copy, Clone)]
217pub(crate) enum StrictType {
218    Off,
219    Global,
220    Function,
221}
222
223/// Javascript context. It is the primary way to interact with the runtime.
224///
225/// `Context`s constructed in a thread share the same runtime, therefore it
226/// is possible to share objects from one context to another context, but they
227/// have to be in the same thread.
228///
229/// # Examples
230///
231/// ## Execute Function of Script File
232///
233/// ```rust
234/// use boa::{Context, object::ObjectInitializer, property::{Attribute, PropertyDescriptor}};
235///
236/// let script = r#"
237/// function test(arg1) {
238///     if(arg1 != null) {
239///         return arg1.x;
240///     }
241///     return 112233;
242/// }
243/// "#;
244///
245/// let mut context = Context::new();
246///
247/// // Populate the script definition to the context.
248/// context.eval(script).unwrap();
249///
250/// // Create an object that can be used in eval calls.
251/// let arg = ObjectInitializer::new(&mut context)
252///     .property("x", 12, Attribute::READONLY)
253///     .build();
254/// context.register_global_property(
255///     "arg",
256///     arg,
257///     Attribute::all()
258/// );
259///
260/// let value = context.eval("test(arg)").unwrap();
261///
262/// assert_eq!(value.as_number(), Some(12.0))
263/// ```
264#[derive(Debug)]
265pub struct Context {
266    /// realm holds both the global object and the environment
267    pub(crate) realm: Realm,
268
269    /// The current executor.
270    executor: Interpreter,
271
272    /// console object state.
273    #[cfg(feature = "console")]
274    console: Console,
275
276    /// Cached iterator prototypes.
277    iterator_prototypes: IteratorPrototypes,
278
279    /// Cached standard objects and their prototypes.
280    standard_objects: StandardObjects,
281
282    /// Whether or not to show trace of instructions being ran
283    pub trace: bool,
284
285    /// Whether or not strict mode is active.
286    strict: StrictType,
287}
288
289impl Default for Context {
290    fn default() -> Self {
291        let realm = Realm::create();
292        let executor = Interpreter::new();
293        let mut context = Self {
294            realm,
295            executor,
296            #[cfg(feature = "console")]
297            console: Console::default(),
298            iterator_prototypes: IteratorPrototypes::default(),
299            standard_objects: Default::default(),
300            trace: false,
301            strict: StrictType::Off,
302        };
303
304        // Add new builtIns to Context Realm
305        // At a later date this can be removed from here and called explicitly,
306        // but for now we almost always want these default builtins
307        context.create_intrinsics();
308        context.iterator_prototypes = IteratorPrototypes::init(&mut context);
309        context
310    }
311}
312
313impl Context {
314    /// Create a new `Context`.
315    #[inline]
316    pub fn new() -> Self {
317        Default::default()
318    }
319
320    #[inline]
321    pub fn executor(&mut self) -> &mut Interpreter {
322        &mut self.executor
323    }
324
325    /// A helper function for getting an immutable reference to the `console` object.
326    #[cfg(feature = "console")]
327    pub(crate) fn console(&self) -> &Console {
328        &self.console
329    }
330
331    /// A helper function for getting a mutable reference to the `console` object.
332    #[cfg(feature = "console")]
333    #[inline]
334    pub(crate) fn console_mut(&mut self) -> &mut Console {
335        &mut self.console
336    }
337
338    /// Returns if strict mode is currently active.
339    #[inline]
340    pub fn strict(&self) -> bool {
341        matches!(self.strict, StrictType::Global | StrictType::Function)
342    }
343
344    /// Returns the strict mode type.
345    #[inline]
346    pub(crate) fn strict_type(&self) -> StrictType {
347        self.strict
348    }
349
350    /// Set strict type.
351    #[inline]
352    pub(crate) fn set_strict(&mut self, strict: StrictType) {
353        self.strict = strict;
354    }
355
356    /// Disable the strict mode.
357    #[inline]
358    pub fn set_strict_mode_off(&mut self) {
359        self.strict = StrictType::Off;
360    }
361
362    /// Enable the global strict mode.
363    #[inline]
364    pub fn set_strict_mode_global(&mut self) {
365        self.strict = StrictType::Global;
366    }
367
368    /// Sets up the default global objects within Global
369    #[inline]
370    fn create_intrinsics(&mut self) {
371        let _timer = BoaProfiler::global().start_event("create_intrinsics", "interpreter");
372        // Create intrinsics, add global objects here
373        builtins::init(self);
374    }
375
376    /// Construct an empty object.
377    #[inline]
378    pub fn construct_object(&self) -> JsObject {
379        let object_prototype: JsValue = self.standard_objects().object_object().prototype().into();
380        JsObject::new(Object::create(object_prototype))
381    }
382
383    /// <https://tc39.es/ecma262/#sec-call>
384    #[inline]
385    pub(crate) fn call(
386        &mut self,
387        f: &JsValue,
388        this: &JsValue,
389        args: &[JsValue],
390    ) -> JsResult<JsValue> {
391        match *f {
392            JsValue::Object(ref object) => object.call(this, args, self),
393            _ => self.throw_type_error("not a function"),
394        }
395    }
396
397    /// Return the global object.
398    #[inline]
399    pub fn global_object(&self) -> JsObject {
400        self.realm.global_object.clone()
401    }
402
403    /// Constructs a `Error` with the specified message.
404    #[inline]
405    pub fn construct_error<M>(&mut self, message: M) -> JsValue
406    where
407        M: Into<Box<str>>,
408    {
409        // Runs a `new Error(message)`.
410        New::from(Call::new(
411            Identifier::from("Error"),
412            vec![Const::from(message.into()).into()],
413        ))
414        .run(self)
415        .expect("Into<String> used as message")
416    }
417
418    /// Throws a `Error` with the specified message.
419    #[inline]
420    pub fn throw_error<M>(&mut self, message: M) -> JsResult<JsValue>
421    where
422        M: Into<Box<str>>,
423    {
424        Err(self.construct_error(message))
425    }
426
427    /// Constructs a `RangeError` with the specified message.
428    #[inline]
429    pub fn construct_range_error<M>(&mut self, message: M) -> JsValue
430    where
431        M: Into<Box<str>>,
432    {
433        // Runs a `new RangeError(message)`.
434        New::from(Call::new(
435            Identifier::from("RangeError"),
436            vec![Const::from(message.into()).into()],
437        ))
438        .run(self)
439        .expect("Into<String> used as message")
440    }
441
442    /// Throws a `RangeError` with the specified message.
443    #[inline]
444    pub fn throw_range_error<M>(&mut self, message: M) -> JsResult<JsValue>
445    where
446        M: Into<Box<str>>,
447    {
448        Err(self.construct_range_error(message))
449    }
450
451    /// Constructs a `TypeError` with the specified message.
452    #[inline]
453    pub fn construct_type_error<M>(&mut self, message: M) -> JsValue
454    where
455        M: Into<Box<str>>,
456    {
457        // Runs a `new TypeError(message)`.
458        New::from(Call::new(
459            Identifier::from("TypeError"),
460            vec![Const::from(message.into()).into()],
461        ))
462        .run(self)
463        .expect("Into<String> used as message")
464    }
465
466    /// Throws a `TypeError` with the specified message.
467    #[inline]
468    pub fn throw_type_error<M>(&mut self, message: M) -> JsResult<JsValue>
469    where
470        M: Into<Box<str>>,
471    {
472        Err(self.construct_type_error(message))
473    }
474
475    /// Constructs a `ReferenceError` with the specified message.
476    #[inline]
477    pub fn construct_reference_error<M>(&mut self, message: M) -> JsValue
478    where
479        M: Into<Box<str>>,
480    {
481        New::from(Call::new(
482            Identifier::from("ReferenceError"),
483            vec![Const::from(message.into()).into()],
484        ))
485        .run(self)
486        .expect("Into<String> used as message")
487    }
488
489    /// Throws a `ReferenceError` with the specified message.
490    #[inline]
491    pub fn throw_reference_error<M>(&mut self, message: M) -> JsResult<JsValue>
492    where
493        M: Into<Box<str>>,
494    {
495        Err(self.construct_reference_error(message))
496    }
497
498    /// Constructs a `SyntaxError` with the specified message.
499    #[inline]
500    pub fn construct_syntax_error<M>(&mut self, message: M) -> JsValue
501    where
502        M: Into<Box<str>>,
503    {
504        New::from(Call::new(
505            Identifier::from("SyntaxError"),
506            vec![Const::from(message.into()).into()],
507        ))
508        .run(self)
509        .expect("Into<String> used as message")
510    }
511
512    /// Throws a `SyntaxError` with the specified message.
513    #[inline]
514    pub fn throw_syntax_error<M>(&mut self, message: M) -> JsResult<JsValue>
515    where
516        M: Into<Box<str>>,
517    {
518        Err(self.construct_syntax_error(message))
519    }
520
521    /// Constructs a `EvalError` with the specified message.
522    pub fn construct_eval_error<M>(&mut self, message: M) -> JsValue
523    where
524        M: Into<Box<str>>,
525    {
526        New::from(Call::new(
527            Identifier::from("EvalError"),
528            vec![Const::from(message.into()).into()],
529        ))
530        .run(self)
531        .expect("Into<String> used as message")
532    }
533
534    /// Constructs a `URIError` with the specified message.
535    pub fn construct_uri_error<M>(&mut self, message: M) -> JsValue
536    where
537        M: Into<Box<str>>,
538    {
539        New::from(Call::new(
540            Identifier::from("URIError"),
541            vec![Const::from(message.into()).into()],
542        ))
543        .run(self)
544        .expect("Into<String> used as message")
545    }
546
547    /// Throws a `EvalError` with the specified message.
548    pub fn throw_eval_error<M>(&mut self, message: M) -> JsResult<JsValue>
549    where
550        M: Into<Box<str>>,
551    {
552        Err(self.construct_eval_error(message))
553    }
554
555    /// Throws a `URIError` with the specified message.
556    pub fn throw_uri_error<M>(&mut self, message: M) -> JsResult<JsValue>
557    where
558        M: Into<Box<str>>,
559    {
560        Err(self.construct_uri_error(message))
561    }
562
563    /// Utility to create a function Value for Function Declarations, Arrow Functions or Function Expressions
564    pub(crate) fn create_function<N, P>(
565        &mut self,
566        name: N,
567        params: P,
568        mut body: StatementList,
569        flags: FunctionFlags,
570    ) -> JsResult<JsValue>
571    where
572        N: Into<JsString>,
573        P: Into<Box<[FormalParameter]>>,
574    {
575        let name = name.into();
576        let function_prototype: JsValue =
577            self.standard_objects().function_object().prototype().into();
578
579        // Every new function has a prototype property pre-made
580        let prototype = self.construct_object();
581
582        // If a function is defined within a strict context, it is strict.
583        if self.strict() {
584            body.set_strict(true);
585        }
586
587        let params = params.into();
588        let params_len = params.len();
589        let func = Function::Ordinary {
590            flags,
591            body: RcStatementList::from(body),
592            params,
593            environment: self.get_current_environment().clone(),
594        };
595
596        let function = JsObject::new(Object::function(func, function_prototype));
597
598        // Set constructor field to the newly created Value (function object)
599        let constructor = PropertyDescriptor::builder()
600            .value(function.clone())
601            .writable(true)
602            .enumerable(false)
603            .configurable(true);
604        prototype.define_property_or_throw("constructor", constructor, self)?;
605
606        let prototype = PropertyDescriptor::builder()
607            .value(prototype)
608            .writable(true)
609            .enumerable(false)
610            .configurable(false);
611        function.define_property_or_throw(PROTOTYPE, prototype, self)?;
612
613        let length = PropertyDescriptor::builder()
614            .value(params_len)
615            .writable(false)
616            .enumerable(false)
617            .configurable(true);
618        function.define_property_or_throw("length", length, self)?;
619
620        let name = PropertyDescriptor::builder()
621            .value(name)
622            .writable(false)
623            .enumerable(false)
624            .configurable(true);
625        function.define_property_or_throw("name", name, self)?;
626
627        Ok(function.into())
628    }
629
630    /// Register a global native function.
631    ///
632    /// This is more efficient that creating a closure function, since this does not allocate,
633    /// it is just a function pointer.
634    ///
635    /// The function will be both `constructable` (call with `new`).
636    ///
637    /// The function will be bound to the global object with `writable`, `non-enumerable`
638    /// and `configurable` attributes. The same as when you create a function in JavaScript.
639    ///
640    /// # Note
641    ///
642    /// If you want to make a function only `constructable`, or wish to bind it differently
643    /// to the global object, you can create the function object with [`FunctionBuilder`](crate::object::FunctionBuilder::native).
644    /// And bind it to the global object with [`Context::register_global_property`](Context::register_global_property) method.
645    #[inline]
646    pub fn register_global_function(
647        &mut self,
648        name: &str,
649        length: usize,
650        body: NativeFunction,
651    ) -> JsResult<()> {
652        let function = FunctionBuilder::native(self, body)
653            .name(name)
654            .length(length)
655            .constructable(true)
656            .build();
657
658        self.global_object().insert_property(
659            name,
660            PropertyDescriptor::builder()
661                .value(function)
662                .writable(true)
663                .enumerable(false)
664                .configurable(true),
665        );
666        Ok(())
667    }
668
669    /// Register a global closure function.
670    ///
671    /// The function will be both `constructable` (call with `new`).
672    ///
673    /// The function will be bound to the global object with `writable`, `non-enumerable`
674    /// and `configurable` attributes. The same as when you create a function in JavaScript.
675    ///
676    /// # Note #1
677    ///
678    /// If you want to make a function only `constructable`, or wish to bind it differently
679    /// to the global object, you can create the function object with [`FunctionBuilder`](crate::object::FunctionBuilder::closure).
680    /// And bind it to the global object with [`Context::register_global_property`](Context::register_global_property) method.
681    ///
682    /// # Note #2
683    ///
684    /// This function will only accept `Copy` closures, meaning you cannot
685    /// move `Clone` types, just `Copy` types. If you need to move `Clone` types
686    /// as captures, see [`FunctionBuilder::closure_with_captures`].
687    ///
688    /// See <https://github.com/boa-dev/boa/issues/1515> for an explanation on
689    /// why we need to restrict the set of accepted closures.
690    #[inline]
691    pub fn register_global_closure<F>(&mut self, name: &str, length: usize, body: F) -> JsResult<()>
692    where
693        F: Fn(&JsValue, &[JsValue], &mut Context) -> JsResult<JsValue> + Copy + 'static,
694    {
695        let function = FunctionBuilder::closure(self, body)
696            .name(name)
697            .length(length)
698            .constructable(true)
699            .build();
700
701        self.global_object().insert_property(
702            name,
703            PropertyDescriptor::builder()
704                .value(function)
705                .writable(true)
706                .enumerable(false)
707                .configurable(true),
708        );
709        Ok(())
710    }
711
712    /// <https://tc39.es/ecma262/#sec-hasproperty>
713    #[inline]
714    pub(crate) fn has_property(&mut self, obj: &JsValue, key: &PropertyKey) -> JsResult<bool> {
715        if let Some(obj) = obj.as_object() {
716            obj.__has_property__(key, self)
717        } else {
718            Ok(false)
719        }
720    }
721
722    #[inline]
723    pub(crate) fn set_value(&mut self, node: &Node, value: JsValue) -> JsResult<JsValue> {
724        match node {
725            Node::Identifier(ref name) => {
726                self.set_mutable_binding(name.as_ref(), value.clone(), true)?;
727                Ok(value)
728            }
729            Node::GetConstField(ref get_const_field_node) => Ok(get_const_field_node
730                .obj()
731                .run(self)?
732                .set_field(get_const_field_node.field(), value, false, self)?),
733            Node::GetField(ref get_field) => {
734                let field = get_field.field().run(self)?;
735                let key = field.to_property_key(self)?;
736                Ok(get_field
737                    .obj()
738                    .run(self)?
739                    .set_field(key, value, false, self)?)
740            }
741            _ => self.throw_type_error(format!("invalid assignment to {}", node)),
742        }
743    }
744
745    /// Register a global class of type `T`, where `T` implements `Class`.
746    ///
747    /// # Example
748    /// ```ignore
749    /// #[derive(Debug, Trace, Finalize)]
750    /// struct MyClass;
751    ///
752    /// impl Class for MyClass {
753    ///    // ...
754    /// }
755    ///
756    /// context.register_global_class::<MyClass>();
757    /// ```
758    #[inline]
759    pub fn register_global_class<T>(&mut self) -> JsResult<()>
760    where
761        T: Class,
762    {
763        let mut class_builder = ClassBuilder::new::<T>(self);
764        T::init(&mut class_builder)?;
765
766        let class = class_builder.build();
767        let property = PropertyDescriptor::builder()
768            .value(class)
769            .writable(T::ATTRIBUTES.writable())
770            .enumerable(T::ATTRIBUTES.enumerable())
771            .configurable(T::ATTRIBUTES.configurable());
772        self.global_object().insert(T::NAME, property);
773        Ok(())
774    }
775
776    /// Register a global property.
777    ///
778    /// # Example
779    /// ```
780    /// use boa::{Context, property::{Attribute, PropertyDescriptor}, object::ObjectInitializer};
781    ///
782    /// let mut context = Context::new();
783    ///
784    /// context.register_global_property(
785    ///     "myPrimitiveProperty",
786    ///     10,
787    ///     Attribute::all()
788    /// );
789    ///
790    /// let object = ObjectInitializer::new(&mut context)
791    ///    .property(
792    ///         "x",
793    ///         0,
794    ///         Attribute::all()
795    ///     )
796    ///     .property(
797    ///         "y",
798    ///         1,
799    ///         Attribute::all()
800    ///     )
801    ///    .build();
802    /// context.register_global_property(
803    ///     "myObjectProperty",
804    ///     object,
805    ///     Attribute::all()
806    /// );
807    /// ```
808    #[inline]
809    pub fn register_global_property<K, V>(&mut self, key: K, value: V, attribute: Attribute)
810    where
811        K: Into<PropertyKey>,
812        V: Into<JsValue>,
813    {
814        self.global_object().insert(
815            key,
816            PropertyDescriptor::builder()
817                .value(value)
818                .writable(attribute.writable())
819                .enumerable(attribute.enumerable())
820                .configurable(attribute.configurable()),
821        );
822    }
823
824    /// Evaluates the given code.
825    ///
826    /// # Examples
827    /// ```
828    ///# use boa::Context;
829    /// let mut context = Context::new();
830    ///
831    /// let value = context.eval("1 + 3").unwrap();
832    ///
833    /// assert!(value.is_number());
834    /// assert_eq!(value.as_number().unwrap(), 4.0);
835    /// ```
836    #[cfg(not(feature = "vm"))]
837    #[allow(clippy::unit_arg, clippy::drop_copy)]
838    #[inline]
839    pub fn eval<T: AsRef<[u8]>>(&mut self, src: T) -> JsResult<JsValue> {
840        let main_timer = BoaProfiler::global().start_event("Main", "Main");
841        let src_bytes: &[u8] = src.as_ref();
842
843        let parsing_result = Parser::new(src_bytes, false)
844            .parse_all()
845            .map_err(|e| e.to_string());
846
847        let execution_result = match parsing_result {
848            Ok(statement_list) => {
849                if statement_list.strict() {
850                    self.set_strict_mode_global();
851                }
852                statement_list.run(self)
853            }
854            Err(e) => self.throw_syntax_error(e),
855        };
856
857        // The main_timer needs to be dropped before the BoaProfiler is.
858        drop(main_timer);
859        BoaProfiler::global().drop();
860
861        execution_result
862    }
863
864    /// Evaluates the given code by compiling down to bytecode, then interpreting the bytecode into a value
865    ///
866    /// # Examples
867    /// ```
868    ///# use boa::Context;
869    /// let mut context = Context::new();
870    ///
871    /// let value = context.eval("1 + 3").unwrap();
872    ///
873    /// assert!(value.is_number());
874    /// assert_eq!(value.as_number().unwrap(), 4.0);
875    /// ```
876    #[cfg(feature = "vm")]
877    #[allow(clippy::unit_arg, clippy::drop_copy)]
878    pub fn eval<T: AsRef<[u8]>>(&mut self, src: T) -> JsResult<JsValue> {
879        let main_timer = BoaProfiler::global().start_event("Main", "Main");
880        let src_bytes: &[u8] = src.as_ref();
881
882        let parsing_result = Parser::new(src_bytes, false)
883            .parse_all()
884            .map_err(|e| e.to_string());
885
886        let statement_list = match parsing_result {
887            Ok(statement_list) => statement_list,
888            Err(e) => return self.throw_syntax_error(e),
889        };
890
891        let mut compiler = crate::bytecompiler::ByteCompiler::default();
892        compiler.compile_statement_list(&statement_list, true);
893        let code_block = compiler.finish();
894        let mut vm = Vm::new(code_block, self);
895        let result = vm.run();
896
897        // The main_timer needs to be dropped before the BoaProfiler is.
898        drop(main_timer);
899        BoaProfiler::global().drop();
900
901        result
902    }
903
904    /// Return the cached iterator prototypes.
905    #[inline]
906    pub fn iterator_prototypes(&self) -> &IteratorPrototypes {
907        &self.iterator_prototypes
908    }
909
910    /// Return the core standard objects.
911    #[inline]
912    pub fn standard_objects(&self) -> &StandardObjects {
913        &self.standard_objects
914    }
915
916    /// Set the value of trace on the context
917    pub fn set_trace(&mut self, trace: bool) {
918        self.trace = trace;
919    }
920}