/src/serenity/Userland/Libraries/LibJS/Runtime/FunctionObject.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> |
3 | | * Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org> |
4 | | * |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | */ |
7 | | |
8 | | #include <LibJS/Interpreter.h> |
9 | | #include <LibJS/Runtime/Completion.h> |
10 | | #include <LibJS/Runtime/FunctionObject.h> |
11 | | |
12 | | namespace JS { |
13 | | |
14 | | FunctionObject::FunctionObject(GlobalObject& global_object, Object* prototype) |
15 | | : Object(global_object, prototype) |
16 | 57.8k | { |
17 | 57.8k | } |
18 | | |
19 | | FunctionObject::FunctionObject(Object& prototype) |
20 | | : Object(prototype) |
21 | 347k | { |
22 | 347k | } |
23 | | |
24 | | // 10.2.9 SetFunctionName ( F, name [ , prefix ] ), https://tc39.es/ecma262/#sec-setfunctionname |
25 | | void FunctionObject::set_function_name(Variant<PropertyKey, PrivateName> const& name_arg, Optional<StringView> const& prefix) |
26 | 57.8k | { |
27 | 57.8k | auto& vm = this->vm(); |
28 | | |
29 | | // 1. Assert: F is an extensible object that does not have a "name" own property. |
30 | 57.8k | VERIFY(m_is_extensible); |
31 | 57.8k | VERIFY(!storage_has(vm.names.name)); |
32 | | |
33 | 0 | String name; |
34 | | |
35 | | // 2. If Type(name) is Symbol, then |
36 | 57.8k | if (auto const* property_key = name_arg.get_pointer<PropertyKey>(); property_key && property_key->is_symbol()) { |
37 | | // a. Let description be name's [[Description]] value. |
38 | 1.52k | auto const& description = property_key->as_symbol()->raw_description(); |
39 | | |
40 | | // b. If description is undefined, set name to the empty String. |
41 | 1.52k | if (!description.has_value()) |
42 | 0 | name = String::empty(); |
43 | | // c. Else, set name to the string-concatenation of "[", description, and "]". |
44 | 1.52k | else |
45 | 1.52k | name = String::formatted("[{}]", *description); |
46 | 1.52k | } |
47 | | // 3. Else if name is a Private Name, then |
48 | 56.3k | else if (auto const* private_name = name_arg.get_pointer<PrivateName>()) { |
49 | | // a. Set name to name.[[Description]]. |
50 | 0 | name = private_name->description; |
51 | 0 | } |
52 | | // NOTE: This is necessary as we use a different parameter name. |
53 | 56.3k | else { |
54 | 56.3k | name = name_arg.get<PropertyKey>().to_string(); |
55 | 56.3k | } |
56 | | |
57 | | // 4. If F has an [[InitialName]] internal slot, then |
58 | 57.8k | if (is<NativeFunction>(this)) { |
59 | | // a. Set F.[[InitialName]] to name. |
60 | 57.8k | static_cast<NativeFunction&>(*this).set_initial_name({}, name); |
61 | 57.8k | } |
62 | | |
63 | | // 5. If prefix is present, then |
64 | 57.8k | if (prefix.has_value()) { |
65 | | // a. Set name to the string-concatenation of prefix, the code unit 0x0020 (SPACE), and name. |
66 | 11.4k | name = String::formatted("{} {}", *prefix, name); |
67 | | |
68 | | // b. If F has an [[InitialName]] internal slot, then |
69 | 11.4k | if (is<NativeFunction>(this)) { |
70 | | // i. Optionally, set F.[[InitialName]] to name. |
71 | 11.4k | static_cast<NativeFunction&>(*this).set_initial_name({}, name); |
72 | 11.4k | } |
73 | 11.4k | } |
74 | | |
75 | | // 6. Perform ! DefinePropertyOrThrow(F, "name", PropertyDescriptor { [[Value]]: name, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }). |
76 | 57.8k | MUST(define_property_or_throw(vm.names.name, PropertyDescriptor { .value = js_string(vm, move(name)), .writable = false, .enumerable = false, .configurable = true })); |
77 | | |
78 | | // 7. Return unused. |
79 | 57.8k | } |
80 | | |
81 | | // 10.2.10 SetFunctionLength ( F, length ), https://tc39.es/ecma262/#sec-setfunctionlength |
82 | | void FunctionObject::set_function_length(double length) |
83 | 57.8k | { |
84 | 57.8k | auto& vm = this->vm(); |
85 | | |
86 | | // "length (a non-negative integer or +∞)" |
87 | 57.8k | VERIFY(trunc(length) == length || __builtin_isinf_sign(length) == 1); |
88 | | |
89 | | // 1. Assert: F is an extensible object that does not have a "length" own property. |
90 | 57.8k | VERIFY(m_is_extensible); |
91 | 57.8k | VERIFY(!storage_has(vm.names.length)); |
92 | | |
93 | | // 2. Perform ! DefinePropertyOrThrow(F, "length", PropertyDescriptor { [[Value]]: 𝔽(length), [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }). |
94 | 57.8k | MUST(define_property_or_throw(vm.names.length, PropertyDescriptor { .value = Value { length }, .writable = false, .enumerable = false, .configurable = true })); |
95 | | |
96 | | // 3. Return unused. |
97 | 57.8k | } |
98 | | |
99 | | } |