Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 1 | // Copyright 2011 the V8 project authors. All rights reserved. |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 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 | #include "utils.h" |
| 33 | |
| 34 | namespace v8 { |
| 35 | namespace internal { |
| 36 | |
| 37 | |
| 38 | ElementsAccessor** ElementsAccessor::elements_accessors_; |
| 39 | |
| 40 | |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 41 | bool HasKey(FixedArray* array, Object* key) { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 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 | |
| 55 | // Base class for element handler implementations. Contains the |
| 56 | // the common logic for objects with different ElementsKinds. |
| 57 | // Subclasses must specialize method for which the element |
| 58 | // implementation differs from the base class implementation. |
| 59 | // |
| 60 | // This class is intended to be used in the following way: |
| 61 | // |
| 62 | // class SomeElementsAccessor : |
| 63 | // public ElementsAccessorBase<SomeElementsAccessor, |
| 64 | // BackingStoreClass> { |
| 65 | // ... |
| 66 | // } |
| 67 | // |
| 68 | // This is an example of the Curiously Recurring Template Pattern (see |
| 69 | // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use |
| 70 | // CRTP to guarantee aggressive compile time optimizations (i.e. inlining and |
| 71 | // specialization of SomeElementsAccessor methods). |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 72 | template <typename ElementsAccessorSubclass, typename BackingStoreClass> |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 73 | class ElementsAccessorBase : public ElementsAccessor { |
| 74 | protected: |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 75 | ElementsAccessorBase() { } |
| 76 | virtual MaybeObject* Get(FixedArrayBase* backing_store, |
Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame] | 77 | uint32_t key, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 78 | JSObject* obj, |
| 79 | Object* receiver) { |
| 80 | return ElementsAccessorSubclass::Get( |
| 81 | BackingStoreClass::cast(backing_store), key, obj, receiver); |
| 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); |
Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame] | 90 | } |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 91 | return backing_store->GetHeap()->the_hole_value(); |
Ben Murdoch | c7cc028 | 2012-03-05 14:35:55 +0000 | [diff] [blame] | 92 | } |
| 93 | |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 94 | virtual MaybeObject* Delete(JSObject* obj, |
| 95 | uint32_t key, |
| 96 | JSReceiver::DeleteMode mode) = 0; |
| 97 | |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 98 | virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from, |
Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame] | 99 | FixedArray* to, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 100 | JSObject* holder, |
| 101 | Object* receiver) { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 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 |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 110 | BackingStoreClass* backing_store = BackingStoreClass::cast(from); |
| 111 | uint32_t len1 = ElementsAccessorSubclass::GetCapacity(backing_store); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 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. |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 118 | int extra = 0; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 119 | for (uint32_t y = 0; y < len1; y++) { |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 120 | if (ElementsAccessorSubclass::HasElementAtIndex(backing_store, |
| 121 | y, |
| 122 | holder, |
| 123 | receiver)) { |
| 124 | uint32_t key = |
| 125 | ElementsAccessorSubclass::GetKeyForIndex(backing_store, y); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 126 | MaybeObject* maybe_value = |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 127 | ElementsAccessorSubclass::Get(backing_store, key, holder, receiver); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 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. |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 156 | int index = 0; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 157 | for (uint32_t y = 0; y < len1; y++) { |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 158 | if (ElementsAccessorSubclass::HasElementAtIndex(backing_store, |
| 159 | y, |
| 160 | holder, |
| 161 | receiver)) { |
| 162 | uint32_t key = |
| 163 | ElementsAccessorSubclass::GetKeyForIndex(backing_store, y); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 164 | MaybeObject* maybe_value = |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 165 | ElementsAccessorSubclass::Get(backing_store, key, holder, receiver); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 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; |
| 176 | } |
| 177 | |
| 178 | protected: |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 179 | static uint32_t GetCapacity(BackingStoreClass* backing_store) { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 180 | return backing_store->length(); |
| 181 | } |
| 182 | |
| 183 | virtual uint32_t GetCapacity(FixedArrayBase* backing_store) { |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 184 | return ElementsAccessorSubclass::GetCapacity( |
| 185 | BackingStoreClass::cast(backing_store)); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 186 | } |
| 187 | |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 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) { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 211 | return index; |
| 212 | } |
| 213 | |
| 214 | virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 215 | uint32_t index) { |
| 216 | return ElementsAccessorSubclass::GetKeyForIndex( |
| 217 | BackingStoreClass::cast(backing_store), index); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 218 | } |
| 219 | |
| 220 | private: |
| 221 | DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase); |
| 222 | }; |
| 223 | |
| 224 | |
| 225 | class FastElementsAccessor |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 226 | : public ElementsAccessorBase<FastElementsAccessor, FixedArray> { |
Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame] | 227 | public: |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 228 | static MaybeObject* DeleteCommon(JSObject* obj, |
| 229 | uint32_t key) { |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 230 | ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements()); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 231 | Heap* heap = obj->GetHeap(); |
| 232 | FixedArray* backing_store = FixedArray::cast(obj->elements()); |
| 233 | if (backing_store->map() == heap->non_strict_arguments_elements_map()) { |
| 234 | backing_store = FixedArray::cast(backing_store->get(1)); |
| 235 | } else { |
| 236 | Object* writable; |
| 237 | MaybeObject* maybe = obj->EnsureWritableFastElements(); |
| 238 | if (!maybe->ToObject(&writable)) return maybe; |
| 239 | backing_store = FixedArray::cast(writable); |
| 240 | } |
| 241 | uint32_t length = static_cast<uint32_t>( |
| 242 | obj->IsJSArray() |
| 243 | ? Smi::cast(JSArray::cast(obj)->length())->value() |
| 244 | : backing_store->length()); |
| 245 | if (key < length) { |
| 246 | backing_store->set_the_hole(key); |
| 247 | // If an old space backing store is larger than a certain size and |
| 248 | // has too few used values, normalize it. |
| 249 | // To avoid doing the check on every delete we require at least |
| 250 | // one adjacent hole to the value being deleted. |
| 251 | Object* hole = heap->the_hole_value(); |
| 252 | const int kMinLengthForSparsenessCheck = 64; |
| 253 | if (backing_store->length() >= kMinLengthForSparsenessCheck && |
| 254 | !heap->InNewSpace(backing_store) && |
| 255 | ((key > 0 && backing_store->get(key - 1) == hole) || |
| 256 | (key + 1 < length && backing_store->get(key + 1) == hole))) { |
| 257 | int num_used = 0; |
| 258 | for (int i = 0; i < backing_store->length(); ++i) { |
| 259 | if (backing_store->get(i) != hole) ++num_used; |
| 260 | // Bail out early if more than 1/4 is used. |
| 261 | if (4 * num_used > backing_store->length()) break; |
| 262 | } |
| 263 | if (4 * num_used <= backing_store->length()) { |
| 264 | MaybeObject* result = obj->NormalizeElements(); |
| 265 | if (result->IsFailure()) return result; |
| 266 | } |
| 267 | } |
| 268 | } |
| 269 | return heap->true_value(); |
| 270 | } |
| 271 | |
Ben Murdoch | c7cc028 | 2012-03-05 14:35:55 +0000 | [diff] [blame] | 272 | protected: |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 273 | virtual MaybeObject* Delete(JSObject* obj, |
| 274 | uint32_t key, |
| 275 | JSReceiver::DeleteMode mode) { |
| 276 | return DeleteCommon(obj, key); |
| 277 | } |
| 278 | }; |
| 279 | |
| 280 | |
| 281 | class FastDoubleElementsAccessor |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 282 | : public ElementsAccessorBase<FastDoubleElementsAccessor, |
| 283 | FixedDoubleArray> { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 284 | protected: |
| 285 | friend class ElementsAccessorBase<FastDoubleElementsAccessor, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 286 | FixedDoubleArray>; |
Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame] | 287 | |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 288 | virtual MaybeObject* Delete(JSObject* obj, |
| 289 | uint32_t key, |
| 290 | JSReceiver::DeleteMode mode) { |
| 291 | int length = obj->IsJSArray() |
| 292 | ? Smi::cast(JSArray::cast(obj)->length())->value() |
| 293 | : FixedDoubleArray::cast(obj->elements())->length(); |
| 294 | if (key < static_cast<uint32_t>(length)) { |
| 295 | FixedDoubleArray::cast(obj->elements())->set_the_hole(key); |
| 296 | } |
| 297 | return obj->GetHeap()->true_value(); |
| 298 | } |
| 299 | |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 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); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 305 | } |
| 306 | }; |
| 307 | |
| 308 | |
| 309 | // Super class for all external element arrays. |
| 310 | template<typename ExternalElementsAccessorSubclass, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 311 | typename ExternalArray> |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 312 | class ExternalElementsAccessor |
| 313 | : public ElementsAccessorBase<ExternalElementsAccessorSubclass, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 314 | ExternalArray> { |
Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame] | 315 | protected: |
Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame] | 316 | friend class ElementsAccessorBase<ExternalElementsAccessorSubclass, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 317 | ExternalArray>; |
Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame] | 318 | |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 319 | static MaybeObject* Get(ExternalArray* backing_store, |
| 320 | uint32_t key, |
| 321 | JSObject* obj, |
| 322 | Object* receiver) { |
| 323 | if (key < ExternalElementsAccessorSubclass::GetCapacity(backing_store)) { |
| 324 | return backing_store->get(key); |
| 325 | } else { |
| 326 | return backing_store->GetHeap()->undefined_value(); |
| 327 | } |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 328 | } |
| 329 | |
| 330 | virtual MaybeObject* Delete(JSObject* obj, |
| 331 | uint32_t key, |
| 332 | JSReceiver::DeleteMode mode) { |
| 333 | // External arrays always ignore deletes. |
| 334 | return obj->GetHeap()->true_value(); |
| 335 | } |
| 336 | }; |
| 337 | |
| 338 | |
| 339 | class ExternalByteElementsAccessor |
| 340 | : public ExternalElementsAccessor<ExternalByteElementsAccessor, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 341 | ExternalByteArray> { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 342 | }; |
| 343 | |
| 344 | |
| 345 | class ExternalUnsignedByteElementsAccessor |
| 346 | : public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 347 | ExternalUnsignedByteArray> { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 348 | }; |
| 349 | |
| 350 | |
| 351 | class ExternalShortElementsAccessor |
| 352 | : public ExternalElementsAccessor<ExternalShortElementsAccessor, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 353 | ExternalShortArray> { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 354 | }; |
| 355 | |
| 356 | |
| 357 | class ExternalUnsignedShortElementsAccessor |
| 358 | : public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 359 | ExternalUnsignedShortArray> { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 360 | }; |
| 361 | |
| 362 | |
| 363 | class ExternalIntElementsAccessor |
| 364 | : public ExternalElementsAccessor<ExternalIntElementsAccessor, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 365 | ExternalIntArray> { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 366 | }; |
| 367 | |
| 368 | |
| 369 | class ExternalUnsignedIntElementsAccessor |
| 370 | : public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 371 | ExternalUnsignedIntArray> { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 372 | }; |
| 373 | |
| 374 | |
| 375 | class ExternalFloatElementsAccessor |
| 376 | : public ExternalElementsAccessor<ExternalFloatElementsAccessor, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 377 | ExternalFloatArray> { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 378 | }; |
| 379 | |
| 380 | |
| 381 | class ExternalDoubleElementsAccessor |
| 382 | : public ExternalElementsAccessor<ExternalDoubleElementsAccessor, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 383 | ExternalDoubleArray> { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 384 | }; |
| 385 | |
| 386 | |
| 387 | class PixelElementsAccessor |
| 388 | : public ExternalElementsAccessor<PixelElementsAccessor, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 389 | ExternalPixelArray> { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 390 | }; |
| 391 | |
| 392 | |
| 393 | class DictionaryElementsAccessor |
| 394 | : public ElementsAccessorBase<DictionaryElementsAccessor, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 395 | SeededNumberDictionary> { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 396 | public: |
| 397 | static MaybeObject* DeleteCommon(JSObject* obj, |
| 398 | uint32_t key, |
| 399 | JSReceiver::DeleteMode mode) { |
| 400 | Isolate* isolate = obj->GetIsolate(); |
| 401 | Heap* heap = isolate->heap(); |
| 402 | FixedArray* backing_store = FixedArray::cast(obj->elements()); |
| 403 | bool is_arguments = |
Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 404 | (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 405 | if (is_arguments) { |
| 406 | backing_store = FixedArray::cast(backing_store->get(1)); |
| 407 | } |
Ben Murdoch | c7cc028 | 2012-03-05 14:35:55 +0000 | [diff] [blame] | 408 | SeededNumberDictionary* dictionary = |
| 409 | SeededNumberDictionary::cast(backing_store); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 410 | int entry = dictionary->FindEntry(key); |
Ben Murdoch | c7cc028 | 2012-03-05 14:35:55 +0000 | [diff] [blame] | 411 | if (entry != SeededNumberDictionary::kNotFound) { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 412 | Object* result = dictionary->DeleteProperty(entry, mode); |
| 413 | if (result == heap->true_value()) { |
| 414 | MaybeObject* maybe_elements = dictionary->Shrink(key); |
| 415 | FixedArray* new_elements = NULL; |
| 416 | if (!maybe_elements->To(&new_elements)) { |
| 417 | return maybe_elements; |
| 418 | } |
| 419 | if (is_arguments) { |
| 420 | FixedArray::cast(obj->elements())->set(1, new_elements); |
| 421 | } else { |
| 422 | obj->set_elements(new_elements); |
| 423 | } |
| 424 | } |
| 425 | if (mode == JSObject::STRICT_DELETION && |
| 426 | result == heap->false_value()) { |
| 427 | // In strict mode, attempting to delete a non-configurable property |
| 428 | // throws an exception. |
| 429 | HandleScope scope(isolate); |
| 430 | Handle<Object> holder(obj); |
| 431 | Handle<Object> name = isolate->factory()->NewNumberFromUint(key); |
| 432 | Handle<Object> args[2] = { name, holder }; |
| 433 | Handle<Object> error = |
| 434 | isolate->factory()->NewTypeError("strict_delete_property", |
| 435 | HandleVector(args, 2)); |
| 436 | return isolate->Throw(*error); |
| 437 | } |
| 438 | } |
| 439 | return heap->true_value(); |
| 440 | } |
| 441 | |
| 442 | protected: |
| 443 | friend class ElementsAccessorBase<DictionaryElementsAccessor, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 444 | SeededNumberDictionary>; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 445 | |
| 446 | virtual MaybeObject* Delete(JSObject* obj, |
| 447 | uint32_t key, |
| 448 | JSReceiver::DeleteMode mode) { |
| 449 | return DeleteCommon(obj, key, mode); |
| 450 | } |
| 451 | |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 452 | static MaybeObject* Get(SeededNumberDictionary* backing_store, |
| 453 | uint32_t key, |
| 454 | JSObject* obj, |
| 455 | Object* receiver) { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 456 | int entry = backing_store->FindEntry(key); |
Ben Murdoch | c7cc028 | 2012-03-05 14:35:55 +0000 | [diff] [blame] | 457 | if (entry != SeededNumberDictionary::kNotFound) { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 458 | Object* element = backing_store->ValueAt(entry); |
| 459 | PropertyDetails details = backing_store->DetailsAt(entry); |
| 460 | if (details.type() == CALLBACKS) { |
| 461 | return obj->GetElementWithCallback(receiver, |
| 462 | element, |
| 463 | key, |
| 464 | obj); |
| 465 | } else { |
| 466 | return element; |
| 467 | } |
| 468 | } |
| 469 | return obj->GetHeap()->the_hole_value(); |
| 470 | } |
| 471 | |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 472 | static uint32_t GetKeyForIndex(SeededNumberDictionary* dict, |
| 473 | uint32_t index) { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 474 | Object* key = dict->KeyAt(index); |
| 475 | return Smi::cast(key)->value(); |
| 476 | } |
| 477 | }; |
| 478 | |
| 479 | |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 480 | class NonStrictArgumentsElementsAccessor |
| 481 | : public ElementsAccessorBase<NonStrictArgumentsElementsAccessor, |
| 482 | FixedArray> { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 483 | protected: |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 484 | friend class ElementsAccessorBase<NonStrictArgumentsElementsAccessor, |
| 485 | FixedArray>; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 486 | |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 487 | static MaybeObject* Get(FixedArray* parameter_map, |
| 488 | uint32_t key, |
| 489 | JSObject* obj, |
| 490 | Object* receiver) { |
| 491 | Object* probe = GetParameterMapArg(parameter_map, key); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 492 | if (!probe->IsTheHole()) { |
| 493 | Context* context = Context::cast(parameter_map->get(0)); |
| 494 | int context_index = Smi::cast(probe)->value(); |
| 495 | ASSERT(!context->get(context_index)->IsTheHole()); |
| 496 | return context->get(context_index); |
| 497 | } else { |
| 498 | // Object is not mapped, defer to the arguments. |
| 499 | FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 500 | return ElementsAccessor::ForArray(arguments)->Get(arguments, |
| 501 | key, |
| 502 | obj, |
| 503 | receiver); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 504 | } |
| 505 | } |
| 506 | |
| 507 | virtual MaybeObject* Delete(JSObject* obj, |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 508 | uint32_t key |
| 509 | , |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 510 | JSReceiver::DeleteMode mode) { |
| 511 | FixedArray* parameter_map = FixedArray::cast(obj->elements()); |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 512 | Object* probe = GetParameterMapArg(parameter_map, key); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 513 | if (!probe->IsTheHole()) { |
| 514 | // TODO(kmillikin): We could check if this was the last aliased |
| 515 | // parameter, and revert to normal elements in that case. That |
| 516 | // would enable GC of the context. |
| 517 | parameter_map->set_the_hole(key + 2); |
| 518 | } else { |
| 519 | FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 520 | if (arguments->IsDictionary()) { |
| 521 | return DictionaryElementsAccessor::DeleteCommon(obj, key, mode); |
| 522 | } else { |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 523 | return FastElementsAccessor::DeleteCommon(obj, key); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 524 | } |
| 525 | } |
| 526 | return obj->GetHeap()->true_value(); |
| 527 | } |
| 528 | |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 529 | static uint32_t GetCapacity(FixedArray* parameter_map) { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 530 | FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); |
| 531 | return Max(static_cast<uint32_t>(parameter_map->length() - 2), |
| 532 | ForArray(arguments)->GetCapacity(arguments)); |
| 533 | } |
| 534 | |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 535 | static uint32_t GetKeyForIndex(FixedArray* dict, |
| 536 | uint32_t index) { |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 537 | return index; |
| 538 | } |
| 539 | |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 540 | static bool HasElementAtIndex(FixedArray* parameter_map, |
| 541 | uint32_t index, |
| 542 | JSObject* holder, |
| 543 | Object* receiver) { |
| 544 | Object* probe = GetParameterMapArg(parameter_map, index); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 545 | if (!probe->IsTheHole()) { |
| 546 | return true; |
| 547 | } else { |
| 548 | FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); |
| 549 | ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments); |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 550 | return !accessor->Get(arguments, index, holder, receiver)->IsTheHole(); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 551 | } |
| 552 | } |
| 553 | |
| 554 | private: |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 555 | static Object* GetParameterMapArg(FixedArray* parameter_map, |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 556 | uint32_t key) { |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 557 | uint32_t length = parameter_map->length(); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 558 | return key < (length - 2 ) |
| 559 | ? parameter_map->get(key + 2) |
| 560 | : parameter_map->GetHeap()->the_hole_value(); |
| 561 | } |
| 562 | }; |
| 563 | |
| 564 | |
| 565 | ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) { |
| 566 | switch (array->map()->instance_type()) { |
| 567 | case FIXED_ARRAY_TYPE: |
| 568 | if (array->IsDictionary()) { |
Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 569 | return elements_accessors_[DICTIONARY_ELEMENTS]; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 570 | } else { |
Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 571 | return elements_accessors_[FAST_ELEMENTS]; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 572 | } |
| 573 | case EXTERNAL_BYTE_ARRAY_TYPE: |
Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 574 | return elements_accessors_[EXTERNAL_BYTE_ELEMENTS]; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 575 | case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: |
Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 576 | return elements_accessors_[EXTERNAL_UNSIGNED_BYTE_ELEMENTS]; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 577 | case EXTERNAL_SHORT_ARRAY_TYPE: |
Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 578 | return elements_accessors_[EXTERNAL_SHORT_ELEMENTS]; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 579 | case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: |
Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 580 | return elements_accessors_[EXTERNAL_UNSIGNED_SHORT_ELEMENTS]; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 581 | case EXTERNAL_INT_ARRAY_TYPE: |
Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 582 | return elements_accessors_[EXTERNAL_INT_ELEMENTS]; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 583 | case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: |
Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 584 | return elements_accessors_[EXTERNAL_UNSIGNED_INT_ELEMENTS]; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 585 | case EXTERNAL_FLOAT_ARRAY_TYPE: |
Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 586 | return elements_accessors_[EXTERNAL_FLOAT_ELEMENTS]; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 587 | case EXTERNAL_DOUBLE_ARRAY_TYPE: |
Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 588 | return elements_accessors_[EXTERNAL_DOUBLE_ELEMENTS]; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 589 | case EXTERNAL_PIXEL_ARRAY_TYPE: |
Ben Murdoch | 589d697 | 2011-11-30 16:04:58 +0000 | [diff] [blame] | 590 | return elements_accessors_[EXTERNAL_PIXEL_ELEMENTS]; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 591 | default: |
| 592 | UNREACHABLE(); |
| 593 | return NULL; |
| 594 | } |
| 595 | } |
| 596 | |
| 597 | |
| 598 | void ElementsAccessor::InitializeOncePerProcess() { |
Ben Murdoch | 592a9fc | 2012-03-05 11:04:45 +0000 | [diff] [blame] | 599 | static struct ConcreteElementsAccessors { |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 600 | FastElementsAccessor fast_elements_handler; |
| 601 | FastDoubleElementsAccessor fast_double_elements_handler; |
| 602 | DictionaryElementsAccessor dictionary_elements_handler; |
| 603 | NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler; |
| 604 | ExternalByteElementsAccessor byte_elements_handler; |
| 605 | ExternalUnsignedByteElementsAccessor unsigned_byte_elements_handler; |
| 606 | ExternalShortElementsAccessor short_elements_handler; |
| 607 | ExternalUnsignedShortElementsAccessor unsigned_short_elements_handler; |
| 608 | ExternalIntElementsAccessor int_elements_handler; |
| 609 | ExternalUnsignedIntElementsAccessor unsigned_int_elements_handler; |
| 610 | ExternalFloatElementsAccessor float_elements_handler; |
| 611 | ExternalDoubleElementsAccessor double_elements_handler; |
| 612 | PixelElementsAccessor pixel_elements_handler; |
| 613 | } element_accessors; |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 614 | |
Ben Murdoch | 592a9fc | 2012-03-05 11:04:45 +0000 | [diff] [blame] | 615 | static ElementsAccessor* accessor_array[] = { |
Ben Murdoch | 85b7179 | 2012-04-11 18:30:58 +0100 | [diff] [blame^] | 616 | &element_accessors.fast_elements_handler, |
| 617 | &element_accessors.fast_double_elements_handler, |
| 618 | &element_accessors.dictionary_elements_handler, |
| 619 | &element_accessors.non_strict_arguments_elements_handler, |
| 620 | &element_accessors.byte_elements_handler, |
| 621 | &element_accessors.unsigned_byte_elements_handler, |
| 622 | &element_accessors.short_elements_handler, |
| 623 | &element_accessors.unsigned_short_elements_handler, |
| 624 | &element_accessors.int_elements_handler, |
| 625 | &element_accessors.unsigned_int_elements_handler, |
| 626 | &element_accessors.float_elements_handler, |
| 627 | &element_accessors.double_elements_handler, |
| 628 | &element_accessors.pixel_elements_handler |
Ben Murdoch | 592a9fc | 2012-03-05 11:04:45 +0000 | [diff] [blame] | 629 | }; |
| 630 | |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 631 | elements_accessors_ = accessor_array; |
| 632 | } |
| 633 | |
| 634 | |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 635 | } } // namespace v8::internal |