kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 1 | // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 | // Redistribution and use in source and binary forms, with or without |
| 3 | // modification, are permitted provided that the following conditions are |
| 4 | // met: |
| 5 | // |
| 6 | // * Redistributions of source code must retain the above copyright |
| 7 | // notice, this list of conditions and the following disclaimer. |
| 8 | // * Redistributions in binary form must reproduce the above |
| 9 | // copyright notice, this list of conditions and the following |
| 10 | // disclaimer in the documentation and/or other materials provided |
| 11 | // with the distribution. |
| 12 | // * Neither the name of Google Inc. nor the names of its |
| 13 | // contributors may be used to endorse or promote products derived |
| 14 | // from this software without specific prior written permission. |
| 15 | // |
| 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 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. |
| 27 | |
| 28 | #include "v8.h" |
| 29 | |
| 30 | #include "objects.h" |
| 31 | #include "elements.h" |
| 32 | |
| 33 | namespace v8 { |
| 34 | namespace internal { |
| 35 | |
| 36 | |
| 37 | ElementsAccessor** ElementsAccessor::elements_accessors_; |
| 38 | |
| 39 | |
| 40 | bool HasKey(FixedArray* array, Object* key) { |
| 41 | int len0 = array->length(); |
| 42 | for (int i = 0; i < len0; i++) { |
| 43 | Object* element = array->get(i); |
| 44 | if (element->IsSmi() && element == key) return true; |
| 45 | if (element->IsString() && |
| 46 | key->IsString() && String::cast(element)->Equals(String::cast(key))) { |
| 47 | return true; |
| 48 | } |
| 49 | } |
| 50 | return false; |
| 51 | } |
| 52 | |
| 53 | |
| 54 | // Base class for element handler implementations. Contains the |
| 55 | // the common logic for objects with different ElementsKinds. |
| 56 | // Subclasses must specialize method for which the element |
| 57 | // implementation differs from the base class implementation. |
| 58 | // |
| 59 | // This class is intended to be used in the following way: |
| 60 | // |
| 61 | // class SomeElementsAccessor : |
| 62 | // public ElementsAccessorBase<SomeElementsAccessor, |
| 63 | // BackingStoreClass> { |
| 64 | // ... |
| 65 | // } |
| 66 | // |
| 67 | // This is an example of the Curiously Recurring Template Pattern (see |
| 68 | // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use |
| 69 | // CRTP to guarantee aggressive compile time optimizations (i.e. inlining and |
| 70 | // specialization of SomeElementsAccessor methods). |
| 71 | template <typename ElementsAccessorSubclass, typename BackingStoreClass> |
| 72 | class ElementsAccessorBase : public ElementsAccessor { |
| 73 | public: |
| 74 | ElementsAccessorBase() { } |
| 75 | virtual MaybeObject* GetWithReceiver(JSObject* obj, |
| 76 | Object* receiver, |
| 77 | uint32_t index) { |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 78 | BackingStoreClass* backing_store = BackingStoreClass::cast(obj->elements()); |
| 79 | if (index < ElementsAccessorSubclass::GetLength(backing_store)) { |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 80 | return backing_store->get(index); |
| 81 | } |
| 82 | return obj->GetHeap()->the_hole_value(); |
| 83 | } |
| 84 | |
| 85 | virtual MaybeObject* Delete(JSObject* obj, |
| 86 | uint32_t index, |
| 87 | JSReceiver::DeleteMode mode) = 0; |
| 88 | |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 89 | virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from, |
| 90 | FixedArray* to) { |
| 91 | int len0 = to->length(); |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 92 | #ifdef DEBUG |
| 93 | if (FLAG_enable_slow_asserts) { |
| 94 | for (int i = 0; i < len0; i++) { |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 95 | ASSERT(!to->get(i)->IsTheHole()); |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 96 | } |
| 97 | } |
| 98 | #endif |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 99 | BackingStoreClass* backing_store = BackingStoreClass::cast(from); |
| 100 | int len1 = ElementsAccessorSubclass::GetCapacity(backing_store); |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 101 | |
| 102 | // Optimize if 'other' is empty. |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 103 | // We cannot optimize if 'this' is empty, as other may have holes. |
| 104 | if (len1 == 0) return to; |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 105 | |
| 106 | // Compute how many elements are not in other. |
| 107 | int extra = 0; |
| 108 | for (int y = 0; y < len1; y++) { |
| 109 | Object* value; |
| 110 | MaybeObject* maybe_value = |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 111 | ElementsAccessorSubclass::GetElementAtCapacityIndex(backing_store, y); |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 112 | if (!maybe_value->ToObject(&value)) return maybe_value; |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 113 | if (!value->IsTheHole() && !HasKey(to, value)) extra++; |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 114 | } |
| 115 | |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 116 | if (extra == 0) return to; |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 117 | |
| 118 | // Allocate the result |
| 119 | FixedArray* result; |
| 120 | MaybeObject* maybe_obj = |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 121 | backing_store->GetHeap()->AllocateFixedArray(len0 + extra); |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 122 | if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj; |
| 123 | |
| 124 | // Fill in the content |
| 125 | { |
| 126 | AssertNoAllocation no_gc; |
| 127 | WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); |
| 128 | for (int i = 0; i < len0; i++) { |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 129 | Object* e = to->get(i); |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 130 | ASSERT(e->IsString() || e->IsNumber()); |
| 131 | result->set(i, e, mode); |
| 132 | } |
| 133 | } |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 134 | // Fill in the extra values. |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 135 | int index = 0; |
| 136 | for (int y = 0; y < len1; y++) { |
| 137 | MaybeObject* maybe_value = |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 138 | ElementsAccessorSubclass::GetElementAtCapacityIndex(backing_store, y); |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 139 | Object* value; |
| 140 | if (!maybe_value->ToObject(&value)) return maybe_value; |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 141 | if (!value->IsTheHole() && !HasKey(to, value)) { |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 142 | result->set(len0 + index, value); |
| 143 | index++; |
| 144 | } |
| 145 | } |
| 146 | ASSERT(extra == index); |
| 147 | return result; |
| 148 | } |
| 149 | |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 150 | static uint32_t GetLength(BackingStoreClass* backing_store) { |
| 151 | return backing_store->length(); |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 152 | } |
| 153 | |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 154 | static uint32_t GetCapacity(BackingStoreClass* backing_store) { |
| 155 | return GetLength(backing_store); |
| 156 | } |
| 157 | |
| 158 | static MaybeObject* GetElementAtCapacityIndex( |
| 159 | BackingStoreClass* backing_store, |
| 160 | int index) { |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 161 | return backing_store->get(index); |
| 162 | } |
| 163 | |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 164 | private: |
| 165 | DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase); |
| 166 | }; |
| 167 | |
| 168 | |
| 169 | class FastElementsAccessor |
| 170 | : public ElementsAccessorBase<FastElementsAccessor, FixedArray> { |
| 171 | public: |
| 172 | static MaybeObject* DeleteCommon(JSObject* obj, |
| 173 | uint32_t index) { |
| 174 | ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements()); |
| 175 | Heap* heap = obj->GetHeap(); |
| 176 | FixedArray* backing_store = FixedArray::cast(obj->elements()); |
| 177 | if (backing_store->map() == heap->non_strict_arguments_elements_map()) { |
| 178 | backing_store = FixedArray::cast(backing_store->get(1)); |
| 179 | } else { |
| 180 | Object* writable; |
| 181 | MaybeObject* maybe = obj->EnsureWritableFastElements(); |
| 182 | if (!maybe->ToObject(&writable)) return maybe; |
| 183 | backing_store = FixedArray::cast(writable); |
| 184 | } |
| 185 | uint32_t length = static_cast<uint32_t>( |
| 186 | obj->IsJSArray() |
| 187 | ? Smi::cast(JSArray::cast(obj)->length())->value() |
| 188 | : backing_store->length()); |
| 189 | if (index < length) { |
| 190 | backing_store->set_the_hole(index); |
| 191 | // If an old space backing store is larger than a certain size and |
| 192 | // has too few used values, normalize it. |
| 193 | // To avoid doing the check on every delete we require at least |
| 194 | // one adjacent hole to the value being deleted. |
| 195 | Object* hole = heap->the_hole_value(); |
| 196 | const int kMinLengthForSparsenessCheck = 64; |
| 197 | if (backing_store->length() >= kMinLengthForSparsenessCheck && |
| 198 | !heap->InNewSpace(backing_store) && |
| 199 | ((index > 0 && backing_store->get(index - 1) == hole) || |
| 200 | (index + 1 < length && backing_store->get(index + 1) == hole))) { |
| 201 | int num_used = 0; |
| 202 | for (int i = 0; i < backing_store->length(); ++i) { |
| 203 | if (backing_store->get(i) != hole) ++num_used; |
| 204 | // Bail out early if more than 1/4 is used. |
| 205 | if (4 * num_used > backing_store->length()) break; |
| 206 | } |
| 207 | if (4 * num_used <= backing_store->length()) { |
| 208 | MaybeObject* result = obj->NormalizeElements(); |
| 209 | if (result->IsFailure()) return result; |
| 210 | } |
| 211 | } |
| 212 | } |
| 213 | return heap->true_value(); |
| 214 | } |
| 215 | |
| 216 | virtual MaybeObject* Delete(JSObject* obj, |
| 217 | uint32_t index, |
| 218 | JSReceiver::DeleteMode mode) { |
| 219 | return DeleteCommon(obj, index); |
| 220 | } |
| 221 | }; |
| 222 | |
| 223 | |
| 224 | class FastDoubleElementsAccessor |
| 225 | : public ElementsAccessorBase<FastDoubleElementsAccessor, |
| 226 | FixedDoubleArray> { |
| 227 | virtual MaybeObject* Delete(JSObject* obj, |
| 228 | uint32_t index, |
| 229 | JSReceiver::DeleteMode mode) { |
| 230 | int length = obj->IsJSArray() |
| 231 | ? Smi::cast(JSArray::cast(obj)->length())->value() |
| 232 | : FixedDoubleArray::cast(obj->elements())->length(); |
| 233 | if (index < static_cast<uint32_t>(length)) { |
| 234 | FixedDoubleArray::cast(obj->elements())->set_the_hole(index); |
| 235 | } |
| 236 | return obj->GetHeap()->true_value(); |
| 237 | } |
| 238 | }; |
| 239 | |
| 240 | |
| 241 | // Super class for all external element arrays. |
| 242 | template<typename ExternalElementsAccessorSubclass, |
| 243 | typename ExternalArray> |
| 244 | class ExternalElementsAccessor |
| 245 | : public ElementsAccessorBase<ExternalElementsAccessorSubclass, |
| 246 | ExternalArray> { |
| 247 | public: |
| 248 | virtual MaybeObject* GetWithReceiver(JSObject* obj, |
| 249 | Object* receiver, |
| 250 | uint32_t index) { |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 251 | ExternalArray* backing_store = ExternalArray::cast(obj->elements()); |
| 252 | if (index < ExternalElementsAccessorSubclass::GetLength(backing_store)) { |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 253 | return backing_store->get(index); |
| 254 | } else { |
| 255 | return obj->GetHeap()->undefined_value(); |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | virtual MaybeObject* Delete(JSObject* obj, |
| 260 | uint32_t index, |
| 261 | JSReceiver::DeleteMode mode) { |
| 262 | // External arrays always ignore deletes. |
| 263 | return obj->GetHeap()->true_value(); |
| 264 | } |
| 265 | }; |
| 266 | |
| 267 | |
| 268 | class ExternalByteElementsAccessor |
| 269 | : public ExternalElementsAccessor<ExternalByteElementsAccessor, |
| 270 | ExternalByteArray> { |
| 271 | }; |
| 272 | |
| 273 | |
| 274 | class ExternalUnsignedByteElementsAccessor |
| 275 | : public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor, |
| 276 | ExternalUnsignedByteArray> { |
| 277 | }; |
| 278 | |
| 279 | |
| 280 | class ExternalShortElementsAccessor |
| 281 | : public ExternalElementsAccessor<ExternalShortElementsAccessor, |
| 282 | ExternalShortArray> { |
| 283 | }; |
| 284 | |
| 285 | |
| 286 | class ExternalUnsignedShortElementsAccessor |
| 287 | : public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor, |
| 288 | ExternalUnsignedShortArray> { |
| 289 | }; |
| 290 | |
| 291 | |
| 292 | class ExternalIntElementsAccessor |
| 293 | : public ExternalElementsAccessor<ExternalIntElementsAccessor, |
| 294 | ExternalIntArray> { |
| 295 | }; |
| 296 | |
| 297 | |
| 298 | class ExternalUnsignedIntElementsAccessor |
| 299 | : public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor, |
| 300 | ExternalUnsignedIntArray> { |
| 301 | }; |
| 302 | |
| 303 | |
| 304 | class ExternalFloatElementsAccessor |
| 305 | : public ExternalElementsAccessor<ExternalFloatElementsAccessor, |
| 306 | ExternalFloatArray> { |
| 307 | }; |
| 308 | |
| 309 | |
| 310 | class ExternalDoubleElementsAccessor |
| 311 | : public ExternalElementsAccessor<ExternalDoubleElementsAccessor, |
| 312 | ExternalDoubleArray> { |
| 313 | }; |
| 314 | |
| 315 | |
| 316 | class PixelElementsAccessor |
| 317 | : public ExternalElementsAccessor<PixelElementsAccessor, |
| 318 | ExternalPixelArray> { |
| 319 | }; |
| 320 | |
| 321 | |
| 322 | class DictionaryElementsAccessor |
| 323 | : public ElementsAccessorBase<DictionaryElementsAccessor, |
| 324 | NumberDictionary> { |
| 325 | public: |
| 326 | static MaybeObject* GetNumberDictionaryElement( |
| 327 | JSObject* obj, |
| 328 | Object* receiver, |
| 329 | NumberDictionary* backing_store, |
| 330 | uint32_t index) { |
| 331 | int entry = backing_store->FindEntry(index); |
| 332 | if (entry != NumberDictionary::kNotFound) { |
| 333 | Object* element = backing_store->ValueAt(entry); |
| 334 | PropertyDetails details = backing_store->DetailsAt(entry); |
| 335 | if (details.type() == CALLBACKS) { |
| 336 | return obj->GetElementWithCallback(receiver, |
| 337 | element, |
| 338 | index, |
| 339 | obj); |
| 340 | } else { |
| 341 | return element; |
| 342 | } |
| 343 | } |
| 344 | return obj->GetHeap()->the_hole_value(); |
| 345 | } |
| 346 | |
| 347 | |
| 348 | static MaybeObject* DeleteCommon(JSObject* obj, |
| 349 | uint32_t index, |
| 350 | JSReceiver::DeleteMode mode) { |
| 351 | Isolate* isolate = obj->GetIsolate(); |
| 352 | Heap* heap = isolate->heap(); |
| 353 | FixedArray* backing_store = FixedArray::cast(obj->elements()); |
| 354 | bool is_arguments = |
| 355 | (obj->GetElementsKind() == JSObject::NON_STRICT_ARGUMENTS_ELEMENTS); |
| 356 | if (is_arguments) { |
| 357 | backing_store = FixedArray::cast(backing_store->get(1)); |
| 358 | } |
| 359 | NumberDictionary* dictionary = NumberDictionary::cast(backing_store); |
| 360 | int entry = dictionary->FindEntry(index); |
| 361 | if (entry != NumberDictionary::kNotFound) { |
| 362 | Object* result = dictionary->DeleteProperty(entry, mode); |
| 363 | if (result == heap->true_value()) { |
| 364 | MaybeObject* maybe_elements = dictionary->Shrink(index); |
| 365 | FixedArray* new_elements = NULL; |
| 366 | if (!maybe_elements->To(&new_elements)) { |
| 367 | return maybe_elements; |
| 368 | } |
| 369 | if (is_arguments) { |
| 370 | FixedArray::cast(obj->elements())->set(1, new_elements); |
| 371 | } else { |
| 372 | obj->set_elements(new_elements); |
| 373 | } |
| 374 | } |
| 375 | if (mode == JSObject::STRICT_DELETION && |
| 376 | result == heap->false_value()) { |
| 377 | // In strict mode, attempting to delete a non-configurable property |
| 378 | // throws an exception. |
| 379 | HandleScope scope(isolate); |
| 380 | Handle<Object> holder(obj); |
| 381 | Handle<Object> name = isolate->factory()->NewNumberFromUint(index); |
| 382 | Handle<Object> args[2] = { name, holder }; |
| 383 | Handle<Object> error = |
| 384 | isolate->factory()->NewTypeError("strict_delete_property", |
| 385 | HandleVector(args, 2)); |
| 386 | return isolate->Throw(*error); |
| 387 | } |
| 388 | } |
| 389 | return heap->true_value(); |
| 390 | } |
| 391 | |
| 392 | virtual MaybeObject* Delete(JSObject* obj, |
| 393 | uint32_t index, |
| 394 | JSReceiver::DeleteMode mode) { |
| 395 | return DeleteCommon(obj, index, mode); |
| 396 | } |
| 397 | |
| 398 | virtual MaybeObject* GetWithReceiver(JSObject* obj, |
| 399 | Object* receiver, |
| 400 | uint32_t index) { |
| 401 | return GetNumberDictionaryElement(obj, |
| 402 | receiver, |
| 403 | obj->element_dictionary(), |
| 404 | index); |
| 405 | } |
| 406 | |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 407 | static uint32_t GetCapacity(NumberDictionary* dict) { |
| 408 | return dict->Capacity(); |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 409 | } |
| 410 | |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 411 | static MaybeObject* GetElementAtCapacityIndex(NumberDictionary* dict, |
| 412 | int index) { |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 413 | if (dict->IsKey(dict->KeyAt(index))) { |
| 414 | return dict->ValueAt(index); |
| 415 | } else { |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 416 | return dict->GetHeap()->the_hole_value(); |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 417 | } |
| 418 | } |
| 419 | }; |
| 420 | |
| 421 | |
| 422 | class NonStrictArgumentsElementsAccessor |
| 423 | : public ElementsAccessorBase<NonStrictArgumentsElementsAccessor, |
| 424 | FixedArray> { |
| 425 | public: |
| 426 | virtual MaybeObject* GetWithReceiver(JSObject* obj, |
| 427 | Object* receiver, |
| 428 | uint32_t index) { |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 429 | FixedArray* parameter_map = FixedArray::cast(obj->elements()); |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 430 | uint32_t length = parameter_map->length(); |
| 431 | Object* probe = |
| 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)); |
| 435 | int context_index = Smi::cast(probe)->value(); |
| 436 | ASSERT(!context->get(context_index)->IsTheHole()); |
| 437 | return context->get(context_index); |
| 438 | } else { |
| 439 | // Object is not mapped, defer to the arguments. |
| 440 | FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 441 | if (arguments->IsDictionary()) { |
| 442 | return DictionaryElementsAccessor::GetNumberDictionaryElement( |
| 443 | obj, |
| 444 | receiver, |
| 445 | NumberDictionary::cast(arguments), |
| 446 | index); |
| 447 | } else if (index < static_cast<uint32_t>(arguments->length())) { |
| 448 | return arguments->get(index); |
| 449 | } |
| 450 | } |
| 451 | return obj->GetHeap()->the_hole_value(); |
| 452 | } |
| 453 | |
| 454 | virtual MaybeObject* Delete(JSObject* obj, |
| 455 | uint32_t index, |
| 456 | JSReceiver::DeleteMode mode) { |
| 457 | FixedArray* parameter_map = FixedArray::cast(obj->elements()); |
| 458 | uint32_t length = parameter_map->length(); |
| 459 | Object* probe = |
| 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 |
| 463 | // parameter, and revert to normal elements in that case. That |
| 464 | // would enable GC of the context. |
| 465 | parameter_map->set_the_hole(index + 2); |
| 466 | } else { |
| 467 | FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 468 | if (arguments->IsDictionary()) { |
| 469 | return DictionaryElementsAccessor::DeleteCommon(obj, index, mode); |
| 470 | } else { |
| 471 | return FastElementsAccessor::DeleteCommon(obj, index); |
| 472 | } |
| 473 | } |
| 474 | return obj->GetHeap()->true_value(); |
| 475 | } |
| 476 | |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 477 | static uint32_t GetCapacity(FixedArray* obj) { |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 478 | // TODO(danno): Return max of parameter map length or backing store |
| 479 | // capacity. |
| 480 | return 0; |
| 481 | } |
| 482 | |
whesse@chromium.org | 4acdc2c | 2011-08-15 13:01:23 +0000 | [diff] [blame^] | 483 | static MaybeObject* GetElementAtCapacityIndex(FixedArray* obj, int index) { |
kmillikin@chromium.org | 7c2628c | 2011-08-10 11:27:35 +0000 | [diff] [blame] | 484 | // TODO(danno): Return either value from parameter map of backing |
| 485 | // store value at index. |
| 486 | return obj->GetHeap()->the_hole_value(); |
| 487 | } |
| 488 | }; |
| 489 | |
| 490 | |
| 491 | void ElementsAccessor::InitializeOncePerProcess() { |
| 492 | static struct ConcreteElementsAccessors { |
| 493 | FastElementsAccessor fast_elements_handler; |
| 494 | FastDoubleElementsAccessor fast_double_elements_handler; |
| 495 | DictionaryElementsAccessor dictionary_elements_handler; |
| 496 | NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler; |
| 497 | ExternalByteElementsAccessor byte_elements_handler; |
| 498 | ExternalUnsignedByteElementsAccessor unsigned_byte_elements_handler; |
| 499 | ExternalShortElementsAccessor short_elements_handler; |
| 500 | ExternalUnsignedShortElementsAccessor unsigned_short_elements_handler; |
| 501 | ExternalIntElementsAccessor int_elements_handler; |
| 502 | ExternalUnsignedIntElementsAccessor unsigned_int_elements_handler; |
| 503 | ExternalFloatElementsAccessor float_elements_handler; |
| 504 | ExternalDoubleElementsAccessor double_elements_handler; |
| 505 | PixelElementsAccessor pixel_elements_handler; |
| 506 | } element_accessors; |
| 507 | |
| 508 | static ElementsAccessor* accessor_array[] = { |
| 509 | &element_accessors.fast_elements_handler, |
| 510 | &element_accessors.fast_double_elements_handler, |
| 511 | &element_accessors.dictionary_elements_handler, |
| 512 | &element_accessors.non_strict_arguments_elements_handler, |
| 513 | &element_accessors.byte_elements_handler, |
| 514 | &element_accessors.unsigned_byte_elements_handler, |
| 515 | &element_accessors.short_elements_handler, |
| 516 | &element_accessors.unsigned_short_elements_handler, |
| 517 | &element_accessors.int_elements_handler, |
| 518 | &element_accessors.unsigned_int_elements_handler, |
| 519 | &element_accessors.float_elements_handler, |
| 520 | &element_accessors.double_elements_handler, |
| 521 | &element_accessors.pixel_elements_handler |
| 522 | }; |
| 523 | |
| 524 | elements_accessors_ = accessor_array; |
| 525 | } |
| 526 | |
| 527 | |
| 528 | } } // namespace v8::internal |