1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
// Copyright 2023 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/objects/js-struct.h"
#include "src/objects/lookup-inl.h"
#include "src/objects/map-inl.h"
#include "src/objects/property-descriptor.h"
namespace v8 {
namespace internal {
namespace {
void PrepareMapCommon(Map map) {
DCHECK(IsAlwaysSharedSpaceJSObjectMap(map));
DisallowGarbageCollection no_gc;
// Shared objects have fixed layout ahead of time, so there's no slack.
map->SetInObjectUnusedPropertyFields(0);
// Shared objects are not extensible and have a null prototype.
map->set_is_extensible(false);
// Shared space objects are not optimizable as prototypes because it is
// not threadsafe.
map->set_prototype_validity_cell(Smi::FromInt(Map::kPrototypeChainValid),
kRelaxedStore, SKIP_WRITE_BARRIER);
}
} // namespace
// static
void AlwaysSharedSpaceJSObject::PrepareMapNoEnumerableProperties(
Tagged<Map> map) {
PrepareMapCommon(map);
map->SetEnumLength(0);
}
// static
void AlwaysSharedSpaceJSObject::PrepareMapWithEnumerableProperties(
Isolate* isolate, Handle<Map> map, Handle<DescriptorArray> descriptors,
int enum_length) {
PrepareMapCommon(*map);
// Shared objects with enumerable own properties need to pre-create the enum
// cache, as creating it lazily is racy.
map->InitializeDescriptors(isolate, *descriptors);
FastKeyAccumulator::InitializeFastPropertyEnumCache(
isolate, map, enum_length, AllocationType::kSharedOld);
DCHECK_EQ(enum_length, map->EnumLength());
}
// static
Maybe<bool> AlwaysSharedSpaceJSObject::DefineOwnProperty(
Isolate* isolate, Handle<AlwaysSharedSpaceJSObject> shared_obj,
Handle<Object> key, PropertyDescriptor* desc,
Maybe<ShouldThrow> should_throw) {
// Shared objects are designed to have fixed layout, i.e. their maps are
// effectively immutable. They are constructed seal, but the semantics of
// ordinary ECMAScript objects allow writable properties to be upgraded to
// non-writable properties. This upgrade violates the fixed layout invariant
// and is disallowed.
DCHECK(IsName(*key) || IsNumber(*key)); // |key| is a PropertyKey.
PropertyKey lookup_key(isolate, key);
LookupIterator it(isolate, shared_obj, lookup_key, LookupIterator::OWN);
PropertyDescriptor current;
MAYBE_RETURN(GetOwnPropertyDescriptor(&it, ¤t), Nothing<bool>());
// The only redefinition allowed is to set the value if all attributes match.
if (!it.IsFound() ||
PropertyDescriptor::IsDataDescriptor(desc) !=
PropertyDescriptor::IsDataDescriptor(¤t) ||
desc->ToAttributes() != current.ToAttributes()) {
DCHECK(!shared_obj->map()->is_extensible());
RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
NewTypeError(MessageTemplate::kDefineDisallowedFixedLayout,
it.GetName()));
}
DCHECK(it.property_attributes() == desc->ToAttributes());
if (desc->has_value()) {
return Object::SetDataProperty(&it, desc->value());
}
return Just(true);
}
Maybe<bool> AlwaysSharedSpaceJSObject::HasInstance(
Isolate* isolate, Handle<JSFunction> constructor, Handle<Object> object) {
if (!constructor->has_prototype_slot() || !constructor->has_initial_map() ||
!IsJSReceiver(*object)) {
return Just(false);
}
Handle<Map> constructor_map = handle(constructor->initial_map(), isolate);
PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(object),
kStartAtReceiver);
Handle<Map> current_map;
while (true) {
current_map = handle(PrototypeIterator::GetCurrent(iter)->map(), isolate);
if (current_map.is_identical_to(constructor_map)) {
return Just(true);
}
if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
if (iter.IsAtEnd()) return Just(false);
}
}
} // namespace internal
} // namespace v8
|