1use crate::{
15 Context, JsArgs, JsExpect, JsResult, JsStr, JsString, JsValue, SpannedSourceText,
16 builtins::{
17 BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject, OrdinaryObject,
18 },
19 bytecompiler::FunctionCompiler,
20 context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
21 environments::{EnvironmentStack, FunctionSlots, PrivateEnvironment, ThisBindingStatus},
22 error::JsNativeError,
23 js_error, js_string,
24 native_function::NativeFunctionObject,
25 object::{
26 JsData, JsFunction, JsObject, PrivateElement, PrivateName,
27 internal_methods::{
28 CallValue, InternalMethodCallContext, InternalObjectMethods, ORDINARY_INTERNAL_METHODS,
29 get_prototype_from_constructor,
30 },
31 },
32 property::{Attribute, PropertyDescriptor, PropertyKey},
33 realm::Realm,
34 string::StaticJsStrings,
35 symbol::JsSymbol,
36 value::IntegerOrInfinity,
37 vm::{ActiveRunnable, CallFrame, CallFrameFlags, CodeBlock},
38};
39use boa_ast::{
40 Position, Span, Spanned, StatementList,
41 function::{FormalParameterList, FunctionBody},
42 operations::{
43 ContainsSymbol, all_private_identifiers_valid, bound_names, contains,
44 lexically_declared_names,
45 },
46 scope::BindingLocatorScope,
47};
48use boa_gc::{self, Finalize, Gc, Trace, custom_trace};
49use boa_interner::Sym;
50use boa_macros::js_str;
51use boa_parser::{Parser, Source};
52use thin_vec::ThinVec;
53
54use super::Proxy;
55
56pub(crate) mod arguments;
57mod bound;
58
59pub use bound::BoundFunction;
60
61#[cfg(test)]
62mod tests;
63
64#[derive(Debug, Trace, Finalize, PartialEq, Eq, Clone)]
71pub enum ThisMode {
72 Lexical,
74
75 Strict,
77
78 Global,
81}
82
83impl ThisMode {
84 #[must_use]
86 pub const fn is_lexical(&self) -> bool {
87 matches!(self, Self::Lexical)
88 }
89
90 #[must_use]
92 pub const fn is_strict(&self) -> bool {
93 matches!(self, Self::Strict)
94 }
95
96 #[must_use]
98 pub const fn is_global(&self) -> bool {
99 matches!(self, Self::Global)
100 }
101}
102
103#[derive(Clone, Copy, Debug, PartialEq, Eq)]
110pub enum ConstructorKind {
111 Base,
113
114 Derived,
116}
117
118impl ConstructorKind {
119 #[must_use]
121 pub const fn is_base(&self) -> bool {
122 matches!(self, Self::Base)
123 }
124
125 #[must_use]
127 pub const fn is_derived(&self) -> bool {
128 matches!(self, Self::Derived)
129 }
130}
131
132#[derive(Clone, Debug, Finalize)]
139pub enum ClassFieldDefinition {
140 Public(PropertyKey, JsFunction, Option<PropertyKey>),
142
143 Private(PrivateName, JsFunction),
145}
146
147unsafe impl Trace for ClassFieldDefinition {
148 custom_trace! {this, mark, {
149 match this {
150 Self::Public(_key, func, _) => {
151 mark(func);
152 }
153 Self::Private(_, func) => {
154 mark(func);
155 }
156 }
157 }}
158}
159
160#[derive(Debug, Trace, Finalize)]
167pub struct OrdinaryFunction {
168 pub(crate) code: Gc<CodeBlock>,
170
171 pub(crate) environments: EnvironmentStack,
173
174 pub(crate) home_object: Option<JsObject>,
176
177 pub(crate) script_or_module: Option<ActiveRunnable>,
179
180 pub(crate) realm: Realm,
182
183 fields: ThinVec<ClassFieldDefinition>,
185
186 private_methods: ThinVec<(PrivateName, PrivateElement)>,
188}
189
190impl JsData for OrdinaryFunction {
191 fn internal_methods(&self) -> &'static InternalObjectMethods {
192 static FUNCTION_METHODS: InternalObjectMethods = InternalObjectMethods {
193 __call__: function_call,
194 ..ORDINARY_INTERNAL_METHODS
195 };
196
197 static CONSTRUCTOR_METHODS: InternalObjectMethods = InternalObjectMethods {
198 __call__: function_call,
199 __construct__: function_construct,
200 ..ORDINARY_INTERNAL_METHODS
201 };
202
203 if self.code.has_prototype_property() {
204 &CONSTRUCTOR_METHODS
205 } else {
206 &FUNCTION_METHODS
207 }
208 }
209}
210
211impl OrdinaryFunction {
212 pub(crate) fn new(
213 code: Gc<CodeBlock>,
214 environments: EnvironmentStack,
215 script_or_module: Option<ActiveRunnable>,
216 realm: Realm,
217 ) -> Self {
218 Self {
219 code,
220 environments,
221 home_object: None,
222 script_or_module,
223 realm,
224 fields: ThinVec::default(),
225 private_methods: ThinVec::default(),
226 }
227 }
228
229 #[must_use]
231 pub fn codeblock(&self) -> &CodeBlock {
232 &self.code
233 }
234
235 pub(crate) fn push_private_environment(&mut self, environment: Gc<PrivateEnvironment>) {
237 self.environments.push_private(environment);
238 }
239
240 pub(crate) fn is_derived_constructor(&self) -> bool {
242 self.code.is_derived_constructor()
243 }
244
245 pub(crate) fn in_class_field_initializer(&self) -> bool {
247 self.code.in_class_field_initializer()
248 }
249
250 pub(crate) const fn get_home_object(&self) -> Option<&JsObject> {
252 self.home_object.as_ref()
253 }
254
255 pub(crate) fn set_home_object(&mut self, object: JsObject) {
257 self.home_object = Some(object);
258 }
259
260 pub(crate) fn get_fields(&self) -> &[ClassFieldDefinition] {
262 &self.fields
263 }
264
265 pub(crate) fn push_field(
267 &mut self,
268 key: PropertyKey,
269 value: JsFunction,
270 function_name: Option<PropertyKey>,
271 ) {
272 self.fields
273 .push(ClassFieldDefinition::Public(key, value, function_name));
274 }
275
276 pub(crate) fn push_field_private(&mut self, name: PrivateName, value: JsFunction) {
278 self.fields.push(ClassFieldDefinition::Private(name, value));
279 }
280
281 pub(crate) fn get_private_methods(&self) -> &[(PrivateName, PrivateElement)] {
283 &self.private_methods
284 }
285
286 pub(crate) fn push_private_method(&mut self, name: PrivateName, method: PrivateElement) {
288 self.private_methods.push((name, method));
289 }
290
291 #[must_use]
293 pub const fn realm(&self) -> &Realm {
294 &self.realm
295 }
296
297 pub(crate) fn is_ordinary(&self) -> bool {
299 self.code.is_ordinary()
300 }
301}
302
303#[derive(Debug, Clone, Copy)]
305pub struct BuiltInFunctionObject;
306
307impl IntrinsicObject for BuiltInFunctionObject {
308 fn init(realm: &Realm) {
309 let has_instance = BuiltInBuilder::callable(realm, Self::has_instance)
310 .name(js_string!("[Symbol.hasInstance]"))
311 .length(1)
312 .build();
313
314 let throw_type_error = realm.intrinsics().objects().throw_type_error();
315
316 BuiltInBuilder::from_standard_constructor::<Self>(realm)
317 .method(Self::apply, js_string!("apply"), 2)
318 .method(Self::bind, js_string!("bind"), 1)
319 .method(Self::call, js_string!("call"), 1)
320 .method(Self::to_string, js_string!("toString"), 0)
321 .property(JsSymbol::has_instance(), has_instance, Attribute::default())
322 .accessor(
323 js_string!("caller"),
324 Some(throw_type_error.clone()),
325 Some(throw_type_error.clone()),
326 Attribute::CONFIGURABLE,
327 )
328 .accessor(
329 js_string!("arguments"),
330 Some(throw_type_error.clone()),
331 Some(throw_type_error),
332 Attribute::CONFIGURABLE,
333 )
334 .build();
335
336 let prototype = realm.intrinsics().constructors().function().prototype();
337
338 BuiltInBuilder::callable_with_object(realm, prototype.clone(), Self::prototype)
339 .name(js_string!())
340 .length(0)
341 .build();
342
343 prototype.set_prototype(Some(realm.intrinsics().constructors().object().prototype()));
344 }
345
346 fn get(intrinsics: &Intrinsics) -> JsObject {
347 Self::STANDARD_CONSTRUCTOR(intrinsics.constructors()).constructor()
348 }
349}
350
351impl BuiltInObject for BuiltInFunctionObject {
352 const NAME: JsString = StaticJsStrings::FUNCTION;
353}
354
355impl BuiltInConstructor for BuiltInFunctionObject {
356 const CONSTRUCTOR_ARGUMENTS: usize = 1;
357 const PROTOTYPE_STORAGE_SLOTS: usize = 10;
358 const CONSTRUCTOR_STORAGE_SLOTS: usize = 0;
359
360 const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor =
361 StandardConstructors::function;
362
363 fn constructor(
375 new_target: &JsValue,
376 args: &[JsValue],
377 context: &mut Context,
378 ) -> JsResult<JsValue> {
379 let active_function = context
380 .active_function_object()
381 .unwrap_or_else(|| context.intrinsics().constructors().function().constructor());
382 Self::create_dynamic_function(active_function, new_target, args, false, false, context)
383 .map(Into::into)
384 }
385}
386
387impl BuiltInFunctionObject {
388 pub(crate) fn create_dynamic_function(
395 constructor: JsObject,
396 new_target: &JsValue,
397 args: &[JsValue],
398 r#async: bool,
399 generator: bool,
400 context: &mut Context,
401 ) -> JsResult<JsObject> {
402 let new_target = if new_target.is_undefined() {
404 constructor.into()
405 } else {
406 new_target.clone()
407 };
408
409 let strict = context.is_strict();
410
411 let default = if r#async && generator {
412 StandardConstructors::async_generator_function
420 } else if r#async {
421 StandardConstructors::async_function
428 } else if generator {
429 StandardConstructors::generator_function
436 } else {
437 StandardConstructors::function
444 };
445
446 let prototype = get_prototype_from_constructor(&new_target, default, context)?;
448
449 let (body, param_list) = if let Some((body, params)) = args.split_last() {
451 let mut parameters = Vec::with_capacity(args.len());
453
454 for param in params {
456 parameters.push(param.to_string(context)?);
458 }
459
460 let body = body.to_string(context)?;
462
463 (body, parameters)
464 } else {
465 (js_string!(), Vec::new())
466 };
467 let current_realm = context.realm().clone();
468
469 context.host_hooks().ensure_can_compile_strings(
470 current_realm,
471 ¶m_list,
472 &body,
473 false,
474 context,
475 )?;
476
477 let parameters = if param_list.is_empty() {
478 FormalParameterList::default()
479 } else {
480 let parameters = itertools::Itertools::intersperse(
492 param_list.iter().map(JsString::iter),
493 js_str!(",").iter(),
494 )
495 .flatten()
496 .collect::<Vec<_>>();
497 let mut parser = Parser::new(Source::from_utf16(¶meters));
498 parser.set_identifier(context.next_parser_identifier());
499
500 let parameters = parser
503 .parse_formal_parameters(context.interner_mut(), generator, r#async)
504 .map_err(|e| {
505 JsNativeError::syntax()
506 .with_message(format!("failed to parse function parameters: {e}"))
507 })?;
508
509 if generator && contains(¶meters, ContainsSymbol::YieldExpression) {
511 return Err(JsNativeError::syntax().with_message(
512 if r#async {
513 "yield expression is not allowed in formal parameter list of async generator"
514 } else {
515 "yield expression is not allowed in formal parameter list of generator"
516 }
517 ).into());
518 }
519
520 if r#async && contains(¶meters, ContainsSymbol::AwaitExpression) {
522 return Err(JsNativeError::syntax()
523 .with_message(
524 if generator {
525 "await expression is not allowed in formal parameter list of async function"
526 } else {
527 "await expression is not allowed in formal parameter list of async generator"
528 })
529 .into());
530 }
531
532 parameters
533 };
534
535 let body = if body.is_empty() {
536 FunctionBody::new(StatementList::default(), Span::new((1, 1), (1, 1)))
537 } else {
538 let mut body_parse = Vec::with_capacity(body.len());
540 body_parse.push(u16::from(b'\n'));
541 body_parse.extend(body.iter());
542 body_parse.push(u16::from(b'\n'));
543
544 let mut parser = Parser::new(Source::from_utf16(&body_parse));
547 parser.set_identifier(context.next_parser_identifier());
548
549 let body = parser
552 .parse_function_body(context.interner_mut(), generator, r#async)
553 .map_err(|e| {
554 JsNativeError::syntax()
555 .with_message(format!("failed to parse function body: {e}"))
556 })?;
557
558 if !all_private_identifiers_valid(&body, Vec::new()) {
563 return Err(JsNativeError::syntax()
564 .with_message("invalid private identifier usage")
565 .into());
566 }
567
568 if body.strict() {
577 for name in bound_names(¶meters) {
578 if name == Sym::ARGUMENTS || name == Sym::EVAL {
579 return Err(JsNativeError::syntax()
580 .with_message("Unexpected 'eval' or 'arguments' in strict mode")
581 .into());
582 }
583 }
584 }
585
586 if (body.strict()) && parameters.has_duplicates() {
589 return Err(JsNativeError::syntax()
590 .with_message("Duplicate parameter name not allowed in this context")
591 .into());
592 }
593
594 if body.strict() && !parameters.is_simple() {
597 return Err(JsNativeError::syntax()
598 .with_message(
599 "Illegal 'use strict' directive in function with non-simple parameter list",
600 )
601 .into());
602 }
603
604 if contains(&body, ContainsSymbol::SuperProperty) {
606 return Err(JsNativeError::syntax()
607 .with_message("invalid `super` reference")
608 .into());
609 }
610
611 if contains(&body, ContainsSymbol::SuperCall) {
613 return Err(JsNativeError::syntax()
614 .with_message("invalid `super` call")
615 .into());
616 }
617
618 {
622 let lexically_declared_names = lexically_declared_names(&body);
623 for name in bound_names(¶meters) {
624 if lexically_declared_names.contains(&name) {
625 return Err(JsNativeError::syntax()
626 .with_message(format!(
627 "Redeclaration of formal parameter `{}`",
628 context.interner().resolve_expect(name)
629 ))
630 .into());
631 }
632 }
633 }
634
635 body
636 };
637
638 let function_span_start = Position::new(1, 1);
641 let function_span_end = body.span().end();
642 let mut function = boa_ast::function::FunctionExpression::new(
643 None,
644 parameters,
645 body,
646 None,
647 false,
648 Span::new(function_span_start, function_span_end),
649 );
650 if let Err(reason) =
651 function.analyze_scope(strict, context.realm().scope(), context.interner())
652 {
653 return Err(js_error!(SyntaxError: "failed to analyze function scope: {}", reason));
654 }
655
656 let in_with = context.vm.frame().environments.has_object_environment();
657 let spanned_source_text = SpannedSourceText::new_empty();
658
659 let code = FunctionCompiler::new(spanned_source_text)
660 .name(js_string!("anonymous"))
661 .generator(generator)
662 .r#async(r#async)
663 .in_with(in_with)
664 .force_function_scope(true)
665 .compile(
666 function.parameters(),
667 function.body(),
668 context.realm().scope().clone(),
669 context.realm().scope().clone(),
670 function.scopes(),
671 function.contains_direct_eval(),
672 context.interner_mut(),
673 );
674
675 let saved = context.vm.frame_mut().environments.pop_to_global();
676 let function_object = crate::vm::create_function_object(code, prototype, context);
677 context
678 .vm
679 .frame_mut()
680 .environments
681 .restore_from_saved(saved);
682
683 Ok(function_object)
684 }
685
686 fn apply(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
698 let func = this.as_callable().ok_or_else(|| {
701 JsNativeError::typ().with_message(format!("{} is not a function", this.display()))
702 })?;
703
704 let this_arg = args.get_or_undefined(0);
705 let arg_array = args.get_or_undefined(1);
706 if arg_array.is_null_or_undefined() {
708 return func.call(this_arg, &[], context);
713 }
714
715 let arg_list = arg_array.create_list_from_array_like(&[], context)?;
717
718 func.call(this_arg, &arg_list, context)
723 }
724
725 fn bind(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
738 let target = this.as_callable().ok_or_else(|| {
741 JsNativeError::typ()
742 .with_message("cannot bind `this` without a `[[Call]]` internal method")
743 })?;
744
745 let this_arg = args.get_or_undefined(0).clone();
746 let bound_args = args.get(1..).unwrap_or(&[]).to_vec();
747 let arg_count = bound_args.len() as i64;
748
749 let f = BoundFunction::create(target.clone(), this_arg, bound_args, context)?;
751
752 let mut l = JsValue::new(0);
754
755 if target.has_own_property(StaticJsStrings::LENGTH, context)? {
758 let target_len = target.get(StaticJsStrings::LENGTH, context)?;
760 if target_len.is_number() {
762 match target_len
764 .to_integer_or_infinity(context)
765 .js_expect("to_integer_or_infinity cannot fail for a number")?
766 {
767 IntegerOrInfinity::PositiveInfinity => l = f64::INFINITY.into(),
769 IntegerOrInfinity::NegativeInfinity => {}
771 IntegerOrInfinity::Integer(target_len) => {
773 l = (target_len - arg_count).max(0).into();
777 }
778 }
779 }
780 }
781
782 f.define_property_or_throw(
784 StaticJsStrings::LENGTH,
785 PropertyDescriptor::builder()
786 .value(l)
787 .writable(false)
788 .enumerable(false)
789 .configurable(true),
790 context,
791 )
792 .js_expect("defining the `length` property for a new object should not fail")?;
793
794 let target_name = target.get(js_string!("name"), context)?;
796
797 let target_name = target_name.as_string().unwrap_or_default();
799
800 set_function_name(&f, &target_name.into(), Some(js_str!("bound")), context)?;
802
803 Ok(f.into())
805 }
806
807 fn call(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
818 let func = this.as_callable().ok_or_else(|| {
821 JsNativeError::typ().with_message(format!("{} is not a function", this.display()))
822 })?;
823 let this_arg = args.get_or_undefined(0);
824
825 func.call(this_arg, args.get(1..).unwrap_or(&[]), context)
830 }
831
832 #[allow(clippy::wrong_self_convention)]
841 fn to_string(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
842 let func = this;
844
845 let Some(object) = func.as_callable() else {
858 return Err(JsNativeError::typ().with_message("not a function").into());
859 };
860
861 if object.is::<NativeFunctionObject>() {
862 let name = {
863 let value = object.get(js_string!("name"), &mut *context)?;
866 if value.is_null_or_undefined() {
867 js_string!()
868 } else {
869 value.to_string(context)?
870 }
871 };
872 return Ok(
873 js_string!(js_str!("function "), &name, js_str!("() { [native code] }")).into(),
874 );
875 } else if object.is::<Proxy>() || object.is::<BoundFunction>() {
876 return Ok(js_string!("function () { [native code] }").into());
877 }
878
879 let function = object
880 .downcast_ref::<OrdinaryFunction>()
881 .ok_or_else(|| JsNativeError::typ().with_message("not a function"))?;
882
883 let code = function.codeblock();
884 if let Some(code_points) = code.source_info().text_spanned().to_code_points() {
885 return Ok(JsString::from(code_points).into());
886 }
887
888 Ok(js_string!(
889 js_str!("function "),
890 code.name(),
891 js_str!("() { [native code] }")
892 )
893 .into())
894 }
895
896 fn has_instance(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
903 Ok(JsValue::ordinary_has_instance(this, args.get_or_undefined(0), context)?.into())
906 }
907
908 #[allow(clippy::unnecessary_wraps)]
909 fn prototype(_: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
910 Ok(JsValue::undefined())
911 }
912}
913
914pub(crate) fn set_function_name(
921 function: &JsObject,
922 name: &PropertyKey,
923 prefix: Option<JsStr<'_>>,
924 context: &mut Context,
925) -> JsResult<()> {
926 let mut name = match name {
929 PropertyKey::Symbol(sym) => {
930 sym.description().map_or_else(
934 || js_string!(),
935 |desc| js_string!(js_str!("["), &desc, js_str!("]")),
936 )
937 }
938 PropertyKey::String(string) => string.clone(),
939 PropertyKey::Index(index) => js_string!(format!("{}", index.get())),
940 };
941
942 if let Some(prefix) = prefix {
952 name = js_string!(prefix, js_str!(" "), &name);
953 }
957
958 function
961 .define_property_or_throw(
962 js_string!("name"),
963 PropertyDescriptor::builder()
964 .value(name)
965 .writable(false)
966 .enumerable(false)
967 .configurable(true),
968 context,
969 )
970 .js_expect("defining the `name` property must not fail per the spec")?;
971
972 Ok(())
973}
974
975pub(crate) fn function_call(
983 function_object: &JsObject,
984 argument_count: usize,
985 #[allow(
986 unused_variables,
987 reason = "Only used if native-backtrace feature is enabled"
988 )]
989 context: &mut InternalMethodCallContext<'_>,
990) -> JsResult<CallValue> {
991 context.check_runtime_limits()?;
992
993 let function = function_object
994 .downcast_ref::<OrdinaryFunction>()
995 .js_expect("not a function")?;
996 let realm = function.realm().clone();
997
998 if function.code.is_class_constructor() {
999 debug_assert!(
1000 function.is_ordinary(),
1001 "only ordinary functions can be classes"
1002 );
1003 return Err(JsNativeError::typ()
1004 .with_message("class constructor cannot be invoked without 'new'")
1005 .with_realm(realm)
1006 .into());
1007 }
1008
1009 let code = function.code.clone();
1010 let environments = function.environments.clone();
1011 let script_or_module = function.script_or_module.clone();
1012
1013 drop(function);
1014
1015 let env_fp = environments.len() as u32;
1016
1017 let frame = CallFrame::new(code, script_or_module, environments, realm)
1018 .with_argument_count(argument_count as u32)
1019 .with_env_fp(env_fp);
1020
1021 #[cfg(feature = "native-backtrace")]
1022 {
1023 let native_source_info = context.native_source_info();
1024 context
1025 .vm
1026 .shadow_stack
1027 .patch_last_native(native_source_info);
1028 }
1029
1030 context.vm.push_frame(frame);
1031 context.vm.set_return_value(JsValue::undefined());
1032
1033 let context = context.context();
1034
1035 let lexical_this_mode = context.vm.frame().code_block.this_mode == ThisMode::Lexical;
1036 let this = if lexical_this_mode {
1037 ThisBindingStatus::Lexical
1038 } else {
1039 let this = context.vm.stack.get_this(context.vm.frame());
1040 if context.vm.frame().code_block.strict() {
1041 context.vm.frame_mut().flags |= CallFrameFlags::THIS_VALUE_CACHED;
1042 ThisBindingStatus::Initialized(this)
1043 } else if this.is_null_or_undefined() {
1044 context.vm.frame_mut().flags |= CallFrameFlags::THIS_VALUE_CACHED;
1045 let this: JsValue = context.realm().global_this().clone().into();
1046 context.vm.stack.set_this(
1047 context.vm.frames.last().js_expect("frame must exist")?,
1048 this.clone(),
1049 );
1050 ThisBindingStatus::Initialized(this)
1051 } else {
1052 let this: JsValue = this
1053 .to_object(context)
1054 .js_expect("conversion cannot fail")?
1055 .into();
1056 context.vm.frame_mut().flags |= CallFrameFlags::THIS_VALUE_CACHED;
1057 context.vm.stack.set_this(
1058 context.vm.frames.last().js_expect("frame must exist")?,
1059 this.clone(),
1060 );
1061 ThisBindingStatus::Initialized(this)
1062 }
1063 };
1064
1065 let mut last_env = 0;
1066
1067 let has_binding_identifier = context.vm.frame().code_block().has_binding_identifier();
1068 let has_function_scope = context.vm.frame().code_block().has_function_scope();
1069
1070 if has_binding_identifier {
1071 let frame = context.vm.frame_mut();
1072 let global = frame.realm.environment();
1073 let index = frame.environments.push_lexical(1, global);
1074 frame.environments.put_lexical_value(
1075 BindingLocatorScope::Stack(index),
1076 0,
1077 function_object.clone().into(),
1078 global,
1079 );
1080 last_env += 1;
1081 }
1082
1083 if has_function_scope {
1084 let scope = context.vm.frame().code_block().constant_scope(last_env);
1085 let frame = context.vm.frame_mut();
1086 let global = frame.realm.environment();
1087 frame.environments.push_function(
1088 scope,
1089 FunctionSlots::new(this, function_object.clone(), None),
1090 global,
1091 );
1092 }
1093
1094 Ok(CallValue::Ready)
1095}
1096
1097fn function_construct(
1104 this_function_object: &JsObject,
1105 argument_count: usize,
1106 context: &mut InternalMethodCallContext<'_>,
1107) -> JsResult<CallValue> {
1108 context.check_runtime_limits()?;
1109
1110 let function = this_function_object
1111 .downcast_ref::<OrdinaryFunction>()
1112 .js_expect("not a function")?;
1113 let realm = function.realm().clone();
1114
1115 debug_assert!(
1116 function.is_ordinary(),
1117 "only ordinary functions can be constructed"
1118 );
1119
1120 let code = function.code.clone();
1121 let environments = function.environments.clone();
1122 let script_or_module = function.script_or_module.clone();
1123 drop(function);
1124
1125 let env_fp = environments.len() as u32;
1126
1127 let new_target = context.vm.stack.pop();
1128
1129 let this = if code.is_derived_constructor() {
1130 None
1131 } else {
1132 let prototype =
1137 get_prototype_from_constructor(&new_target, StandardConstructors::object, context)?;
1138 let this = JsObject::from_proto_and_data_with_shared_shape(
1139 context.root_shape(),
1140 prototype,
1141 OrdinaryObject,
1142 )
1143 .upcast();
1144
1145 this.initialize_instance_elements(this_function_object, context)?;
1146
1147 Some(this)
1148 };
1149
1150 let mut frame = CallFrame::new(code, script_or_module, environments, realm)
1151 .with_argument_count(argument_count as u32)
1152 .with_env_fp(env_fp)
1153 .with_flags(CallFrameFlags::CONSTRUCT);
1154
1155 frame
1158 .flags
1159 .set(CallFrameFlags::THIS_VALUE_CACHED, this.is_some());
1160
1161 #[cfg(feature = "native-backtrace")]
1162 {
1163 let native_source_info = context.native_source_info();
1164 context
1165 .vm
1166 .shadow_stack
1167 .patch_last_native(native_source_info);
1168 }
1169
1170 context.vm.push_frame(frame);
1171 context.vm.set_return_value(JsValue::undefined());
1172
1173 let mut last_env = 0;
1174
1175 let has_binding_identifier = context.vm.frame().code_block().has_binding_identifier();
1176 let has_function_scope = context.vm.frame().code_block().has_function_scope();
1177
1178 if has_binding_identifier {
1179 let frame = context.vm.frame_mut();
1180 let global = frame.realm.environment();
1181 let index = frame.environments.push_lexical(1, global);
1182 frame.environments.put_lexical_value(
1183 BindingLocatorScope::Stack(index),
1184 0,
1185 this_function_object.clone().into(),
1186 global,
1187 );
1188 last_env += 1;
1189 }
1190
1191 if has_function_scope {
1192 let scope = context.vm.frame().code_block().constant_scope(last_env);
1193 let frame = context.vm.frame_mut();
1194 let global = frame.realm.environment();
1195 frame.environments.push_function(
1196 scope,
1197 FunctionSlots::new(
1198 this.clone().map_or(ThisBindingStatus::Uninitialized, |o| {
1199 ThisBindingStatus::Initialized(o.into())
1200 }),
1201 this_function_object.clone(),
1202 Some(
1203 new_target
1204 .as_object()
1205 .js_expect("new.target should be an object")?
1206 .clone(),
1207 ),
1208 ),
1209 global,
1210 );
1211 }
1212
1213 let context = context.context();
1214 context.vm.stack.set_this(
1215 context.vm.frames.last().js_expect("frame must exist")?,
1216 this.map(JsValue::new).unwrap_or_default(),
1217 );
1218
1219 Ok(CallValue::Ready)
1220}