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