source: webkit/trunk/JavaScriptCore/runtime/JSArray.h@ 64177

Last change on this file since 64177 was 64177, checked in by [email protected], 15 years ago

Changed the handling for removing and adding elements at the front
of an array. The code now keeps a bias that indicates the amount of
JSValue sized holes are prior to the ArrayStorage block. This means
that shift operations are now memmove's of the header part of
the ArrayStorage and unshift operations are similar, but may require a
realloc first to create the space. Similar operations are performed
for special cases of splice and slice.
Also optimized the new Array(size) case so that we don't allocate and
initialize array elements until the JS code starts using elements.
The array growth code is slightly more aggressive for initial growth
based on size growth of any previous array.

Patch by Michael Saboff <[email protected]> on 2010-07-27
Reviewed by Gavin Barraclough.

  • Configurations/JavaScriptCore.xcconfig:
  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::privateCompilePatchGetArrayLength):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::privateCompilePatchGetArrayLength):

  • runtime/ArrayPrototype.cpp:

(JSC::arrayProtoFuncShift):
(JSC::arrayProtoFuncSplice):
(JSC::arrayProtoFuncUnShift):

  • runtime/JSArray.cpp:

(JSC::JSArray::JSArray):
(JSC::JSArray::~JSArray):
(JSC::JSArray::getOwnPropertySlot):
(JSC::JSArray::getOwnPropertyDescriptor):
(JSC::JSArray::put):
(JSC::JSArray::putSlowCase):
(JSC::JSArray::deleteProperty):
(JSC::JSArray::getOwnPropertyNames):
(JSC::JSArray::getNewVectorLength):
(JSC::JSArray::increaseVectorLength):
(JSC::JSArray::increaseVectorPrefixLength):
(JSC::JSArray::setLength):
(JSC::JSArray::pop):
(JSC::JSArray::push):
(JSC::JSArray::shiftCount):
(JSC::JSArray::unshiftCount):
(JSC::JSArray::sortNumeric):
(JSC::JSArray::sort):
(JSC::JSArray::fillArgList):
(JSC::JSArray::copyToRegisters):
(JSC::JSArray::compactForSorting):
(JSC::JSArray::subclassData):
(JSC::JSArray::setSubclassData):
(JSC::JSArray::checkConsistency):

  • runtime/JSArray.h:

(JSC::JSArray::length):
(JSC::JSArray::canGetIndex):
(JSC::JSArray::getIndex):
(JSC::JSArray::setIndex):
(JSC::JSArray::uncheckedSetIndex):
(JSC::JSArray::arrayStorage):
(JSC::JSArray::setArrayStorage):
(JSC::JSArray::markChildrenDirect):

  • Property svn:eol-style set to native
