]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/Structure.h
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / runtime / Structure.h
CommitLineData
9dae56ea 1/*
f9bf01c6 2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
9dae56ea
A
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
6fe7ccc8 29#include "ClassInfo.h"
9dae56ea 30#include "Identifier.h"
14957cd0 31#include "JSCell.h"
9dae56ea
A
32#include "JSType.h"
33#include "JSValue.h"
34#include "PropertyMapHashTable.h"
f9bf01c6
A
35#include "PropertyNameArray.h"
36#include "Protect.h"
9dae56ea 37#include "StructureTransitionTable.h"
f9bf01c6 38#include "JSTypeInfo.h"
9dae56ea 39#include "UString.h"
14957cd0
A
40#include "Weak.h"
41#include <wtf/PassOwnPtr.h>
9dae56ea
A
42#include <wtf/PassRefPtr.h>
43#include <wtf/RefCounted.h>
44
9dae56ea
A
45
46namespace JSC {
47
6fe7ccc8 48 class LLIntOffsetsExtractor;
9dae56ea
A
49 class PropertyNameArray;
50 class PropertyNameArrayData;
14957cd0 51 class StructureChain;
6fe7ccc8
A
52 class SlotVisitor;
53 class JSString;
f9bf01c6 54
14957cd0 55 class Structure : public JSCell {
9dae56ea 56 public:
f9bf01c6 57 friend class StructureTransitionTable;
6fe7ccc8
A
58
59 typedef JSCell Base;
60
61 static Structure* create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo)
9dae56ea 62 {
14957cd0
A
63 ASSERT(globalData.structureStructure);
64 ASSERT(classInfo);
6fe7ccc8
A
65 Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo);
66 structure->finishCreation(globalData);
67 return structure;
9dae56ea
A
68 }
69
6fe7ccc8
A
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:
9dae56ea
A
87 static void dumpStatistics();
88
6fe7ccc8
A
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);
14957cd0 91 static Structure* removePropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, size_t& offset);
6fe7ccc8
A
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);
14957cd0
A
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; }
6fe7ccc8
A
105 bool shouldGrowPropertyStorage() { return propertyStorageCapacity() == propertyStorageSize(); }
106 JS_EXPORT_PRIVATE size_t suggestedNewPropertyStorageSize();
14957cd0
A
107
108 Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
9dae56ea 109
6fe7ccc8 110 static void destroy(JSCell*);
9dae56ea 111
9dae56ea 112 // These should be used with caution.
6fe7ccc8 113 JS_EXPORT_PRIVATE size_t addPropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
14957cd0
A
114 size_t removePropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName);
115 void setPrototypeWithoutTransition(JSGlobalData& globalData, JSValue prototype) { m_prototype.set(globalData, this, prototype); }
ba379fdc
A
116
117 bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
118 bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
9dae56ea 119
6fe7ccc8 120 // Type accessors.
14957cd0 121 const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == &s_info); return m_typeInfo; }
6fe7ccc8 122 bool isObject() const { return typeInfo().isObject(); }
9dae56ea 123
6fe7ccc8
A
124
125 JSGlobalObject* globalObject() const { return m_globalObject.get(); }
126 void setGlobalObject(JSGlobalData& globalData, JSGlobalObject* globalObject) { m_globalObject.set(globalData, this, globalObject); }
127
14957cd0 128 JSValue storedPrototype() const { return m_prototype.get(); }
ba379fdc 129 JSValue prototypeForLookup(ExecState*) const;
9dae56ea 130 StructureChain* prototypeChain(ExecState*) const;
6fe7ccc8 131 static void visitChildren(JSCell*, SlotVisitor&);
9dae56ea 132
14957cd0 133 Structure* previousID() const { ASSERT(structure()->classInfo() == &s_info); return m_previous.get(); }
6fe7ccc8 134 bool transitivelyTransitionedFrom(Structure* structureToFind);
9dae56ea
A
135
136 void growPropertyStorageCapacity();
14957cd0 137 unsigned propertyStorageCapacity() const { ASSERT(structure()->classInfo() == &s_info); return m_propertyStorageCapacity; }
6fe7ccc8 138 unsigned propertyStorageSize() const { ASSERT(structure()->classInfo() == &s_info); return (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(m_offset + 1)); }
ba379fdc 139 bool isUsingInlineStorage() const;
9dae56ea 140
14957cd0 141 size_t get(JSGlobalData&, const Identifier& propertyName);
6fe7ccc8
A
142 size_t get(JSGlobalData&, const UString& name);
143 JS_EXPORT_PRIVATE size_t get(JSGlobalData&, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue);
14957cd0 144 size_t get(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
ba379fdc
A
145 {
146 ASSERT(!propertyName.isNull());
14957cd0
A
147 ASSERT(structure()->classInfo() == &s_info);
148 return get(globalData, propertyName.impl(), attributes, specificValue);
ba379fdc
A
149 }
150
9dae56ea 151 bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
6fe7ccc8
A
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 }
9dae56ea 163
f9bf01c6 164 bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
f9bf01c6 165
14957cd0 166 bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; }
9dae56ea 167
6fe7ccc8 168 JS_EXPORT_PRIVATE void despecifyDictionaryFunction(JSGlobalData&, const Identifier& propertyName);
f9bf01c6 169 void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
9dae56ea 170
14957cd0 171 void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
f9bf01c6 172 JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
6fe7ccc8
A
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 }
14957cd0
A
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);
6fe7ccc8
A
212 Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData);
213 structure->finishCreation(globalData, CreatingEarlyCell);
214 return structure;
14957cd0 215 }
f9bf01c6 216
14957cd0
A
217 static JS_EXPORTDATA const ClassInfo s_info;
218
ba379fdc 219 private:
6fe7ccc8
A
220 friend class LLIntOffsetsExtractor;
221
222 JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*);
14957cd0
A
223 Structure(JSGlobalData&);
224 Structure(JSGlobalData&, const Structure*);
f9bf01c6 225
14957cd0
A
226 static Structure* create(JSGlobalData& globalData, const Structure* structure)
227 {
228 ASSERT(globalData.structureStructure);
6fe7ccc8
A
229 Structure* newStructure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, structure);
230 newStructure->finishCreation(globalData);
231 return newStructure;
14957cd0 232 }
ba379fdc
A
233
234 typedef enum {
235 NoneDictionaryKind = 0,
236 CachedDictionaryKind = 1,
237 UncachedDictionaryKind = 2
238 } DictionaryKind;
14957cd0 239 static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind);
ba379fdc 240
14957cd0 241 size_t putSpecificValue(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
9dae56ea 242 size_t remove(const Identifier& propertyName);
9dae56ea 243
14957cd0 244 void createPropertyMap(unsigned keyCount = 0);
9dae56ea
A
245 void checkConsistency();
246
14957cd0
A
247 bool despecifyFunction(JSGlobalData&, const Identifier&);
248 void despecifyAllFunctions(JSGlobalData&);
ba379fdc 249
14957cd0 250 PassOwnPtr<PropertyTable> copyPropertyTable(JSGlobalData&, Structure* owner);
6fe7ccc8
A
251 PassOwnPtr<PropertyTable> copyPropertyTableForPinning(JSGlobalData&, Structure* owner);
252 JS_EXPORT_PRIVATE void materializePropertyMap(JSGlobalData&);
14957cd0 253 void materializePropertyMapIfNecessary(JSGlobalData& globalData)
9dae56ea 254 {
14957cd0
A
255 ASSERT(structure()->classInfo() == &s_info);
256 if (!m_propertyTable && m_previous)
257 materializePropertyMap(globalData);
9dae56ea 258 }
6fe7ccc8
A
259 void materializePropertyMapIfNecessaryForPinning(JSGlobalData& globalData)
260 {
261 ASSERT(structure()->classInfo() == &s_info);
262 if (!m_propertyTable)
263 materializePropertyMap(globalData);
264 }
9dae56ea 265
6fe7ccc8 266 int transitionCount() const
9dae56ea
A
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 }
4e4e5a6f 271
9dae56ea 272 bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
6fe7ccc8
A
273
274 void pin();
9dae56ea 275
6fe7ccc8 276 static const int s_maxTransitionLength = 64;
9dae56ea 277
6fe7ccc8 278 static const int noOffset = -1;
9dae56ea 279
f9bf01c6
A
280 static const unsigned maxSpecificFunctionThrashCount = 3;
281
9dae56ea 282 TypeInfo m_typeInfo;
6fe7ccc8
A
283
284 WriteBarrier<JSGlobalObject> m_globalObject;
14957cd0
A
285 WriteBarrier<Unknown> m_prototype;
286 mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
9dae56ea 287
14957cd0
A
288 WriteBarrier<Structure> m_previous;
289 RefPtr<StringImpl> m_nameInPrevious;
290 WriteBarrier<JSCell> m_specificValueInPrevious;
9dae56ea 291
14957cd0 292 const ClassInfo* m_classInfo;
9dae56ea 293
14957cd0 294 StructureTransitionTable m_transitionTable;
9dae56ea 295
14957cd0
A
296 WriteBarrier<JSPropertyNameIterator> m_enumerationCache;
297
298 OwnPtr<PropertyTable> m_propertyTable;
9dae56ea 299
f9bf01c6
A
300 uint32_t m_propertyStorageCapacity;
301
6fe7ccc8
A
302 WriteBarrier<JSString> m_objectToStringValue;
303
f9bf01c6 304 // m_offset does not account for anonymous slots
6fe7ccc8 305 int m_offset;
9dae56ea 306
ba379fdc 307 unsigned m_dictionaryKind : 2;
9dae56ea
A
308 bool m_isPinnedPropertyTable : 1;
309 bool m_hasGetterSetterProperties : 1;
6fe7ccc8 310 bool m_hasReadOnlyOrGetterSetterPropertiesExcludingProto : 1;
f9bf01c6 311 bool m_hasNonEnumerableProperties : 1;
ba379fdc 312 unsigned m_attributesInPrevious : 7;
f9bf01c6 313 unsigned m_specificFunctionThrashCount : 2;
14957cd0
A
314 unsigned m_preventExtensions : 1;
315 unsigned m_didTransition : 1;
6fe7ccc8 316 unsigned m_staticFunctionReified;
9dae56ea
A
317 };
318
14957cd0 319 inline size_t Structure::get(JSGlobalData& globalData, const Identifier& propertyName)
9dae56ea 320 {
14957cd0
A
321 ASSERT(structure()->classInfo() == &s_info);
322 materializePropertyMapIfNecessary(globalData);
9dae56ea 323 if (!m_propertyTable)
14957cd0 324 return notFound;
9dae56ea 325
14957cd0 326 PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
14957cd0
A
327 return entry ? entry->offset : notFound;
328 }
9dae56ea 329
6fe7ccc8
A
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
14957cd0
A
341 inline bool JSCell::isObject() const
342 {
6fe7ccc8 343 return m_structure->isObject();
14957cd0 344 }
9dae56ea 345
14957cd0
A
346 inline bool JSCell::isString() const
347 {
348 return m_structure->typeInfo().type() == StringType;
349 }
9dae56ea 350
6fe7ccc8 351 inline bool JSCell::isGetterSetter() const
14957cd0 352 {
6fe7ccc8 353 return m_structure->typeInfo().type() == GetterSetterType;
14957cd0 354 }
9dae56ea 355
6fe7ccc8 356 inline bool JSCell::isAPIValueWrapper() const
14957cd0 357 {
6fe7ccc8 358 return m_structure->typeInfo().type() == APIValueWrapperType;
14957cd0 359 }
9dae56ea 360
6fe7ccc8 361 inline void JSCell::setStructure(JSGlobalData& globalData, Structure* structure)
14957cd0 362 {
6fe7ccc8
A
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;
14957cd0 376 }
9dae56ea 377
14957cd0
A
378 ALWAYS_INLINE void MarkStack::internalAppend(JSCell* cell)
379 {
380 ASSERT(!m_isCheckingForDefaultMarkViolation);
6fe7ccc8
A
381#if ENABLE(GC_VALIDATION)
382 validate(cell);
383#endif
384 m_visitCount++;
385 if (Heap::testAndSetMarked(cell) || !cell->structure())
14957cd0 386 return;
6fe7ccc8
A
387
388 // Should never attempt to mark something that is zapped.
389 ASSERT(!cell->isZapped());
390
391 m_stack.append(cell);
14957cd0 392 }
9dae56ea 393
14957cd0
A
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);
9dae56ea
A
400 }
401
6fe7ccc8
A
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
9dae56ea
A
430} // namespace JSC
431
432#endif // Structure_h