17
17
#include " src/objects/js-array-inl.h"
18
18
#include " src/objects/property-descriptor-object.h"
19
19
#include " src/objects/property-descriptor.h"
20
+ #include " src/objects/property-details.h"
20
21
#include " src/runtime/runtime-utils.h"
21
22
#include " src/runtime/runtime.h"
22
23
@@ -93,6 +94,54 @@ MaybeHandle<Object> Runtime::HasProperty(Isolate* isolate,
93
94
94
95
namespace {
95
96
97
+ void GeneralizeAllTransitionsToFieldAsMutable (Isolate* isolate, Handle<Map> map,
98
+ Handle<Name> name) {
99
+ InternalIndex descriptor (map->NumberOfOwnDescriptors ());
100
+
101
+ Handle<Map> target_maps[kPropertyAttributesCombinationsCount ];
102
+ int target_maps_count = 0 ;
103
+
104
+ // Collect all outgoing field transitions.
105
+ {
106
+ DisallowHeapAllocation no_gc;
107
+ TransitionsAccessor transitions (isolate, *map, &no_gc);
108
+ transitions.ForEachTransitionTo (
109
+ *name,
110
+ [&](Map target) {
111
+ DCHECK_EQ (descriptor, target.LastAdded ());
112
+ DCHECK_EQ (*name, target.GetLastDescriptorName (isolate));
113
+ PropertyDetails details = target.GetLastDescriptorDetails (isolate);
114
+ // Currently, we track constness only for fields.
115
+ if (details.kind () == kData &&
116
+ details.constness () == PropertyConstness::kConst ) {
117
+ target_maps[target_maps_count++] = handle (target, isolate);
118
+ }
119
+ DCHECK_IMPLIES (details.kind () == kAccessor ,
120
+ details.constness () == PropertyConstness::kConst );
121
+ },
122
+ &no_gc);
123
+ CHECK_LE (target_maps_count, kPropertyAttributesCombinationsCount );
124
+ }
125
+
126
+ for (int i = 0 ; i < target_maps_count; i++) {
127
+ Handle<Map> target = target_maps[i];
128
+ PropertyDetails details =
129
+ target->instance_descriptors (isolate)
130
+ .GetDetails (descriptor);
131
+ Handle<FieldType> field_type (
132
+ target->instance_descriptors (isolate)
133
+ .GetFieldType (descriptor),
134
+ isolate);
135
+ Map::GeneralizeField (isolate, target, descriptor,
136
+ PropertyConstness::kMutable , details.representation (),
137
+ field_type);
138
+ DCHECK_EQ (PropertyConstness::kMutable ,
139
+ target->instance_descriptors (isolate)
140
+ .GetDetails (descriptor)
141
+ .constness ());
142
+ }
143
+ }
144
+
96
145
bool DeleteObjectPropertyFast (Isolate* isolate, Handle<JSReceiver> receiver,
97
146
Handle<Object> raw_key) {
98
147
// This implements a special case for fast property deletion: when the
@@ -102,6 +151,8 @@ bool DeleteObjectPropertyFast(Isolate* isolate, Handle<JSReceiver> receiver,
102
151
// (1) The receiver must be a regular object and the key a unique name.
103
152
Handle<Map> receiver_map (receiver->map (), isolate);
104
153
if (receiver_map->IsSpecialReceiverMap ()) return false ;
154
+ DCHECK (receiver_map->IsJSObjectMap ());
155
+
105
156
if (!raw_key->IsUniqueName ()) return false ;
106
157
Handle<Name> key = Handle<Name>::cast (raw_key);
107
158
// (2) The property to be deleted must be the last property.
@@ -124,26 +175,6 @@ bool DeleteObjectPropertyFast(Isolate* isolate, Handle<JSReceiver> receiver,
124
175
125
176
// Preconditions successful. No more bailouts after this point.
126
177
127
- // If the {descriptor} was "const" so far, we need to update the
128
- // {receiver_map} here, otherwise we could get the constants wrong, i.e.
129
- //
130
- // o.x = 1;
131
- // delete o.x;
132
- // o.x = 2;
133
- //
134
- // could trick V8 into thinking that `o.x` is still 1 even after the second
135
- // assignment.
136
- if (details.constness () == PropertyConstness::kConst &&
137
- details.location () == kField ) {
138
- Handle<FieldType> field_type (descriptors->GetFieldType (descriptor),
139
- isolate);
140
- Map::GeneralizeField (isolate, receiver_map, descriptor,
141
- PropertyConstness::kMutable , details.representation (),
142
- field_type);
143
- DCHECK_EQ (PropertyConstness::kMutable ,
144
- descriptors->GetDetails (descriptor).constness ());
145
- }
146
-
147
178
// Zap the property to avoid keeping objects alive. Zapping is not necessary
148
179
// for properties stored in the descriptor array.
149
180
if (details.location () == kField ) {
@@ -190,6 +221,30 @@ bool DeleteObjectPropertyFast(Isolate* isolate, Handle<JSReceiver> receiver,
190
221
receiver->HeapObjectVerify (isolate);
191
222
receiver->property_array ().PropertyArrayVerify (isolate);
192
223
#endif
224
+
225
+ // If the {descriptor} was "const" so far, we need to update the
226
+ // {receiver_map} here, otherwise we could get the constants wrong, i.e.
227
+ //
228
+ // o.x = 1;
229
+ // [change o.x's attributes or reconfigure property kind]
230
+ // delete o.x;
231
+ // o.x = 2;
232
+ //
233
+ // could trick V8 into thinking that `o.x` is still 1 even after the second
234
+ // assignment.
235
+
236
+ // Step 1: Migrate object to an up-to-date shape.
237
+ if (parent_map->is_deprecated ()) {
238
+ JSObject::MigrateInstance (isolate, Handle<JSObject>::cast (receiver));
239
+ parent_map = handle (receiver->map (), isolate);
240
+ }
241
+
242
+ // Step 2: Mark outgoing transitions from the up-to-date version of the
243
+ // parent_map to same property name of any kind or attributes as mutable.
244
+ // Also migrate object to the up-to-date map to make the object shapes
245
+ // converge sooner.
246
+ GeneralizeAllTransitionsToFieldAsMutable (isolate, parent_map, key);
247
+
193
248
return true ;
194
249
}
195
250
0 commit comments