File size: 10.3 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21#ifndef JSArray_h
22#define JSArray_h
23
24#include "JSObject.h"
25
26#define CHECK_ARRAY_CONSISTENCY 0
27
28namespace JSC {
29
30 typedef HashMap<unsigned, JSValue> SparseArrayValueMap;
31
32 // This struct holds the actual data values of an array. A JSArray object points to it's contained ArrayStorage
33 // struct by pointing to m_vector. To access the contained ArrayStorage struct, use the getStorage() and
34 // setStorage() methods. It is important to note that there may be space before the ArrayStorage that
35 // is used to quick unshift / shift operation. The actual allocated pointer is available by using:
36 // getStorage() - m_indexBias * sizeof(JSValue)
37 struct ArrayStorage {
38 unsigned m_length; // The "length" property on the array
39 unsigned m_numValuesInVector;
40 SparseArrayValueMap* m_sparseValueMap;
41 void* subclassData; // A JSArray subclass can use this to fill the vector lazily.
42 size_t reportedMapCapacity;
43#if CHECK_ARRAY_CONSISTENCY
44 bool m_inCompactInitialization;
45#endif
46 JSValue m_vector[1];
47 };
48
49 // The CreateCompact creation mode is used for fast construction of arrays
50 // whose size and contents are known at time of creation.
51 //
52 // There are two obligations when using this mode:
53 //
54 // - uncheckedSetIndex() must be used when initializing the array.
55 // - setLength() must be called after initialization.
56
57 enum ArrayCreationMode { CreateCompact, CreateInitialized };
58
59 class JSArray : public JSObject {
60 friend class JIT;
61 friend class Walker;
62
63 public:
64 explicit JSArray(NonNullPassRefPtr<Structure>);
65 JSArray(NonNullPassRefPtr<Structure>, unsigned initialLength, ArrayCreationMode);
66 JSArray(NonNullPassRefPtr<Structure>, const ArgList& initialValues);
67 virtual ~JSArray();
68
69 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
70 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
71 virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
72 virtual void put(ExecState*, unsigned propertyName, JSValue); // FIXME: Make protected and add setItem.
73
74 static JS_EXPORTDATA const ClassInfo info;
75
76 unsigned length() const { return arrayStorage()->m_length; }
77 void setLength(unsigned); // OK to use on new arrays, but not if it might be a RegExpMatchArray.
78
79 void sort(ExecState*);
80 void sort(ExecState*, JSValue compareFunction, CallType, const CallData&);
81 void sortNumeric(ExecState*, JSValue compareFunction, CallType, const CallData&);
82
83 void push(ExecState*, JSValue);
84 JSValue pop();
85
86 void shiftCount(ExecState*, int count);
87 void unshiftCount(ExecState*, int count);
88
89 bool canGetIndex(unsigned i) { return i < m_vectorLength && m_vector[i]; }
90 JSValue getIndex(unsigned i)
91 {
92 ASSERT(canGetIndex(i));
93 return m_vector[i];
94 }
95
96 bool canSetIndex(unsigned i) { return i < m_vectorLength; }
97 void setIndex(unsigned i, JSValue v)
98 {
99 ASSERT(canSetIndex(i));
100
101 JSValue& x = m_vector[i];
102 if (!x) {
103 ArrayStorage *storage = arrayStorage();
104 ++storage->m_numValuesInVector;
105 if (i >= storage->m_length)
106 storage->m_length = i + 1;
107 }
108 x = v;
109 }
110
111 void uncheckedSetIndex(unsigned i, JSValue v)
112 {
113 ASSERT(canSetIndex(i));
114 ArrayStorage *storage = arrayStorage();
115#if CHECK_ARRAY_CONSISTENCY
116 ASSERT(storage->m_inCompactInitialization);
117#endif
118 storage->m_vector[i] = v;
119 }
120
121 void fillArgList(ExecState*, MarkedArgumentBuffer&);
122 void copyToRegisters(ExecState*, Register*, uint32_t);
123
124 static PassRefPtr<Structure> createStructure(JSValue prototype)
125 {
126 return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
127 }
128
129 inline void markChildrenDirect(MarkStack& markStack);
130
131 protected:
132 static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
133 virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
134 virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
135 virtual bool deleteProperty(ExecState*, unsigned propertyName);
136 virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
137 virtual void markChildren(MarkStack&);
138
139 void* subclassData() const;
140 void setSubclassData(void*);
141
142 inline ArrayStorage *arrayStorage() const
143 {
144 return reinterpret_cast<ArrayStorage*>(reinterpret_cast<char*>(m_vector) - (sizeof(ArrayStorage) - sizeof(JSValue)));
145 }
146
147 inline void setArrayStorage(ArrayStorage *storage)
148 {
149 m_vector = &storage->m_vector[0];
150 }
151
152 private:
153 virtual const ClassInfo* classInfo() const { return &info; }
154
155 bool getOwnPropertySlotSlowCase(ExecState*, unsigned propertyName, PropertySlot&);
156 void putSlowCase(ExecState*, unsigned propertyName, JSValue);
157
158 unsigned getNewVectorLength(unsigned desiredLength);
159 bool increaseVectorLength(unsigned newLength);
160 bool increaseVectorPrefixLength(unsigned newLength);
161
162 unsigned compactForSorting();
163
164 enum ConsistencyCheckType { NormalConsistencyCheck, DestructorConsistencyCheck, SortConsistencyCheck };
165 void checkConsistency(ConsistencyCheckType = NormalConsistencyCheck);
166
167 unsigned m_vectorLength; // The valid length of m_vector
168 int m_indexBias; // The number of JSValue sized blocks before ArrayStorage.
169 JSValue* m_vector; // Copy of ArrayStorage.m_vector. Used for quick vector access and to materialize ArrayStorage ptr.
170 };
171
172 JSArray* asArray(JSValue);
173
174 inline JSArray* asArray(JSCell* cell)
175 {
176 ASSERT(cell->inherits(&JSArray::info));
177 return static_cast<JSArray*>(cell);
178 }
179
180 inline JSArray* asArray(JSValue value)
181 {
182 return asArray(value.asCell());
183 }
184
185 inline bool isJSArray(JSGlobalData* globalData, JSValue v)
186 {
187 return v.isCell() && v.asCell()->vptr() == globalData->jsArrayVPtr;
188 }
189 inline bool isJSArray(JSGlobalData* globalData, JSCell* cell) { return cell->vptr() == globalData->jsArrayVPtr; }
190
191 inline void JSArray::markChildrenDirect(MarkStack& markStack)
192 {
193 JSObject::markChildrenDirect(markStack);
194
195 ArrayStorage* storage = arrayStorage();
196
197 unsigned usedVectorLength = std::min(storage->m_length, m_vectorLength);
198 markStack.appendValues(storage->m_vector, usedVectorLength, MayContainNullValues);
199
200 if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
201 SparseArrayValueMap::iterator end = map->end();
202 for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
203 markStack.append(it->second);
204 }
205 }
206
207 inline void MarkStack::markChildren(JSCell* cell)
208 {
209 ASSERT(Heap::isCellMarked(cell));
210 if (!cell->structure()->typeInfo().overridesMarkChildren()) {
211#ifdef NDEBUG
212 asObject(cell)->markChildrenDirect(*this);
213#else
214 ASSERT(!m_isCheckingForDefaultMarkViolation);
215 m_isCheckingForDefaultMarkViolation = true;
216 cell->markChildren(*this);
217 ASSERT(m_isCheckingForDefaultMarkViolation);
218 m_isCheckingForDefaultMarkViolation = false;
219#endif
220 return;
221 }
222 if (cell->vptr() == m_jsArrayVPtr) {
223 asArray(cell)->markChildrenDirect(*this);
224 return;
225 }
226 cell->markChildren(*this);
227 }
228
229 inline void MarkStack::drain()
230 {
231 while (!m_markSets.isEmpty() || !m_values.isEmpty()) {
232 while (!m_markSets.isEmpty() && m_values.size() < 50) {
233 ASSERT(!m_markSets.isEmpty());
234 MarkSet& current = m_markSets.last();
235 ASSERT(current.m_values);
236 JSValue* end = current.m_end;
237 ASSERT(current.m_values);
238 ASSERT(current.m_values != end);
239 findNextUnmarkedNullValue:
240 ASSERT(current.m_values != end);
241 JSValue value = *current.m_values;
242 current.m_values++;
243
244 JSCell* cell;
245 if (!value || !value.isCell() || Heap::isCellMarked(cell = value.asCell())) {
246 if (current.m_values == end) {
247 m_markSets.removeLast();
248 continue;
249 }
250 goto findNextUnmarkedNullValue;
251 }
252
253 Heap::markCell(cell);
254 if (cell->structure()->typeInfo().type() < CompoundType) {
255 if (current.m_values == end) {
256 m_markSets.removeLast();
257 continue;
258 }
259 goto findNextUnmarkedNullValue;
260 }
261
262 if (current.m_values == end)
263 m_markSets.removeLast();
264
265 markChildren(cell);
266 }
267 while (!m_values.isEmpty())
268 markChildren(m_values.removeLast());
269 }
270 }
271
272} // namespace JSC
273
274#endif // JSArray_h
Note: See TracBrowser for help on using the repository browser.