/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 = ¶meter_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&) constUnexecuted 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 | | } |