@@ -81,182 +81,10 @@ MaybeHandle<Object> Runtime::HasProperty(Isolate* isolate,
81
81
: ReadOnlyRoots (isolate).false_value_handle ();
82
82
}
83
83
84
- namespace {
85
-
86
- // This function sets the sentinel value in a deleted field. Thes sentinel has
87
- // to look like a proper standalone object because the slack tracking may
88
- // complete at any time. For this reason we use the filler map word.
89
- // If V8_MAP_PACKING is enabled, then the filler map word is a packed filler
90
- // map. Otherwise, the filler map word is the same as the filler map.
91
- inline void ClearField (Isolate* isolate, JSObject object, FieldIndex index) {
92
- if (index .is_inobject ()) {
93
- MapWord filler_map_word =
94
- ReadOnlyRoots (isolate).one_pointer_filler_map_word ();
95
- #ifndef V8_MAP_PACKING
96
- DCHECK_EQ (filler_map_word.ToMap (),
97
- ReadOnlyRoots (isolate).one_pointer_filler_map ());
98
- #endif
99
- int offset = index .offset ();
100
- TaggedField<MapWord>::Release_Store (object, offset, filler_map_word);
101
- } else {
102
- object.property_array ().set (
103
- index .outobject_array_index (),
104
- ReadOnlyRoots (isolate).one_pointer_filler_map ());
105
- }
106
- }
107
-
108
- void GeneralizeAllTransitionsToFieldAsMutable (Isolate* isolate, Handle <Map> map,
109
- Handle <Name> name) {
110
- InternalIndex descriptor (map->NumberOfOwnDescriptors ());
111
-
112
- Handle <Map> target_maps[kPropertyAttributesCombinationsCount ];
113
- int target_maps_count = 0 ;
114
-
115
- // Collect all outgoing field transitions.
116
- {
117
- DisallowGarbageCollection no_gc;
118
- TransitionsAccessor transitions (isolate, *map);
119
- transitions.ForEachTransitionTo (
120
- *name,
121
- [&](Map target) {
122
- DCHECK_EQ (descriptor, target.LastAdded ());
123
- DCHECK_EQ (*name, target.GetLastDescriptorName (isolate));
124
- PropertyDetails details = target.GetLastDescriptorDetails (isolate);
125
- // Currently, we track constness only for fields.
126
- if (details.kind () == PropertyKind::kData &&
127
- details.constness () == PropertyConstness::kConst ) {
128
- target_maps[target_maps_count++] = handle (target, isolate);
129
- }
130
- DCHECK_IMPLIES (details.kind () == PropertyKind::kAccessor ,
131
- details.constness () == PropertyConstness::kConst );
132
- },
133
- &no_gc);
134
- CHECK_LE (target_maps_count, kPropertyAttributesCombinationsCount );
135
- }
136
-
137
- for (int i = 0 ; i < target_maps_count; i++) {
138
- Handle <Map> target = target_maps[i];
139
- PropertyDetails details =
140
- target->instance_descriptors (isolate).GetDetails (descriptor);
141
- Handle <FieldType> field_type (
142
- target->instance_descriptors (isolate).GetFieldType (descriptor),
143
- isolate);
144
- MapUpdater::GeneralizeField (isolate, target, descriptor,
145
- PropertyConstness::kMutable ,
146
- details.representation (), field_type);
147
- DCHECK_EQ (PropertyConstness::kMutable , target->instance_descriptors (isolate)
148
- .GetDetails (descriptor)
149
- .constness ());
150
- }
151
- }
152
-
153
- bool DeleteObjectPropertyFast (Isolate* isolate, Handle <JSReceiver> receiver,
154
- Handle <Object> raw_key) {
155
- // This implements a special case for fast property deletion: when the
156
- // last property in an object is deleted, then instead of normalizing
157
- // the properties, we can undo the last map transition, with a few
158
- // prerequisites:
159
- // (1) The receiver must be a regular object and the key a unique name.
160
- Handle <Map> receiver_map (receiver->map (), isolate);
161
- if (receiver_map->IsSpecialReceiverMap ()) return false ;
162
- DCHECK (receiver_map->IsJSObjectMap ());
163
-
164
- if (!raw_key->IsUniqueName ()) return false ;
165
- Handle <Name> key = Handle <Name>::cast (raw_key);
166
- // (2) The property to be deleted must be the last property.
167
- int nof = receiver_map->NumberOfOwnDescriptors ();
168
- if (nof == 0 ) return false ;
169
- InternalIndex descriptor (nof - 1 );
170
- Handle <DescriptorArray> descriptors (
171
- receiver_map->instance_descriptors (isolate), isolate);
172
- if (descriptors->GetKey (descriptor) != *key) return false ;
173
- // (3) The property to be deleted must be deletable.
174
- PropertyDetails details = descriptors->GetDetails (descriptor);
175
- if (!details.IsConfigurable ()) return false ;
176
- // (4) The map must have a back pointer.
177
- Handle <Object> backpointer (receiver_map->GetBackPointer (), isolate);
178
- if (!backpointer->IsMap ()) return false ;
179
- Handle <Map> parent_map = Handle <Map>::cast (backpointer);
180
- // (5) The last transition must have been caused by adding a property
181
- // (and not any kind of special transition).
182
- if (parent_map->NumberOfOwnDescriptors () != nof - 1 ) return false ;
183
-
184
- // Preconditions successful. No more bailouts after this point.
185
-
186
- // Zap the property to avoid keeping objects alive. Zapping is not necessary
187
- // for properties stored in the descriptor array.
188
- if (details.location () == PropertyLocation::kField ) {
189
- DisallowGarbageCollection no_gc;
190
-
191
- // Invalidate slots manually later in case we delete an in-object tagged
192
- // property. In this case we might later store an untagged value in the
193
- // recorded slot.
194
- isolate->heap ()->NotifyObjectLayoutChange (*receiver, no_gc,
195
- InvalidateRecordedSlots::kNo );
196
- FieldIndex index =
197
- FieldIndex::ForPropertyIndex (*receiver_map, details.field_index ());
198
- // Special case deleting the last out-of object property.
199
- if (!index .is_inobject () && index .outobject_array_index () == 0 ) {
200
- DCHECK (!parent_map->HasOutOfObjectProperties ());
201
- // Clear out the properties backing store.
202
- receiver->SetProperties (ReadOnlyRoots (isolate).empty_fixed_array ());
203
- } else {
204
- ClearField (isolate, JSObject::cast (*receiver), index );
205
- if (index .is_inobject ()) {
206
- // We need to clear the recorded slot in this case because in-object
207
- // slack tracking might not be finished. This ensures that we don't
208
- // have recorded slots in free space.
209
- isolate->heap ()->ClearRecordedSlot (*receiver,
210
- receiver->RawField (index .offset ()));
211
- }
212
- }
213
- }
214
- // If the {receiver_map} was marked stable before, then there could be
215
- // optimized code that depends on the assumption that no object that
216
- // reached this {receiver_map} transitions away from it without triggering
217
- // the "deoptimize dependent code" mechanism.
218
- receiver_map->NotifyLeafMapLayoutChange (isolate);
219
- // Finally, perform the map rollback.
220
- receiver->set_map (*parent_map, kReleaseStore );
221
- #if VERIFY_HEAP
222
- receiver->HeapObjectVerify (isolate);
223
- receiver->property_array ().PropertyArrayVerify (isolate);
224
- #endif
225
-
226
- // If the {descriptor} was "const" so far, we need to update the
227
- // {receiver_map} here, otherwise we could get the constants wrong, i.e.
228
- //
229
- // o.x = 1;
230
- // [change o.x's attributes or reconfigure property kind]
231
- // delete o.x;
232
- // o.x = 2;
233
- //
234
- // could trick V8 into thinking that `o.x` is still 1 even after the second
235
- // assignment.
236
-
237
- // Step 1: Migrate object to an up-to-date shape.
238
- if (parent_map->is_deprecated ()) {
239
- JSObject::MigrateInstance (isolate, Handle <JSObject>::cast (receiver));
240
- parent_map = handle (receiver->map (), isolate);
241
- }
242
-
243
- // Step 2: Mark outgoing transitions from the up-to-date version of the
244
- // parent_map to same property name of any kind or attributes as mutable.
245
- // Also migrate object to the up-to-date map to make the object shapes
246
- // converge sooner.
247
- GeneralizeAllTransitionsToFieldAsMutable (isolate, parent_map, key);
248
-
249
- return true ;
250
- }
251
-
252
- } // namespace
253
-
254
84
Maybe<bool > Runtime::DeleteObjectProperty (Isolate* isolate,
255
85
Handle <JSReceiver> receiver,
256
86
Handle <Object> key,
257
87
LanguageMode language_mode) {
258
- if (DeleteObjectPropertyFast (isolate, receiver, key)) return Just (true );
259
-
260
88
bool success = false ;
261
89
PropertyKey lookup_key (isolate, key, &success);
262
90
if (!success) return Nothing<bool >();
0 commit comments