Coverage Report

Created: 2026-11-13 08:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2020, Stephan Unverwerth <s.unverwerth@serenityos.org>
3
 * Copyright (c) 2020-2023, Linus Groh <linusg@serenityos.org>
4
 * Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
5
 * Copyright (c) 2023, Shannon Booth <shannon@serenityos.org>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 */
9
10
#include <AK/Debug.h>
11
#include <AK/Function.h>
12
#include <LibJS/AST.h>
13
#include <LibJS/Bytecode/BasicBlock.h>
14
#include <LibJS/Bytecode/Generator.h>
15
#include <LibJS/Bytecode/Interpreter.h>
16
#include <LibJS/Runtime/AbstractOperations.h>
17
#include <LibJS/Runtime/Array.h>
18
#include <LibJS/Runtime/AsyncFunctionDriverWrapper.h>
19
#include <LibJS/Runtime/AsyncGenerator.h>
20
#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
21
#include <LibJS/Runtime/Error.h>
22
#include <LibJS/Runtime/ExecutionContext.h>
23
#include <LibJS/Runtime/FunctionEnvironment.h>
24
#include <LibJS/Runtime/GeneratorObject.h>
25
#include <LibJS/Runtime/GlobalEnvironment.h>
26
#include <LibJS/Runtime/GlobalObject.h>
27
#include <LibJS/Runtime/NativeFunction.h>
28
#include <LibJS/Runtime/PromiseCapability.h>
29
#include <LibJS/Runtime/PromiseConstructor.h>
30
#include <LibJS/Runtime/Value.h>
31
32
namespace JS {
33
34
JS_DEFINE_ALLOCATOR(ECMAScriptFunctionObject);
35
36
NonnullGCPtr<ECMAScriptFunctionObject> ECMAScriptFunctionObject::create(Realm& realm, DeprecatedFlyString name, ByteString source_text, Statement const& ecmascript_code, Vector<FunctionParameter> parameters, i32 m_function_length, Vector<DeprecatedFlyString> local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind kind, bool is_strict, FunctionParsingInsights parsing_insights, bool is_arrow_function, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name)
37
0
{
38
0
    Object* prototype = nullptr;
39
0
    switch (kind) {
40
0
    case FunctionKind::Normal:
41
0
        prototype = realm.intrinsics().function_prototype();
42
0
        break;
43
0
    case FunctionKind::Generator:
44
0
        prototype = realm.intrinsics().generator_function_prototype();
45
0
        break;
46
0
    case FunctionKind::Async:
47
0
        prototype = realm.intrinsics().async_function_prototype();
48
0
        break;
49
0
    case FunctionKind::AsyncGenerator:
50
0
        prototype = realm.intrinsics().async_generator_function_prototype();
51
0
        break;
52
0
    }
53
0
    return realm.heap().allocate<ECMAScriptFunctionObject>(realm, move(name), move(source_text), ecmascript_code, move(parameters), m_function_length, move(local_variables_names), parent_environment, private_environment, *prototype, kind, is_strict, parsing_insights, is_arrow_function, move(class_field_initializer_name));
54
0
}
55
56
NonnullGCPtr<ECMAScriptFunctionObject> ECMAScriptFunctionObject::create(Realm& realm, DeprecatedFlyString name, Object& prototype, ByteString source_text, Statement const& ecmascript_code, Vector<FunctionParameter> parameters, i32 m_function_length, Vector<DeprecatedFlyString> local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind kind, bool is_strict, FunctionParsingInsights parsing_insights, bool is_arrow_function, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name)
57
0
{
58
0
    return realm.heap().allocate<ECMAScriptFunctionObject>(realm, move(name), move(source_text), ecmascript_code, move(parameters), m_function_length, move(local_variables_names), parent_environment, private_environment, prototype, kind, is_strict, parsing_insights, is_arrow_function, move(class_field_initializer_name));
59
0
}
60
61
ECMAScriptFunctionObject::ECMAScriptFunctionObject(DeprecatedFlyString name, ByteString source_text, Statement const& ecmascript_code, Vector<FunctionParameter> formal_parameters, i32 function_length, Vector<DeprecatedFlyString> local_variables_names, Environment* parent_environment, PrivateEnvironment* private_environment, Object& prototype, FunctionKind kind, bool strict, FunctionParsingInsights parsing_insights, bool is_arrow_function, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name)
62
0
    : FunctionObject(prototype)
63
0
    , m_name(move(name))
64
0
    , m_function_length(function_length)
65
0
    , m_local_variables_names(move(local_variables_names))
66
0
    , m_environment(parent_environment)
67
0
    , m_private_environment(private_environment)
68
0
    , m_formal_parameters(move(formal_parameters))
69
0
    , m_ecmascript_code(ecmascript_code)
70
0
    , m_realm(&prototype.shape().realm())
71
0
    , m_source_text(move(source_text))
72
0
    , m_class_field_initializer_name(move(class_field_initializer_name))
73
0
    , m_strict(strict)
74
0
    , m_might_need_arguments_object(parsing_insights.might_need_arguments_object)
75
0
    , m_contains_direct_call_to_eval(parsing_insights.contains_direct_call_to_eval)
76
0
    , m_is_arrow_function(is_arrow_function)
77
0
    , m_kind(kind)
78
0
{
79
    // NOTE: This logic is from OrdinaryFunctionCreate, https://tc39.es/ecma262/#sec-ordinaryfunctioncreate
80
81
    // 9. If thisMode is lexical-this, set F.[[ThisMode]] to lexical.
82
0
    if (m_is_arrow_function)
83
0
        m_this_mode = ThisMode::Lexical;
84
    // 10. Else if Strict is true, set F.[[ThisMode]] to strict.
85
0
    else if (m_strict)
86
0
        m_this_mode = ThisMode::Strict;
87
0
    else
88
        // 11. Else, set F.[[ThisMode]] to global.
89
0
        m_this_mode = ThisMode::Global;
90
91
    // 15. Set F.[[ScriptOrModule]] to GetActiveScriptOrModule().
92
0
    m_script_or_module = vm().get_active_script_or_module();
93
94
    // 15.1.3 Static Semantics: IsSimpleParameterList, https://tc39.es/ecma262/#sec-static-semantics-issimpleparameterlist
95
0
    m_has_simple_parameter_list = all_of(m_formal_parameters, [&](auto& parameter) {
96
0
        if (parameter.is_rest)
97
0
            return false;
98
0
        if (parameter.default_value)
99
0
            return false;
100
0
        if (!parameter.binding.template has<NonnullRefPtr<Identifier const>>())
101
0
            return false;
102
0
        return true;
103
0
    });
104
105
    // NOTE: The following steps are from FunctionDeclarationInstantiation that could be executed once
106
    //       and then reused in all subsequent function instantiations.
107
108
    // 2. Let code be func.[[ECMAScriptCode]].
109
0
    ScopeNode const* scope_body = nullptr;
110
0
    if (is<ScopeNode>(*m_ecmascript_code))
111
0
        scope_body = static_cast<ScopeNode const*>(m_ecmascript_code.ptr());
112
113
    // 3. Let strict be func.[[Strict]].
114
115
    // 4. Let formals be func.[[FormalParameters]].
116
0
    auto const& formals = m_formal_parameters;
117
118
    // 5. Let parameterNames be the BoundNames of formals.
119
    // 6. If parameterNames has any duplicate entries, let hasDuplicates be true. Otherwise, let hasDuplicates be false.
120
121
0
    size_t parameters_in_environment = 0;
122
123
    // NOTE: This loop performs step 5, 6, and 8.
124
0
    for (auto const& parameter : formals) {
125
0
        if (parameter.default_value)
126
0
            m_has_parameter_expressions = true;
127
128
0
        parameter.binding.visit(
129
0
            [&](Identifier const& identifier) {
130
0
                if (m_parameter_names.set(identifier.string(), identifier.is_local() ? ParameterIsLocal::Yes : ParameterIsLocal::No) != AK::HashSetResult::InsertedNewEntry)
131
0
                    m_has_duplicates = true;
132
0
                else if (!identifier.is_local())
133
0
                    ++parameters_in_environment;
134
0
            },
135
0
            [&](NonnullRefPtr<BindingPattern const> const& pattern) {
136
0
                if (pattern->contains_expression())
137
0
                    m_has_parameter_expressions = true;
138
139
                // NOTE: Nothing in the callback throws an exception.
140
0
                MUST(pattern->for_each_bound_identifier([&](auto& identifier) {
141
0
                    if (m_parameter_names.set(identifier.string(), identifier.is_local() ? ParameterIsLocal::Yes : ParameterIsLocal::No) != AK::HashSetResult::InsertedNewEntry)
142
0
                        m_has_duplicates = true;
143
0
                    else if (!identifier.is_local())
144
0
                        ++parameters_in_environment;
145
0
                }));
146
0
            });
147
0
    }
148
149
    // 15. Let argumentsObjectNeeded be true.
150
0
    m_arguments_object_needed = m_might_need_arguments_object;
151
152
    // 16. If func.[[ThisMode]] is lexical, then
153
0
    if (this_mode() == ThisMode::Lexical) {
154
        // a. NOTE: Arrow functions never have an arguments object.
155
        // b. Set argumentsObjectNeeded to false.
156
0
        m_arguments_object_needed = false;
157
0
    }
158
    // 17. Else if parameterNames contains "arguments", then
159
0
    else if (m_parameter_names.contains(vm().names.arguments.as_string())) {
160
        // a. Set argumentsObjectNeeded to false.
161
0
        m_arguments_object_needed = false;
162
0
    }
163
164
0
    HashTable<DeprecatedFlyString> function_names;
165
166
    // 18. Else if hasParameterExpressions is false, then
167
    //     a. If functionNames contains "arguments" or lexicalNames contains "arguments", then
168
    //         i. Set argumentsObjectNeeded to false.
169
    // NOTE: The block below is a combination of step 14 and step 18.
170
0
    if (scope_body) {
171
        // NOTE: Nothing in the callback throws an exception.
172
0
        MUST(scope_body->for_each_var_function_declaration_in_reverse_order([&](FunctionDeclaration const& function) {
173
0
            if (function_names.set(function.name()) == AK::HashSetResult::InsertedNewEntry)
174
0
                m_functions_to_initialize.append(function);
175
0
        }));
176
177
0
        auto const& arguments_name = vm().names.arguments.as_string();
178
179
0
        if (!m_has_parameter_expressions && function_names.contains(arguments_name))
180
0
            m_arguments_object_needed = false;
181
182
0
        if (!m_has_parameter_expressions && m_arguments_object_needed) {
183
            // NOTE: Nothing in the callback throws an exception.
184
0
            MUST(scope_body->for_each_lexically_declared_identifier([&](auto const& identifier) {
185
0
                if (identifier.string() == arguments_name)
186
0
                    m_arguments_object_needed = false;
187
0
            }));
188
0
        }
189
0
    } else {
190
0
        m_arguments_object_needed = false;
191
0
    }
192
193
0
    size_t* environment_size = nullptr;
194
195
0
    size_t parameter_environment_bindings_count = 0;
196
    // 19. If strict is true or hasParameterExpressions is false, then
197
0
    if (m_strict || !m_has_parameter_expressions) {
198
        // a. NOTE: Only a single Environment Record is needed for the parameters, since calls to eval in strict mode code cannot create new bindings which are visible outside of the eval.
199
        // b. Let env be the LexicalEnvironment of calleeContext
200
        // NOTE: Here we are only interested in the size of the environment.
201
0
        environment_size = &m_function_environment_bindings_count;
202
0
    }
203
    // 20. Else,
204
0
    else {
205
        // a. NOTE: A separate Environment Record is needed to ensure that bindings created by direct eval calls in the formal parameter list are outside the environment where parameters are declared.
206
        // b. Let calleeEnv be the LexicalEnvironment of calleeContext.
207
        // c. Let env be NewDeclarativeEnvironment(calleeEnv).
208
0
        environment_size = &parameter_environment_bindings_count;
209
0
    }
210
211
0
    *environment_size += parameters_in_environment;
212
213
0
    HashMap<DeprecatedFlyString, ParameterIsLocal> parameter_bindings;
214
215
0
    auto arguments_object_needs_binding = m_arguments_object_needed && !m_local_variables_names.contains_slow(vm().names.arguments.as_string());
216
217
    // 22. If argumentsObjectNeeded is true, then
218
0
    if (m_arguments_object_needed) {
219
        // f. Let parameterBindings be the list-concatenation of parameterNames and « "arguments" ».
220
0
        parameter_bindings = m_parameter_names;
221
0
        parameter_bindings.set(vm().names.arguments.as_string(), ParameterIsLocal::No);
222
223
0
        if (arguments_object_needs_binding)
224
0
            (*environment_size)++;
225
0
    } else {
226
0
        parameter_bindings = m_parameter_names;
227
        // a. Let parameterBindings be parameterNames.
228
0
    }
229
230
0
    HashMap<DeprecatedFlyString, ParameterIsLocal> instantiated_var_names;
231
232
0
    size_t* var_environment_size = nullptr;
233
234
    // 27. If hasParameterExpressions is false, then
235
0
    if (!m_has_parameter_expressions) {
236
        // b. Let instantiatedVarNames be a copy of the List parameterBindings.
237
0
        instantiated_var_names = parameter_bindings;
238
239
0
        if (scope_body) {
240
            // c. For each element n of varNames, do
241
0
            MUST(scope_body->for_each_var_declared_identifier([&](auto const& id) {
242
                // i. If instantiatedVarNames does not contain n, then
243
0
                if (instantiated_var_names.set(id.string(), id.is_local() ? ParameterIsLocal::Yes : ParameterIsLocal::No) == AK::HashSetResult::InsertedNewEntry) {
244
                    // 1. Append n to instantiatedVarNames.
245
                    // Following steps will be executed in function_declaration_instantiation:
246
                    // 2. Perform ! env.CreateMutableBinding(n, false).
247
                    // 3. Perform ! env.InitializeBinding(n, undefined).
248
0
                    m_var_names_to_initialize_binding.append({
249
0
                        .identifier = id,
250
0
                        .parameter_binding = parameter_bindings.contains(id.string()),
251
0
                        .function_name = function_names.contains(id.string()),
252
0
                    });
253
254
0
                    if (!id.is_local())
255
0
                        (*environment_size)++;
256
0
                }
257
0
            }));
258
0
        }
259
260
        // d. Let varEnv be env
261
0
        var_environment_size = environment_size;
262
0
    } else {
263
        // a. NOTE: A separate Environment Record is needed to ensure that closures created by expressions in the formal parameter list do not have visibility of declarations in the function body.
264
265
        // b. Let varEnv be NewDeclarativeEnvironment(env).
266
        // NOTE: Here we are only interested in the size of the environment.
267
0
        var_environment_size = &m_var_environment_bindings_count;
268
269
        // 28. Else,
270
        // NOTE: Steps a, b, c and d are executed in function_declaration_instantiation.
271
        // e. For each element n of varNames, do
272
0
        if (scope_body) {
273
0
            MUST(scope_body->for_each_var_declared_identifier([&](auto const& id) {
274
                // 1. Append n to instantiatedVarNames.
275
                // Following steps will be executed in function_declaration_instantiation:
276
                // 2. Perform ! env.CreateMutableBinding(n, false).
277
                // 3. Perform ! env.InitializeBinding(n, undefined).
278
0
                if (instantiated_var_names.set(id.string(), id.is_local() ? ParameterIsLocal::Yes : ParameterIsLocal::No) == AK::HashSetResult::InsertedNewEntry) {
279
0
                    m_var_names_to_initialize_binding.append({
280
0
                        .identifier = id,
281
0
                        .parameter_binding = parameter_bindings.contains(id.string()),
282
0
                        .function_name = function_names.contains(id.string()),
283
0
                    });
284
285
0
                    if (!id.is_local())
286
0
                        (*var_environment_size)++;
287
0
                }
288
0
            }));
289
0
        }
290
0
    }
291
292
    // 29. NOTE: Annex B.3.2.1 adds additional steps at this point.
293
    // B.3.2.1 Changes to FunctionDeclarationInstantiation, https://tc39.es/ecma262/#sec-web-compat-functiondeclarationinstantiation
294
0
    if (!m_strict && scope_body) {
295
0
        MUST(scope_body->for_each_function_hoistable_with_annexB_extension([&](FunctionDeclaration& function_declaration) {
296
0
            auto function_name = function_declaration.name();
297
0
            if (parameter_bindings.contains(function_name))
298
0
                return;
299
300
0
            if (!instantiated_var_names.contains(function_name) && function_name != vm().names.arguments.as_string()) {
301
0
                m_function_names_to_initialize_binding.append(function_name);
302
0
                instantiated_var_names.set(function_name, ParameterIsLocal::No);
303
0
                (*var_environment_size)++;
304
0
            }
305
306
0
            function_declaration.set_should_do_additional_annexB_steps();
307
0
        }));
308
0
    }
309
310
0
    size_t* lex_environment_size = nullptr;
311
312
    // 30. If strict is false, then
313
0
    if (!m_strict) {
314
0
        bool can_elide_declarative_environment = !m_contains_direct_call_to_eval && (!scope_body || !scope_body->has_non_local_lexical_declarations());
315
0
        if (can_elide_declarative_environment) {
316
0
            lex_environment_size = var_environment_size;
317
0
        } else {
318
            // a. Let lexEnv be NewDeclarativeEnvironment(varEnv).
319
0
            lex_environment_size = &m_lex_environment_bindings_count;
320
0
        }
321
0
    } else {
322
        // a. let lexEnv be varEnv.
323
        // NOTE: Here we are only interested in the size of the environment.
324
0
        lex_environment_size = var_environment_size;
325
0
    }
326
327
0
    if (scope_body) {
328
0
        MUST(scope_body->for_each_lexically_declared_identifier([&](auto const& id) {
329
0
            if (!id.is_local())
330
0
                (*lex_environment_size)++;
331
0
        }));
332
0
    }
333
334
0
    m_function_environment_needed = arguments_object_needs_binding || m_function_environment_bindings_count > 0 || m_var_environment_bindings_count > 0 || m_lex_environment_bindings_count > 0 || parsing_insights.uses_this_from_environment || m_contains_direct_call_to_eval;
335
0
    m_uses_this = parsing_insights.uses_this;
336
0
}
337
338
void ECMAScriptFunctionObject::initialize(Realm& realm)
339
0
{
340
0
    auto& vm = this->vm();
341
0
    Base::initialize(realm);
342
    // Note: The ordering of these properties must be: length, name, prototype which is the order
343
    //       they are defined in the spec: https://tc39.es/ecma262/#sec-function-instances .
344
    //       This is observable through something like: https://tc39.es/ecma262/#sec-ordinaryownpropertykeys
345
    //       which must give the properties in chronological order which in this case is the order they
346
    //       are defined in the spec.
347
348
0
    m_name_string = PrimitiveString::create(vm, m_name);
349
350
0
    MUST(define_property_or_throw(vm.names.length, { .value = Value(m_function_length), .writable = false, .enumerable = false, .configurable = true }));
351
0
    MUST(define_property_or_throw(vm.names.name, { .value = m_name_string, .writable = false, .enumerable = false, .configurable = true }));
352
353
0
    if (!m_is_arrow_function) {
354
0
        Object* prototype = nullptr;
355
0
        switch (m_kind) {
356
0
        case FunctionKind::Normal:
357
0
            prototype = Object::create_prototype(realm, realm.intrinsics().object_prototype());
358
0
            MUST(prototype->define_property_or_throw(vm.names.constructor, { .value = this, .writable = true, .enumerable = false, .configurable = true }));
359
0
            break;
360
0
        case FunctionKind::Generator:
361
            // prototype is "g1.prototype" in figure-2 (https://tc39.es/ecma262/img/figure-2.png)
362
0
            prototype = Object::create_prototype(realm, realm.intrinsics().generator_function_prototype_prototype());
363
0
            break;
364
0
        case FunctionKind::Async:
365
0
            break;
366
0
        case FunctionKind::AsyncGenerator:
367
0
            prototype = Object::create_prototype(realm, realm.intrinsics().async_generator_function_prototype_prototype());
368
0
            break;
369
0
        }
370
        // 27.7.4 AsyncFunction Instances, https://tc39.es/ecma262/#sec-async-function-instances
371
        // AsyncFunction instances do not have a prototype property as they are not constructible.
372
0
        if (m_kind != FunctionKind::Async)
373
0
            define_direct_property(vm.names.prototype, prototype, Attribute::Writable);
374
0
    }
375
0
}
376
377
// 10.2.1 [[Call]] ( thisArgument, argumentsList ), https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist
378
ThrowCompletionOr<Value> ECMAScriptFunctionObject::internal_call(Value this_argument, ReadonlySpan<Value> arguments_list)
379
0
{
380
0
    auto& vm = this->vm();
381
382
    // 1. Let callerContext be the running execution context.
383
    // NOTE: No-op, kept by the VM in its execution context stack.
384
385
0
    auto callee_context = ExecutionContext::create();
386
387
    // Non-standard
388
0
    callee_context->arguments.ensure_capacity(max(arguments_list.size(), m_formal_parameters.size()));
389
0
    callee_context->arguments.append(arguments_list.data(), arguments_list.size());
390
0
    callee_context->passed_argument_count = arguments_list.size();
391
0
    if (arguments_list.size() < m_formal_parameters.size()) {
392
0
        for (size_t i = arguments_list.size(); i < m_formal_parameters.size(); ++i)
393
0
            callee_context->arguments.append(js_undefined());
394
0
    }
395
396
    // 2. Let calleeContext be PrepareForOrdinaryCall(F, undefined).
397
    // NOTE: We throw if the end of the native stack is reached, so unlike in the spec this _does_ need an exception check.
398
0
    TRY(prepare_for_ordinary_call(*callee_context, nullptr));
399
400
    // 3. Assert: calleeContext is now the running execution context.
401
0
    VERIFY(&vm.running_execution_context() == callee_context);
402
403
    // 4. If F.[[IsClassConstructor]] is true, then
404
0
    if (m_is_class_constructor) {
405
        // a. Let error be a newly created TypeError object.
406
        // b. NOTE: error is created in calleeContext with F's associated Realm Record.
407
0
        auto throw_completion = vm.throw_completion<TypeError>(ErrorType::ClassConstructorWithoutNew, m_name);
408
409
        // c. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
410
0
        vm.pop_execution_context();
411
412
        // d. Return ThrowCompletion(error).
413
0
        return throw_completion;
414
0
    }
415
416
    // 5. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument).
417
0
    if (m_uses_this)
418
0
        ordinary_call_bind_this(*callee_context, this_argument);
419
420
    // 6. Let result be Completion(OrdinaryCallEvaluateBody(F, argumentsList)).
421
0
    auto result = ordinary_call_evaluate_body();
422
423
    // 7. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
424
0
    vm.pop_execution_context();
425
426
    // 8. If result.[[Type]] is return, return result.[[Value]].
427
0
    if (result.type() == Completion::Type::Return)
428
0
        return *result.value();
429
430
    // 9. ReturnIfAbrupt(result).
431
0
    if (result.is_abrupt()) {
432
0
        VERIFY(result.is_error());
433
0
        return result;
434
0
    }
435
436
    // 10. Return undefined.
437
0
    return js_undefined();
438
0
}
439
440
// 10.2.2 [[Construct]] ( argumentsList, newTarget ), https://tc39.es/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget
441
ThrowCompletionOr<NonnullGCPtr<Object>> ECMAScriptFunctionObject::internal_construct(ReadonlySpan<Value> arguments_list, FunctionObject& new_target)
442
0
{
443
0
    auto& vm = this->vm();
444
445
    // 1. Let callerContext be the running execution context.
446
    // NOTE: No-op, kept by the VM in its execution context stack.
447
448
    // 2. Let kind be F.[[ConstructorKind]].
449
0
    auto kind = m_constructor_kind;
450
451
0
    GCPtr<Object> this_argument;
452
453
    // 3. If kind is base, then
454
0
    if (kind == ConstructorKind::Base) {
455
        // a. Let thisArgument be ? OrdinaryCreateFromConstructor(newTarget, "%Object.prototype%").
456
0
        this_argument = TRY(ordinary_create_from_constructor<Object>(vm, new_target, &Intrinsics::object_prototype, ConstructWithPrototypeTag::Tag));
457
0
    }
458
459
0
    auto callee_context = ExecutionContext::create();
460
461
    // Non-standard
462
0
    callee_context->arguments.ensure_capacity(max(arguments_list.size(), m_formal_parameters.size()));
463
0
    callee_context->arguments.append(arguments_list.data(), arguments_list.size());
464
0
    callee_context->passed_argument_count = arguments_list.size();
465
0
    if (arguments_list.size() < m_formal_parameters.size()) {
466
0
        for (size_t i = arguments_list.size(); i < m_formal_parameters.size(); ++i)
467
0
            callee_context->arguments.append(js_undefined());
468
0
    }
469
470
    // 4. Let calleeContext be PrepareForOrdinaryCall(F, newTarget).
471
    // NOTE: We throw if the end of the native stack is reached, so unlike in the spec this _does_ need an exception check.
472
0
    TRY(prepare_for_ordinary_call(*callee_context, &new_target));
473
474
    // 5. Assert: calleeContext is now the running execution context.
475
0
    VERIFY(&vm.running_execution_context() == callee_context);
476
477
    // 6. If kind is base, then
478
0
    if (kind == ConstructorKind::Base) {
479
        // a. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument).
480
0
        if (m_uses_this)
481
0
            ordinary_call_bind_this(*callee_context, this_argument);
482
483
        // b. Let initializeResult be Completion(InitializeInstanceElements(thisArgument, F)).
484
0
        auto initialize_result = this_argument->initialize_instance_elements(*this);
485
486
        // c. If initializeResult is an abrupt completion, then
487
0
        if (initialize_result.is_throw_completion()) {
488
            // i. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
489
0
            vm.pop_execution_context();
490
491
            // ii. Return ? initializeResult.
492
0
            return initialize_result.throw_completion();
493
0
        }
494
0
    }
495
496
    // 7. Let constructorEnv be the LexicalEnvironment of calleeContext.
497
0
    auto constructor_env = callee_context->lexical_environment;
498
499
    // 8. Let result be Completion(OrdinaryCallEvaluateBody(F, argumentsList)).
500
0
    auto result = ordinary_call_evaluate_body();
501
502
    // 9. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
503
0
    vm.pop_execution_context();
504
505
    // 10. If result.[[Type]] is return, then
506
0
    if (result.type() == Completion::Type::Return) {
507
        // a. If Type(result.[[Value]]) is Object, return result.[[Value]].
508
0
        if (result.value()->is_object())
509
0
            return result.value()->as_object();
510
511
        // b. If kind is base, return thisArgument.
512
0
        if (kind == ConstructorKind::Base)
513
0
            return *this_argument;
514
515
        // c. If result.[[Value]] is not undefined, throw a TypeError exception.
516
0
        if (!result.value()->is_undefined())
517
0
            return vm.throw_completion<TypeError>(ErrorType::DerivedConstructorReturningInvalidValue);
518
0
    }
519
    // 11. Else, ReturnIfAbrupt(result).
520
0
    else if (result.is_abrupt()) {
521
0
        VERIFY(result.is_error());
522
0
        return result;
523
0
    }
524
525
    // 12. Let thisBinding be ? constructorEnv.GetThisBinding().
526
0
    auto this_binding = TRY(constructor_env->get_this_binding(vm));
527
528
    // 13. Assert: Type(thisBinding) is Object.
529
0
    VERIFY(this_binding.is_object());
530
531
    // 14. Return thisBinding.
532
0
    return this_binding.as_object();
533
0
}
534
535
void ECMAScriptFunctionObject::visit_edges(Visitor& visitor)
536
0
{
537
0
    Base::visit_edges(visitor);
538
0
    visitor.visit(m_environment);
539
0
    visitor.visit(m_private_environment);
540
0
    visitor.visit(m_realm);
541
0
    visitor.visit(m_home_object);
542
0
    visitor.visit(m_name_string);
543
544
0
    visitor.visit(m_bytecode_executable);
545
546
0
    for (auto& field : m_fields) {
547
0
        visitor.visit(field.initializer);
548
0
        if (auto* property_key_ptr = field.name.get_pointer<PropertyKey>(); property_key_ptr && property_key_ptr->is_symbol())
549
0
            visitor.visit(property_key_ptr->as_symbol());
550
0
    }
551
552
0
    for (auto& private_element : m_private_methods)
553
0
        visitor.visit(private_element.value);
554
555
0
    m_script_or_module.visit(
556
0
        [](Empty) {},
557
0
        [&](auto& script_or_module) {
558
0
            visitor.visit(script_or_module);
559
0
        });
Unexecuted instantiation: ECMAScriptFunctionObject.cpp:auto JS::ECMAScriptFunctionObject::visit_edges(JS::Cell::Visitor&)::$_1::operator()<JS::NonnullGCPtr<JS::Script> >(JS::NonnullGCPtr<JS::Script>&) const
Unexecuted instantiation: ECMAScriptFunctionObject.cpp:auto JS::ECMAScriptFunctionObject::visit_edges(JS::Cell::Visitor&)::$_1::operator()<JS::NonnullGCPtr<JS::Module> >(JS::NonnullGCPtr<JS::Module>&) const
560
0
}
561
562
// 10.2.7 MakeMethod ( F, homeObject ), https://tc39.es/ecma262/#sec-makemethod
563
void ECMAScriptFunctionObject::make_method(Object& home_object)
564
0
{
565
    // 1. Set F.[[HomeObject]] to homeObject.
566
0
    m_home_object = &home_object;
567
568
    // 2. Return unused.
569
0
}
570
571
// 10.2.1.1 PrepareForOrdinaryCall ( F, newTarget ), https://tc39.es/ecma262/#sec-prepareforordinarycall
572
ThrowCompletionOr<void> ECMAScriptFunctionObject::prepare_for_ordinary_call(ExecutionContext& callee_context, Object* new_target)
573
0
{
574
0
    auto& vm = this->vm();
575
576
    // Non-standard
577
0
    callee_context.is_strict_mode = m_strict;
578
579
    // 1. Let callerContext be the running execution context.
580
    // 2. Let calleeContext be a new ECMAScript code execution context.
581
582
    // NOTE: In the specification, PrepareForOrdinaryCall "returns" a new callee execution context.
583
    // To avoid heap allocations, we put our ExecutionContext objects on the C++ stack instead.
584
    // Whoever calls us should put an ExecutionContext on their stack and pass that as the `callee_context`.
585
586
    // 3. Set the Function of calleeContext to F.
587
0
    callee_context.function = this;
588
0
    callee_context.function_name = m_name_string;
589
590
    // 4. Let calleeRealm be F.[[Realm]].
591
0
    auto callee_realm = m_realm;
592
    // NOTE: This non-standard fallback is needed until we can guarantee that literally
593
    // every function has a realm - especially in LibWeb that's sometimes not the case
594
    // when a function is created while no JS is running, as we currently need to rely on
595
    // that (:acid2:, I know - see set_event_handler_attribute() for an example).
596
    // If there's no 'current realm' either, we can't continue and crash.
597
0
    if (!callee_realm)
598
0
        callee_realm = vm.current_realm();
599
0
    VERIFY(callee_realm);
600
601
    // 5. Set the Realm of calleeContext to calleeRealm.
602
0
    callee_context.realm = callee_realm;
603
604
    // 6. Set the ScriptOrModule of calleeContext to F.[[ScriptOrModule]].
605
0
    callee_context.script_or_module = m_script_or_module;
606
607
0
    if (m_function_environment_needed) {
608
        // 7. Let localEnv be NewFunctionEnvironment(F, newTarget).
609
0
        auto local_environment = new_function_environment(*this, new_target);
610
0
        local_environment->ensure_capacity(m_function_environment_bindings_count);
611
612
        // 8. Set the LexicalEnvironment of calleeContext to localEnv.
613
0
        callee_context.lexical_environment = local_environment;
614
615
        // 9. Set the VariableEnvironment of calleeContext to localEnv.
616
0
        callee_context.variable_environment = local_environment;
617
0
    } else {
618
0
        callee_context.lexical_environment = environment();
619
0
        callee_context.variable_environment = environment();
620
0
    }
621
622
    // 10. Set the PrivateEnvironment of calleeContext to F.[[PrivateEnvironment]].
623
0
    callee_context.private_environment = m_private_environment;
624
625
    // 11. If callerContext is not already suspended, suspend callerContext.
626
    // FIXME: We don't have this concept yet.
627
628
    // 12. Push calleeContext onto the execution context stack; calleeContext is now the running execution context.
629
0
    TRY(vm.push_execution_context(callee_context, {}));
630
631
    // 13. NOTE: Any exception objects produced after this point are associated with calleeRealm.
632
    // 14. Return calleeContext.
633
    // NOTE: See the comment after step 2 above about how contexts are allocated on the C++ stack.
634
0
    return {};
635
0
}
636
637
// 10.2.1.2 OrdinaryCallBindThis ( F, calleeContext, thisArgument ), https://tc39.es/ecma262/#sec-ordinarycallbindthis
638
void ECMAScriptFunctionObject::ordinary_call_bind_this(ExecutionContext& callee_context, Value this_argument)
639
0
{
640
0
    auto& vm = this->vm();
641
642
    // 1. Let thisMode be F.[[ThisMode]].
643
0
    auto this_mode = m_this_mode;
644
645
    // If thisMode is lexical, return unused.
646
0
    if (this_mode == ThisMode::Lexical)
647
0
        return;
648
649
    // 3. Let calleeRealm be F.[[Realm]].
650
0
    auto callee_realm = m_realm;
651
    // NOTE: This non-standard fallback is needed until we can guarantee that literally
652
    // every function has a realm - especially in LibWeb that's sometimes not the case
653
    // when a function is created while no JS is running, as we currently need to rely on
654
    // that (:acid2:, I know - see set_event_handler_attribute() for an example).
655
    // If there's no 'current realm' either, we can't continue and crash.
656
0
    if (!callee_realm)
657
0
        callee_realm = vm.current_realm();
658
0
    VERIFY(callee_realm);
659
660
    // 4. Let localEnv be the LexicalEnvironment of calleeContext.
661
0
    auto local_env = callee_context.lexical_environment;
662
663
0
    Value this_value;
664
665
    // 5. If thisMode is strict, let thisValue be thisArgument.
666
0
    if (this_mode == ThisMode::Strict) {
667
0
        this_value = this_argument;
668
0
    }
669
    // 6. Else,
670
0
    else {
671
        // a. If thisArgument is undefined or null, then
672
0
        if (this_argument.is_nullish()) {
673
            // i. Let globalEnv be calleeRealm.[[GlobalEnv]].
674
            // ii. Assert: globalEnv is a global Environment Record.
675
0
            auto& global_env = callee_realm->global_environment();
676
677
            // iii. Let thisValue be globalEnv.[[GlobalThisValue]].
678
0
            this_value = &global_env.global_this_value();
679
0
        }
680
        // b. Else,
681
0
        else {
682
            // i. Let thisValue be ! ToObject(thisArgument).
683
0
            this_value = MUST(this_argument.to_object(vm));
684
685
            // ii. NOTE: ToObject produces wrapper objects using calleeRealm.
686
0
            VERIFY(vm.current_realm() == callee_realm);
687
0
        }
688
0
    }
689
690
    // 7. Assert: localEnv is a function Environment Record.
691
    // 8. Assert: The next step never returns an abrupt completion because localEnv.[[ThisBindingStatus]] is not initialized.
692
    // 9. Perform ! localEnv.BindThisValue(thisValue).
693
0
    callee_context.this_value = this_value;
694
0
    if (m_function_environment_needed)
695
0
        MUST(verify_cast<FunctionEnvironment>(*local_env).bind_this_value(vm, this_value));
696
697
    // 10. Return unused.
698
0
}
699
700
// 27.7.5.1 AsyncFunctionStart ( promiseCapability, asyncFunctionBody ), https://tc39.es/ecma262/#sec-async-functions-abstract-operations-async-function-start
701
template<typename T>
702
void async_function_start(VM& vm, PromiseCapability const& promise_capability, T const& async_function_body)
703
0
{
704
    // 1. Let runningContext be the running execution context.
705
0
    auto& running_context = vm.running_execution_context();
706
707
    // 2. Let asyncContext be a copy of runningContext.
708
0
    auto async_context = running_context.copy();
709
710
    // 3. NOTE: Copying the execution state is required for AsyncBlockStart to resume its execution. It is ill-defined to resume a currently executing context.
711
712
    // 4. Perform AsyncBlockStart(promiseCapability, asyncFunctionBody, asyncContext).
713
0
    async_block_start(vm, async_function_body, promise_capability, *async_context);
714
715
    // 5. Return unused.
716
0
}
Unexecuted instantiation: void JS::async_function_start<AK::NonnullRefPtr<JS::Statement const> >(JS::VM&, JS::PromiseCapability const&, AK::NonnullRefPtr<JS::Statement const> const&)
Unexecuted instantiation: void JS::async_function_start<JS::SafeFunction<JS::Completion ()> >(JS::VM&, JS::PromiseCapability const&, JS::SafeFunction<JS::Completion ()> const&)
717
718
// 27.7.5.2 AsyncBlockStart ( promiseCapability, asyncBody, asyncContext ), https://tc39.es/ecma262/#sec-asyncblockstart
719
// 12.7.1.1 AsyncBlockStart ( promiseCapability, asyncBody, asyncContext ), https://tc39.es/proposal-explicit-resource-management/#sec-asyncblockstart
720
// 1.2.1.1 AsyncBlockStart ( promiseCapability, asyncBody, asyncContext ), https://tc39.es/proposal-array-from-async/#sec-asyncblockstart
721
template<typename T>
722
void async_block_start(VM& vm, T const& async_body, PromiseCapability const& promise_capability, ExecutionContext& async_context)
723
0
{
724
    // NOTE: This function is a combination between two proposals, so does not exactly match spec steps of either.
725
726
0
    auto& realm = *vm.current_realm();
727
728
    // 1. Assert: promiseCapability is a PromiseCapability Record.
729
730
    // 2. Let runningContext be the running execution context.
731
0
    auto& running_context = vm.running_execution_context();
732
733
    // 3. Set the code evaluation state of asyncContext such that when evaluation is resumed for that execution context the following steps will be performed:
734
0
    auto execution_steps = NativeFunction::create(realm, "", [&async_body, &promise_capability, &async_context](auto& vm) -> ThrowCompletionOr<Value> {
735
0
        Completion result;
736
737
        // a. If asyncBody is a Parse Node, then
738
0
        if constexpr (!IsCallableWithArguments<T, Completion>) {
739
            // a. Let result be the result of evaluating asyncBody.
740
            // FIXME: Cache this executable somewhere.
741
0
            auto maybe_executable = Bytecode::compile(vm, async_body, FunctionKind::Async, "AsyncBlockStart"sv);
742
0
            if (maybe_executable.is_error())
743
0
                result = maybe_executable.release_error();
744
0
            else
745
0
                result = vm.bytecode_interpreter().run_executable(*maybe_executable.value(), {}).value;
746
        }
747
        // b. Else,
748
0
        else {
749
            // i. Assert: asyncBody is an Abstract Closure with no parameters.
750
0
            static_assert(IsCallableWithArguments<T, Completion>);
751
752
            // ii. Let result be asyncBody().
753
0
            result = async_body();
754
0
        }
755
756
        // c. Assert: If we return here, the async function either threw an exception or performed an implicit or explicit return; all awaiting is done.
757
758
        // d. Remove asyncContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context.
759
0
        vm.pop_execution_context();
760
761
        // NOTE: This does not work for Array.fromAsync, likely due to conflicts between that proposal and Explicit Resource Management proposal.
762
0
        if constexpr (!IsCallableWithArguments<T, Completion>) {
763
            // e. Let env be asyncContext's LexicalEnvironment.
764
0
            auto env = async_context.lexical_environment;
765
766
            // f. Set result to DisposeResources(env, result).
767
0
            result = dispose_resources(vm, verify_cast<DeclarativeEnvironment>(env.ptr()), result);
768
0
        } else {
769
0
            (void)async_context;
770
0
        }
771
772
        // g. If result.[[Type]] is normal, then
773
0
        if (result.type() == Completion::Type::Normal) {
774
            // i. Perform ! Call(promiseCapability.[[Resolve]], undefined, « undefined »).
775
0
            MUST(call(vm, *promise_capability.resolve(), js_undefined(), js_undefined()));
776
0
        }
777
        // h. Else if result.[[Type]] is return, then
778
0
        else if (result.type() == Completion::Type::Return) {
779
            // i. Perform ! Call(promiseCapability.[[Resolve]], undefined, « result.[[Value]] »).
780
0
            MUST(call(vm, *promise_capability.resolve(), js_undefined(), *result.value()));
781
0
        }
782
        // i. Else,
783
0
        else {
784
            // i. Assert: result.[[Type]] is throw.
785
0
            VERIFY(result.type() == Completion::Type::Throw);
786
787
            // ii. Perform ! Call(promiseCapability.[[Reject]], undefined, « result.[[Value]] »).
788
0
            MUST(call(vm, *promise_capability.reject(), js_undefined(), *result.value()));
789
0
        }
790
        // j. Return unused.
791
        // NOTE: We don't support returning an empty/optional/unused value here.
792
0
        return js_undefined();
793
0
    });
Unexecuted instantiation: JS::ThrowCompletionOr<JS::Value> JS::async_block_start<AK::NonnullRefPtr<JS::Statement const> >(JS::VM&, AK::NonnullRefPtr<JS::Statement const> const&, JS::PromiseCapability const&, JS::ExecutionContext&)::{lambda(auto:1&)#1}::operator()<JS::VM>(JS::VM&) const
Unexecuted instantiation: JS::ThrowCompletionOr<JS::Value> JS::async_block_start<JS::SafeFunction<JS::Completion ()> >(JS::VM&, JS::SafeFunction<JS::Completion ()> const&, JS::PromiseCapability const&, JS::ExecutionContext&)::{lambda(auto:1&)#1}::operator()<JS::VM>(JS::VM&) const
794
795
    // 4. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
796
0
    auto push_result = vm.push_execution_context(async_context, {});
797
0
    if (push_result.is_error())
798
0
        return;
799
800
    // 5. Resume the suspended evaluation of asyncContext. Let result be the value returned by the resumed computation.
801
0
    auto result = call(vm, *execution_steps, async_context.this_value.is_empty() ? js_undefined() : async_context.this_value);
802
803
    // 6. Assert: When we return here, asyncContext has already been removed from the execution context stack and runningContext is the currently running execution context.
804
0
    VERIFY(&vm.running_execution_context() == &running_context);
805
806
    // 7. Assert: result is a normal completion with a value of unused. The possible sources of this value are Await or, if the async function doesn't await anything, step 3.g above.
807
0
    VERIFY(result.has_value() && result.value().is_undefined());
808
809
    // 8. Return unused.
810
0
}
Unexecuted instantiation: void JS::async_block_start<AK::NonnullRefPtr<JS::Statement const> >(JS::VM&, AK::NonnullRefPtr<JS::Statement const> const&, JS::PromiseCapability const&, JS::ExecutionContext&)
Unexecuted instantiation: void JS::async_block_start<JS::SafeFunction<JS::Completion ()> >(JS::VM&, JS::SafeFunction<JS::Completion ()> const&, JS::PromiseCapability const&, JS::ExecutionContext&)
811
812
template void async_block_start(VM&, NonnullRefPtr<Statement const> const& async_body, PromiseCapability const&, ExecutionContext&);
813
template void async_function_start(VM&, PromiseCapability const&, NonnullRefPtr<Statement const> const& async_function_body);
814
815
template void async_block_start(VM&, SafeFunction<Completion()> const& async_body, PromiseCapability const&, ExecutionContext&);
816
template void async_function_start(VM&, PromiseCapability const&, SafeFunction<Completion()> const& async_function_body);
817
818
// 10.2.1.4 OrdinaryCallEvaluateBody ( F, argumentsList ), https://tc39.es/ecma262/#sec-ordinarycallevaluatebody
819
// 15.8.4 Runtime Semantics: EvaluateAsyncFunctionBody, https://tc39.es/ecma262/#sec-runtime-semantics-evaluatefunctionbody
820
Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body()
821
0
{
822
0
    auto& vm = this->vm();
823
0
    auto& realm = *vm.current_realm();
824
825
0
    if (!m_bytecode_executable) {
826
0
        if (!m_ecmascript_code->bytecode_executable()) {
827
0
            if (is_module_wrapper()) {
828
0
                const_cast<Statement&>(*m_ecmascript_code).set_bytecode_executable(TRY(Bytecode::compile(vm, *m_ecmascript_code, m_kind, m_name)));
829
0
            } else {
830
0
                const_cast<Statement&>(*m_ecmascript_code).set_bytecode_executable(TRY(Bytecode::compile(vm, *this)));
831
0
            }
832
0
        }
833
0
        m_bytecode_executable = m_ecmascript_code->bytecode_executable();
834
0
    }
835
836
0
    vm.running_execution_context().registers_and_constants_and_locals.resize(m_local_variables_names.size() + m_bytecode_executable->number_of_registers + m_bytecode_executable->constants.size());
837
838
0
    auto result_and_frame = vm.bytecode_interpreter().run_executable(*m_bytecode_executable, {});
839
840
0
    if (result_and_frame.value.is_error())
841
0
        return result_and_frame.value.release_error();
842
843
0
    auto result = result_and_frame.value.release_value();
844
845
    // NOTE: Running the bytecode should eventually return a completion.
846
    // Until it does, we assume "return" and include the undefined fallback from the call site.
847
0
    if (m_kind == FunctionKind::Normal)
848
0
        return { Completion::Type::Return, result.value_or(js_undefined()) };
849
850
0
    if (m_kind == FunctionKind::AsyncGenerator) {
851
0
        auto async_generator_object = TRY(AsyncGenerator::create(realm, result, this, vm.running_execution_context().copy()));
852
0
        return { Completion::Type::Return, async_generator_object };
853
0
    }
854
855
0
    auto generator_object = TRY(GeneratorObject::create(realm, result, this, vm.running_execution_context().copy()));
856
857
    // NOTE: Async functions are entirely transformed to generator functions, and wrapped in a custom driver that returns a promise
858
    //       See AwaitExpression::generate_bytecode() for the transformation.
859
0
    if (m_kind == FunctionKind::Async)
860
0
        return { Completion::Type::Return, AsyncFunctionDriverWrapper::create(realm, generator_object) };
861
862
0
    VERIFY(m_kind == FunctionKind::Generator);
863
0
    return { Completion::Type::Return, generator_object };
864
0
}
865
866
void ECMAScriptFunctionObject::set_name(DeprecatedFlyString const& name)
867
0
{
868
0
    auto& vm = this->vm();
869
0
    m_name = name;
870
0
    m_name_string = PrimitiveString::create(vm, m_name);
871
0
    MUST(define_property_or_throw(vm.names.name, { .value = m_name_string, .writable = false, .enumerable = false, .configurable = true }));
872
0
}
873
}