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

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

Fixed a crash seen on the GTK 64bit buildbot.

Reviewed by Oliver Hunt.

When JSArray is allocated for the vptr stealing hack, it's not allocated
in the heap, so the JSArray constructor can't safely call Heap::heap().

Since this was subtle enough to confuse smart people, I've changed JSArray
to have an explicit vptr stealing constructor.

(JSC::JSArray::JSArray):

  • runtime/JSArray.h:

(JSC::JSArray::):

  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::storeVPtrs):

  • Property svn:eol-style set to native
File size: 10.6 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 void* m_allocBase; // Pointer to base address returned by malloc(). Keeping this pointer does eliminate false positives from the leak detector.
43 size_t reportedMapCapacity;
44#if CHECK_ARRAY_CONSISTENCY
45 bool m_inCompactInitialization;
46#endif
47 JSValue m_vector[1];
48 };
49
50 // The CreateCompact creation mode is used for fast construction of arrays
51 // whose size and contents are known at time of creation.
52 //
53 // There are two obligations when using this mode:
54 //
55 // - uncheckedSetIndex() must be used when initializing the array.
56 // - setLength() must be called after initialization.
57
58 enum ArrayCreationMode { CreateCompact, CreateInitialized };
59
60 class JSArray : public JSObject {
61 friend class JIT;
62 friend class Walker;
63
64 public:
65 enum VPtrStealingHackType { VPtrStealingHack };
66 JSArray(VPtrStealingHackType);
67
68 explicit JSArray(NonNullPassRefPtr<Structure>);
69 JSArray(NonNullPassRefPtr<Structure>, unsigned initialLength, ArrayCreationMode);
70 JSArray(NonNullPassRefPtr<Structure>, const ArgList& initialValues);
71 virtual ~JSArray();
72
73 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
74 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
75 virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
76 virtual void put(ExecState*, unsigned propertyName, JSValue); // FIXME: Make protected and add setItem.
77
78 static JS_EXPORTDATA const ClassInfo info;
79
80 unsigned length() const { return arrayStorage()->m_length; }
81 void setLength(unsigned); // OK to use on new arrays, but not if it might be a RegExpMatchArray.
82
83 void sort(ExecState*);
84 void sort(ExecState*, JSValue compareFunction, CallType, const CallData&);
85 void sortNumeric(ExecState*, JSValue compareFunction, CallType, const CallData&);
86
87 void push(ExecState*, JSValue);
88 JSValue pop();
89
90 void shiftCount(ExecState*, int count);
91 void unshiftCount(ExecState*, int count);
92
93 bool canGetIndex(unsigned i) { return i < m_vectorLength && m_vector[i]; }
94 JSValue getIndex(unsigned i)
95 {
96 ASSERT(canGetIndex(i));
97 return m_vector[i];
98 }
99
100 bool canSetIndex(unsigned i) { return i < m_vectorLength; }
101 void setIndex(unsigned i, JSValue v)
102 {
103 ASSERT(canSetIndex(i));
104
105 JSValue& x = m_vector[i];
106 if (!x) {
107 ArrayStorage *storage = arrayStorage();
108 ++storage->m_numValuesInVector;
109 if (i >= storage->m_length)
110 storage->m_length = i + 1;
111 }
112 x = v;
113 }
114
115 void uncheckedSetIndex(unsigned i, JSValue v)
116 {
117 ASSERT(canSetIndex(i));
118 ArrayStorage *storage = arrayStorage();
119#if CHECK_ARRAY_CONSISTENCY
120 ASSERT(storage->m_inCompactInitialization);
121#endif
122 storage->m_vector[i] = v;
123 }
124
125 void fillArgList(ExecState*, MarkedArgumentBuffer&);
126 void copyToRegisters(ExecState*, Register*, uint32_t);
127
128 static PassRefPtr<Structure> createStructure(JSValue prototype)
129 {
130 return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
131 }
132
133 inline void markChildrenDirect(MarkStack& markStack);
134
135 protected:
136 static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
137 virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
138 virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
139 virtual bool deleteProperty(ExecState*, unsigned propertyName);
140 virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
141 virtual void markChildren(MarkStack&);
142
143 void* subclassData() const;
144 void setSubclassData(void*);
145
146 inline ArrayStorage *arrayStorage() const
147 {
148 return reinterpret_cast<ArrayStorage*>(reinterpret_cast<char*>(m_vector) - (sizeof(ArrayStorage) - sizeof(JSValue)));
149 }
150
151 inline void setArrayStorage(ArrayStorage *storage)
152 {
153 m_vector = &storage->m_vector[0];
154 }
155
156 private:
157 virtual const ClassInfo* classInfo() const { return &info; }
158
159 bool getOwnPropertySlotSlowCase(ExecState*, unsigned propertyName, PropertySlot&);
160 void putSlowCase(ExecState*, unsigned propertyName, JSValue);
161
162 unsigned getNewVectorLength(unsigned desiredLength);
163 bool increaseVectorLength(unsigned newLength);
164 bool increaseVectorPrefixLength(unsigned newLength);
165
166 unsigned compactForSorting();
167
168 enum ConsistencyCheckType { NormalConsistencyCheck, DestructorConsistencyCheck, SortConsistencyCheck };
169 void checkConsistency(ConsistencyCheckType = NormalConsistencyCheck);
170
171 unsigned m_vectorLength; // The valid length of m_vector
172 int m_indexBias; // The number of JSValue sized blocks before ArrayStorage.
173 JSValue* m_vector; // Copy of ArrayStorage.m_vector. Used for quick vector access and to materialize ArrayStorage ptr.
174 };
175
176 JSArray* asArray(JSValue);
177
178 inline JSArray* asArray(JSCell* cell)
179 {
180 ASSERT(cell->inherits(&JSArray::info));
181 return static_cast<JSArray*>(cell);
182 }
183
184 inline JSArray* asArray(JSValue value)
185 {
186 return asArray(value.asCell());
187 }
188
189 inline bool isJSArray(JSGlobalData* globalData, JSValue v)
190 {
191 return v.isCell() && v.asCell()->vptr() == globalData->jsArrayVPtr;
192 }
193 inline bool isJSArray(JSGlobalData* globalData, JSCell* cell) { return cell->vptr() == globalData->jsArrayVPtr; }
194
195 inline void JSArray::markChildrenDirect(MarkStack& markStack)
196 {
197 JSObject::markChildrenDirect(markStack);
198
199 ArrayStorage* storage = arrayStorage();
200
201 unsigned usedVectorLength = std::min(storage->m_length, m_vectorLength);
202 markStack.appendValues(storage->m_vector, usedVectorLength, MayContainNullValues);
203
204 if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
205 SparseArrayValueMap::iterator end = map->end();
206 for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
207 markStack.append(it->second);
208 }
209 }
210
211 inline void MarkStack::markChildren(JSCell* cell)
212 {
213 ASSERT(Heap::isCellMarked(cell));
214 if (!cell->structure()->typeInfo().overridesMarkChildren()) {
215#ifdef NDEBUG
216 asObject(cell)->markChildrenDirect(*this);
217#else
218 ASSERT(!m_isCheckingForDefaultMarkViolation);
219 m_isCheckingForDefaultMarkViolation = true;
220 cell->markChildren(*this);
221 ASSERT(m_isCheckingForDefaultMarkViolation);
222 m_isCheckingForDefaultMarkViolation = false;
223#endif
224 return;
225 }
226 if (cell->vptr() == m_jsArrayVPtr) {
227 asArray(cell)->markChildrenDirect(*this);
228 return;
229 }
230 cell->markChildren(*this);
231 }
232
233 inline void MarkStack::drain()
234 {
235 while (!m_markSets.isEmpty() || !m_values.isEmpty()) {
236 while (!m_markSets.isEmpty() && m_values.size() < 50) {
237 ASSERT(!m_markSets.isEmpty());
238 MarkSet& current = m_markSets.last();
239 ASSERT(current.m_values);
240 JSValue* end = current.m_end;
241 ASSERT(current.m_values);
242 ASSERT(current.m_values != end);
243 findNextUnmarkedNullValue:
244 ASSERT(current.m_values != end);
245 JSValue value = *current.m_values;
246 current.m_values++;
247
248 JSCell* cell;
249 if (!value || !value.isCell() || Heap::isCellMarked(cell = value.asCell())) {
250 if (current.m_values == end) {
251 m_markSets.removeLast();
252 continue;
253 }
254 goto findNextUnmarkedNullValue;
255 }
256
257 Heap::markCell(cell);
258 if (cell->structure()->typeInfo().type() < CompoundType) {
259 if (current.m_values == end) {
260 m_markSets.removeLast();
261 continue;
262 }
263 goto findNextUnmarkedNullValue;
264 }
265
266 if (current.m_values == end)
267 m_markSets.removeLast();
268
269 markChildren(cell);
270 }
271 while (!m_values.isEmpty())
272 markChildren(m_values.removeLast());
273 }
274 }
275
276} // namespace JSC
277
278#endif // JSArray_h
Note: See TracBrowser for help on using the repository browser.