| 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 11 matching lines...) Expand all Loading... |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "objects.h" | 30 #include "objects.h" |
| 31 #include "elements.h" | 31 #include "elements.h" |
| 32 #include "utils.h" |
| 32 | 33 |
| 33 namespace v8 { | 34 namespace v8 { |
| 34 namespace internal { | 35 namespace internal { |
| 35 | 36 |
| 36 | 37 |
| 37 ElementsAccessor** ElementsAccessor::elements_accessors_; | 38 ElementsAccessor** ElementsAccessor::elements_accessors_; |
| 38 | 39 |
| 39 | 40 |
| 41 bool HasKey(FixedArray* array, Object* key) { |
| 42 int len0 = array->length(); |
| 43 for (int i = 0; i < len0; i++) { |
| 44 Object* element = array->get(i); |
| 45 if (element->IsSmi() && element == key) return true; |
| 46 if (element->IsString() && |
| 47 key->IsString() && String::cast(element)->Equals(String::cast(key))) { |
| 48 return true; |
| 49 } |
| 50 } |
| 51 return false; |
| 52 } |
| 53 |
| 54 |
| 40 // Base class for element handler implementations. Contains the | 55 // Base class for element handler implementations. Contains the |
| 41 // the common logic for objects with different ElementsKinds. | 56 // the common logic for objects with different ElementsKinds. |
| 42 // Subclasses must specialize method for which the element | 57 // Subclasses must specialize method for which the element |
| 43 // implementation differs from the base class implementation. | 58 // implementation differs from the base class implementation. |
| 44 // | 59 // |
| 45 // This class is intended to be used in the following way: | 60 // This class is intended to be used in the following way: |
| 46 // | 61 // |
| 47 // class SomeElementsAccessor : | 62 // class SomeElementsAccessor : |
| 48 // public ElementsAccessorBase<SomeElementsAccessor, | 63 // public ElementsAccessorBase<SomeElementsAccessor, |
| 49 // BackingStoreClass> { | 64 // BackingStoreClass> { |
| 50 // ... | 65 // ... |
| 51 // } | 66 // } |
| 52 // | 67 // |
| 53 // This is an example of the Curiously Recurring Template Pattern (see | 68 // This is an example of the Curiously Recurring Template Pattern (see |
| 54 // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use | 69 // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use |
| 55 // CRTP to guarantee aggressive compile time optimizations (i.e. inlining and | 70 // CRTP to guarantee aggressive compile time optimizations (i.e. inlining and |
| 56 // specialization of SomeElementsAccessor methods). | 71 // specialization of SomeElementsAccessor methods). |
| 57 template <typename ElementsAccessorSubclass, typename BackingStoreClass> | 72 template <typename ElementsAccessorSubclass, typename BackingStoreClass> |
| 58 class ElementsAccessorBase : public ElementsAccessor { | 73 class ElementsAccessorBase : public ElementsAccessor { |
| 59 public: | 74 protected: |
| 60 ElementsAccessorBase() { } | 75 ElementsAccessorBase() { } |
| 61 virtual MaybeObject* GetWithReceiver(JSObject* obj, | 76 virtual MaybeObject* Get(FixedArrayBase* backing_store, |
| 62 Object* receiver, | 77 uint32_t key, |
| 63 uint32_t index) { | 78 JSObject* obj, |
| 64 if (index < ElementsAccessorSubclass::GetLength(obj)) { | 79 Object* receiver) { |
| 65 BackingStoreClass* backing_store = | 80 return ElementsAccessorSubclass::Get( |
| 66 ElementsAccessorSubclass::GetBackingStore(obj); | 81 BackingStoreClass::cast(backing_store), key, obj, receiver); |
| 67 return backing_store->get(index); | 82 } |
| 83 |
| 84 static MaybeObject* Get(BackingStoreClass* backing_store, |
| 85 uint32_t key, |
| 86 JSObject* obj, |
| 87 Object* receiver) { |
| 88 if (key < ElementsAccessorSubclass::GetCapacity(backing_store)) { |
| 89 return backing_store->get(key); |
| 68 } | 90 } |
| 69 return obj->GetHeap()->the_hole_value(); | 91 return backing_store->GetHeap()->the_hole_value(); |
| 70 } | 92 } |
| 71 | 93 |
| 72 virtual MaybeObject* Delete(JSObject* obj, | 94 virtual MaybeObject* Delete(JSObject* obj, |
| 73 uint32_t index, | 95 uint32_t key, |
| 74 JSReceiver::DeleteMode mode) = 0; | 96 JSReceiver::DeleteMode mode) = 0; |
| 75 | 97 |
| 76 protected: | 98 virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from, |
| 77 static BackingStoreClass* GetBackingStore(JSObject* obj) { | 99 FixedArray* to, |
| 78 return BackingStoreClass::cast(obj->elements()); | 100 JSObject* holder, |
| 101 Object* receiver) { |
| 102 int len0 = to->length(); |
| 103 #ifdef DEBUG |
| 104 if (FLAG_enable_slow_asserts) { |
| 105 for (int i = 0; i < len0; i++) { |
| 106 ASSERT(!to->get(i)->IsTheHole()); |
| 107 } |
| 108 } |
| 109 #endif |
| 110 BackingStoreClass* backing_store = BackingStoreClass::cast(from); |
| 111 uint32_t len1 = ElementsAccessorSubclass::GetCapacity(backing_store); |
| 112 |
| 113 // Optimize if 'other' is empty. |
| 114 // We cannot optimize if 'this' is empty, as other may have holes. |
| 115 if (len1 == 0) return to; |
| 116 |
| 117 // Compute how many elements are not in other. |
| 118 int extra = 0; |
| 119 for (uint32_t y = 0; y < len1; y++) { |
| 120 if (ElementsAccessorSubclass::HasElementAtIndex(backing_store, |
| 121 y, |
| 122 holder, |
| 123 receiver)) { |
| 124 uint32_t key = |
| 125 ElementsAccessorSubclass::GetKeyForIndex(backing_store, y); |
| 126 MaybeObject* maybe_value = |
| 127 ElementsAccessorSubclass::Get(backing_store, key, holder, receiver); |
| 128 Object* value; |
| 129 if (!maybe_value->ToObject(&value)) return maybe_value; |
| 130 ASSERT(!value->IsTheHole()); |
| 131 if (!HasKey(to, value)) { |
| 132 extra++; |
| 133 } |
| 134 } |
| 135 } |
| 136 |
| 137 if (extra == 0) return to; |
| 138 |
| 139 // Allocate the result |
| 140 FixedArray* result; |
| 141 MaybeObject* maybe_obj = |
| 142 backing_store->GetHeap()->AllocateFixedArray(len0 + extra); |
| 143 if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj; |
| 144 |
| 145 // Fill in the content |
| 146 { |
| 147 AssertNoAllocation no_gc; |
| 148 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); |
| 149 for (int i = 0; i < len0; i++) { |
| 150 Object* e = to->get(i); |
| 151 ASSERT(e->IsString() || e->IsNumber()); |
| 152 result->set(i, e, mode); |
| 153 } |
| 154 } |
| 155 // Fill in the extra values. |
| 156 int index = 0; |
| 157 for (uint32_t y = 0; y < len1; y++) { |
| 158 if (ElementsAccessorSubclass::HasElementAtIndex(backing_store, |
| 159 y, |
| 160 holder, |
| 161 receiver)) { |
| 162 uint32_t key = |
| 163 ElementsAccessorSubclass::GetKeyForIndex(backing_store, y); |
| 164 MaybeObject* maybe_value = |
| 165 ElementsAccessorSubclass::Get(backing_store, key, holder, receiver); |
| 166 Object* value; |
| 167 if (!maybe_value->ToObject(&value)) return maybe_value; |
| 168 if (!value->IsTheHole() && !HasKey(to, value)) { |
| 169 result->set(len0 + index, value); |
| 170 index++; |
| 171 } |
| 172 } |
| 173 } |
| 174 ASSERT(extra == index); |
| 175 return result; |
| 79 } | 176 } |
| 80 | 177 |
| 81 static uint32_t GetLength(JSObject* obj) { | 178 protected: |
| 82 return ElementsAccessorSubclass::GetBackingStore(obj)->length(); | 179 static uint32_t GetCapacity(BackingStoreClass* backing_store) { |
| 180 return backing_store->length(); |
| 181 } |
| 182 |
| 183 virtual uint32_t GetCapacity(FixedArrayBase* backing_store) { |
| 184 return ElementsAccessorSubclass::GetCapacity( |
| 185 BackingStoreClass::cast(backing_store)); |
| 186 } |
| 187 |
| 188 static bool HasElementAtIndex(BackingStoreClass* backing_store, |
| 189 uint32_t index, |
| 190 JSObject* holder, |
| 191 Object* receiver) { |
| 192 uint32_t key = |
| 193 ElementsAccessorSubclass::GetKeyForIndex(backing_store, index); |
| 194 MaybeObject* element = ElementsAccessorSubclass::Get(backing_store, |
| 195 key, |
| 196 holder, |
| 197 receiver); |
| 198 return !element->IsTheHole(); |
| 199 } |
| 200 |
| 201 virtual bool HasElementAtIndex(FixedArrayBase* backing_store, |
| 202 uint32_t index, |
| 203 JSObject* holder, |
| 204 Object* receiver) { |
| 205 return ElementsAccessorSubclass::HasElementAtIndex( |
| 206 BackingStoreClass::cast(backing_store), index, holder, receiver); |
| 207 } |
| 208 |
| 209 static uint32_t GetKeyForIndex(BackingStoreClass* backing_store, |
| 210 uint32_t index) { |
| 211 return index; |
| 212 } |
| 213 |
| 214 virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store, |
| 215 uint32_t index) { |
| 216 return ElementsAccessorSubclass::GetKeyForIndex( |
| 217 BackingStoreClass::cast(backing_store), index); |
| 83 } | 218 } |
| 84 | 219 |
| 85 private: | 220 private: |
| 86 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase); | 221 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase); |
| 87 }; | 222 }; |
| 88 | 223 |
| 89 | 224 |
| 90 class FastElementsAccessor | 225 class FastElementsAccessor |
| 91 : public ElementsAccessorBase<FastElementsAccessor, FixedArray> { | 226 : public ElementsAccessorBase<FastElementsAccessor, FixedArray> { |
| 92 public: | 227 public: |
| 93 static MaybeObject* DeleteCommon(JSObject* obj, | 228 static MaybeObject* DeleteCommon(JSObject* obj, |
| 94 uint32_t index) { | 229 uint32_t key) { |
| 95 ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements()); | 230 ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements()); |
| 96 Heap* heap = obj->GetHeap(); | 231 Heap* heap = obj->GetHeap(); |
| 97 FixedArray* backing_store = FixedArray::cast(obj->elements()); | 232 FixedArray* backing_store = FixedArray::cast(obj->elements()); |
| 98 if (backing_store->map() == heap->non_strict_arguments_elements_map()) { | 233 if (backing_store->map() == heap->non_strict_arguments_elements_map()) { |
| 99 backing_store = FixedArray::cast(backing_store->get(1)); | 234 backing_store = FixedArray::cast(backing_store->get(1)); |
| 100 } else { | 235 } else { |
| 101 Object* writable; | 236 Object* writable; |
| 102 MaybeObject* maybe = obj->EnsureWritableFastElements(); | 237 MaybeObject* maybe = obj->EnsureWritableFastElements(); |
| 103 if (!maybe->ToObject(&writable)) return maybe; | 238 if (!maybe->ToObject(&writable)) return maybe; |
| 104 backing_store = FixedArray::cast(writable); | 239 backing_store = FixedArray::cast(writable); |
| 105 } | 240 } |
| 106 uint32_t length = static_cast<uint32_t>( | 241 uint32_t length = static_cast<uint32_t>( |
| 107 obj->IsJSArray() | 242 obj->IsJSArray() |
| 108 ? Smi::cast(JSArray::cast(obj)->length())->value() | 243 ? Smi::cast(JSArray::cast(obj)->length())->value() |
| 109 : backing_store->length()); | 244 : backing_store->length()); |
| 110 if (index < length) { | 245 if (key < length) { |
| 111 backing_store->set_the_hole(index); | 246 backing_store->set_the_hole(key); |
| 112 // If an old space backing store is larger than a certain size and | 247 // If an old space backing store is larger than a certain size and |
| 113 // has too few used values, normalize it. | 248 // has too few used values, normalize it. |
| 114 // To avoid doing the check on every delete we require at least | 249 // To avoid doing the check on every delete we require at least |
| 115 // one adjacent hole to the value being deleted. | 250 // one adjacent hole to the value being deleted. |
| 116 Object* hole = heap->the_hole_value(); | 251 Object* hole = heap->the_hole_value(); |
| 117 const int kMinLengthForSparsenessCheck = 64; | 252 const int kMinLengthForSparsenessCheck = 64; |
| 118 if (backing_store->length() >= kMinLengthForSparsenessCheck && | 253 if (backing_store->length() >= kMinLengthForSparsenessCheck && |
| 119 !heap->InNewSpace(backing_store) && | 254 !heap->InNewSpace(backing_store) && |
| 120 ((index > 0 && backing_store->get(index - 1) == hole) || | 255 ((key > 0 && backing_store->get(key - 1) == hole) || |
| 121 (index + 1 < length && backing_store->get(index + 1) == hole))) { | 256 (key + 1 < length && backing_store->get(key + 1) == hole))) { |
| 122 int num_used = 0; | 257 int num_used = 0; |
| 123 for (int i = 0; i < backing_store->length(); ++i) { | 258 for (int i = 0; i < backing_store->length(); ++i) { |
| 124 if (backing_store->get(i) != hole) ++num_used; | 259 if (backing_store->get(i) != hole) ++num_used; |
| 125 // Bail out early if more than 1/4 is used. | 260 // Bail out early if more than 1/4 is used. |
| 126 if (4 * num_used > backing_store->length()) break; | 261 if (4 * num_used > backing_store->length()) break; |
| 127 } | 262 } |
| 128 if (4 * num_used <= backing_store->length()) { | 263 if (4 * num_used <= backing_store->length()) { |
| 129 MaybeObject* result = obj->NormalizeElements(); | 264 MaybeObject* result = obj->NormalizeElements(); |
| 130 if (result->IsFailure()) return result; | 265 if (result->IsFailure()) return result; |
| 131 } | 266 } |
| 132 } | 267 } |
| 133 } | 268 } |
| 134 return heap->true_value(); | 269 return heap->true_value(); |
| 135 } | 270 } |
| 136 | 271 |
| 272 protected: |
| 137 virtual MaybeObject* Delete(JSObject* obj, | 273 virtual MaybeObject* Delete(JSObject* obj, |
| 138 uint32_t index, | 274 uint32_t key, |
| 139 JSReceiver::DeleteMode mode) { | 275 JSReceiver::DeleteMode mode) { |
| 140 return DeleteCommon(obj, index); | 276 return DeleteCommon(obj, key); |
| 141 } | 277 } |
| 142 }; | 278 }; |
| 143 | 279 |
| 144 | 280 |
| 145 class FastDoubleElementsAccessor | 281 class FastDoubleElementsAccessor |
| 146 : public ElementsAccessorBase<FastDoubleElementsAccessor, | 282 : public ElementsAccessorBase<FastDoubleElementsAccessor, |
| 147 FixedDoubleArray> { | 283 FixedDoubleArray> { |
| 284 protected: |
| 285 friend class ElementsAccessorBase<FastDoubleElementsAccessor, |
| 286 FixedDoubleArray>; |
| 287 |
| 148 virtual MaybeObject* Delete(JSObject* obj, | 288 virtual MaybeObject* Delete(JSObject* obj, |
| 149 uint32_t index, | 289 uint32_t key, |
| 150 JSReceiver::DeleteMode mode) { | 290 JSReceiver::DeleteMode mode) { |
| 151 int length = obj->IsJSArray() | 291 int length = obj->IsJSArray() |
| 152 ? Smi::cast(JSArray::cast(obj)->length())->value() | 292 ? Smi::cast(JSArray::cast(obj)->length())->value() |
| 153 : FixedDoubleArray::cast(obj->elements())->length(); | 293 : FixedDoubleArray::cast(obj->elements())->length(); |
| 154 if (index < static_cast<uint32_t>(length)) { | 294 if (key < static_cast<uint32_t>(length)) { |
| 155 FixedDoubleArray::cast(obj->elements())->set_the_hole(index); | 295 FixedDoubleArray::cast(obj->elements())->set_the_hole(key); |
| 156 } | 296 } |
| 157 return obj->GetHeap()->true_value(); | 297 return obj->GetHeap()->true_value(); |
| 158 } | 298 } |
| 299 |
| 300 static bool HasElementAtIndex(FixedDoubleArray* backing_store, |
| 301 uint32_t index, |
| 302 JSObject* holder, |
| 303 Object* receiver) { |
| 304 return !backing_store->is_the_hole(index); |
| 305 } |
| 159 }; | 306 }; |
| 160 | 307 |
| 161 | 308 |
| 162 // Super class for all external element arrays. | 309 // Super class for all external element arrays. |
| 163 template<typename ExternalElementsAccessorSubclass, | 310 template<typename ExternalElementsAccessorSubclass, |
| 164 typename ExternalArray> | 311 typename ExternalArray> |
| 165 class ExternalElementsAccessor | 312 class ExternalElementsAccessor |
| 166 : public ElementsAccessorBase<ExternalElementsAccessorSubclass, | 313 : public ElementsAccessorBase<ExternalElementsAccessorSubclass, |
| 167 ExternalArray> { | 314 ExternalArray> { |
| 168 public: | 315 protected: |
| 169 virtual MaybeObject* GetWithReceiver(JSObject* obj, | 316 friend class ElementsAccessorBase<ExternalElementsAccessorSubclass, |
| 170 Object* receiver, | 317 ExternalArray>; |
| 171 uint32_t index) { | 318 |
| 172 if (index < ExternalElementsAccessorSubclass::GetLength(obj)) { | 319 static MaybeObject* Get(ExternalArray* backing_store, |
| 173 ExternalArray* backing_store = | 320 uint32_t key, |
| 174 ExternalElementsAccessorSubclass::GetBackingStore(obj); | 321 JSObject* obj, |
| 175 return backing_store->get(index); | 322 Object* receiver) { |
| 323 if (key < ExternalElementsAccessorSubclass::GetCapacity(backing_store)) { |
| 324 return backing_store->get(key); |
| 176 } else { | 325 } else { |
| 177 return obj->GetHeap()->undefined_value(); | 326 return backing_store->GetHeap()->undefined_value(); |
| 178 } | 327 } |
| 179 } | 328 } |
| 180 | 329 |
| 181 virtual MaybeObject* Delete(JSObject* obj, | 330 virtual MaybeObject* Delete(JSObject* obj, |
| 182 uint32_t index, | 331 uint32_t key, |
| 183 JSReceiver::DeleteMode mode) { | 332 JSReceiver::DeleteMode mode) { |
| 184 // External arrays always ignore deletes. | 333 // External arrays always ignore deletes. |
| 185 return obj->GetHeap()->true_value(); | 334 return obj->GetHeap()->true_value(); |
| 186 } | 335 } |
| 187 }; | 336 }; |
| 188 | 337 |
| 189 | 338 |
| 190 class ExternalByteElementsAccessor | 339 class ExternalByteElementsAccessor |
| 191 : public ExternalElementsAccessor<ExternalByteElementsAccessor, | 340 : public ExternalElementsAccessor<ExternalByteElementsAccessor, |
| 192 ExternalByteArray> { | 341 ExternalByteArray> { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 class PixelElementsAccessor | 387 class PixelElementsAccessor |
| 239 : public ExternalElementsAccessor<PixelElementsAccessor, | 388 : public ExternalElementsAccessor<PixelElementsAccessor, |
| 240 ExternalPixelArray> { | 389 ExternalPixelArray> { |
| 241 }; | 390 }; |
| 242 | 391 |
| 243 | 392 |
| 244 class DictionaryElementsAccessor | 393 class DictionaryElementsAccessor |
| 245 : public ElementsAccessorBase<DictionaryElementsAccessor, | 394 : public ElementsAccessorBase<DictionaryElementsAccessor, |
| 246 NumberDictionary> { | 395 NumberDictionary> { |
| 247 public: | 396 public: |
| 248 static MaybeObject* GetNumberDictionaryElement( | |
| 249 JSObject* obj, | |
| 250 Object* receiver, | |
| 251 NumberDictionary* backing_store, | |
| 252 uint32_t index) { | |
| 253 int entry = backing_store->FindEntry(index); | |
| 254 if (entry != NumberDictionary::kNotFound) { | |
| 255 Object* element = backing_store->ValueAt(entry); | |
| 256 PropertyDetails details = backing_store->DetailsAt(entry); | |
| 257 if (details.type() == CALLBACKS) { | |
| 258 return obj->GetElementWithCallback(receiver, | |
| 259 element, | |
| 260 index, | |
| 261 obj); | |
| 262 } else { | |
| 263 return element; | |
| 264 } | |
| 265 } | |
| 266 return obj->GetHeap()->the_hole_value(); | |
| 267 } | |
| 268 | |
| 269 | |
| 270 static MaybeObject* DeleteCommon(JSObject* obj, | 397 static MaybeObject* DeleteCommon(JSObject* obj, |
| 271 uint32_t index, | 398 uint32_t key, |
| 272 JSReceiver::DeleteMode mode) { | 399 JSReceiver::DeleteMode mode) { |
| 273 Isolate* isolate = obj->GetIsolate(); | 400 Isolate* isolate = obj->GetIsolate(); |
| 274 Heap* heap = isolate->heap(); | 401 Heap* heap = isolate->heap(); |
| 275 FixedArray* backing_store = FixedArray::cast(obj->elements()); | 402 FixedArray* backing_store = FixedArray::cast(obj->elements()); |
| 276 bool is_arguments = | 403 bool is_arguments = |
| 277 (obj->GetElementsKind() == JSObject::NON_STRICT_ARGUMENTS_ELEMENTS); | 404 (obj->GetElementsKind() == JSObject::NON_STRICT_ARGUMENTS_ELEMENTS); |
| 278 if (is_arguments) { | 405 if (is_arguments) { |
| 279 backing_store = FixedArray::cast(backing_store->get(1)); | 406 backing_store = FixedArray::cast(backing_store->get(1)); |
| 280 } | 407 } |
| 281 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); | 408 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); |
| 282 int entry = dictionary->FindEntry(index); | 409 int entry = dictionary->FindEntry(key); |
| 283 if (entry != NumberDictionary::kNotFound) { | 410 if (entry != NumberDictionary::kNotFound) { |
| 284 Object* result = dictionary->DeleteProperty(entry, mode); | 411 Object* result = dictionary->DeleteProperty(entry, mode); |
| 285 if (result == heap->true_value()) { | 412 if (result == heap->true_value()) { |
| 286 MaybeObject* maybe_elements = dictionary->Shrink(index); | 413 MaybeObject* maybe_elements = dictionary->Shrink(key); |
| 287 FixedArray* new_elements = NULL; | 414 FixedArray* new_elements = NULL; |
| 288 if (!maybe_elements->To(&new_elements)) { | 415 if (!maybe_elements->To(&new_elements)) { |
| 289 return maybe_elements; | 416 return maybe_elements; |
| 290 } | 417 } |
| 291 if (is_arguments) { | 418 if (is_arguments) { |
| 292 FixedArray::cast(obj->elements())->set(1, new_elements); | 419 FixedArray::cast(obj->elements())->set(1, new_elements); |
| 293 } else { | 420 } else { |
| 294 obj->set_elements(new_elements); | 421 obj->set_elements(new_elements); |
| 295 } | 422 } |
| 296 } | 423 } |
| 297 if (mode == JSObject::STRICT_DELETION && | 424 if (mode == JSObject::STRICT_DELETION && |
| 298 result == heap->false_value()) { | 425 result == heap->false_value()) { |
| 299 // In strict mode, attempting to delete a non-configurable property | 426 // In strict mode, attempting to delete a non-configurable property |
| 300 // throws an exception. | 427 // throws an exception. |
| 301 HandleScope scope(isolate); | 428 HandleScope scope(isolate); |
| 302 Handle<Object> holder(obj); | 429 Handle<Object> holder(obj); |
| 303 Handle<Object> name = isolate->factory()->NewNumberFromUint(index); | 430 Handle<Object> name = isolate->factory()->NewNumberFromUint(key); |
| 304 Handle<Object> args[2] = { name, holder }; | 431 Handle<Object> args[2] = { name, holder }; |
| 305 Handle<Object> error = | 432 Handle<Object> error = |
| 306 isolate->factory()->NewTypeError("strict_delete_property", | 433 isolate->factory()->NewTypeError("strict_delete_property", |
| 307 HandleVector(args, 2)); | 434 HandleVector(args, 2)); |
| 308 return isolate->Throw(*error); | 435 return isolate->Throw(*error); |
| 309 } | 436 } |
| 310 } | 437 } |
| 311 return heap->true_value(); | 438 return heap->true_value(); |
| 312 } | 439 } |
| 313 | 440 |
| 441 protected: |
| 442 friend class ElementsAccessorBase<DictionaryElementsAccessor, |
| 443 NumberDictionary>; |
| 444 |
| 314 virtual MaybeObject* Delete(JSObject* obj, | 445 virtual MaybeObject* Delete(JSObject* obj, |
| 315 uint32_t index, | 446 uint32_t key, |
| 316 JSReceiver::DeleteMode mode) { | 447 JSReceiver::DeleteMode mode) { |
| 317 return DeleteCommon(obj, index, mode); | 448 return DeleteCommon(obj, key, mode); |
| 318 } | 449 } |
| 319 | 450 |
| 320 virtual MaybeObject* GetWithReceiver(JSObject* obj, | 451 static MaybeObject* Get(NumberDictionary* backing_store, |
| 321 Object* receiver, | 452 uint32_t key, |
| 322 uint32_t index) { | 453 JSObject* obj, |
| 323 return GetNumberDictionaryElement(obj, | 454 Object* receiver) { |
| 324 receiver, | 455 int entry = backing_store->FindEntry(key); |
| 325 obj->element_dictionary(), | 456 if (entry != NumberDictionary::kNotFound) { |
| 326 index); | 457 Object* element = backing_store->ValueAt(entry); |
| 458 PropertyDetails details = backing_store->DetailsAt(entry); |
| 459 if (details.type() == CALLBACKS) { |
| 460 return obj->GetElementWithCallback(receiver, |
| 461 element, |
| 462 key, |
| 463 obj); |
| 464 } else { |
| 465 return element; |
| 466 } |
| 467 } |
| 468 return obj->GetHeap()->the_hole_value(); |
| 469 } |
| 470 |
| 471 static uint32_t GetKeyForIndex(NumberDictionary* dict, |
| 472 uint32_t index) { |
| 473 Object* key = dict->KeyAt(index); |
| 474 return Smi::cast(key)->value(); |
| 327 } | 475 } |
| 328 }; | 476 }; |
| 329 | 477 |
| 330 | 478 |
| 331 class NonStrictArgumentsElementsAccessor | 479 class NonStrictArgumentsElementsAccessor |
| 332 : public ElementsAccessorBase<NonStrictArgumentsElementsAccessor, | 480 : public ElementsAccessorBase<NonStrictArgumentsElementsAccessor, |
| 333 FixedArray> { | 481 FixedArray> { |
| 334 public: | 482 protected: |
| 335 virtual MaybeObject* GetWithReceiver(JSObject* obj, | 483 friend class ElementsAccessorBase<NonStrictArgumentsElementsAccessor, |
| 336 Object* receiver, | 484 FixedArray>; |
| 337 uint32_t index) { | 485 |
| 338 FixedArray* parameter_map = GetBackingStore(obj); | 486 static MaybeObject* Get(FixedArray* parameter_map, |
| 339 uint32_t length = parameter_map->length(); | 487 uint32_t key, |
| 340 Object* probe = | 488 JSObject* obj, |
| 341 (index < length - 2) ? parameter_map->get(index + 2) : NULL; | 489 Object* receiver) { |
| 342 if (probe != NULL && !probe->IsTheHole()) { | 490 Object* probe = GetParameterMapArg(parameter_map, key); |
| 491 if (!probe->IsTheHole()) { |
| 343 Context* context = Context::cast(parameter_map->get(0)); | 492 Context* context = Context::cast(parameter_map->get(0)); |
| 344 int context_index = Smi::cast(probe)->value(); | 493 int context_index = Smi::cast(probe)->value(); |
| 345 ASSERT(!context->get(context_index)->IsTheHole()); | 494 ASSERT(!context->get(context_index)->IsTheHole()); |
| 346 return context->get(context_index); | 495 return context->get(context_index); |
| 347 } else { | 496 } else { |
| 348 // Object is not mapped, defer to the arguments. | 497 // Object is not mapped, defer to the arguments. |
| 349 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 498 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 350 if (arguments->IsDictionary()) { | 499 return ElementsAccessor::ForArray(arguments)->Get(arguments, |
| 351 return DictionaryElementsAccessor::GetNumberDictionaryElement( | 500 key, |
| 352 obj, | 501 obj, |
| 353 receiver, | 502 receiver); |
| 354 NumberDictionary::cast(arguments), | |
| 355 index); | |
| 356 } else if (index < static_cast<uint32_t>(arguments->length())) { | |
| 357 return arguments->get(index); | |
| 358 } | |
| 359 } | 503 } |
| 360 return obj->GetHeap()->the_hole_value(); | |
| 361 } | 504 } |
| 362 | 505 |
| 363 virtual MaybeObject* Delete(JSObject* obj, | 506 virtual MaybeObject* Delete(JSObject* obj, |
| 364 uint32_t index, | 507 uint32_t key |
| 508 , |
| 365 JSReceiver::DeleteMode mode) { | 509 JSReceiver::DeleteMode mode) { |
| 366 FixedArray* parameter_map = FixedArray::cast(obj->elements()); | 510 FixedArray* parameter_map = FixedArray::cast(obj->elements()); |
| 367 uint32_t length = parameter_map->length(); | 511 Object* probe = GetParameterMapArg(parameter_map, key); |
| 368 Object* probe = | 512 if (!probe->IsTheHole()) { |
| 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 | 513 // TODO(kmillikin): We could check if this was the last aliased |
| 372 // parameter, and revert to normal elements in that case. That | 514 // parameter, and revert to normal elements in that case. That |
| 373 // would enable GC of the context. | 515 // would enable GC of the context. |
| 374 parameter_map->set_the_hole(index + 2); | 516 parameter_map->set_the_hole(key + 2); |
| 375 } else { | 517 } else { |
| 376 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 518 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 377 if (arguments->IsDictionary()) { | 519 if (arguments->IsDictionary()) { |
| 378 return DictionaryElementsAccessor::DeleteCommon(obj, index, mode); | 520 return DictionaryElementsAccessor::DeleteCommon(obj, key, mode); |
| 379 } else { | 521 } else { |
| 380 return FastElementsAccessor::DeleteCommon(obj, index); | 522 return FastElementsAccessor::DeleteCommon(obj, key); |
| 381 } | 523 } |
| 382 } | 524 } |
| 383 return obj->GetHeap()->true_value(); | 525 return obj->GetHeap()->true_value(); |
| 384 } | 526 } |
| 527 |
| 528 static uint32_t GetCapacity(FixedArray* parameter_map) { |
| 529 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); |
| 530 return Max(static_cast<uint32_t>(parameter_map->length() - 2), |
| 531 ForArray(arguments)->GetCapacity(arguments)); |
| 532 } |
| 533 |
| 534 static uint32_t GetKeyForIndex(FixedArray* dict, |
| 535 uint32_t index) { |
| 536 return index; |
| 537 } |
| 538 |
| 539 static bool HasElementAtIndex(FixedArray* parameter_map, |
| 540 uint32_t index, |
| 541 JSObject* holder, |
| 542 Object* receiver) { |
| 543 Object* probe = GetParameterMapArg(parameter_map, index); |
| 544 if (!probe->IsTheHole()) { |
| 545 return true; |
| 546 } else { |
| 547 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); |
| 548 ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments); |
| 549 return !accessor->Get(arguments, index, holder, receiver)->IsTheHole(); |
| 550 } |
| 551 } |
| 552 |
| 553 private: |
| 554 static Object* GetParameterMapArg(FixedArray* parameter_map, |
| 555 uint32_t key) { |
| 556 uint32_t length = parameter_map->length(); |
| 557 return key < (length - 2 ) |
| 558 ? parameter_map->get(key + 2) |
| 559 : parameter_map->GetHeap()->the_hole_value(); |
| 560 } |
| 385 }; | 561 }; |
| 386 | 562 |
| 387 | 563 |
| 564 ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) { |
| 565 switch (array->map()->instance_type()) { |
| 566 case FIXED_ARRAY_TYPE: |
| 567 if (array->IsDictionary()) { |
| 568 return elements_accessors_[JSObject::DICTIONARY_ELEMENTS]; |
| 569 } else { |
| 570 return elements_accessors_[JSObject::FAST_ELEMENTS]; |
| 571 } |
| 572 case EXTERNAL_BYTE_ARRAY_TYPE: |
| 573 return elements_accessors_[JSObject::EXTERNAL_BYTE_ELEMENTS]; |
| 574 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: |
| 575 return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS]; |
| 576 case EXTERNAL_SHORT_ARRAY_TYPE: |
| 577 return elements_accessors_[JSObject::EXTERNAL_SHORT_ELEMENTS]; |
| 578 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: |
| 579 return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS]; |
| 580 case EXTERNAL_INT_ARRAY_TYPE: |
| 581 return elements_accessors_[JSObject::EXTERNAL_INT_ELEMENTS]; |
| 582 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: |
| 583 return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS]; |
| 584 case EXTERNAL_FLOAT_ARRAY_TYPE: |
| 585 return elements_accessors_[JSObject::EXTERNAL_FLOAT_ELEMENTS]; |
| 586 case EXTERNAL_DOUBLE_ARRAY_TYPE: |
| 587 return elements_accessors_[JSObject::EXTERNAL_DOUBLE_ELEMENTS]; |
| 588 case EXTERNAL_PIXEL_ARRAY_TYPE: |
| 589 return elements_accessors_[JSObject::EXTERNAL_PIXEL_ELEMENTS]; |
| 590 default: |
| 591 UNREACHABLE(); |
| 592 return NULL; |
| 593 break; |
| 594 } |
| 595 } |
| 596 |
| 597 |
| 388 void ElementsAccessor::InitializeOncePerProcess() { | 598 void ElementsAccessor::InitializeOncePerProcess() { |
| 389 static struct ConcreteElementsAccessors { | 599 static struct ConcreteElementsAccessors { |
| 390 FastElementsAccessor fast_elements_handler; | 600 FastElementsAccessor fast_elements_handler; |
| 391 FastDoubleElementsAccessor fast_double_elements_handler; | 601 FastDoubleElementsAccessor fast_double_elements_handler; |
| 392 DictionaryElementsAccessor dictionary_elements_handler; | 602 DictionaryElementsAccessor dictionary_elements_handler; |
| 393 NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler; | 603 NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler; |
| 394 ExternalByteElementsAccessor byte_elements_handler; | 604 ExternalByteElementsAccessor byte_elements_handler; |
| 395 ExternalUnsignedByteElementsAccessor unsigned_byte_elements_handler; | 605 ExternalUnsignedByteElementsAccessor unsigned_byte_elements_handler; |
| 396 ExternalShortElementsAccessor short_elements_handler; | 606 ExternalShortElementsAccessor short_elements_handler; |
| 397 ExternalUnsignedShortElementsAccessor unsigned_short_elements_handler; | 607 ExternalUnsignedShortElementsAccessor unsigned_short_elements_handler; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 416 &element_accessors.float_elements_handler, | 626 &element_accessors.float_elements_handler, |
| 417 &element_accessors.double_elements_handler, | 627 &element_accessors.double_elements_handler, |
| 418 &element_accessors.pixel_elements_handler | 628 &element_accessors.pixel_elements_handler |
| 419 }; | 629 }; |
| 420 | 630 |
| 421 elements_accessors_ = accessor_array; | 631 elements_accessors_ = accessor_array; |
| 422 } | 632 } |
| 423 | 633 |
| 424 | 634 |
| 425 } } // namespace v8::internal | 635 } } // namespace v8::internal |
| OLD | NEW |