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/heap/heap.h" 10 #include "src/isolate.h" 11 #include "src/objects.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: ElementsAccessor(const char * name)20 explicit ElementsAccessor(const char* name) : name_(name) { } ~ElementsAccessor()21 virtual ~ElementsAccessor() { } 22 23 virtual ElementsKind kind() const = 0; name()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 HasElement(Handle<Object> receiver,Handle<JSObject> holder,uint32_t key)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 Get(Handle<Object> receiver,Handle<JSObject> holder,uint32_t key)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 GetAttributes(Handle<Object> receiver,Handle<JSObject> holder,uint32_t key)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 accessors, or NULL if the element does not exist or 85 // is plain. 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 MaybeHandle<AccessorPair> GetAccessorPair( 90 Handle<Object> receiver, 91 Handle<JSObject> holder, 92 uint32_t key, 93 Handle<FixedArrayBase> backing_store) = 0; 94 GetAccessorPair(Handle<Object> receiver,Handle<JSObject> holder,uint32_t key)95 MUST_USE_RESULT inline MaybeHandle<AccessorPair> GetAccessorPair( 96 Handle<Object> receiver, 97 Handle<JSObject> holder, 98 uint32_t key) { 99 return GetAccessorPair(receiver, holder, key, handle(holder->elements())); 100 } 101 102 // Modifies the length data property as specified for JSArrays and resizes the 103 // underlying backing store accordingly. The method honors the semantics of 104 // changing array sizes as defined in EcmaScript 5.1 15.4.5.2, i.e. array that 105 // have non-deletable elements can only be shrunk to the size of highest 106 // element that is non-deletable. 107 MUST_USE_RESULT virtual MaybeHandle<Object> SetLength( 108 Handle<JSArray> holder, 109 Handle<Object> new_length) = 0; 110 111 // Modifies both the length and capacity of a JSArray, resizing the underlying 112 // backing store as necessary. This method does NOT honor the semantics of 113 // EcmaScript 5.1 15.4.5.2, arrays can be shrunk beyond non-deletable 114 // elements. This method should only be called for array expansion OR by 115 // runtime JavaScript code that use InternalArrays and don't care about 116 // EcmaScript 5.1 semantics. 117 virtual void SetCapacityAndLength( 118 Handle<JSArray> array, 119 int capacity, 120 int length) = 0; 121 122 // Deletes an element in an object, returning a new elements backing store. 123 MUST_USE_RESULT virtual MaybeHandle<Object> Delete( 124 Handle<JSObject> holder, 125 uint32_t key, 126 JSReceiver::DeleteMode mode) = 0; 127 128 // If kCopyToEnd is specified as the copy_size to CopyElements, it copies all 129 // of elements from source after source_start to the destination array. 130 static const int kCopyToEnd = -1; 131 // If kCopyToEndAndInitializeToHole is specified as the copy_size to 132 // CopyElements, it copies all of elements from source after source_start to 133 // destination array, padding any remaining uninitialized elements in the 134 // destination array with the hole. 135 static const int kCopyToEndAndInitializeToHole = -2; 136 137 // Copy elements from one backing store to another. Typically, callers specify 138 // the source JSObject or JSArray in source_holder. If the holder's backing 139 // store is available, it can be passed in source and source_holder is 140 // ignored. 141 virtual void CopyElements( 142 Handle<FixedArrayBase> source, 143 uint32_t source_start, 144 ElementsKind source_kind, 145 Handle<FixedArrayBase> destination, 146 uint32_t destination_start, 147 int copy_size) = 0; 148 149 // TODO(ishell): Keeping |source_holder| parameter in a non-handlified form 150 // helps avoiding ArrayConcat() builtin performance degradation. 151 // Revisit this later. 152 virtual void CopyElements( 153 JSObject* source_holder, 154 uint32_t source_start, 155 ElementsKind source_kind, 156 Handle<FixedArrayBase> destination, 157 uint32_t destination_start, 158 int copy_size) = 0; 159 CopyElements(Handle<JSObject> from_holder,Handle<FixedArrayBase> to,ElementsKind from_kind)160 inline void CopyElements( 161 Handle<JSObject> from_holder, 162 Handle<FixedArrayBase> to, 163 ElementsKind from_kind) { 164 CopyElements( 165 *from_holder, 0, from_kind, to, 0, kCopyToEndAndInitializeToHole); 166 } 167 168 MUST_USE_RESULT virtual MaybeHandle<FixedArray> AddElementsToFixedArray( 169 Handle<Object> receiver, 170 Handle<JSObject> holder, 171 Handle<FixedArray> to, 172 Handle<FixedArrayBase> from) = 0; 173 AddElementsToFixedArray(Handle<Object> receiver,Handle<JSObject> holder,Handle<FixedArray> to)174 MUST_USE_RESULT inline MaybeHandle<FixedArray> AddElementsToFixedArray( 175 Handle<Object> receiver, 176 Handle<JSObject> holder, 177 Handle<FixedArray> to) { 178 return AddElementsToFixedArray( 179 receiver, holder, to, handle(holder->elements())); 180 } 181 182 // Returns a shared ElementsAccessor for the specified ElementsKind. ForKind(ElementsKind elements_kind)183 static ElementsAccessor* ForKind(ElementsKind elements_kind) { 184 DCHECK(elements_kind < kElementsKindCount); 185 return elements_accessors_[elements_kind]; 186 } 187 188 static ElementsAccessor* ForArray(Handle<FixedArrayBase> array); 189 190 static void InitializeOncePerProcess(); 191 static void TearDown(); 192 193 protected: 194 friend class SloppyArgumentsElementsAccessor; 195 196 virtual uint32_t GetCapacity(Handle<FixedArrayBase> backing_store) = 0; 197 198 // Element handlers distinguish between indexes and keys when they manipulate 199 // elements. Indexes refer to elements in terms of their location in the 200 // underlying storage's backing store representation, and are between 0 and 201 // GetCapacity. Keys refer to elements in terms of the value that would be 202 // specified in JavaScript to access the element. In most implementations, 203 // keys are equivalent to indexes, and GetKeyForIndex returns the same value 204 // it is passed. In the NumberDictionary ElementsAccessor, GetKeyForIndex maps 205 // the index to a key using the KeyAt method on the NumberDictionary. 206 virtual uint32_t GetKeyForIndex(Handle<FixedArrayBase> backing_store, 207 uint32_t index) = 0; 208 209 private: 210 static ElementsAccessor** elements_accessors_; 211 const char* name_; 212 213 DISALLOW_COPY_AND_ASSIGN(ElementsAccessor); 214 }; 215 216 void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t key, 217 bool allow_appending = false); 218 219 MUST_USE_RESULT MaybeHandle<Object> ArrayConstructInitializeElements( 220 Handle<JSArray> array, 221 Arguments* args); 222 223 } } // namespace v8::internal 224 225 #endif // V8_ELEMENTS_H_ 226