Coverage Report

Created: 2025-11-16 07:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibJS/Runtime/Object.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2020-2024, Andreas Kling <kling@serenityos.org>
3
 * Copyright (c) 2020-2023, Linus Groh <linusg@serenityos.org>
4
 *
5
 * SPDX-License-Identifier: BSD-2-Clause
6
 */
7
8
#include <AK/ByteString.h>
9
#include <AK/TypeCasts.h>
10
#include <LibJS/Runtime/AbstractOperations.h>
11
#include <LibJS/Runtime/Accessor.h>
12
#include <LibJS/Runtime/Array.h>
13
#include <LibJS/Runtime/ClassFieldDefinition.h>
14
#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
15
#include <LibJS/Runtime/Error.h>
16
#include <LibJS/Runtime/GlobalObject.h>
17
#include <LibJS/Runtime/NativeFunction.h>
18
#include <LibJS/Runtime/Object.h>
19
#include <LibJS/Runtime/PropertyDescriptor.h>
20
#include <LibJS/Runtime/ProxyObject.h>
21
#include <LibJS/Runtime/Shape.h>
22
#include <LibJS/Runtime/Value.h>
23
24
namespace JS {
25
26
JS_DEFINE_ALLOCATOR(Object);
27
28
static HashMap<GCPtr<Object const>, HashMap<DeprecatedFlyString, Object::IntrinsicAccessor>> s_intrinsics;
29
30
// 10.1.12 OrdinaryObjectCreate ( proto [ , additionalInternalSlotsList ] ), https://tc39.es/ecma262/#sec-ordinaryobjectcreate
31
NonnullGCPtr<Object> Object::create(Realm& realm, Object* prototype)
32
0
{
33
0
    if (!prototype)
34
0
        return realm.heap().allocate<Object>(realm, realm.intrinsics().empty_object_shape());
35
0
    if (prototype == realm.intrinsics().object_prototype())
36
0
        return realm.heap().allocate<Object>(realm, realm.intrinsics().new_object_shape());
37
0
    return realm.heap().allocate<Object>(realm, ConstructWithPrototypeTag::Tag, *prototype);
38
0
}
39
40
NonnullGCPtr<Object> Object::create_prototype(Realm& realm, Object* prototype)
41
0
{
42
0
    auto shape = realm.heap().allocate_without_realm<Shape>(realm);
43
0
    if (prototype)
44
0
        shape->set_prototype_without_transition(prototype);
45
0
    return realm.heap().allocate<Object>(realm, shape);
46
0
}
47
48
NonnullGCPtr<Object> Object::create_with_premade_shape(Shape& shape)
49
0
{
50
0
    return shape.heap().allocate<Object>(shape.realm(), shape);
51
0
}
52
53
Object::Object(GlobalObjectTag, Realm& realm, MayInterfereWithIndexedPropertyAccess may_interfere_with_indexed_property_access)
54
0
    : m_may_interfere_with_indexed_property_access(may_interfere_with_indexed_property_access == MayInterfereWithIndexedPropertyAccess::Yes)
55
0
{
56
    // This is the global object
57
0
    m_shape = heap().allocate_without_realm<Shape>(realm);
58
0
}
59
60
Object::Object(ConstructWithoutPrototypeTag, Realm& realm, MayInterfereWithIndexedPropertyAccess may_interfere_with_indexed_property_access)
61
0
    : m_may_interfere_with_indexed_property_access(may_interfere_with_indexed_property_access == MayInterfereWithIndexedPropertyAccess::Yes)
62
0
{
63
0
    m_shape = heap().allocate_without_realm<Shape>(realm);
64
0
}
65
66
Object::Object(Realm& realm, Object* prototype, MayInterfereWithIndexedPropertyAccess may_interfere_with_indexed_property_access)
67
0
    : m_may_interfere_with_indexed_property_access(may_interfere_with_indexed_property_access == MayInterfereWithIndexedPropertyAccess::Yes)
68
0
{
69
0
    m_shape = realm.intrinsics().empty_object_shape();
70
0
    VERIFY(m_shape);
71
0
    if (prototype != nullptr)
72
0
        set_prototype(prototype);
73
0
}
74
75
Object::Object(ConstructWithPrototypeTag, Object& prototype, MayInterfereWithIndexedPropertyAccess may_interfere_with_indexed_property_access)
76
0
    : m_may_interfere_with_indexed_property_access(may_interfere_with_indexed_property_access == MayInterfereWithIndexedPropertyAccess::Yes)
77
0
{
78
0
    m_shape = prototype.shape().realm().intrinsics().empty_object_shape();
79
0
    VERIFY(m_shape);
80
0
    set_prototype(&prototype);
81
0
}
82
83
Object::Object(Shape& shape, MayInterfereWithIndexedPropertyAccess may_interfere_with_indexed_property_access)
84
0
    : m_may_interfere_with_indexed_property_access(may_interfere_with_indexed_property_access == MayInterfereWithIndexedPropertyAccess::Yes)
85
0
    , m_shape(&shape)
86
0
{
87
0
    m_storage.resize(shape.property_count());
88
0
}
89
90
Object::~Object()
91
0
{
92
0
    if (m_has_intrinsic_accessors)
93
0
        s_intrinsics.remove(this);
94
0
}
95
96
void Object::initialize(Realm&)
97
0
{
98
0
}
99
100
// 7.2 Testing and Comparison Operations, https://tc39.es/ecma262/#sec-testing-and-comparison-operations
101
102
// 7.2.5 IsExtensible ( O ), https://tc39.es/ecma262/#sec-isextensible-o
103
ThrowCompletionOr<bool> Object::is_extensible() const
104
0
{
105
    // 1. Return ? O.[[IsExtensible]]().
106
0
    return internal_is_extensible();
107
0
}
108
109
// 7.3 Operations on Objects, https://tc39.es/ecma262/#sec-operations-on-objects
110
111
// 7.3.2 Get ( O, P ), https://tc39.es/ecma262/#sec-get-o-p
112
ThrowCompletionOr<Value> Object::get(PropertyKey const& property_key) const
113
0
{
114
0
    VERIFY(property_key.is_valid());
115
116
    // 1. Return ? O.[[Get]](P, O).
117
0
    return TRY(internal_get(property_key, this));
118
0
}
119
120
// NOTE: 7.3.3 GetV ( V, P ) is implemented as Value::get().
121
122
// 7.3.4 Set ( O, P, V, Throw ), https://tc39.es/ecma262/#sec-set-o-p-v-throw
123
ThrowCompletionOr<void> Object::set(PropertyKey const& property_key, Value value, ShouldThrowExceptions throw_exceptions)
124
0
{
125
0
    auto& vm = this->vm();
126
127
0
    VERIFY(property_key.is_valid());
128
0
    VERIFY(!value.is_empty());
129
130
    // 1. Let success be ? O.[[Set]](P, V, O).
131
0
    auto success = TRY(internal_set(property_key, value, this));
132
133
    // 2. If success is false and Throw is true, throw a TypeError exception.
134
0
    if (!success && throw_exceptions == ShouldThrowExceptions::Yes) {
135
        // FIXME: Improve/contextualize error message
136
0
        return vm.throw_completion<TypeError>(ErrorType::ObjectSetReturnedFalse);
137
0
    }
138
139
    // 3. Return unused.
140
0
    return {};
141
0
}
142
143
// 7.3.5 CreateDataProperty ( O, P, V ), https://tc39.es/ecma262/#sec-createdataproperty
144
ThrowCompletionOr<bool> Object::create_data_property(PropertyKey const& property_key, Value value)
145
0
{
146
0
    VERIFY(property_key.is_valid());
147
148
    // 1. Let newDesc be the PropertyDescriptor { [[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true }.
149
0
    auto new_descriptor = PropertyDescriptor {
150
0
        .value = value,
151
0
        .writable = true,
152
0
        .enumerable = true,
153
0
        .configurable = true,
154
0
    };
155
156
    // 2. Return ? O.[[DefineOwnProperty]](P, newDesc).
157
0
    return internal_define_own_property(property_key, new_descriptor);
158
0
}
159
160
// 7.3.6 CreateMethodProperty ( O, P, V ), https://tc39.es/ecma262/#sec-createmethodproperty
161
void Object::create_method_property(PropertyKey const& property_key, Value value)
162
0
{
163
0
    VERIFY(property_key.is_valid());
164
0
    VERIFY(!value.is_empty());
165
166
    // 1. Assert: O is an ordinary, extensible object with no non-configurable properties.
167
168
    // 2. Let newDesc be the PropertyDescriptor { [[Value]]: V, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }.
169
0
    auto new_descriptor = PropertyDescriptor {
170
0
        .value = value,
171
0
        .writable = true,
172
0
        .enumerable = false,
173
0
        .configurable = true,
174
0
    };
175
176
    // 3. Perform ! O.[[DefineOwnProperty]](P, newDesc).
177
0
    MUST(internal_define_own_property(property_key, new_descriptor));
178
179
    // 4. Return unused.
180
0
}
181
182
// 7.3.7 CreateDataPropertyOrThrow ( O, P, V ), https://tc39.es/ecma262/#sec-createdatapropertyorthrow
183
ThrowCompletionOr<bool> Object::create_data_property_or_throw(PropertyKey const& property_key, Value value)
184
0
{
185
0
    auto& vm = this->vm();
186
187
0
    VERIFY(property_key.is_valid());
188
0
    VERIFY(!value.is_empty());
189
190
    // 1. Let success be ? CreateDataProperty(O, P, V).
191
0
    auto success = TRY(create_data_property(property_key, value));
192
193
    // 2. If success is false, throw a TypeError exception.
194
0
    if (!success) {
195
        // FIXME: Improve/contextualize error message
196
0
        return vm.throw_completion<TypeError>(ErrorType::ObjectDefineOwnPropertyReturnedFalse);
197
0
    }
198
199
    // 3. Return success.
200
0
    return success;
201
0
}
202
203
// 7.3.8 CreateNonEnumerableDataPropertyOrThrow ( O, P, V ), https://tc39.es/ecma262/#sec-createnonenumerabledatapropertyorthrow
204
void Object::create_non_enumerable_data_property_or_throw(PropertyKey const& property_key, Value value)
205
0
{
206
0
    VERIFY(property_key.is_valid());
207
0
    VERIFY(!value.is_empty());
208
209
    // 1. Assert: O is an ordinary, extensible object with no non-configurable properties.
210
211
    // 2. Let newDesc be the PropertyDescriptor { [[Value]]: V, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }.
212
0
    auto new_description = PropertyDescriptor { .value = value, .writable = true, .enumerable = false, .configurable = true };
213
214
    // 3. Perform ! DefinePropertyOrThrow(O, P, newDesc).
215
0
    MUST(define_property_or_throw(property_key, new_description));
216
217
    // 4. Return unused.
218
0
}
219
220
// 7.3.9 DefinePropertyOrThrow ( O, P, desc ), https://tc39.es/ecma262/#sec-definepropertyorthrow
221
ThrowCompletionOr<void> Object::define_property_or_throw(PropertyKey const& property_key, PropertyDescriptor const& property_descriptor)
222
0
{
223
0
    auto& vm = this->vm();
224
225
0
    VERIFY(property_key.is_valid());
226
227
    // 1. Let success be ? O.[[DefineOwnProperty]](P, desc).
228
0
    auto success = TRY(internal_define_own_property(property_key, property_descriptor));
229
230
    // 2. If success is false, throw a TypeError exception.
231
0
    if (!success) {
232
        // FIXME: Improve/contextualize error message
233
0
        return vm.throw_completion<TypeError>(ErrorType::ObjectDefineOwnPropertyReturnedFalse);
234
0
    }
235
236
    // 3. Return unused.
237
0
    return {};
238
0
}
239
240
// 7.3.10 DeletePropertyOrThrow ( O, P ), https://tc39.es/ecma262/#sec-deletepropertyorthrow
241
ThrowCompletionOr<void> Object::delete_property_or_throw(PropertyKey const& property_key)
242
0
{
243
0
    auto& vm = this->vm();
244
245
0
    VERIFY(property_key.is_valid());
246
247
    // 1. Let success be ? O.[[Delete]](P).
248
0
    auto success = TRY(internal_delete(property_key));
249
250
    // 2. If success is false, throw a TypeError exception.
251
0
    if (!success) {
252
        // FIXME: Improve/contextualize error message
253
0
        return vm.throw_completion<TypeError>(ErrorType::ObjectDeleteReturnedFalse);
254
0
    }
255
256
    // 3. Return unused.
257
0
    return {};
258
0
}
259
260
// 7.3.12 HasProperty ( O, P ), https://tc39.es/ecma262/#sec-hasproperty
261
ThrowCompletionOr<bool> Object::has_property(PropertyKey const& property_key) const
262
0
{
263
0
    VERIFY(property_key.is_valid());
264
265
    // 1. Return ? O.[[HasProperty]](P).
266
0
    return internal_has_property(property_key);
267
0
}
268
269
// 7.3.13 HasOwnProperty ( O, P ), https://tc39.es/ecma262/#sec-hasownproperty
270
ThrowCompletionOr<bool> Object::has_own_property(PropertyKey const& property_key) const
271
0
{
272
0
    VERIFY(property_key.is_valid());
273
274
    // 1. Let desc be ? O.[[GetOwnProperty]](P).
275
0
    auto descriptor = TRY(internal_get_own_property(property_key));
276
277
    // 2. If desc is undefined, return false.
278
0
    if (!descriptor.has_value())
279
0
        return false;
280
281
    // 3. Return true.
282
0
    return true;
283
0
}
284
285
// 7.3.16 SetIntegrityLevel ( O, level ), https://tc39.es/ecma262/#sec-setintegritylevel
286
ThrowCompletionOr<bool> Object::set_integrity_level(IntegrityLevel level)
287
0
{
288
0
    auto& vm = this->vm();
289
290
    // 1. Let status be ? O.[[PreventExtensions]]().
291
0
    auto status = TRY(internal_prevent_extensions());
292
293
    // 2. If status is false, return false.
294
0
    if (!status)
295
0
        return false;
296
297
    // 3. Let keys be ? O.[[OwnPropertyKeys]]().
298
0
    auto keys = TRY(internal_own_property_keys());
299
300
    // 4. If level is sealed, then
301
0
    if (level == IntegrityLevel::Sealed) {
302
        // a. For each element k of keys, do
303
0
        for (auto& key : keys) {
304
0
            auto property_key = MUST(PropertyKey::from_value(vm, key));
305
306
            // i. Perform ? DefinePropertyOrThrow(O, k, PropertyDescriptor { [[Configurable]]: false }).
307
0
            TRY(define_property_or_throw(property_key, { .configurable = false }));
308
0
        }
309
0
    }
310
    // 5. Else,
311
0
    else {
312
        // a. Assert: level is frozen.
313
314
        // b. For each element k of keys, do
315
0
        for (auto& key : keys) {
316
0
            auto property_key = MUST(PropertyKey::from_value(vm, key));
317
318
            // i. Let currentDesc be ? O.[[GetOwnProperty]](k).
319
0
            auto current_descriptor = TRY(internal_get_own_property(property_key));
320
321
            // ii. If currentDesc is not undefined, then
322
0
            if (!current_descriptor.has_value())
323
0
                continue;
324
325
0
            PropertyDescriptor descriptor;
326
327
            // 1. If IsAccessorDescriptor(currentDesc) is true, then
328
0
            if (current_descriptor->is_accessor_descriptor()) {
329
                // a. Let desc be the PropertyDescriptor { [[Configurable]]: false }.
330
0
                descriptor = { .configurable = false };
331
0
            }
332
            // 2. Else,
333
0
            else {
334
                // a. Let desc be the PropertyDescriptor { [[Configurable]]: false, [[Writable]]: false }.
335
0
                descriptor = { .writable = false, .configurable = false };
336
0
            }
337
338
            // 3. Perform ? DefinePropertyOrThrow(O, k, desc).
339
0
            TRY(define_property_or_throw(property_key, descriptor));
340
0
        }
341
0
    }
342
343
    // 6. Return true.
344
0
    return true;
345
0
}
346
347
// 7.3.17 TestIntegrityLevel ( O, level ), https://tc39.es/ecma262/#sec-testintegritylevel
348
ThrowCompletionOr<bool> Object::test_integrity_level(IntegrityLevel level) const
349
0
{
350
0
    auto& vm = this->vm();
351
352
    // 1. Let extensible be ? IsExtensible(O).
353
0
    auto extensible = TRY(is_extensible());
354
355
    // 2. If extensible is true, return false.
356
    // 3. NOTE: If the object is extensible, none of its properties are examined.
357
0
    if (extensible)
358
0
        return false;
359
360
    // 4. Let keys be ? O.[[OwnPropertyKeys]]().
361
0
    auto keys = TRY(internal_own_property_keys());
362
363
    // 5. For each element k of keys, do
364
0
    for (auto& key : keys) {
365
0
        auto property_key = MUST(PropertyKey::from_value(vm, key));
366
367
        // a. Let currentDesc be ? O.[[GetOwnProperty]](k).
368
0
        auto current_descriptor = TRY(internal_get_own_property(property_key));
369
370
        // b. If currentDesc is not undefined, then
371
0
        if (!current_descriptor.has_value())
372
0
            continue;
373
        // i. If currentDesc.[[Configurable]] is true, return false.
374
0
        if (*current_descriptor->configurable)
375
0
            return false;
376
377
        // ii. If level is frozen and IsDataDescriptor(currentDesc) is true, then
378
0
        if (level == IntegrityLevel::Frozen && current_descriptor->is_data_descriptor()) {
379
            // 1. If currentDesc.[[Writable]] is true, return false.
380
0
            if (*current_descriptor->writable)
381
0
                return false;
382
0
        }
383
0
    }
384
385
    // 6. Return true.
386
0
    return true;
387
0
}
388
389
// 7.3.24 EnumerableOwnPropertyNames ( O, kind ), https://tc39.es/ecma262/#sec-enumerableownpropertynames
390
ThrowCompletionOr<MarkedVector<Value>> Object::enumerable_own_property_names(PropertyKind kind) const
391
0
{
392
    // NOTE: This has been flattened for readability, so some `else` branches in the
393
    //       spec text have been replaced with `continue`s in the loop below.
394
395
0
    auto& vm = this->vm();
396
0
    auto& realm = *vm.current_realm();
397
398
    // 1. Let ownKeys be ? O.[[OwnPropertyKeys]]().
399
0
    auto own_keys = TRY(internal_own_property_keys());
400
401
    // 2. Let properties be a new empty List.
402
0
    auto properties = MarkedVector<Value> { heap() };
403
404
    // 3. For each element key of ownKeys, do
405
0
    for (auto& key : own_keys) {
406
        // a. If Type(key) is String, then
407
0
        if (!key.is_string())
408
0
            continue;
409
0
        auto property_key = MUST(PropertyKey::from_value(vm, key));
410
411
        // i. Let desc be ? O.[[GetOwnProperty]](key).
412
0
        auto descriptor = TRY(internal_get_own_property(property_key));
413
414
        // ii. If desc is not undefined and desc.[[Enumerable]] is true, then
415
0
        if (descriptor.has_value() && *descriptor->enumerable) {
416
            // 1. If kind is key, append key to properties.
417
0
            if (kind == PropertyKind::Key) {
418
0
                properties.append(key);
419
0
                continue;
420
0
            }
421
            // 2. Else,
422
423
            // a. Let value be ? Get(O, key).
424
0
            auto value = TRY(get(property_key));
425
426
            // b. If kind is value, append value to properties.
427
0
            if (kind == PropertyKind::Value) {
428
0
                properties.append(value);
429
0
                continue;
430
0
            }
431
            // c. Else,
432
433
            // i. Assert: kind is key+value.
434
0
            VERIFY(kind == PropertyKind::KeyAndValue);
435
436
            // ii. Let entry be CreateArrayFromList(« key, value »).
437
0
            auto entry = Array::create_from(realm, { key, value });
438
439
            // iii. Append entry to properties.
440
0
            properties.append(entry);
441
0
        }
442
0
    }
443
444
    // 4. Return properties.
445
0
    return { move(properties) };
446
0
}
447
448
// 7.3.26 CopyDataProperties ( target, source, excludedItems ), https://tc39.es/ecma262/#sec-copydataproperties
449
// 14.6 CopyDataProperties ( target, source, excludedItems, excludedKeys [ , excludedValues ] ), https://tc39.es/proposal-temporal/#sec-copydataproperties
450
ThrowCompletionOr<void> Object::copy_data_properties(VM& vm, Value source, HashTable<PropertyKey> const& excluded_keys, HashTable<JS::Value> const& excluded_values)
451
0
{
452
    // 1. If source is either undefined or null, return unused.
453
0
    if (source.is_nullish())
454
0
        return {};
455
456
    // 2. Let from be ! ToObject(source).
457
0
    auto from = MUST(source.to_object(vm));
458
459
    // 3. Let keys be ? from.[[OwnPropertyKeys]]().
460
0
    auto keys = TRY(from->internal_own_property_keys());
461
462
    // 4. For each element nextKey of keys, do
463
0
    for (auto& next_key_value : keys) {
464
0
        auto next_key = MUST(PropertyKey::from_value(vm, next_key_value));
465
466
        // a. Let excluded be false.
467
        // b. For each element e of excludedKeys, do
468
        //    i. If SameValue(e, nextKey) is true, then
469
        //        1. Set excluded to true.
470
0
        if (excluded_keys.contains(next_key))
471
0
            continue;
472
473
        // c. If excluded is false, then
474
475
        // i. Let desc be ? from.[[GetOwnProperty]](nextKey).
476
0
        auto desc = TRY(from->internal_get_own_property(next_key));
477
478
        // ii. If desc is not undefined and desc.[[Enumerable]] is true, then
479
0
        if (desc.has_value() && desc->attributes().is_enumerable()) {
480
            // 1. Let propValue be ? Get(from, nextKey).
481
0
            auto prop_value = TRY(from->get(next_key));
482
483
            // 2. If excludedValues is present, then
484
            //     a. For each element e of excludedValues, do
485
            //         i. If SameValue(e, propValue) is true, then
486
            //             i. Set excluded to true.
487
            // 3. If excluded is false, Perform ! CreateDataPropertyOrThrow(target, nextKey, propValue).
488
            // NOTE: HashTable traits for JS::Value uses SameValue.
489
0
            if (!excluded_values.contains(prop_value))
490
0
                MUST(create_data_property_or_throw(next_key, prop_value));
491
0
        }
492
0
    }
493
494
    // 5. Return unused.
495
0
    return {};
496
0
}
497
498
// 14.7 SnapshotOwnProperties ( source, proto [ , excludedKeys [ , excludedValues ] ] ), https://tc39.es/proposal-temporal/#sec-snapshotownproperties
499
ThrowCompletionOr<NonnullGCPtr<Object>> Object::snapshot_own_properties(VM& vm, GCPtr<Object> prototype, HashTable<PropertyKey> const& excluded_keys, HashTable<Value> const& excluded_values)
500
0
{
501
0
    auto& realm = *vm.current_realm();
502
503
    // 1. Let copy be OrdinaryObjectCreate(proto).
504
0
    auto copy = Object::create(realm, prototype);
505
506
    // 2. If excludedKeys is not present, set excludedKeys to « ».
507
    // 3. If excludedValues is not present, set excludedValues to « ».
508
    // 4. Perform ? CopyDataProperties(copy, source, excludedKeys, excludedValues).
509
0
    TRY(copy->copy_data_properties(vm, Value { this }, excluded_keys, excluded_values));
510
511
    // 5. Return copy.
512
0
    return copy;
513
0
}
514
515
// 7.3.27 PrivateElementFind ( O, P ), https://tc39.es/ecma262/#sec-privateelementfind
516
PrivateElement* Object::private_element_find(PrivateName const& name)
517
0
{
518
0
    if (!m_private_elements)
519
0
        return nullptr;
520
521
    // 1. If O.[[PrivateElements]] contains a PrivateElement pe such that pe.[[Key]] is P, then
522
0
    auto it = m_private_elements->find_if([&](auto const& element) {
523
0
        return element.key == name;
524
0
    });
525
526
0
    if (!it.is_end()) {
527
        // a. Return pe.
528
0
        return &(*it);
529
0
    }
530
531
    // 2. Return empty.
532
0
    return nullptr;
533
0
}
534
535
// 7.3.28 PrivateFieldAdd ( O, P, value ), https://tc39.es/ecma262/#sec-privatefieldadd
536
ThrowCompletionOr<void> Object::private_field_add(PrivateName const& name, Value value)
537
0
{
538
0
    auto& vm = this->vm();
539
540
    // 1. If the host is a web browser, then
541
    //    a. Perform ? HostEnsureCanAddPrivateElement(O).
542
    // NOTE: Since LibJS has no way of knowing whether it is in a browser we just always call the hook.
543
0
    TRY(vm.host_ensure_can_add_private_element(*this));
544
545
    // 2. Let entry be PrivateElementFind(O, P).
546
    // 3. If entry is not empty, throw a TypeError exception.
547
0
    if (auto* entry = private_element_find(name); entry)
548
0
        return vm.throw_completion<TypeError>(ErrorType::PrivateFieldAlreadyDeclared, name.description);
549
550
0
    if (!m_private_elements)
551
0
        m_private_elements = make<Vector<PrivateElement>>();
552
553
    // 4. Append PrivateElement { [[Key]]: P, [[Kind]]: field, [[Value]]: value } to O.[[PrivateElements]].
554
0
    m_private_elements->empend(name, PrivateElement::Kind::Field, value);
555
556
    // 5. Return unused.
557
0
    return {};
558
0
}
559
560
// 7.3.29 PrivateMethodOrAccessorAdd ( O, method ), https://tc39.es/ecma262/#sec-privatemethodoraccessoradd
561
ThrowCompletionOr<void> Object::private_method_or_accessor_add(PrivateElement element)
562
0
{
563
0
    auto& vm = this->vm();
564
565
    // 1. Assert: method.[[Kind]] is either method or accessor.
566
0
    VERIFY(element.kind == PrivateElement::Kind::Method || element.kind == PrivateElement::Kind::Accessor);
567
568
    // 2. If the host is a web browser, then
569
    //    a. Perform ? HostEnsureCanAddPrivateElement(O).
570
    // NOTE: Since LibJS has no way of knowing whether it is in a browser we just always call the hook.
571
0
    TRY(vm.host_ensure_can_add_private_element(*this));
572
573
    // 3. Let entry be PrivateElementFind(O, method.[[Key]]).
574
    // 4. If entry is not empty, throw a TypeError exception.
575
0
    if (auto* entry = private_element_find(element.key); entry)
576
0
        return vm.throw_completion<TypeError>(ErrorType::PrivateFieldAlreadyDeclared, element.key.description);
577
578
0
    if (!m_private_elements)
579
0
        m_private_elements = make<Vector<PrivateElement>>();
580
581
    // 5. Append method to O.[[PrivateElements]].
582
0
    m_private_elements->append(move(element));
583
584
    // 6. Return unused.
585
0
    return {};
586
0
}
587
588
// 7.3.31 PrivateGet ( O, P ), https://tc39.es/ecma262/#sec-privateget
589
ThrowCompletionOr<Value> Object::private_get(PrivateName const& name)
590
0
{
591
0
    auto& vm = this->vm();
592
593
    // 1. Let entry be PrivateElementFind(O, P).
594
0
    auto* entry = private_element_find(name);
595
596
    // 2. If entry is empty, throw a TypeError exception.
597
0
    if (!entry)
598
0
        return vm.throw_completion<TypeError>(ErrorType::PrivateFieldDoesNotExistOnObject, name.description);
599
600
0
    auto& value = entry->value;
601
602
    // 3. If entry.[[Kind]] is either field or method, then
603
0
    if (entry->kind != PrivateElement::Kind::Accessor) {
604
        // a. Return entry.[[Value]].
605
0
        return value;
606
0
    }
607
608
    // Assert: entry.[[Kind]] is accessor.
609
0
    VERIFY(value.is_accessor());
610
611
    // 6. Let getter be entry.[[Get]].
612
0
    auto* getter = value.as_accessor().getter();
613
614
    // 5. If entry.[[Get]] is undefined, throw a TypeError exception.
615
0
    if (!getter)
616
0
        return vm.throw_completion<TypeError>(ErrorType::PrivateFieldGetAccessorWithoutGetter, name.description);
617
618
    // 7. Return ? Call(getter, O).
619
0
    return TRY(call(vm, *getter, this));
620
0
}
621
622
// 7.3.32 PrivateSet ( O, P, value ), https://tc39.es/ecma262/#sec-privateset
623
ThrowCompletionOr<void> Object::private_set(PrivateName const& name, Value value)
624
0
{
625
0
    auto& vm = this->vm();
626
627
    // 1. Let entry be PrivateElementFind(O, P).
628
0
    auto* entry = private_element_find(name);
629
630
    // 2. If entry is empty, throw a TypeError exception.
631
0
    if (!entry)
632
0
        return vm.throw_completion<TypeError>(ErrorType::PrivateFieldDoesNotExistOnObject, name.description);
633
634
    // 3. If entry.[[Kind]] is field, then
635
0
    if (entry->kind == PrivateElement::Kind::Field) {
636
        // a. Set entry.[[Value]] to value.
637
0
        entry->value = value;
638
0
        return {};
639
0
    }
640
    // 4. Else if entry.[[Kind]] is method, then
641
0
    else if (entry->kind == PrivateElement::Kind::Method) {
642
        // a. Throw a TypeError exception.
643
0
        return vm.throw_completion<TypeError>(ErrorType::PrivateFieldSetMethod, name.description);
644
0
    }
645
646
    // 5. Else,
647
648
    // a. Assert: entry.[[Kind]] is accessor.
649
0
    VERIFY(entry->kind == PrivateElement::Kind::Accessor);
650
651
0
    auto& accessor = entry->value;
652
0
    VERIFY(accessor.is_accessor());
653
654
    // c. Let setter be entry.[[Set]].
655
0
    auto* setter = accessor.as_accessor().setter();
656
657
    // b. If entry.[[Set]] is undefined, throw a TypeError exception.
658
0
    if (!setter)
659
0
        return vm.throw_completion<TypeError>(ErrorType::PrivateFieldSetAccessorWithoutSetter, name.description);
660
661
    // d. Perform ? Call(setter, O, « value »).
662
0
    TRY(call(vm, *setter, this, value));
663
664
    // 6. Return unused.
665
0
    return {};
666
0
}
667
668
// 7.3.33 DefineField ( receiver, fieldRecord ), https://tc39.es/ecma262/#sec-definefield
669
ThrowCompletionOr<void> Object::define_field(ClassFieldDefinition const& field)
670
0
{
671
0
    auto& vm = this->vm();
672
673
    // 1. Let fieldName be fieldRecord.[[Name]].
674
0
    auto const& field_name = field.name;
675
676
    // 2. Let initializer be fieldRecord.[[Initializer]].
677
0
    auto const& initializer = field.initializer;
678
679
0
    auto init_value = js_undefined();
680
681
    // 3. If initializer is not empty, then
682
0
    if (initializer) {
683
        // a. Let initValue be ? Call(initializer, receiver).
684
0
        init_value = TRY(call(vm, initializer, this));
685
0
    }
686
    // 4. Else, let initValue be undefined.
687
688
    // 5. If fieldName is a Private Name, then
689
0
    if (field_name.has<PrivateName>()) {
690
        // a. Perform ? PrivateFieldAdd(receiver, fieldName, initValue).
691
0
        TRY(private_field_add(field_name.get<PrivateName>(), init_value));
692
0
    }
693
    // 6. Else,
694
0
    else {
695
        // a. Assert: IsPropertyKey(fieldName) is true.
696
        // b. Perform ? CreateDataPropertyOrThrow(receiver, fieldName, initValue).
697
0
        TRY(create_data_property_or_throw(field_name.get<PropertyKey>(), init_value));
698
0
    }
699
700
    // 7. Return unused.
701
0
    return {};
702
0
}
703
704
// 7.3.34 InitializeInstanceElements ( O, constructor ), https://tc39.es/ecma262/#sec-initializeinstanceelements
705
ThrowCompletionOr<void> Object::initialize_instance_elements(ECMAScriptFunctionObject& constructor)
706
0
{
707
    // 1. Let methods be the value of constructor.[[PrivateMethods]].
708
    // 2. For each PrivateElement method of methods, do
709
0
    for (auto const& method : constructor.private_methods()) {
710
        // a. Perform ? PrivateMethodOrAccessorAdd(O, method).
711
0
        TRY(private_method_or_accessor_add(method));
712
0
    }
713
714
    // 3. Let fields be the value of constructor.[[Fields]].
715
    // 4. For each element fieldRecord of fields, do
716
0
    for (auto const& field : constructor.fields()) {
717
        // a. Perform ? DefineField(O, fieldRecord).
718
0
        TRY(define_field(field));
719
0
    }
720
721
    // 5. Return unused.
722
0
    return {};
723
0
}
724
725
// 10.1 Ordinary Object Internal Methods and Internal Slots, https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots
726
727
// 10.1.1 [[GetPrototypeOf]] ( ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-getprototypeof
728
ThrowCompletionOr<Object*> Object::internal_get_prototype_of() const
729
0
{
730
    // 1. Return O.[[Prototype]].
731
0
    return const_cast<Object*>(prototype());
732
0
}
733
734
// 10.1.2 [[SetPrototypeOf]] ( V ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-setprototypeof-v
735
ThrowCompletionOr<bool> Object::internal_set_prototype_of(Object* new_prototype)
736
0
{
737
    // 1. Let current be O.[[Prototype]].
738
    // 2. If SameValue(V, current) is true, return true.
739
0
    if (prototype() == new_prototype)
740
0
        return true;
741
742
    // 3. Let extensible be O.[[Extensible]].
743
    // 4. If extensible is false, return false.
744
0
    if (!m_is_extensible)
745
0
        return false;
746
747
    // 5. Let p be V.
748
0
    auto* prototype = new_prototype;
749
750
    // 6. Let done be false.
751
    // 7. Repeat, while done is false,
752
0
    while (prototype) {
753
        // a. If p is null, set done to true.
754
755
        // b. Else if SameValue(p, O) is true, return false.
756
0
        if (prototype == this)
757
0
            return false;
758
        // c. Else,
759
760
        // i. If p.[[GetPrototypeOf]] is not the ordinary object internal method defined in 10.1.1, set done to true.
761
        // NOTE: This is a best-effort implementation; we don't have a good way of detecting whether certain virtual
762
        // Object methods have been overridden by a given object, but as ProxyObject is the only one doing that for
763
        // [[SetPrototypeOf]], this check does the trick.
764
0
        if (is<ProxyObject>(prototype))
765
0
            break;
766
767
        // ii. Else, set p to p.[[Prototype]].
768
0
        prototype = prototype->prototype();
769
0
    }
770
771
    // 8. Set O.[[Prototype]] to V.
772
0
    set_prototype(new_prototype);
773
774
    // 9. Return true.
775
0
    return true;
776
0
}
777
778
// 10.1.3 [[IsExtensible]] ( ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-isextensible
779
ThrowCompletionOr<bool> Object::internal_is_extensible() const
780
0
{
781
    // 1. Return O.[[Extensible]].
782
0
    return m_is_extensible;
783
0
}
784
785
// 10.1.4 [[PreventExtensions]] ( ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-preventextensions
786
ThrowCompletionOr<bool> Object::internal_prevent_extensions()
787
0
{
788
    // 1. Set O.[[Extensible]] to false.
789
0
    m_is_extensible = false;
790
791
    // 2. Return true.
792
0
    return true;
793
0
}
794
795
// 10.1.5 [[GetOwnProperty]] ( P ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-getownproperty-p
796
ThrowCompletionOr<Optional<PropertyDescriptor>> Object::internal_get_own_property(PropertyKey const& property_key) const
797
0
{
798
0
    VERIFY(property_key.is_valid());
799
800
    // 1. If O does not have an own property with key P, return undefined.
801
0
    auto maybe_storage_entry = storage_get(property_key);
802
0
    if (!maybe_storage_entry.has_value())
803
0
        return Optional<PropertyDescriptor> {};
804
805
    // 2. Let D be a newly created Property Descriptor with no fields.
806
0
    PropertyDescriptor descriptor;
807
808
    // 3. Let X be O's own property whose key is P.
809
0
    auto [value, attributes, property_offset] = *maybe_storage_entry;
810
811
    // AD-HOC: Properties with the [[Unimplemented]] attribute are used for reporting unimplemented IDL interfaces.
812
0
    if (attributes.is_unimplemented()) {
813
0
        if (vm().on_unimplemented_property_access)
814
0
            vm().on_unimplemented_property_access(*this, property_key);
815
0
        descriptor.unimplemented = true;
816
0
    }
817
818
    // 4. If X is a data property, then
819
0
    if (!value.is_accessor()) {
820
        // a. Set D.[[Value]] to the value of X's [[Value]] attribute.
821
0
        descriptor.value = value.value_or(js_undefined());
822
823
        // b. Set D.[[Writable]] to the value of X's [[Writable]] attribute.
824
0
        descriptor.writable = attributes.is_writable();
825
0
    }
826
    // 5. Else,
827
0
    else {
828
        // a. Assert: X is an accessor property.
829
830
        // b. Set D.[[Get]] to the value of X's [[Get]] attribute.
831
0
        descriptor.get = value.as_accessor().getter();
832
833
        // c. Set D.[[Set]] to the value of X's [[Set]] attribute.
834
0
        descriptor.set = value.as_accessor().setter();
835
0
    }
836
837
    // 6. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
838
0
    descriptor.enumerable = attributes.is_enumerable();
839
840
    // 7. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
841
0
    descriptor.configurable = attributes.is_configurable();
842
843
    // Non-standard: Add the property offset to the descriptor. This is used to populate CacheablePropertyMetadata.
844
0
    descriptor.property_offset = property_offset;
845
846
    // 8. Return D.
847
0
    return descriptor;
848
0
}
849
850
// 10.1.6 [[DefineOwnProperty]] ( P, Desc ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-defineownproperty-p-desc
851
ThrowCompletionOr<bool> Object::internal_define_own_property(PropertyKey const& property_key, PropertyDescriptor const& property_descriptor, Optional<PropertyDescriptor>* precomputed_get_own_property)
852
0
{
853
0
    VERIFY(property_key.is_valid());
854
855
    // 1. Let current be ? O.[[GetOwnProperty]](P).
856
0
    auto current = precomputed_get_own_property ? *precomputed_get_own_property : TRY(internal_get_own_property(property_key));
857
858
    // 2. Let extensible be ? IsExtensible(O).
859
0
    auto extensible = TRY(is_extensible());
860
861
    // 3. Return ValidateAndApplyPropertyDescriptor(O, P, extensible, Desc, current).
862
0
    return validate_and_apply_property_descriptor(this, property_key, extensible, property_descriptor, current);
863
0
}
864
865
// 10.1.7 [[HasProperty]] ( P ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-hasproperty-p
866
ThrowCompletionOr<bool> Object::internal_has_property(PropertyKey const& property_key) const
867
0
{
868
0
    VERIFY(property_key.is_valid());
869
870
    // 1. Let hasOwn be ? O.[[GetOwnProperty]](P).
871
0
    auto has_own = TRY(internal_get_own_property(property_key));
872
873
    // 2. If hasOwn is not undefined, return true.
874
0
    if (has_own.has_value())
875
0
        return true;
876
877
    // 3. Let parent be ? O.[[GetPrototypeOf]]().
878
0
    auto* parent = TRY(internal_get_prototype_of());
879
880
    // 4. If parent is not null, then
881
0
    if (parent) {
882
        // a. Return ? parent.[[HasProperty]](P).
883
0
        return parent->internal_has_property(property_key);
884
0
    }
885
886
    // 5. Return false.
887
0
    return false;
888
0
}
889
890
// 10.1.8 [[Get]] ( P, Receiver ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-get-p-receiver
891
ThrowCompletionOr<Value> Object::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata, PropertyLookupPhase phase) const
892
0
{
893
0
    VERIFY(!receiver.is_empty());
894
0
    VERIFY(property_key.is_valid());
895
896
0
    auto& vm = this->vm();
897
898
    // 1. Let desc be ? O.[[GetOwnProperty]](P).
899
0
    auto descriptor = TRY(internal_get_own_property(property_key));
900
901
    // 2. If desc is undefined, then
902
0
    if (!descriptor.has_value()) {
903
        // a. Let parent be ? O.[[GetPrototypeOf]]().
904
0
        auto* parent = TRY(internal_get_prototype_of());
905
906
        // b. If parent is null, return undefined.
907
0
        if (!parent)
908
0
            return js_undefined();
909
910
        // c. Return ? parent.[[Get]](P, Receiver).
911
0
        return parent->internal_get(property_key, receiver, cacheable_metadata, PropertyLookupPhase::PrototypeChain);
912
0
    }
913
914
0
    auto update_inline_cache = [&] {
915
        // Non-standard: If the caller has requested cacheable metadata and the property is an own property, fill it in.
916
0
        if (!cacheable_metadata || !descriptor->property_offset.has_value() || !shape().is_cacheable())
917
0
            return;
918
0
        if (phase == PropertyLookupPhase::OwnProperty) {
919
0
            *cacheable_metadata = CacheablePropertyMetadata {
920
0
                .type = CacheablePropertyMetadata::Type::OwnProperty,
921
0
                .property_offset = descriptor->property_offset.value(),
922
0
                .prototype = nullptr,
923
0
            };
924
0
        } else if (phase == PropertyLookupPhase::PrototypeChain) {
925
0
            VERIFY(shape().is_prototype_shape());
926
0
            VERIFY(shape().prototype_chain_validity()->is_valid());
927
0
            *cacheable_metadata = CacheablePropertyMetadata {
928
0
                .type = CacheablePropertyMetadata::Type::InPrototypeChain,
929
0
                .property_offset = descriptor->property_offset.value(),
930
0
                .prototype = this,
931
0
            };
932
0
        }
933
0
    };
934
935
    // 3. If IsDataDescriptor(desc) is true, return desc.[[Value]].
936
0
    if (descriptor->is_data_descriptor()) {
937
0
        update_inline_cache();
938
0
        return *descriptor->value;
939
0
    }
940
941
    // 4. Assert: IsAccessorDescriptor(desc) is true.
942
0
    VERIFY(descriptor->is_accessor_descriptor());
943
944
    // 5. Let getter be desc.[[Get]].
945
0
    auto getter = *descriptor->get;
946
947
    // 6. If getter is undefined, return undefined.
948
0
    if (!getter)
949
0
        return js_undefined();
950
951
0
    update_inline_cache();
952
953
    // 7. Return ? Call(getter, Receiver).
954
0
    return TRY(call(vm, *getter, receiver));
955
0
}
956
957
// 10.1.9 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-set-p-v-receiver
958
ThrowCompletionOr<bool> Object::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata* cacheable_metadata)
959
0
{
960
0
    VERIFY(property_key.is_valid());
961
0
    VERIFY(!value.is_empty());
962
0
    VERIFY(!receiver.is_empty());
963
964
    // 2. Let ownDesc be ? O.[[GetOwnProperty]](P).
965
0
    auto own_descriptor = TRY(internal_get_own_property(property_key));
966
967
    // 3. Return ? OrdinarySetWithOwnDescriptor(O, P, V, Receiver, ownDesc).
968
0
    return ordinary_set_with_own_descriptor(property_key, value, receiver, own_descriptor, cacheable_metadata);
969
0
}
970
971
// 10.1.9.2 OrdinarySetWithOwnDescriptor ( O, P, V, Receiver, ownDesc ), https://tc39.es/ecma262/#sec-ordinarysetwithowndescriptor
972
ThrowCompletionOr<bool> Object::ordinary_set_with_own_descriptor(PropertyKey const& property_key, Value value, Value receiver, Optional<PropertyDescriptor> own_descriptor, CacheablePropertyMetadata* cacheable_metadata)
973
0
{
974
0
    VERIFY(property_key.is_valid());
975
0
    VERIFY(!value.is_empty());
976
0
    VERIFY(!receiver.is_empty());
977
978
0
    auto& vm = this->vm();
979
980
    // 1. If ownDesc is undefined, then
981
0
    if (!own_descriptor.has_value()) {
982
        // a. Let parent be ? O.[[GetPrototypeOf]]().
983
0
        auto* parent = TRY(internal_get_prototype_of());
984
985
        // b. If parent is not null, then
986
0
        if (parent) {
987
            // i. Return ? parent.[[Set]](P, V, Receiver).
988
0
            return TRY(parent->internal_set(property_key, value, receiver));
989
0
        }
990
        // c. Else,
991
0
        else {
992
            // i. Set ownDesc to the PropertyDescriptor { [[Value]]: undefined, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true }.
993
0
            own_descriptor = PropertyDescriptor {
994
0
                .value = js_undefined(),
995
0
                .writable = true,
996
0
                .enumerable = true,
997
0
                .configurable = true,
998
0
            };
999
0
        }
1000
0
    }
1001
1002
    // 2. If IsDataDescriptor(ownDesc) is true, then
1003
0
    if (own_descriptor->is_data_descriptor()) {
1004
        // a. If ownDesc.[[Writable]] is false, return false.
1005
0
        if (!*own_descriptor->writable)
1006
0
            return false;
1007
1008
        // b. If Type(Receiver) is not Object, return false.
1009
0
        if (!receiver.is_object())
1010
0
            return false;
1011
1012
0
        auto& receiver_object = receiver.as_object();
1013
1014
        // c. Let existingDescriptor be ? Receiver.[[GetOwnProperty]](P).
1015
0
        auto existing_descriptor = TRY(receiver_object.internal_get_own_property(property_key));
1016
1017
        // d. If existingDescriptor is not undefined, then
1018
0
        if (existing_descriptor.has_value()) {
1019
            // i. If IsAccessorDescriptor(existingDescriptor) is true, return false.
1020
0
            if (existing_descriptor->is_accessor_descriptor())
1021
0
                return false;
1022
1023
            // ii. If existingDescriptor.[[Writable]] is false, return false.
1024
0
            if (!*existing_descriptor->writable)
1025
0
                return false;
1026
1027
            // iii. Let valueDesc be the PropertyDescriptor { [[Value]]: V }.
1028
0
            auto value_descriptor = PropertyDescriptor { .value = value };
1029
1030
0
            if (cacheable_metadata && own_descriptor.has_value() && own_descriptor->property_offset.has_value() && shape().is_cacheable()) {
1031
0
                *cacheable_metadata = CacheablePropertyMetadata {
1032
0
                    .type = CacheablePropertyMetadata::Type::OwnProperty,
1033
0
                    .property_offset = own_descriptor->property_offset.value(),
1034
0
                    .prototype = nullptr,
1035
0
                };
1036
0
            }
1037
1038
            // iv. Return ? Receiver.[[DefineOwnProperty]](P, valueDesc).
1039
0
            return TRY(receiver_object.internal_define_own_property(property_key, value_descriptor, &existing_descriptor));
1040
0
        }
1041
        // e. Else,
1042
0
        else {
1043
            // i. Assert: Receiver does not currently have a property P.
1044
0
            VERIFY(!receiver_object.storage_has(property_key));
1045
1046
            // ii. Return ? CreateDataProperty(Receiver, P, V).
1047
0
            return TRY(receiver_object.create_data_property(property_key, value));
1048
0
        }
1049
0
    }
1050
1051
    // 3. Assert: IsAccessorDescriptor(ownDesc) is true.
1052
0
    VERIFY(own_descriptor->is_accessor_descriptor());
1053
1054
    // 4. Let setter be ownDesc.[[Set]].
1055
0
    auto setter = *own_descriptor->set;
1056
1057
    // 5. If setter is undefined, return false.
1058
0
    if (!setter)
1059
0
        return false;
1060
1061
    // 6. Perform ? Call(setter, Receiver, « V »).
1062
0
    (void)TRY(call(vm, *setter, receiver, value));
1063
1064
    // 7. Return true.
1065
0
    return true;
1066
0
}
1067
1068
// 10.1.10 [[Delete]] ( P ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-delete-p
1069
ThrowCompletionOr<bool> Object::internal_delete(PropertyKey const& property_key)
1070
0
{
1071
0
    VERIFY(property_key.is_valid());
1072
1073
    // 1. Let desc be ? O.[[GetOwnProperty]](P).
1074
0
    auto descriptor = TRY(internal_get_own_property(property_key));
1075
1076
    // 2. If desc is undefined, return true.
1077
0
    if (!descriptor.has_value())
1078
0
        return true;
1079
1080
    // 3. If desc.[[Configurable]] is true, then
1081
0
    if (*descriptor->configurable) {
1082
        // a. Remove the own property with name P from O.
1083
0
        storage_delete(property_key);
1084
1085
        // b. Return true.
1086
0
        return true;
1087
0
    }
1088
1089
    // 4. Return false.
1090
0
    return false;
1091
0
}
1092
1093
// 10.1.11 [[OwnPropertyKeys]] ( ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys
1094
ThrowCompletionOr<MarkedVector<Value>> Object::internal_own_property_keys() const
1095
0
{
1096
0
    auto& vm = this->vm();
1097
1098
    // 1. Let keys be a new empty List.
1099
0
    MarkedVector<Value> keys { heap() };
1100
1101
    // 2. For each own property key P of O such that P is an array index, in ascending numeric index order, do
1102
0
    for (auto& entry : m_indexed_properties) {
1103
        // a. Add P as the last element of keys.
1104
0
        keys.append(PrimitiveString::create(vm, ByteString::number(entry.index())));
1105
0
    }
1106
1107
    // 3. For each own property key P of O such that Type(P) is String and P is not an array index, in ascending chronological order of property creation, do
1108
0
    for (auto& it : shape().property_table()) {
1109
0
        if (it.key.is_string()) {
1110
            // a. Add P as the last element of keys.
1111
0
            keys.append(it.key.to_value(vm));
1112
0
        }
1113
0
    }
1114
1115
    // 4. For each own property key P of O such that Type(P) is Symbol, in ascending chronological order of property creation, do
1116
0
    for (auto& it : shape().property_table()) {
1117
0
        if (it.key.is_symbol()) {
1118
            // a. Add P as the last element of keys.
1119
0
            keys.append(it.key.to_value(vm));
1120
0
        }
1121
0
    }
1122
1123
    // 5. Return keys.
1124
0
    return { move(keys) };
1125
0
}
1126
1127
// 10.4.7.2 SetImmutablePrototype ( O, V ), https://tc39.es/ecma262/#sec-set-immutable-prototype
1128
ThrowCompletionOr<bool> Object::set_immutable_prototype(Object* prototype)
1129
0
{
1130
    // 1. Let current be ? O.[[GetPrototypeOf]]().
1131
0
    auto* current = TRY(internal_get_prototype_of());
1132
1133
    // 2. If SameValue(V, current) is true, return true.
1134
0
    if (prototype == current)
1135
0
        return true;
1136
1137
    // 3. Return false.
1138
0
    return false;
1139
0
}
1140
1141
static Optional<Object::IntrinsicAccessor> find_intrinsic_accessor(Object const* object, PropertyKey const& property_key)
1142
0
{
1143
0
    if (!property_key.is_string())
1144
0
        return {};
1145
1146
0
    auto intrinsics = s_intrinsics.find(object);
1147
0
    if (intrinsics == s_intrinsics.end())
1148
0
        return {};
1149
1150
0
    auto accessor_iterator = intrinsics->value.find(property_key.as_string());
1151
0
    if (accessor_iterator == intrinsics->value.end())
1152
0
        return {};
1153
1154
0
    auto accessor = accessor_iterator->value;
1155
0
    intrinsics->value.remove(accessor_iterator);
1156
0
    return accessor;
1157
0
}
1158
1159
Optional<ValueAndAttributes> Object::storage_get(PropertyKey const& property_key) const
1160
0
{
1161
0
    VERIFY(property_key.is_valid());
1162
1163
0
    Value value;
1164
0
    PropertyAttributes attributes;
1165
0
    Optional<u32> property_offset;
1166
1167
0
    if (property_key.is_number()) {
1168
0
        auto value_and_attributes = m_indexed_properties.get(property_key.as_number());
1169
0
        if (!value_and_attributes.has_value())
1170
0
            return {};
1171
0
        value = value_and_attributes->value;
1172
0
        attributes = value_and_attributes->attributes;
1173
0
    } else {
1174
0
        auto metadata = shape().lookup(property_key.to_string_or_symbol());
1175
0
        if (!metadata.has_value())
1176
0
            return {};
1177
1178
0
        if (m_has_intrinsic_accessors) {
1179
0
            if (auto accessor = find_intrinsic_accessor(this, property_key); accessor.has_value())
1180
0
                const_cast<Object&>(*this).m_storage[metadata->offset] = (*accessor)(shape().realm());
1181
0
        }
1182
1183
0
        value = m_storage[metadata->offset];
1184
0
        attributes = metadata->attributes;
1185
0
        property_offset = metadata->offset;
1186
0
    }
1187
1188
0
    return ValueAndAttributes { .value = value, .attributes = attributes, .property_offset = property_offset };
1189
0
}
1190
1191
bool Object::storage_has(PropertyKey const& property_key) const
1192
0
{
1193
0
    VERIFY(property_key.is_valid());
1194
0
    if (property_key.is_number())
1195
0
        return m_indexed_properties.has_index(property_key.as_number());
1196
0
    return shape().lookup(property_key.to_string_or_symbol()).has_value();
1197
0
}
1198
1199
void Object::storage_set(PropertyKey const& property_key, ValueAndAttributes const& value_and_attributes)
1200
0
{
1201
0
    VERIFY(property_key.is_valid());
1202
1203
0
    auto [value, attributes, _] = value_and_attributes;
1204
1205
0
    if (property_key.is_number()) {
1206
0
        auto index = property_key.as_number();
1207
0
        m_indexed_properties.put(index, value, attributes);
1208
0
        return;
1209
0
    }
1210
1211
0
    if (m_has_intrinsic_accessors && property_key.is_string()) {
1212
0
        if (auto intrinsics = s_intrinsics.find(this); intrinsics != s_intrinsics.end())
1213
0
            intrinsics->value.remove(property_key.as_string());
1214
0
    }
1215
1216
0
    auto property_key_string_or_symbol = property_key.to_string_or_symbol();
1217
0
    auto metadata = shape().lookup(property_key_string_or_symbol);
1218
1219
0
    if (!metadata.has_value()) {
1220
0
        static constexpr size_t max_transitions_before_converting_to_dictionary = 64;
1221
0
        if (!m_shape->is_dictionary() && m_shape->property_count() >= max_transitions_before_converting_to_dictionary)
1222
0
            set_shape(m_shape->create_cacheable_dictionary_transition());
1223
1224
0
        if (m_shape->is_dictionary())
1225
0
            m_shape->add_property_without_transition(property_key_string_or_symbol, attributes);
1226
0
        else
1227
0
            set_shape(*m_shape->create_put_transition(property_key_string_or_symbol, attributes));
1228
0
        m_storage.append(value);
1229
0
        return;
1230
0
    }
1231
1232
0
    if (attributes != metadata->attributes) {
1233
0
        if (m_shape->is_dictionary())
1234
0
            m_shape->set_property_attributes_without_transition(property_key_string_or_symbol, attributes);
1235
0
        else
1236
0
            set_shape(*m_shape->create_configure_transition(property_key_string_or_symbol, attributes));
1237
0
    }
1238
1239
0
    m_storage[metadata->offset] = value;
1240
0
}
1241
1242
void Object::storage_delete(PropertyKey const& property_key)
1243
0
{
1244
0
    VERIFY(property_key.is_valid());
1245
0
    VERIFY(storage_has(property_key));
1246
1247
0
    if (property_key.is_number())
1248
0
        return m_indexed_properties.remove(property_key.as_number());
1249
1250
0
    if (m_has_intrinsic_accessors && property_key.is_string()) {
1251
0
        if (auto intrinsics = s_intrinsics.find(this); intrinsics != s_intrinsics.end())
1252
0
            intrinsics->value.remove(property_key.as_string());
1253
0
    }
1254
1255
0
    auto metadata = shape().lookup(property_key.to_string_or_symbol());
1256
0
    VERIFY(metadata.has_value());
1257
1258
0
    if (m_shape->is_cacheable_dictionary()) {
1259
0
        m_shape = m_shape->create_uncacheable_dictionary_transition();
1260
0
    }
1261
0
    if (m_shape->is_uncacheable_dictionary()) {
1262
0
        m_shape->remove_property_without_transition(property_key.to_string_or_symbol(), metadata->offset);
1263
0
        m_storage.remove(metadata->offset);
1264
0
        return;
1265
0
    }
1266
0
    m_shape = m_shape->create_delete_transition(property_key.to_string_or_symbol());
1267
0
    m_storage.remove(metadata->offset);
1268
0
}
1269
1270
void Object::set_prototype(Object* new_prototype)
1271
0
{
1272
0
    if (prototype() == new_prototype)
1273
0
        return;
1274
0
    m_shape = shape().create_prototype_transition(new_prototype);
1275
0
}
1276
1277
void Object::define_native_accessor(Realm& realm, PropertyKey const& property_key, Function<ThrowCompletionOr<Value>(VM&)> getter, Function<ThrowCompletionOr<Value>(VM&)> setter, PropertyAttributes attribute)
1278
0
{
1279
0
    FunctionObject* getter_function = nullptr;
1280
0
    if (getter)
1281
0
        getter_function = NativeFunction::create(realm, move(getter), 0, property_key, &realm, {}, "get"sv);
1282
0
    FunctionObject* setter_function = nullptr;
1283
0
    if (setter)
1284
0
        setter_function = NativeFunction::create(realm, move(setter), 1, property_key, &realm, {}, "set"sv);
1285
0
    return define_direct_accessor(property_key, getter_function, setter_function, attribute);
1286
0
}
1287
1288
void Object::define_direct_accessor(PropertyKey const& property_key, FunctionObject* getter, FunctionObject* setter, PropertyAttributes attributes)
1289
0
{
1290
0
    VERIFY(property_key.is_valid());
1291
1292
0
    auto existing_property = storage_get(property_key).value_or({}).value;
1293
0
    auto* accessor = existing_property.is_accessor() ? &existing_property.as_accessor() : nullptr;
1294
0
    if (!accessor) {
1295
0
        accessor = Accessor::create(vm(), getter, setter);
1296
0
        define_direct_property(property_key, accessor, attributes);
1297
0
    } else {
1298
0
        if (getter)
1299
0
            accessor->set_getter(getter);
1300
0
        if (setter)
1301
0
            accessor->set_setter(setter);
1302
0
    }
1303
0
}
1304
1305
void Object::define_intrinsic_accessor(PropertyKey const& property_key, PropertyAttributes attributes, IntrinsicAccessor accessor)
1306
0
{
1307
0
    VERIFY(property_key.is_string());
1308
1309
0
    storage_set(property_key, { {}, attributes });
1310
1311
0
    m_has_intrinsic_accessors = true;
1312
0
    auto& intrinsics = s_intrinsics.ensure(this);
1313
0
    intrinsics.set(property_key.as_string(), move(accessor));
1314
0
}
1315
1316
// Simple side-effect free property lookup, following the prototype chain. Non-standard.
1317
Value Object::get_without_side_effects(PropertyKey const& property_key) const
1318
0
{
1319
0
    auto* object = this;
1320
0
    while (object) {
1321
0
        auto value_and_attributes = object->storage_get(property_key);
1322
0
        if (value_and_attributes.has_value())
1323
0
            return value_and_attributes->value;
1324
0
        object = object->prototype();
1325
0
    }
1326
0
    return {};
1327
0
}
1328
1329
void Object::define_native_function(Realm& realm, PropertyKey const& property_key, Function<ThrowCompletionOr<Value>(VM&)> native_function, i32 length, PropertyAttributes attribute, Optional<Bytecode::Builtin> builtin)
1330
0
{
1331
0
    auto function = NativeFunction::create(realm, move(native_function), length, property_key, &realm);
1332
0
    define_direct_property(property_key, function, attribute);
1333
0
    if (builtin.has_value())
1334
0
        realm.define_builtin(builtin.value(), function);
1335
0
}
1336
1337
// 20.1.2.3.1 ObjectDefineProperties ( O, Properties ), https://tc39.es/ecma262/#sec-objectdefineproperties
1338
ThrowCompletionOr<Object*> Object::define_properties(Value properties)
1339
0
{
1340
0
    auto& vm = this->vm();
1341
1342
    // 1. Let props be ? ToObject(Properties).
1343
0
    auto props = TRY(properties.to_object(vm));
1344
1345
    // 2. Let keys be ? props.[[OwnPropertyKeys]]().
1346
0
    auto keys = TRY(props->internal_own_property_keys());
1347
1348
0
    struct NameAndDescriptor {
1349
0
        PropertyKey name;
1350
0
        PropertyDescriptor descriptor;
1351
0
    };
1352
1353
    // 3. Let descriptors be a new empty List.
1354
0
    Vector<NameAndDescriptor> descriptors;
1355
1356
    // 4. For each element nextKey of keys, do
1357
0
    for (auto& next_key : keys) {
1358
0
        auto property_key = MUST(PropertyKey::from_value(vm, next_key));
1359
1360
        // a. Let propDesc be ? props.[[GetOwnProperty]](nextKey).
1361
0
        auto property_descriptor = TRY(props->internal_get_own_property(property_key));
1362
1363
        // b. If propDesc is not undefined and propDesc.[[Enumerable]] is true, then
1364
0
        if (property_descriptor.has_value() && *property_descriptor->enumerable) {
1365
            // i. Let descObj be ? Get(props, nextKey).
1366
0
            auto descriptor_object = TRY(props->get(property_key));
1367
1368
            // ii. Let desc be ? ToPropertyDescriptor(descObj).
1369
0
            auto descriptor = TRY(to_property_descriptor(vm, descriptor_object));
1370
1371
            // iii. Append the pair (a two element List) consisting of nextKey and desc to the end of descriptors.
1372
0
            descriptors.append({ property_key, descriptor });
1373
0
        }
1374
0
    }
1375
1376
    // 5. For each element pair of descriptors, do
1377
0
    for (auto& [name, descriptor] : descriptors) {
1378
        // a. Let P be the first element of pair.
1379
        // b. Let desc be the second element of pair.
1380
1381
        // c. Perform ? DefinePropertyOrThrow(O, P, desc).
1382
0
        TRY(define_property_or_throw(name, descriptor));
1383
0
    }
1384
1385
    // 6. Return O.
1386
0
    return this;
1387
0
}
1388
1389
// 14.7.5.9 EnumerateObjectProperties ( O ), https://tc39.es/ecma262/#sec-enumerate-object-properties
1390
Optional<Completion> Object::enumerate_object_properties(Function<Optional<Completion>(Value)> callback) const
1391
0
{
1392
    // 1. Return an Iterator object (27.1.1.2) whose next method iterates over all the String-valued keys of enumerable properties of O. The iterator object is never directly accessible to ECMAScript code. The mechanics and order of enumerating the properties is not specified but must conform to the rules specified below.
1393
    //    * Returned property keys do not include keys that are Symbols.
1394
    //    * Properties of the target object may be deleted during enumeration.
1395
    //    * A property that is deleted before it is processed is ignored.
1396
    //    * If new properties are added to the target object during enumeration, the newly added properties are not guaranteed to be processed in the active enumeration.
1397
    //    * A property name will be returned at most once in any enumeration.
1398
    //    * Enumerating the properties of the target object includes enumerating properties of its prototype, and the prototype of the prototype, and so on, recursively.
1399
    //    * A property of a prototype is not processed if it has the same name as a property that has already been processed.
1400
1401
0
    HashTable<DeprecatedFlyString> visited;
1402
1403
0
    auto const* target = this;
1404
0
    while (target) {
1405
0
        auto own_keys = TRY(target->internal_own_property_keys());
1406
0
        for (auto& key : own_keys) {
1407
0
            if (!key.is_string())
1408
0
                continue;
1409
0
            DeprecatedFlyString property_key = key.as_string().byte_string();
1410
0
            if (visited.contains(property_key))
1411
0
                continue;
1412
0
            auto descriptor = TRY(target->internal_get_own_property(property_key));
1413
0
            if (!descriptor.has_value())
1414
0
                continue;
1415
0
            visited.set(property_key);
1416
0
            if (!*descriptor->enumerable)
1417
0
                continue;
1418
0
            if (auto completion = callback(key); completion.has_value())
1419
0
                return completion.release_value();
1420
0
        }
1421
1422
0
        target = TRY(target->internal_get_prototype_of());
1423
0
    };
1424
1425
0
    return {};
1426
0
}
1427
1428
void Object::visit_edges(Cell::Visitor& visitor)
1429
0
{
1430
0
    Base::visit_edges(visitor);
1431
0
    visitor.visit(m_shape);
1432
0
    visitor.visit(m_storage);
1433
1434
0
    m_indexed_properties.for_each_value([&visitor](auto& value) {
1435
0
        visitor.visit(value);
1436
0
    });
1437
1438
0
    if (m_private_elements) {
1439
0
        for (auto& private_element : *m_private_elements)
1440
0
            visitor.visit(private_element.value);
1441
0
    }
1442
0
}
1443
1444
// 7.1.1.1 OrdinaryToPrimitive ( O, hint ), https://tc39.es/ecma262/#sec-ordinarytoprimitive
1445
ThrowCompletionOr<Value> Object::ordinary_to_primitive(Value::PreferredType preferred_type) const
1446
0
{
1447
0
    VERIFY(preferred_type == Value::PreferredType::String || preferred_type == Value::PreferredType::Number);
1448
1449
0
    auto& vm = this->vm();
1450
1451
0
    AK::Array<PropertyKey, 2> method_names;
1452
1453
    // 1. If hint is string, then
1454
0
    if (preferred_type == Value::PreferredType::String) {
1455
        // a. Let methodNames be « "toString", "valueOf" ».
1456
0
        method_names = { vm.names.toString, vm.names.valueOf };
1457
0
    }
1458
    // 2. Else,
1459
0
    else {
1460
        // a. Let methodNames be « "valueOf", "toString" ».
1461
0
        method_names = { vm.names.valueOf, vm.names.toString };
1462
0
    }
1463
1464
    // 3. For each element name of methodNames, do
1465
0
    for (auto& method_name : method_names) {
1466
        // a. Let method be ? Get(O, name).
1467
0
        auto method = TRY(get(method_name));
1468
1469
        // b. If IsCallable(method) is true, then
1470
0
        if (method.is_function()) {
1471
            // i. Let result be ? Call(method, O).
1472
0
            auto result = TRY(call(vm, method.as_function(), const_cast<Object*>(this)));
1473
1474
            // ii. If Type(result) is not Object, return result.
1475
0
            if (!result.is_object())
1476
0
                return result;
1477
0
        }
1478
0
    }
1479
1480
    // 4. Throw a TypeError exception.
1481
0
    return vm.throw_completion<TypeError>(ErrorType::Convert, "object", preferred_type == Value::PreferredType::String ? "string" : "number");
1482
0
}
1483
1484
void Object::convert_to_prototype_if_needed()
1485
0
{
1486
0
    if (shape().is_prototype_shape())
1487
0
        return;
1488
0
    set_shape(shape().clone_for_prototype());
1489
0
}
1490
1491
}