1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_ELEMENTS_H_ 6 #define V8_ELEMENTS_H_ 7 8 #include "src/elements-kind.h" 9 #include "src/objects.h" 10 #include "src/heap.h" 11 #include "src/isolate.h" 12 13 namespace v8 { 14 namespace internal { 15 16 // Abstract base class for handles that can operate on objects with differing 17 // ElementsKinds. 18 class ElementsAccessor { 19 public: 20 explicit ElementsAccessor(const char* name) : name_(name) { } 21 virtual ~ElementsAccessor() { } 22 23 virtual ElementsKind kind() const = 0; 24 const char* name() const { return name_; } 25 26 // Checks the elements of an object for consistency, asserting when a problem 27 // is found. 28 virtual void Validate(Handle<JSObject> obj) = 0; 29 30 // Returns true if a holder contains an element with the specified key 31 // without iterating up the prototype chain. The caller can optionally pass 32 // in the backing store to use for the check, which must be compatible with 33 // the ElementsKind of the ElementsAccessor. If backing_store is NULL, the 34 // holder->elements() is used as the backing store. 35 virtual bool HasElement( 36 Handle<Object> receiver, 37 Handle<JSObject> holder, 38 uint32_t key, 39 Handle<FixedArrayBase> backing_store) = 0; 40 41 inline bool HasElement( 42 Handle<Object> receiver, 43 Handle<JSObject> holder, 44 uint32_t key) { 45 return HasElement(receiver, holder, key, handle(holder->elements())); 46 } 47 48 // Returns the element with the specified key or undefined if there is no such 49 // element. This method doesn't iterate up the prototype chain. The caller 50 // can optionally pass in the backing store to use for the check, which must 51 // be compatible with the ElementsKind of the ElementsAccessor. If 52 // backing_store is NULL, the holder->elements() is used as the backing store. 53 MUST_USE_RESULT virtual MaybeHandle<Object> Get( 54 Handle<Object> receiver, 55 Handle<JSObject> holder, 56 uint32_t key, 57 Handle<FixedArrayBase> backing_store) = 0; 58 59 MUST_USE_RESULT inline MaybeHandle<Object> Get( 60 Handle<Object> receiver, 61 Handle<JSObject> holder, 62 uint32_t key) { 63 return Get(receiver, holder, key, handle(holder->elements())); 64 } 65 66 // Returns an element's attributes, or ABSENT if there is no such 67 // element. This method doesn't iterate up the prototype chain. The caller 68 // can optionally pass in the backing store to use for the check, which must 69 // be compatible with the ElementsKind of the ElementsAccessor. If 70 // backing_store is NULL, the holder->elements() is used as the backing store. 71 MUST_USE_RESULT virtual PropertyAttributes GetAttributes( 72 Handle<Object> receiver, 73 Handle<JSObject> holder, 74 uint32_t key, 75 Handle<FixedArrayBase> backing_store) = 0; 76 77 MUST_USE_RESULT inline PropertyAttributes GetAttributes( 78 Handle<Object> receiver, 79 Handle<JSObject> holder, 80 uint32_t key) { 81 return GetAttributes(receiver, holder, key, handle(holder->elements())); 82 } 83 84 // Returns an element's type, or NONEXISTENT if there is no such 85 // element. This method doesn't iterate up the prototype chain. The caller 86 // can optionally pass in the backing store to use for the check, which must 87 // be compatible with the ElementsKind of the ElementsAccessor. If 88 // backing_store is NULL, the holder->elements() is used as the backing store. 89 MUST_USE_RESULT virtual PropertyType GetType( 90 Handle<Object> receiver, 91 Handle<JSObject> holder, 92 uint32_t key, 93 Handle<FixedArrayBase> backing_store) = 0; 94 95 MUST_USE_RESULT inline PropertyType GetType( 96 Handle<Object> receiver, 97 Handle<JSObject> holder, 98 uint32_t key) { 99 return GetType(receiver, holder, key, handle(holder->elements())); 100 } 101 102 // Returns an element's accessors, or NULL if the element does not exist or 103 // is plain. This method doesn't iterate up the prototype chain. The caller 104 // can optionally pass in the backing store to use for the check, which must 105 // be compatible with the ElementsKind of the ElementsAccessor. If 106 // backing_store is NULL, the holder->elements() is used as the backing store. 107 MUST_USE_RESULT virtual MaybeHandle<AccessorPair> GetAccessorPair( 108 Handle<Object> receiver, 109 Handle<JSObject> holder, 110 uint32_t key, 111 Handle<FixedArrayBase> backing_store) = 0; 112 113 MUST_USE_RESULT inline MaybeHandle<AccessorPair> GetAccessorPair( 114 Handle<Object> receiver, 115 Handle<JSObject> holder, 116 uint32_t key) { 117 return GetAccessorPair(receiver, holder, key, handle(holder->elements())); 118 } 119 120 // Modifies the length data property as specified for JSArrays and resizes the 121 // underlying backing store accordingly. The method honors the semantics of 122 // changing array sizes as defined in EcmaScript 5.1 15.4.5.2, i.e. array that 123 // have non-deletable elements can only be shrunk to the size of highest 124 // element that is non-deletable. 125 MUST_USE_RESULT virtual MaybeHandle<Object> SetLength( 126 Handle<JSArray> holder, 127 Handle<Object> new_length) = 0; 128 129 // Modifies both the length and capacity of a JSArray, resizing the underlying 130 // backing store as necessary. This method does NOT honor the semantics of 131 // EcmaScript 5.1 15.4.5.2, arrays can be shrunk beyond non-deletable 132 // elements. This method should only be called for array expansion OR by 133 // runtime JavaScript code that use InternalArrays and don't care about 134 // EcmaScript 5.1 semantics. 135 virtual void SetCapacityAndLength( 136 Handle<JSArray> array, 137 int capacity, 138 int length) = 0; 139 140 // Deletes an element in an object, returning a new elements backing store. 141 MUST_USE_RESULT virtual MaybeHandle<Object> Delete( 142 Handle<JSObject> holder, 143 uint32_t key, 144 JSReceiver::DeleteMode mode) = 0; 145 146 // If kCopyToEnd is specified as the copy_size to CopyElements, it copies all 147 // of elements from source after source_start to the destination array. 148 static const int kCopyToEnd = -1; 149 // If kCopyToEndAndInitializeToHole is specified as the copy_size to 150 // CopyElements, it copies all of elements from source after source_start to 151 // destination array, padding any remaining uninitialized elements in the 152 // destination array with the hole. 153 static const int kCopyToEndAndInitializeToHole = -2; 154 155 // Copy elements from one backing store to another. Typically, callers specify 156 // the source JSObject or JSArray in source_holder. If the holder's backing 157 // store is available, it can be passed in source and source_holder is 158 // ignored. 159 virtual void CopyElements( 160 Handle<FixedArrayBase> source, 161 uint32_t source_start, 162 ElementsKind source_kind, 163 Handle<FixedArrayBase> destination, 164 uint32_t destination_start, 165 int copy_size) = 0; 166 167 // TODO(ishell): Keeping |source_holder| parameter in a non-handlified form 168 // helps avoiding ArrayConcat() builtin performance degradation. 169 // Revisit this later. 170 virtual void CopyElements( 171 JSObject* source_holder, 172 uint32_t source_start, 173 ElementsKind source_kind, 174 Handle<FixedArrayBase> destination, 175 uint32_t destination_start, 176 int copy_size) = 0; 177 178 inline void CopyElements( 179 Handle<JSObject> from_holder, 180 Handle<FixedArrayBase> to, 181 ElementsKind from_kind) { 182 CopyElements( 183 *from_holder, 0, from_kind, to, 0, kCopyToEndAndInitializeToHole); 184 } 185 186 MUST_USE_RESULT virtual MaybeHandle<FixedArray> AddElementsToFixedArray( 187 Handle<Object> receiver, 188 Handle<JSObject> holder, 189 Handle<FixedArray> to, 190 Handle<FixedArrayBase> from) = 0; 191 192 MUST_USE_RESULT inline MaybeHandle<FixedArray> AddElementsToFixedArray( 193 Handle<Object> receiver, 194 Handle<JSObject> holder, 195 Handle<FixedArray> to) { 196 return AddElementsToFixedArray( 197 receiver, holder, to, handle(holder->elements())); 198 } 199 200 // Returns a shared ElementsAccessor for the specified ElementsKind. 201 static ElementsAccessor* ForKind(ElementsKind elements_kind) { 202 ASSERT(elements_kind < kElementsKindCount); 203 return elements_accessors_[elements_kind]; 204 } 205 206 static ElementsAccessor* ForArray(Handle<FixedArrayBase> array); 207 208 static void InitializeOncePerProcess(); 209 static void TearDown(); 210 211 protected: 212 friend class SloppyArgumentsElementsAccessor; 213 214 virtual uint32_t GetCapacity(Handle<FixedArrayBase> backing_store) = 0; 215 216 // Element handlers distinguish between indexes and keys when they manipulate 217 // elements. Indexes refer to elements in terms of their location in the 218 // underlying storage's backing store representation, and are between 0 and 219 // GetCapacity. Keys refer to elements in terms of the value that would be 220 // specified in JavaScript to access the element. In most implementations, 221 // keys are equivalent to indexes, and GetKeyForIndex returns the same value 222 // it is passed. In the NumberDictionary ElementsAccessor, GetKeyForIndex maps 223 // the index to a key using the KeyAt method on the NumberDictionary. 224 virtual uint32_t GetKeyForIndex(Handle<FixedArrayBase> backing_store, 225 uint32_t index) = 0; 226 227 private: 228 static ElementsAccessor** elements_accessors_; 229 const char* name_; 230 231 DISALLOW_COPY_AND_ASSIGN(ElementsAccessor); 232 }; 233 234 void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t key, 235 bool allow_appending = false); 236 237 MUST_USE_RESULT MaybeHandle<Object> ArrayConstructInitializeElements( 238 Handle<JSArray> array, 239 Arguments* args); 240 241 } } // namespace v8::internal 242 243 #endif // V8_ELEMENTS_H_ 244