@@ -92,170 +92,10 @@ MaybeHandle<Object> Runtime::HasProperty(Isolate* isolate,
92
92
: ReadOnlyRoots (isolate).false_value_handle ();
93
93
}
94
94
95
- namespace {
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
-
145
- bool DeleteObjectPropertyFast (Isolate* isolate, Handle <JSReceiver> receiver,
146
- Handle <Object> raw_key) {
147
- // This implements a special case for fast property deletion: when the
148
- // last property in an object is deleted, then instead of normalizing
149
- // the properties, we can undo the last map transition, with a few
150
- // prerequisites:
151
- // (1) The receiver must be a regular object and the key a unique name.
152
- Handle <Map> receiver_map (receiver->map (), isolate);
153
- if (receiver_map->IsSpecialReceiverMap ()) return false ;
154
- DCHECK (receiver_map->IsJSObjectMap ());
155
-
156
- if (!raw_key->IsUniqueName ()) return false ;
157
- Handle <Name> key = Handle <Name>::cast (raw_key);
158
- // (2) The property to be deleted must be the last property.
159
- int nof = receiver_map->NumberOfOwnDescriptors ();
160
- if (nof == 0 ) return false ;
161
- InternalIndex descriptor (nof - 1 );
162
- Handle <DescriptorArray> descriptors (receiver_map->instance_descriptors (),
163
- isolate);
164
- if (descriptors->GetKey (descriptor) != *key) return false ;
165
- // (3) The property to be deleted must be deletable.
166
- PropertyDetails details = descriptors->GetDetails (descriptor);
167
- if (!details.IsConfigurable ()) return false ;
168
- // (4) The map must have a back pointer.
169
- Handle <Object> backpointer (receiver_map->GetBackPointer (), isolate);
170
- if (!backpointer->IsMap ()) return false ;
171
- Handle <Map> parent_map = Handle <Map>::cast (backpointer);
172
- // (5) The last transition must have been caused by adding a property
173
- // (and not any kind of special transition).
174
- if (parent_map->NumberOfOwnDescriptors () != nof - 1 ) return false ;
175
-
176
- // Preconditions successful. No more bailouts after this point.
177
-
178
- // Zap the property to avoid keeping objects alive. Zapping is not necessary
179
- // for properties stored in the descriptor array.
180
- if (details.location () == kField ) {
181
- DisallowHeapAllocation no_allocation;
182
-
183
- // Invalidate slots manually later in case we delete an in-object tagged
184
- // property. In this case we might later store an untagged value in the
185
- // recorded slot.
186
- isolate->heap ()->NotifyObjectLayoutChange (*receiver, no_allocation,
187
- InvalidateRecordedSlots::kNo );
188
- FieldIndex index =
189
- FieldIndex::ForPropertyIndex (*receiver_map, details.field_index ());
190
- // Special case deleting the last out-of object property.
191
- if (!index .is_inobject () && index .outobject_array_index () == 0 ) {
192
- DCHECK (!parent_map->HasOutOfObjectProperties ());
193
- // Clear out the properties backing store.
194
- receiver->SetProperties (ReadOnlyRoots (isolate).empty_fixed_array ());
195
- } else {
196
- Object filler = ReadOnlyRoots (isolate).one_pointer_filler_map ();
197
- JSObject::cast (*receiver).RawFastPropertyAtPut (index , filler);
198
- // We must clear any recorded slot for the deleted property, because
199
- // subsequent object modifications might put a raw double there.
200
- // Slot clearing is the reason why this entire function cannot currently
201
- // be implemented in the DeleteProperty stub.
202
- if (index .is_inobject () && !receiver_map->IsUnboxedDoubleField (index )) {
203
- // We need to clear the recorded slot in this case because in-object
204
- // slack tracking might not be finished. This ensures that we don't
205
- // have recorded slots in free space.
206
- isolate->heap ()->ClearRecordedSlot (*receiver,
207
- receiver->RawField (index .offset ()));
208
- MemoryChunk* chunk = MemoryChunk::FromHeapObject (*receiver);
209
- chunk->InvalidateRecordedSlots (*receiver);
210
- }
211
- }
212
- }
213
- // If the {receiver_map} was marked stable before, then there could be
214
- // optimized code that depends on the assumption that no object that
215
- // reached this {receiver_map} transitions away from it without triggering
216
- // the "deoptimize dependent code" mechanism.
217
- receiver_map->NotifyLeafMapLayoutChange (isolate);
218
- // Finally, perform the map rollback.
219
- receiver->synchronized_set_map (*parent_map);
220
- #if VERIFY_HEAP
221
- receiver->HeapObjectVerify (isolate);
222
- receiver->property_array ().PropertyArrayVerify (isolate);
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
-
248
- return true ;
249
- }
250
-
251
- } // namespace
252
-
253
95
Maybe<bool > Runtime::DeleteObjectProperty (Isolate* isolate,
254
96
Handle <JSReceiver> receiver,
255
97
Handle <Object> key,
256
98
LanguageMode language_mode) {
257
- if (DeleteObjectPropertyFast (isolate, receiver, key)) return Just (true );
258
-
259
99
bool success = false ;
260
100
LookupIterator::Key lookup_key (isolate, key, &success);
261
101
if (!success) return Nothing<bool >();
0 commit comments