Coverage Report

Created: 2026-06-07 07:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibJS/Runtime/GlobalEnvironment.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2020-2021, 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/Runtime/Completion.h>
9
#include <LibJS/Runtime/DeclarativeEnvironment.h>
10
#include <LibJS/Runtime/EnvironmentCoordinate.h>
11
#include <LibJS/Runtime/GlobalEnvironment.h>
12
#include <LibJS/Runtime/GlobalObject.h>
13
#include <LibJS/Runtime/ObjectEnvironment.h>
14
15
namespace JS {
16
17
JS_DEFINE_ALLOCATOR(GlobalEnvironment);
18
19
// 9.1.2.5 NewGlobalEnvironment ( G, thisValue ), https://tc39.es/ecma262/#sec-newglobalenvironment
20
GlobalEnvironment::GlobalEnvironment(Object& global_object, Object& this_value)
21
52
    : Environment(nullptr)
22
52
    , m_global_this_value(&this_value)
23
52
{
24
52
    m_object_record = global_object.heap().allocate_without_realm<ObjectEnvironment>(global_object, ObjectEnvironment::IsWithEnvironment::No, nullptr);
25
52
    m_declarative_record = global_object.heap().allocate_without_realm<DeclarativeEnvironment>();
26
52
}
27
28
void GlobalEnvironment::visit_edges(Cell::Visitor& visitor)
29
0
{
30
0
    Base::visit_edges(visitor);
31
0
    visitor.visit(m_object_record);
32
0
    visitor.visit(m_global_this_value);
33
0
    visitor.visit(m_declarative_record);
34
0
}
35
36
// 9.1.1.4.11 GetThisBinding ( ), https://tc39.es/ecma262/#sec-global-environment-records-getthisbinding
37
ThrowCompletionOr<Value> GlobalEnvironment::get_this_binding(VM&) const
38
0
{
39
    // 1. Return envRec.[[GlobalThisValue]].
40
0
    return m_global_this_value;
41
0
}
42
43
// 9.1.1.4.1 HasBinding ( N ), https://tc39.es/ecma262/#sec-global-environment-records-hasbinding-n
44
ThrowCompletionOr<bool> GlobalEnvironment::has_binding(DeprecatedFlyString const& name, Optional<size_t>*) const
45
0
{
46
    // 1. Let DclRec be envRec.[[DeclarativeRecord]].
47
    // 2. If ! DclRec.HasBinding(N) is true, return true.
48
0
    if (MUST(m_declarative_record->has_binding(name)))
49
0
        return true;
50
51
    // 3. Let ObjRec be envRec.[[ObjectRecord]].
52
    // 4. Return ? ObjRec.HasBinding(N).
53
0
    return m_object_record->has_binding(name);
54
0
}
55
56
// 9.1.1.4.2 CreateMutableBinding ( N, D ), https://tc39.es/ecma262/#sec-global-environment-records-createmutablebinding-n-d
57
ThrowCompletionOr<void> GlobalEnvironment::create_mutable_binding(VM& vm, DeprecatedFlyString const& name, bool can_be_deleted)
58
0
{
59
    // 1. Let DclRec be envRec.[[DeclarativeRecord]].
60
    // 2. If ! DclRec.HasBinding(N) is true, throw a TypeError exception.
61
0
    if (MUST(m_declarative_record->has_binding(name)))
62
0
        return vm.throw_completion<TypeError>(ErrorType::GlobalEnvironmentAlreadyHasBinding, name);
63
64
    // 3. Return ! DclRec.CreateMutableBinding(N, D).
65
0
    return MUST(m_declarative_record->create_mutable_binding(vm, name, can_be_deleted));
66
0
}
67
68
// 9.1.1.4.3 CreateImmutableBinding ( N, S ), https://tc39.es/ecma262/#sec-global-environment-records-createimmutablebinding-n-s
69
ThrowCompletionOr<void> GlobalEnvironment::create_immutable_binding(VM& vm, DeprecatedFlyString const& name, bool strict)
70
0
{
71
    // 1. Let DclRec be envRec.[[DeclarativeRecord]].
72
    // 2. If ! DclRec.HasBinding(N) is true, throw a TypeError exception.
73
0
    if (MUST(m_declarative_record->has_binding(name)))
74
0
        return vm.throw_completion<TypeError>(ErrorType::GlobalEnvironmentAlreadyHasBinding, name);
75
76
    // 3. Return ! DclRec.CreateImmutableBinding(N, S).
77
0
    return MUST(m_declarative_record->create_immutable_binding(vm, name, strict));
78
0
}
79
80
// 9.1.1.4.4 InitializeBinding ( N, V, hint ), https://tc39.es/ecma262/#sec-global-environment-records-initializebinding-n-v
81
ThrowCompletionOr<void> GlobalEnvironment::initialize_binding(VM& vm, DeprecatedFlyString const& name, Value value, InitializeBindingHint hint)
82
0
{
83
    // 1. Let DclRec be envRec.[[DeclarativeRecord]].
84
    // 2. If ! DclRec.HasBinding(N) is true, then
85
0
    if (MUST(m_declarative_record->has_binding(name))) {
86
        // a. Return ! DclRec.InitializeBinding(N, V, hint).
87
0
        return MUST(m_declarative_record->initialize_binding(vm, name, value, hint));
88
0
    }
89
90
    // 3. Assert: If the binding exists, it must be in the object Environment Record.
91
    // 4. Assert: hint is normal.
92
0
    VERIFY(hint == Environment::InitializeBindingHint::Normal);
93
    // 5. Let ObjRec be envRec.[[ObjectRecord]].
94
    // 6. Return ? ObjRec.InitializeBinding(N, V, normal).
95
0
    return m_object_record->initialize_binding(vm, name, value, Environment::InitializeBindingHint::Normal);
96
0
}
97
98
// 9.1.1.4.5 SetMutableBinding ( N, V, S ), https://tc39.es/ecma262/#sec-global-environment-records-setmutablebinding-n-v-s
99
ThrowCompletionOr<void> GlobalEnvironment::set_mutable_binding(VM& vm, DeprecatedFlyString const& name, Value value, bool strict)
100
0
{
101
    // 1. Let DclRec be envRec.[[DeclarativeRecord]].
102
    // 2. If ! DclRec.HasBinding(N) is true, then
103
0
    if (MUST(m_declarative_record->has_binding(name))) {
104
        // a. Return ? DclRec.SetMutableBinding(N, V, S).
105
0
        return m_declarative_record->set_mutable_binding(vm, name, value, strict);
106
0
    }
107
108
    // 3. Let ObjRec be envRec.[[ObjectRecord]].
109
    // 4. Return ? ObjRec.SetMutableBinding(N, V, S).
110
0
    return m_object_record->set_mutable_binding(vm, name, value, strict);
111
0
}
112
113
// 9.1.1.4.6 GetBindingValue ( N, S ), https://tc39.es/ecma262/#sec-global-environment-records-getbindingvalue-n-s
114
ThrowCompletionOr<Value> GlobalEnvironment::get_binding_value(VM& vm, DeprecatedFlyString const& name, bool strict)
115
0
{
116
    // 1. Let DclRec be envRec.[[DeclarativeRecord]].
117
    // 2. If ! DclRec.HasBinding(N) is true, then
118
0
    Optional<size_t> index;
119
0
    if (MUST(m_declarative_record->has_binding(name, &index))) {
120
        // a. Return ? DclRec.GetBindingValue(N, S).
121
0
        if (index.has_value())
122
0
            return m_declarative_record->get_binding_value_direct(vm, index.value());
123
0
        return m_declarative_record->get_binding_value(vm, name, strict);
124
0
    }
125
126
    // 3. Let ObjRec be envRec.[[ObjectRecord]].
127
    // 4. Return ? ObjRec.GetBindingValue(N, S).
128
0
    return m_object_record->get_binding_value(vm, name, strict);
129
0
}
130
131
// 9.1.1.4.7 DeleteBinding ( N ), https://tc39.es/ecma262/#sec-global-environment-records-deletebinding-n
132
ThrowCompletionOr<bool> GlobalEnvironment::delete_binding(VM& vm, DeprecatedFlyString const& name)
133
0
{
134
    // 1. Let DclRec be envRec.[[DeclarativeRecord]].
135
    // 2. If ! DclRec.HasBinding(N) is true, then
136
0
    if (MUST(m_declarative_record->has_binding(name))) {
137
        // a. Return ! DclRec.DeleteBinding(N).
138
0
        return MUST(m_declarative_record->delete_binding(vm, name));
139
0
    }
140
141
    // 3. Let ObjRec be envRec.[[ObjectRecord]].
142
    // 4. Let globalObject be ObjRec.[[BindingObject]].
143
144
    // 5. Let existingProp be ? HasOwnProperty(globalObject, N).
145
0
    bool existing_prop = TRY(m_object_record->binding_object().has_own_property(name));
146
147
    // 6. If existingProp is true, then
148
0
    if (existing_prop) {
149
        // a. Let status be ? ObjRec.DeleteBinding(N).
150
0
        bool status = TRY(m_object_record->delete_binding(vm, name));
151
152
        // b. If status is true, then
153
0
        if (status) {
154
            // i. Let varNames be envRec.[[VarNames]].
155
            // ii. If N is an element of varNames, remove that element from the varNames.
156
0
            m_var_names.remove_all_matching([&](auto& entry) { return entry == name; });
157
0
        }
158
159
        // c. Return status.
160
0
        return status;
161
0
    }
162
163
    // 7. Return true.
164
0
    return true;
165
0
}
166
167
// 9.1.1.4.12 HasVarDeclaration ( N ), https://tc39.es/ecma262/#sec-hasvardeclaration
168
bool GlobalEnvironment::has_var_declaration(DeprecatedFlyString const& name) const
169
0
{
170
    // 1. Let varDeclaredNames be envRec.[[VarNames]].
171
    // 2. If varDeclaredNames contains N, return true.
172
    // 3. Return false.
173
0
    return m_var_names.contains_slow(name);
174
0
}
175
176
// 9.1.1.4.13 HasLexicalDeclaration ( N ), https://tc39.es/ecma262/#sec-haslexicaldeclaration
177
bool GlobalEnvironment::has_lexical_declaration(DeprecatedFlyString const& name) const
178
0
{
179
    // 1. Let DclRec be envRec.[[DeclarativeRecord]].
180
    // 2. Return ! DclRec.HasBinding(N).
181
0
    return MUST(m_declarative_record->has_binding(name));
182
0
}
183
184
// 9.1.1.4.14 HasRestrictedGlobalProperty ( N ), https://tc39.es/ecma262/#sec-hasrestrictedglobalproperty
185
ThrowCompletionOr<bool> GlobalEnvironment::has_restricted_global_property(DeprecatedFlyString const& name) const
186
0
{
187
    // 1. Let ObjRec be envRec.[[ObjectRecord]].
188
    // 2. Let globalObject be ObjRec.[[BindingObject]].
189
0
    auto& global_object = m_object_record->binding_object();
190
191
    // 3. Let existingProp be ? globalObject.[[GetOwnProperty]](N).
192
0
    auto existing_prop = TRY(global_object.internal_get_own_property(name));
193
194
    // 4. If existingProp is undefined, return false.
195
0
    if (!existing_prop.has_value())
196
0
        return false;
197
198
    // 5. If existingProp.[[Configurable]] is true, return false.
199
0
    if (*existing_prop->configurable)
200
0
        return false;
201
202
    // 6. Return true.
203
0
    return true;
204
0
}
205
206
// 9.1.1.4.15 CanDeclareGlobalVar ( N ), https://tc39.es/ecma262/#sec-candeclareglobalvar
207
ThrowCompletionOr<bool> GlobalEnvironment::can_declare_global_var(DeprecatedFlyString const& name) const
208
0
{
209
    // 1. Let ObjRec be envRec.[[ObjectRecord]].
210
    // 2. Let globalObject be ObjRec.[[BindingObject]].
211
0
    auto& global_object = m_object_record->binding_object();
212
213
    // 3. Let hasProperty be ? HasOwnProperty(globalObject, N).
214
0
    bool has_property = TRY(global_object.has_own_property(name));
215
216
    // 4. If hasProperty is true, return true.
217
0
    if (has_property)
218
0
        return true;
219
220
    // 5. Return ? IsExtensible(globalObject).
221
0
    return global_object.is_extensible();
222
0
}
223
224
// 9.1.1.4.16 CanDeclareGlobalFunction ( N ), https://tc39.es/ecma262/#sec-candeclareglobalfunction
225
ThrowCompletionOr<bool> GlobalEnvironment::can_declare_global_function(DeprecatedFlyString const& name) const
226
0
{
227
    // 1. Let ObjRec be envRec.[[ObjectRecord]].
228
    // 2. Let globalObject be ObjRec.[[BindingObject]].
229
0
    auto& global_object = m_object_record->binding_object();
230
231
    // 3. Let existingProp be ? globalObject.[[GetOwnProperty]](N).
232
0
    auto existing_prop = TRY(global_object.internal_get_own_property(name));
233
234
    // 4. If existingProp is undefined, return ? IsExtensible(globalObject).
235
0
    if (!existing_prop.has_value())
236
0
        return TRY(global_object.is_extensible());
237
238
    // 5. If existingProp.[[Configurable]] is true, return true.
239
0
    if (*existing_prop->configurable)
240
0
        return true;
241
242
    // 6. If IsDataDescriptor(existingProp) is true and existingProp has attribute values { [[Writable]]: true, [[Enumerable]]: true }, return true.
243
0
    if (existing_prop->is_data_descriptor() && *existing_prop->writable && *existing_prop->enumerable)
244
0
        return true;
245
246
    // 7. Return false.
247
0
    return false;
248
0
}
249
250
// 9.1.1.4.17 CreateGlobalVarBinding ( N, D ), https://tc39.es/ecma262/#sec-createglobalvarbinding
251
ThrowCompletionOr<void> GlobalEnvironment::create_global_var_binding(DeprecatedFlyString const& name, bool can_be_deleted)
252
0
{
253
0
    auto& vm = this->vm();
254
255
    // 1. Let ObjRec be envRec.[[ObjectRecord]].
256
    // 2. Let globalObject be ObjRec.[[BindingObject]].
257
0
    auto& global_object = m_object_record->binding_object();
258
259
    // 3. Let hasProperty be ? HasOwnProperty(globalObject, N).
260
0
    auto has_property = TRY(global_object.has_own_property(name));
261
262
    // 4. Let extensible be ? IsExtensible(globalObject).
263
0
    auto extensible = TRY(global_object.is_extensible());
264
265
    // 5. If hasProperty is false and extensible is true, then
266
0
    if (!has_property && extensible) {
267
        // a. Perform ? ObjRec.CreateMutableBinding(N, D).
268
0
        TRY(m_object_record->create_mutable_binding(vm, name, can_be_deleted));
269
270
        // b. Perform ? ObjRec.InitializeBinding(N, undefined, normal).
271
0
        TRY(m_object_record->initialize_binding(vm, name, js_undefined(), Environment::InitializeBindingHint::Normal));
272
0
    }
273
274
    // 6. Let varDeclaredNames be envRec.[[VarNames]].
275
    // 7. If varDeclaredNames does not contain N, then
276
0
    if (!m_var_names.contains_slow(name)) {
277
        // a. Append N to varDeclaredNames.
278
0
        m_var_names.append(name);
279
0
    }
280
281
    // 8. Return unused.
282
0
    return {};
283
0
}
284
285
// 9.1.1.4.18 CreateGlobalFunctionBinding ( N, V, D ), https://tc39.es/ecma262/#sec-createglobalfunctionbinding
286
ThrowCompletionOr<void> GlobalEnvironment::create_global_function_binding(DeprecatedFlyString const& name, Value value, bool can_be_deleted)
287
0
{
288
    // 1. Let ObjRec be envRec.[[ObjectRecord]].
289
    // 2. Let globalObject be ObjRec.[[BindingObject]].
290
0
    auto& global_object = m_object_record->binding_object();
291
292
    // 3. Let existingProp be ? globalObject.[[GetOwnProperty]](N).
293
0
    auto existing_prop = TRY(global_object.internal_get_own_property(name));
294
295
0
    PropertyDescriptor desc;
296
297
    // 4. If existingProp is undefined or existingProp.[[Configurable]] is true, then
298
0
    if (!existing_prop.has_value() || *existing_prop->configurable) {
299
        //     a. Let desc be the PropertyDescriptor { [[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: D }.
300
0
        desc = { .value = value, .writable = true, .enumerable = true, .configurable = can_be_deleted };
301
0
    }
302
    // 5. Else,
303
0
    else {
304
        // a. Let desc be the PropertyDescriptor { [[Value]]: V }.
305
0
        desc = { .value = value };
306
0
    }
307
308
    // 6. Perform ? DefinePropertyOrThrow(globalObject, N, desc).
309
0
    TRY(global_object.define_property_or_throw(name, desc));
310
311
    // 7. Perform ? Set(globalObject, N, V, false).
312
0
    TRY(global_object.set(name, value, Object::ShouldThrowExceptions::Yes));
313
314
    // 8. Let varDeclaredNames be envRec.[[VarNames]].
315
    // 9. If varDeclaredNames does not contain N, then
316
0
    if (!m_var_names.contains_slow(name)) {
317
        // a. Append N to varDeclaredNames.
318
0
        m_var_names.append(name);
319
0
    }
320
321
    // 10. Return unused.
322
0
    return {};
323
0
}
324
325
}