OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 Object* receiver, | 62 Object* receiver, |
63 uint32_t index) { | 63 uint32_t index) { |
64 if (index < ElementsAccessorSubclass::GetLength(obj)) { | 64 if (index < ElementsAccessorSubclass::GetLength(obj)) { |
65 BackingStoreClass* backing_store = | 65 BackingStoreClass* backing_store = |
66 ElementsAccessorSubclass::GetBackingStore(obj); | 66 ElementsAccessorSubclass::GetBackingStore(obj); |
67 return backing_store->get(index); | 67 return backing_store->get(index); |
68 } | 68 } |
69 return obj->GetHeap()->the_hole_value(); | 69 return obj->GetHeap()->the_hole_value(); |
70 } | 70 } |
71 | 71 |
| 72 virtual MaybeObject* Delete(JSObject* obj, |
| 73 uint32_t index, |
| 74 JSReceiver::DeleteMode mode) = 0; |
| 75 |
72 protected: | 76 protected: |
73 static BackingStoreClass* GetBackingStore(JSObject* obj) { | 77 static BackingStoreClass* GetBackingStore(JSObject* obj) { |
74 return BackingStoreClass::cast(obj->elements()); | 78 return BackingStoreClass::cast(obj->elements()); |
75 } | 79 } |
76 | 80 |
77 static uint32_t GetLength(JSObject* obj) { | 81 static uint32_t GetLength(JSObject* obj) { |
78 return ElementsAccessorSubclass::GetBackingStore(obj)->length(); | 82 return ElementsAccessorSubclass::GetBackingStore(obj)->length(); |
79 } | 83 } |
80 | 84 |
81 private: | 85 private: |
82 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase); | 86 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase); |
83 }; | 87 }; |
84 | 88 |
85 | 89 |
86 class FastElementsAccessor | 90 class FastElementsAccessor |
87 : public ElementsAccessorBase<FastElementsAccessor, FixedArray> { | 91 : public ElementsAccessorBase<FastElementsAccessor, FixedArray> { |
| 92 public: |
| 93 static MaybeObject* DeleteCommon(JSObject* obj, |
| 94 uint32_t index) { |
| 95 ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements()); |
| 96 Heap* heap = obj->GetHeap(); |
| 97 FixedArray* backing_store = FixedArray::cast(obj->elements()); |
| 98 if (backing_store->map() == heap->non_strict_arguments_elements_map()) { |
| 99 backing_store = FixedArray::cast(backing_store->get(1)); |
| 100 } else { |
| 101 Object* writable; |
| 102 MaybeObject* maybe = obj->EnsureWritableFastElements(); |
| 103 if (!maybe->ToObject(&writable)) return maybe; |
| 104 backing_store = FixedArray::cast(writable); |
| 105 } |
| 106 uint32_t length = static_cast<uint32_t>( |
| 107 obj->IsJSArray() |
| 108 ? Smi::cast(JSArray::cast(obj)->length())->value() |
| 109 : backing_store->length()); |
| 110 if (index < length) { |
| 111 backing_store->set_the_hole(index); |
| 112 // If an old space backing store is larger than a certain size and |
| 113 // has too few used values, normalize it. |
| 114 // To avoid doing the check on every delete we require at least |
| 115 // one adjacent hole to the value being deleted. |
| 116 Object* hole = heap->the_hole_value(); |
| 117 const int kMinLengthForSparsenessCheck = 64; |
| 118 if (backing_store->length() >= kMinLengthForSparsenessCheck && |
| 119 !heap->InNewSpace(backing_store) && |
| 120 ((index > 0 && backing_store->get(index - 1) == hole) || |
| 121 (index + 1 < length && backing_store->get(index + 1) == hole))) { |
| 122 int num_used = 0; |
| 123 for (int i = 0; i < backing_store->length(); ++i) { |
| 124 if (backing_store->get(i) != hole) ++num_used; |
| 125 // Bail out early if more than 1/4 is used. |
| 126 if (4 * num_used > backing_store->length()) break; |
| 127 } |
| 128 if (4 * num_used <= backing_store->length()) { |
| 129 MaybeObject* result = obj->NormalizeElements(); |
| 130 if (result->IsFailure()) return result; |
| 131 } |
| 132 } |
| 133 } |
| 134 return heap->true_value(); |
| 135 } |
| 136 |
| 137 virtual MaybeObject* Delete(JSObject* obj, |
| 138 uint32_t index, |
| 139 JSReceiver::DeleteMode mode) { |
| 140 return DeleteCommon(obj, index); |
| 141 } |
88 }; | 142 }; |
89 | 143 |
90 | 144 |
91 class FastDoubleElementsAccessor | 145 class FastDoubleElementsAccessor |
92 : public ElementsAccessorBase<FastDoubleElementsAccessor, | 146 : public ElementsAccessorBase<FastDoubleElementsAccessor, |
93 FixedDoubleArray> { | 147 FixedDoubleArray> { |
| 148 virtual MaybeObject* Delete(JSObject* obj, |
| 149 uint32_t index, |
| 150 JSReceiver::DeleteMode mode) { |
| 151 int length = obj->IsJSArray() |
| 152 ? Smi::cast(JSArray::cast(obj)->length())->value() |
| 153 : FixedDoubleArray::cast(obj->elements())->length(); |
| 154 if (index < static_cast<uint32_t>(length)) { |
| 155 FixedDoubleArray::cast(obj->elements())->set_the_hole(index); |
| 156 } |
| 157 return obj->GetHeap()->true_value(); |
| 158 } |
94 }; | 159 }; |
95 | 160 |
96 | 161 |
97 // Super class for all external element arrays. | 162 // Super class for all external element arrays. |
98 template<typename ExternalElementsAccessorSubclass, | 163 template<typename ExternalElementsAccessorSubclass, |
99 typename ExternalArray> | 164 typename ExternalArray> |
100 class ExternalElementsAccessor | 165 class ExternalElementsAccessor |
101 : public ElementsAccessorBase<ExternalElementsAccessorSubclass, | 166 : public ElementsAccessorBase<ExternalElementsAccessorSubclass, |
102 ExternalArray> { | 167 ExternalArray> { |
103 public: | 168 public: |
104 virtual MaybeObject* GetWithReceiver(JSObject* obj, | 169 virtual MaybeObject* GetWithReceiver(JSObject* obj, |
105 Object* receiver, | 170 Object* receiver, |
106 uint32_t index) { | 171 uint32_t index) { |
107 if (index < ExternalElementsAccessorSubclass::GetLength(obj)) { | 172 if (index < ExternalElementsAccessorSubclass::GetLength(obj)) { |
108 ExternalArray* backing_store = | 173 ExternalArray* backing_store = |
109 ExternalElementsAccessorSubclass::GetBackingStore(obj); | 174 ExternalElementsAccessorSubclass::GetBackingStore(obj); |
110 return backing_store->get(index); | 175 return backing_store->get(index); |
111 } else { | 176 } else { |
112 return obj->GetHeap()->undefined_value(); | 177 return obj->GetHeap()->undefined_value(); |
113 } | 178 } |
114 } | 179 } |
| 180 |
| 181 virtual MaybeObject* Delete(JSObject* obj, |
| 182 uint32_t index, |
| 183 JSReceiver::DeleteMode mode) { |
| 184 // External arrays always ignore deletes. |
| 185 return obj->GetHeap()->true_value(); |
| 186 } |
115 }; | 187 }; |
116 | 188 |
117 | 189 |
118 class ExternalByteElementsAccessor | 190 class ExternalByteElementsAccessor |
119 : public ExternalElementsAccessor<ExternalByteElementsAccessor, | 191 : public ExternalElementsAccessor<ExternalByteElementsAccessor, |
120 ExternalByteArray> { | 192 ExternalByteArray> { |
121 }; | 193 }; |
122 | 194 |
123 | 195 |
124 class ExternalUnsignedByteElementsAccessor | 196 class ExternalUnsignedByteElementsAccessor |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 element, | 259 element, |
188 index, | 260 index, |
189 obj); | 261 obj); |
190 } else { | 262 } else { |
191 return element; | 263 return element; |
192 } | 264 } |
193 } | 265 } |
194 return obj->GetHeap()->the_hole_value(); | 266 return obj->GetHeap()->the_hole_value(); |
195 } | 267 } |
196 | 268 |
| 269 |
| 270 static MaybeObject* DeleteCommon(JSObject* obj, |
| 271 uint32_t index, |
| 272 JSReceiver::DeleteMode mode) { |
| 273 Isolate* isolate = obj->GetIsolate(); |
| 274 Heap* heap = isolate->heap(); |
| 275 FixedArray* backing_store = FixedArray::cast(obj->elements()); |
| 276 bool is_arguments = |
| 277 (obj->GetElementsKind() == JSObject::NON_STRICT_ARGUMENTS_ELEMENTS); |
| 278 if (is_arguments) { |
| 279 backing_store = FixedArray::cast(backing_store->get(1)); |
| 280 } |
| 281 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); |
| 282 int entry = dictionary->FindEntry(index); |
| 283 if (entry != NumberDictionary::kNotFound) { |
| 284 Object* result = dictionary->DeleteProperty(entry, mode); |
| 285 if (result == heap->true_value()) { |
| 286 MaybeObject* maybe_elements = dictionary->Shrink(index); |
| 287 FixedArray* new_elements = NULL; |
| 288 if (!maybe_elements->To(&new_elements)) { |
| 289 return maybe_elements; |
| 290 } |
| 291 if (is_arguments) { |
| 292 FixedArray::cast(obj->elements())->set(1, new_elements); |
| 293 } else { |
| 294 obj->set_elements(new_elements); |
| 295 } |
| 296 } |
| 297 if (mode == JSObject::STRICT_DELETION && |
| 298 result == heap->false_value()) { |
| 299 // In strict mode, attempting to delete a non-configurable property |
| 300 // throws an exception. |
| 301 HandleScope scope(isolate); |
| 302 Handle<Object> holder(obj); |
| 303 Handle<Object> name = isolate->factory()->NewNumberFromUint(index); |
| 304 Handle<Object> args[2] = { name, holder }; |
| 305 Handle<Object> error = |
| 306 isolate->factory()->NewTypeError("strict_delete_property", |
| 307 HandleVector(args, 2)); |
| 308 return isolate->Throw(*error); |
| 309 } |
| 310 } |
| 311 return heap->true_value(); |
| 312 } |
| 313 |
| 314 virtual MaybeObject* Delete(JSObject* obj, |
| 315 uint32_t index, |
| 316 JSReceiver::DeleteMode mode) { |
| 317 return DeleteCommon(obj, index, mode); |
| 318 } |
| 319 |
197 virtual MaybeObject* GetWithReceiver(JSObject* obj, | 320 virtual MaybeObject* GetWithReceiver(JSObject* obj, |
198 Object* receiver, | 321 Object* receiver, |
199 uint32_t index) { | 322 uint32_t index) { |
200 return GetNumberDictionaryElement(obj, | 323 return GetNumberDictionaryElement(obj, |
201 receiver, | 324 receiver, |
202 obj->element_dictionary(), | 325 obj->element_dictionary(), |
203 index); | 326 index); |
204 } | 327 } |
205 }; | 328 }; |
206 | 329 |
(...skipping 22 matching lines...) Expand all Loading... |
229 obj, | 352 obj, |
230 receiver, | 353 receiver, |
231 NumberDictionary::cast(arguments), | 354 NumberDictionary::cast(arguments), |
232 index); | 355 index); |
233 } else if (index < static_cast<uint32_t>(arguments->length())) { | 356 } else if (index < static_cast<uint32_t>(arguments->length())) { |
234 return arguments->get(index); | 357 return arguments->get(index); |
235 } | 358 } |
236 } | 359 } |
237 return obj->GetHeap()->the_hole_value(); | 360 return obj->GetHeap()->the_hole_value(); |
238 } | 361 } |
| 362 |
| 363 virtual MaybeObject* Delete(JSObject* obj, |
| 364 uint32_t index, |
| 365 JSReceiver::DeleteMode mode) { |
| 366 FixedArray* parameter_map = FixedArray::cast(obj->elements()); |
| 367 uint32_t length = parameter_map->length(); |
| 368 Object* probe = |
| 369 index < (length - 2) ? parameter_map->get(index + 2) : NULL; |
| 370 if (probe != NULL && !probe->IsTheHole()) { |
| 371 // TODO(kmillikin): We could check if this was the last aliased |
| 372 // parameter, and revert to normal elements in that case. That |
| 373 // would enable GC of the context. |
| 374 parameter_map->set_the_hole(index + 2); |
| 375 } else { |
| 376 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 377 if (arguments->IsDictionary()) { |
| 378 return DictionaryElementsAccessor::DeleteCommon(obj, index, mode); |
| 379 } else { |
| 380 return FastElementsAccessor::DeleteCommon(obj, index); |
| 381 } |
| 382 } |
| 383 return obj->GetHeap()->true_value(); |
| 384 } |
239 }; | 385 }; |
240 | 386 |
241 | 387 |
242 void ElementsAccessor::InitializeOncePerProcess() { | 388 void ElementsAccessor::InitializeOncePerProcess() { |
243 static struct ConcreteElementsAccessors { | 389 static struct ConcreteElementsAccessors { |
244 FastElementsAccessor fast_elements_handler; | 390 FastElementsAccessor fast_elements_handler; |
245 FastDoubleElementsAccessor fast_double_elements_handler; | 391 FastDoubleElementsAccessor fast_double_elements_handler; |
246 DictionaryElementsAccessor dictionary_elements_handler; | 392 DictionaryElementsAccessor dictionary_elements_handler; |
247 NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler; | 393 NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler; |
248 ExternalByteElementsAccessor byte_elements_handler; | 394 ExternalByteElementsAccessor byte_elements_handler; |
(...skipping 21 matching lines...) Expand all Loading... |
270 &element_accessors.float_elements_handler, | 416 &element_accessors.float_elements_handler, |
271 &element_accessors.double_elements_handler, | 417 &element_accessors.double_elements_handler, |
272 &element_accessors.pixel_elements_handler | 418 &element_accessors.pixel_elements_handler |
273 }; | 419 }; |
274 | 420 |
275 elements_accessors_ = accessor_array; | 421 elements_accessors_ = accessor_array; |
276 } | 422 } |
277 | 423 |
278 | 424 |
279 } } // namespace v8::internal | 425 } } // namespace v8::internal |
OLD | NEW |