]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/Structure.h
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / runtime / Structure.h
1 /*
2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #ifndef Structure_h
27 #define Structure_h
28
29 #include "ClassInfo.h"
30 #include "Identifier.h"
31 #include "JSCell.h"
32 #include "JSType.h"
33 #include "JSValue.h"
34 #include "PropertyMapHashTable.h"
35 #include "PropertyNameArray.h"
36 #include "Protect.h"
37 #include "StructureTransitionTable.h"
38 #include "JSTypeInfo.h"
39 #include "UString.h"
40 #include "Weak.h"
41 #include <wtf/PassOwnPtr.h>
42 #include <wtf/PassRefPtr.h>
43 #include <wtf/RefCounted.h>
44
45
46 namespace JSC {
47
48 class LLIntOffsetsExtractor;
49 class PropertyNameArray;
50 class PropertyNameArrayData;
51 class StructureChain;
52 class SlotVisitor;
53 class JSString;
54
55 class Structure : public JSCell {
56 public:
57 friend class StructureTransitionTable;
58
59 typedef JSCell Base;
60
61 static Structure* create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo)
62 {
63 ASSERT(globalData.structureStructure);
64 ASSERT(classInfo);
65 Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo);
66 structure->finishCreation(globalData);
67 return structure;
68 }
69
70 protected:
71 void finishCreation(JSGlobalData& globalData)
72 {
73 Base::finishCreation(globalData);
74 ASSERT(m_prototype);
75 ASSERT(m_prototype.isObject() || m_prototype.isNull());
76 }
77
78 void finishCreation(JSGlobalData& globalData, CreatingEarlyCellTag)
79 {
80 Base::finishCreation(globalData, this, CreatingEarlyCell);
81 ASSERT(m_prototype);
82 ASSERT(m_prototype.isNull());
83 ASSERT(!globalData.structureStructure);
84 }
85
86 public:
87 static void dumpStatistics();
88
89 JS_EXPORT_PRIVATE static Structure* addPropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
90 JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
91 static Structure* removePropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, size_t& offset);
92 JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(JSGlobalData&, Structure*, JSValue prototype);
93 JS_EXPORT_PRIVATE static Structure* despecifyFunctionTransition(JSGlobalData&, Structure*, const Identifier&);
94 static Structure* attributeChangeTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes);
95 static Structure* toCacheableDictionaryTransition(JSGlobalData&, Structure*);
96 static Structure* toUncacheableDictionaryTransition(JSGlobalData&, Structure*);
97 static Structure* sealTransition(JSGlobalData&, Structure*);
98 static Structure* freezeTransition(JSGlobalData&, Structure*);
99 static Structure* preventExtensionsTransition(JSGlobalData&, Structure*);
100
101 bool isSealed(JSGlobalData&);
102 bool isFrozen(JSGlobalData&);
103 bool isExtensible() const { return !m_preventExtensions; }
104 bool didTransition() const { return m_didTransition; }
105 bool shouldGrowPropertyStorage() { return propertyStorageCapacity() == propertyStorageSize(); }
106 JS_EXPORT_PRIVATE size_t suggestedNewPropertyStorageSize();
107
108 Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
109
110 static void destroy(JSCell*);
111
112 // These should be used with caution.
113 JS_EXPORT_PRIVATE size_t addPropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
114 size_t removePropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName);
115 void setPrototypeWithoutTransition(JSGlobalData& globalData, JSValue prototype) { m_prototype.set(globalData, this, prototype); }
116
117 bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
118 bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
119
120 // Type accessors.
121 const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == &s_info); return m_typeInfo; }
122 bool isObject() const { return typeInfo().isObject(); }
123
124
125 JSGlobalObject* globalObject() const { return m_globalObject.get(); }
126 void setGlobalObject(JSGlobalData& globalData, JSGlobalObject* globalObject) { m_globalObject.set(globalData, this, globalObject); }
127
128 JSValue storedPrototype() const { return m_prototype.get(); }
129 JSValue prototypeForLookup(ExecState*) const;
130 StructureChain* prototypeChain(ExecState*) const;
131 static void visitChildren(JSCell*, SlotVisitor&);
132
133 Structure* previousID() const { ASSERT(structure()->classInfo() == &s_info); return m_previous.get(); }
134 bool transitivelyTransitionedFrom(Structure* structureToFind);
135
136 void growPropertyStorageCapacity();
137 unsigned propertyStorageCapacity() const { ASSERT(structure()->classInfo() == &s_info); return m_propertyStorageCapacity; }
138 unsigned propertyStorageSize() const { ASSERT(structure()->classInfo() == &s_info); return (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(m_offset + 1)); }
139 bool isUsingInlineStorage() const;
140
141 size_t get(JSGlobalData&, const Identifier& propertyName);
142 size_t get(JSGlobalData&, const UString& name);
143 JS_EXPORT_PRIVATE size_t get(JSGlobalData&, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue);
144 size_t get(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
145 {
146 ASSERT(!propertyName.isNull());
147 ASSERT(structure()->classInfo() == &s_info);
148 return get(globalData, propertyName.impl(), attributes, specificValue);
149 }
150
151 bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
152 bool hasReadOnlyOrGetterSetterPropertiesExcludingProto() const { return m_hasReadOnlyOrGetterSetterPropertiesExcludingProto; }
153 void setHasGetterSetterProperties(bool is__proto__)
154 {
155 m_hasGetterSetterProperties = true;
156 if (!is__proto__)
157 m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
158 }
159 void setContainsReadOnlyProperties()
160 {
161 m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
162 }
163
164 bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
165
166 bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; }
167
168 JS_EXPORT_PRIVATE void despecifyDictionaryFunction(JSGlobalData&, const Identifier& propertyName);
169 void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
170
171 void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
172 JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
173 void getPropertyNamesFromStructure(JSGlobalData&, PropertyNameArray&, EnumerationMode);
174
175 JSString* objectToStringValue() { return m_objectToStringValue.get(); }
176
177 void setObjectToStringValue(JSGlobalData& globalData, const JSCell* owner, JSString* value)
178 {
179 m_objectToStringValue.set(globalData, owner, value);
180 }
181
182 bool staticFunctionsReified()
183 {
184 return m_staticFunctionReified;
185 }
186
187 void setStaticFunctionsReified()
188 {
189 m_staticFunctionReified = true;
190 }
191
192 const ClassInfo* classInfo() const { return m_classInfo; }
193
194 static ptrdiff_t prototypeOffset()
195 {
196 return OBJECT_OFFSETOF(Structure, m_prototype);
197 }
198
199 static ptrdiff_t typeInfoFlagsOffset()
200 {
201 return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset();
202 }
203
204 static ptrdiff_t typeInfoTypeOffset()
205 {
206 return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
207 }
208
209 static Structure* createStructure(JSGlobalData& globalData)
210 {
211 ASSERT(!globalData.structureStructure);
212 Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData);
213 structure->finishCreation(globalData, CreatingEarlyCell);
214 return structure;
215 }
216
217 static JS_EXPORTDATA const ClassInfo s_info;
218
219 private:
220 friend class LLIntOffsetsExtractor;
221
222 JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*);
223 Structure(JSGlobalData&);
224 Structure(JSGlobalData&, const Structure*);
225
226 static Structure* create(JSGlobalData& globalData, const Structure* structure)
227 {
228 ASSERT(globalData.structureStructure);
229 Structure* newStructure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, structure);
230 newStructure->finishCreation(globalData);
231 return newStructure;
232 }
233
234 typedef enum {
235 NoneDictionaryKind = 0,
236 CachedDictionaryKind = 1,
237 UncachedDictionaryKind = 2
238 } DictionaryKind;
239 static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind);
240
241 size_t putSpecificValue(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
242 size_t remove(const Identifier& propertyName);
243
244 void createPropertyMap(unsigned keyCount = 0);
245 void checkConsistency();
246
247 bool despecifyFunction(JSGlobalData&, const Identifier&);
248 void despecifyAllFunctions(JSGlobalData&);
249
250 PassOwnPtr<PropertyTable> copyPropertyTable(JSGlobalData&, Structure* owner);
251 PassOwnPtr<PropertyTable> copyPropertyTableForPinning(JSGlobalData&, Structure* owner);
252 JS_EXPORT_PRIVATE void materializePropertyMap(JSGlobalData&);
253 void materializePropertyMapIfNecessary(JSGlobalData& globalData)
254 {
255 ASSERT(structure()->classInfo() == &s_info);
256 if (!m_propertyTable && m_previous)
257 materializePropertyMap(globalData);
258 }
259 void materializePropertyMapIfNecessaryForPinning(JSGlobalData& globalData)
260 {
261 ASSERT(structure()->classInfo() == &s_info);
262 if (!m_propertyTable)
263 materializePropertyMap(globalData);
264 }
265
266 int transitionCount() const
267 {
268 // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
269 return m_offset == noOffset ? 0 : m_offset + 1;
270 }
271
272 bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
273
274 void pin();
275
276 static const int s_maxTransitionLength = 64;
277
278 static const int noOffset = -1;
279
280 static const unsigned maxSpecificFunctionThrashCount = 3;
281
282 TypeInfo m_typeInfo;
283
284 WriteBarrier<JSGlobalObject> m_globalObject;
285 WriteBarrier<Unknown> m_prototype;
286 mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
287
288 WriteBarrier<Structure> m_previous;
289 RefPtr<StringImpl> m_nameInPrevious;
290 WriteBarrier<JSCell> m_specificValueInPrevious;
291
292 const ClassInfo* m_classInfo;
293
294 StructureTransitionTable m_transitionTable;
295
296 WriteBarrier<JSPropertyNameIterator> m_enumerationCache;
297
298 OwnPtr<PropertyTable> m_propertyTable;
299
300 uint32_t m_propertyStorageCapacity;
301
302 WriteBarrier<JSString> m_objectToStringValue;
303
304 // m_offset does not account for anonymous slots
305 int m_offset;
306
307 unsigned m_dictionaryKind : 2;
308 bool m_isPinnedPropertyTable : 1;
309 bool m_hasGetterSetterProperties : 1;
310 bool m_hasReadOnlyOrGetterSetterPropertiesExcludingProto : 1;
311 bool m_hasNonEnumerableProperties : 1;
312 unsigned m_attributesInPrevious : 7;
313 unsigned m_specificFunctionThrashCount : 2;
314 unsigned m_preventExtensions : 1;
315 unsigned m_didTransition : 1;
316 unsigned m_staticFunctionReified;
317 };
318
319 inline size_t Structure::get(JSGlobalData& globalData, const Identifier& propertyName)
320 {
321 ASSERT(structure()->classInfo() == &s_info);
322 materializePropertyMapIfNecessary(globalData);
323 if (!m_propertyTable)
324 return notFound;
325
326 PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
327 return entry ? entry->offset : notFound;
328 }
329
330 inline size_t Structure::get(JSGlobalData& globalData, const UString& name)
331 {
332 ASSERT(structure()->classInfo() == &s_info);
333 materializePropertyMapIfNecessary(globalData);
334 if (!m_propertyTable)
335 return notFound;
336
337 PropertyMapEntry* entry = m_propertyTable->findWithString(name.impl()).first;
338 return entry ? entry->offset : notFound;
339 }
340
341 inline bool JSCell::isObject() const
342 {
343 return m_structure->isObject();
344 }
345
346 inline bool JSCell::isString() const
347 {
348 return m_structure->typeInfo().type() == StringType;
349 }
350
351 inline bool JSCell::isGetterSetter() const
352 {
353 return m_structure->typeInfo().type() == GetterSetterType;
354 }
355
356 inline bool JSCell::isAPIValueWrapper() const
357 {
358 return m_structure->typeInfo().type() == APIValueWrapperType;
359 }
360
361 inline void JSCell::setStructure(JSGlobalData& globalData, Structure* structure)
362 {
363 ASSERT(structure->typeInfo().overridesVisitChildren() == this->structure()->typeInfo().overridesVisitChildren());
364 ASSERT(structure->classInfo() == m_structure->classInfo());
365 m_structure.set(globalData, this, structure);
366 }
367
368 inline const ClassInfo* JSCell::validatedClassInfo() const
369 {
370 #if ENABLE(GC_VALIDATION)
371 ASSERT(m_structure.unvalidatedGet()->classInfo() == m_classInfo);
372 #else
373 ASSERT(m_structure->classInfo() == m_classInfo);
374 #endif
375 return m_classInfo;
376 }
377
378 ALWAYS_INLINE void MarkStack::internalAppend(JSCell* cell)
379 {
380 ASSERT(!m_isCheckingForDefaultMarkViolation);
381 #if ENABLE(GC_VALIDATION)
382 validate(cell);
383 #endif
384 m_visitCount++;
385 if (Heap::testAndSetMarked(cell) || !cell->structure())
386 return;
387
388 // Should never attempt to mark something that is zapped.
389 ASSERT(!cell->isZapped());
390
391 m_stack.append(cell);
392 }
393
394 inline StructureTransitionTable::Hash::Key StructureTransitionTable::keyForWeakGCMapFinalizer(void*, Structure* structure)
395 {
396 // Newer versions of the STL have an std::make_pair function that takes rvalue references.
397 // When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue.
398 // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details.
399 return Hash::Key(structure->m_nameInPrevious.get(), +structure->m_attributesInPrevious);
400 }
401
402 inline bool Structure::transitivelyTransitionedFrom(Structure* structureToFind)
403 {
404 for (Structure* current = this; current; current = current->previousID()) {
405 if (current == structureToFind)
406 return true;
407 }
408 return false;
409 }
410
411 inline JSCell::JSCell(JSGlobalData& globalData, Structure* structure)
412 : m_classInfo(structure->classInfo())
413 , m_structure(globalData, this, structure)
414 {
415 }
416
417 inline void JSCell::finishCreation(JSGlobalData& globalData, Structure* structure, CreatingEarlyCellTag)
418 {
419 #if ENABLE(GC_VALIDATION)
420 ASSERT(globalData.isInitializingObject());
421 globalData.setInitializingObjectClass(0);
422 if (structure)
423 #endif
424 m_structure.setEarlyValue(globalData, this, structure);
425 m_classInfo = structure->classInfo();
426 // Very first set of allocations won't have a real structure.
427 ASSERT(m_structure || !globalData.structureStructure);
428 }
429
430 } // namespace JSC
431
432 #endif // Structure_h