165f6ba13e2b90d9ecbdbf964b9f5fa50e709961
[WebKit-https.git] / Source / JavaScriptCore / runtime / Structure.h
1 /*
2  * Copyright (C) 2008, 2009, 2012, 2013, 2014 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 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 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 "ConcurrentJITLock.h"
31 #include "IndexingType.h"
32 #include "JSCJSValue.h"
33 #include "JSCell.h"
34 #include "JSType.h"
35 #include "PropertyName.h"
36 #include "PropertyNameArray.h"
37 #include "PropertyOffset.h"
38 #include "Protect.h"
39 #include "PutPropertySlot.h"
40 #include "StructureIDBlob.h"
41 #include "StructureRareData.h"
42 #include "StructureTransitionTable.h"
43 #include "JSTypeInfo.h"
44 #include "Watchpoint.h"
45 #include "Weak.h"
46 #include "WriteBarrierInlines.h"
47 #include <wtf/CompilationThread.h>
48 #include <wtf/PassRefPtr.h>
49 #include <wtf/PrintStream.h>
50 #include <wtf/RefCounted.h>
51 #include <wtf/text/AtomicStringImpl.h>
52
53 namespace JSC {
54
55 class DeferGC;
56 class LLIntOffsetsExtractor;
57 class PropertyNameArray;
58 class PropertyNameArrayData;
59 class PropertyTable;
60 class StructureChain;
61 class StructureShape;
62 class SlotVisitor;
63 class JSString;
64 struct DumpContext;
65
66 // The out-of-line property storage capacity to use when first allocating out-of-line
67 // storage. Note that all objects start out without having any out-of-line storage;
68 // this comes into play only on the first property store that exhausts inline storage.
69 static const unsigned initialOutOfLineCapacity = 4;
70
71 // The factor by which to grow out-of-line storage when it is exhausted, after the
72 // initial allocation.
73 static const unsigned outOfLineGrowthFactor = 2;
74
75 struct PropertyMapEntry {
76     AtomicStringImpl* key;
77     PropertyOffset offset;
78     unsigned attributes;
79
80     PropertyMapEntry()
81         : key(nullptr)
82         , offset(invalidOffset)
83         , attributes(0)
84     {
85     }
86     
87     PropertyMapEntry(AtomicStringImpl* key, PropertyOffset offset, unsigned attributes)
88         : key(key)
89         , offset(offset)
90         , attributes(attributes)
91     {
92     }
93 };
94
95 class Structure final : public JSCell {
96 public:
97     friend class StructureTransitionTable;
98
99     typedef JSCell Base;
100     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
101     
102     static Structure* create(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0);
103
104     ~Structure();
105
106 protected:
107     void finishCreation(VM& vm)
108     {
109         Base::finishCreation(vm);
110         ASSERT(m_prototype);
111         ASSERT(m_prototype.isObject() || m_prototype.isNull());
112     }
113
114     void finishCreation(VM& vm, CreatingEarlyCellTag)
115     {
116         Base::finishCreation(vm, this, CreatingEarlyCell);
117         ASSERT(m_prototype);
118         ASSERT(m_prototype.isNull());
119         ASSERT(!vm.structureStructure);
120     }
121
122 public:
123     StructureID id() const { return m_blob.structureID(); }
124     int32_t objectInitializationBlob() const { return m_blob.blobExcludingStructureID(); }
125     int64_t idBlob() const { return m_blob.blob(); }
126
127     bool isProxy() const
128     {
129         JSType type = m_blob.type();
130         return type == ImpureProxyType || type == PureForwardingProxyType;
131     }
132
133     static void dumpStatistics();
134
135     JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext);
136     static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, AtomicStringImpl* uid, unsigned attributes, PropertyOffset&);
137     JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, PropertyOffset&);
138     static Structure* removePropertyTransition(VM&, Structure*, PropertyName, PropertyOffset&);
139     JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(VM&, Structure*, JSValue prototype);
140     JS_EXPORT_PRIVATE static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes);
141     JS_EXPORT_PRIVATE static Structure* toCacheableDictionaryTransition(VM&, Structure*);
142     static Structure* toUncacheableDictionaryTransition(VM&, Structure*);
143     JS_EXPORT_PRIVATE static Structure* sealTransition(VM&, Structure*);
144     JS_EXPORT_PRIVATE static Structure* freezeTransition(VM&, Structure*);
145     static Structure* preventExtensionsTransition(VM&, Structure*);
146     JS_EXPORT_PRIVATE static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition);
147
148     JS_EXPORT_PRIVATE bool isSealed(VM&);
149     JS_EXPORT_PRIVATE bool isFrozen(VM&);
150     bool isExtensible() const { return !preventExtensions(); }
151     bool putWillGrowOutOfLineStorage();
152     size_t suggestedNewOutOfLineStorageCapacity(); 
153
154     JS_EXPORT_PRIVATE Structure* flattenDictionaryStructure(VM&, JSObject*);
155
156     static const bool needsDestruction = true;
157     static void destroy(JSCell*);
158
159     // These should be used with caution.  
160     JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(VM&, PropertyName, unsigned attributes);
161     PropertyOffset removePropertyWithoutTransition(VM&, PropertyName);
162     void setPrototypeWithoutTransition(VM& vm, JSValue prototype) { m_prototype.set(vm, this, prototype); }
163         
164     bool isDictionary() const { return dictionaryKind() != NoneDictionaryKind; }
165     bool isUncacheableDictionary() const { return dictionaryKind() == UncachedDictionaryKind; }
166   
167     bool propertyAccessesAreCacheable() { return dictionaryKind() != UncachedDictionaryKind && !typeInfo().prohibitsPropertyCaching(); }
168
169     // We use SlowPath in GetByIdStatus for structures that may get new impure properties later to prevent
170     // DFG from inlining property accesses since structures don't transition when a new impure property appears.
171     bool takesSlowPathInDFGForImpureProperty()
172     {
173         return typeInfo().hasImpureGetOwnPropertySlot();
174     }
175
176     // Type accessors.
177     TypeInfo typeInfo() const { ASSERT(structure()->classInfo() == info()); return m_blob.typeInfo(m_outOfLineTypeFlags); }
178     bool isObject() const { return typeInfo().isObject(); }
179
180     IndexingType indexingType() const { return m_blob.indexingType() & AllArrayTypes; }
181     IndexingType indexingTypeIncludingHistory() const { return m_blob.indexingType(); }
182         
183     bool mayInterceptIndexedAccesses() const
184     {
185         return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors);
186     }
187         
188     bool anyObjectInChainMayInterceptIndexedAccesses() const;
189     bool holesMustForwardToPrototype(VM&) const;
190         
191     bool needsSlowPutIndexing() const;
192     NonPropertyTransition suggestedArrayStorageTransition() const;
193         
194     JSGlobalObject* globalObject() const { return m_globalObject.get(); }
195     void setGlobalObject(VM& vm, JSGlobalObject* globalObject) { m_globalObject.set(vm, this, globalObject); }
196         
197     JSValue storedPrototype() const { return m_prototype.get(); }
198     JSObject* storedPrototypeObject() const;
199     Structure* storedPrototypeStructure() const;
200     JSValue prototypeForLookup(ExecState*) const;
201     JSValue prototypeForLookup(JSGlobalObject*) const;
202     JSValue prototypeForLookup(CodeBlock*) const;
203     StructureChain* prototypeChain(VM&, JSGlobalObject*) const;
204     StructureChain* prototypeChain(ExecState*) const;
205     static void visitChildren(JSCell*, SlotVisitor&);
206         
207     // Will just the prototype chain intercept this property access?
208     bool prototypeChainMayInterceptStoreTo(VM&, PropertyName);
209         
210     Structure* previousID() const
211     {
212         ASSERT(structure()->classInfo() == info());
213         if (hasRareData())
214             return rareData()->previousID();
215         return previous();
216     }
217     bool transitivelyTransitionedFrom(Structure* structureToFind);
218
219     unsigned outOfLineCapacity() const
220     {
221         ASSERT(checkOffsetConsistency());
222             
223         unsigned outOfLineSize = this->outOfLineSize();
224
225         if (!outOfLineSize)
226             return 0;
227
228         if (outOfLineSize <= initialOutOfLineCapacity)
229             return initialOutOfLineCapacity;
230
231         ASSERT(outOfLineSize > initialOutOfLineCapacity);
232         COMPILE_ASSERT(outOfLineGrowthFactor == 2, outOfLineGrowthFactor_is_two);
233         return WTF::roundUpToPowerOfTwo(outOfLineSize);
234     }
235     unsigned outOfLineSize() const
236     {
237         ASSERT(checkOffsetConsistency());
238         ASSERT(structure()->classInfo() == info());
239             
240         return numberOfOutOfLineSlotsForLastOffset(m_offset);
241     }
242     bool hasInlineStorage() const
243     {
244         return !!m_inlineCapacity;
245     }
246     unsigned inlineCapacity() const
247     {
248         return m_inlineCapacity;
249     }
250     unsigned inlineSize() const
251     {
252         return std::min<unsigned>(m_offset + 1, m_inlineCapacity);
253     }
254     unsigned totalStorageSize() const
255     {
256         return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
257     }
258     unsigned totalStorageCapacity() const
259     {
260         ASSERT(structure()->classInfo() == info());
261         return outOfLineCapacity() + inlineCapacity();
262     }
263
264     bool isValidOffset(PropertyOffset offset) const
265     {
266         return JSC::isValidOffset(offset)
267             && offset <= m_offset
268             && (offset < m_inlineCapacity || offset >= firstOutOfLineOffset);
269     }
270     
271     bool couldHaveIndexingHeader() const
272     {
273         return hasIndexedProperties(indexingType())
274             || isTypedView(m_classInfo->typedArrayStorageType);
275     }
276     
277     bool hasIndexingHeader(const JSCell*) const;
278     
279     bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject);
280
281     PropertyOffset get(VM&, PropertyName);
282     PropertyOffset get(VM&, PropertyName, unsigned& attributes);
283
284     // This is a somewhat internalish method. It will call your functor while possibly holding the
285     // Structure's lock. There is no guarantee whether the lock is held or not in any particular
286     // call. So, you have to assume the worst. Also, the functor returns true if it wishes for you
287     // to continue or false if it's done.
288     template<typename Functor>
289     void forEachPropertyConcurrently(const Functor&);
290     
291     PropertyOffset getConcurrently(AtomicStringImpl* uid);
292     PropertyOffset getConcurrently(AtomicStringImpl* uid, unsigned& attributes);
293     
294     Vector<PropertyMapEntry> getPropertiesConcurrently();
295     
296     void setHasGetterSetterPropertiesWithProtoCheck(bool is__proto__)
297     {
298         setHasGetterSetterProperties(true);
299         if (!is__proto__)
300             setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
301     }
302     
303     void setContainsReadOnlyProperties() { setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true); }
304     
305     void setHasCustomGetterSetterPropertiesWithProtoCheck(bool is__proto__)
306     {
307         setHasCustomGetterSetterProperties(true);
308         if (!is__proto__)
309             setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
310     }
311     
312     bool isEmpty() const
313     {
314         ASSERT(checkOffsetConsistency());
315         return !JSC::isValidOffset(m_offset);
316     }
317
318     void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
319     JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
320     bool canCachePropertyNameEnumerator() const;
321     bool canAccessPropertiesQuickly() const;
322
323     void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode);
324
325     JSString* objectToStringValue()
326     {
327         if (!hasRareData())
328             return 0;
329         return rareData()->objectToStringValue();
330     }
331
332     void setObjectToStringValue(VM& vm, JSString* value)
333     {
334         if (!hasRareData())
335             allocateRareData(vm);
336         rareData()->setObjectToStringValue(vm, value);
337     }
338
339     const ClassInfo* classInfo() const { return m_classInfo; }
340
341     static ptrdiff_t structureIDOffset()
342     {
343         return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::structureIDOffset();
344     }
345
346     static ptrdiff_t prototypeOffset()
347     {
348         return OBJECT_OFFSETOF(Structure, m_prototype);
349     }
350
351     static ptrdiff_t globalObjectOffset()
352     {
353         return OBJECT_OFFSETOF(Structure, m_globalObject);
354     }
355
356     static ptrdiff_t classInfoOffset()
357     {
358         return OBJECT_OFFSETOF(Structure, m_classInfo);
359     }
360         
361     static ptrdiff_t indexingTypeOffset()
362     {
363         return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingTypeOffset();
364     }
365
366     static Structure* createStructure(VM&);
367         
368     bool transitionWatchpointSetHasBeenInvalidated() const
369     {
370         return m_transitionWatchpointSet.hasBeenInvalidated();
371     }
372         
373     bool transitionWatchpointSetIsStillValid() const
374     {
375         return m_transitionWatchpointSet.isStillValid();
376     }
377     
378     bool dfgShouldWatchIfPossible() const
379     {
380         // FIXME: We would like to not watch things that are unprofitable to watch, like
381         // dictionaries. Unfortunately, we can't do such things: a dictionary could get flattened,
382         // in which case it will start to appear watchable and so the DFG will think that it is
383         // watching it. We should come up with a comprehensive story for not watching things that
384         // aren't profitable to watch.
385         // https://bugs.webkit.org/show_bug.cgi?id=133625
386         return true;
387     }
388     
389     bool dfgShouldWatch() const
390     {
391         return dfgShouldWatchIfPossible() && transitionWatchpointSetIsStillValid();
392     }
393         
394     void addTransitionWatchpoint(Watchpoint* watchpoint) const
395     {
396         ASSERT(transitionWatchpointSetIsStillValid());
397         m_transitionWatchpointSet.add(watchpoint);
398     }
399     
400     void didTransitionFromThisStructure() const;
401     
402     InlineWatchpointSet& transitionWatchpointSet() const
403     {
404         return m_transitionWatchpointSet;
405     }
406     
407     WatchpointSet* ensurePropertyReplacementWatchpointSet(VM&, PropertyOffset);
408     void startWatchingPropertyForReplacements(VM& vm, PropertyOffset offset)
409     {
410         ensurePropertyReplacementWatchpointSet(vm, offset);
411     }
412     void startWatchingPropertyForReplacements(VM&, PropertyName);
413     WatchpointSet* propertyReplacementWatchpointSet(PropertyOffset);
414     void didReplaceProperty(PropertyOffset);
415     void didCachePropertyReplacement(VM&, PropertyOffset);
416     
417     void startWatchingInternalPropertiesIfNecessary(VM& vm)
418     {
419         if (LIKELY(didWatchInternalProperties()))
420             return;
421         startWatchingInternalProperties(vm);
422     }
423     
424     void startWatchingInternalPropertiesIfNecessaryForEntireChain(VM& vm)
425     {
426         for (Structure* structure = this; structure; structure = structure->storedPrototypeStructure())
427             structure->startWatchingInternalPropertiesIfNecessary(vm);
428     }
429
430     PassRefPtr<StructureShape> toStructureShape(JSValue);
431     
432     // Determines if the two structures match enough that this one could be used for allocations
433     // of the other one.
434     bool canUseForAllocationsOf(Structure*);
435     
436     void dump(PrintStream&) const;
437     void dumpInContext(PrintStream&, DumpContext*) const;
438     void dumpBrief(PrintStream&, const CString&) const;
439     
440     static void dumpContextHeader(PrintStream&);
441     
442     DECLARE_EXPORT_INFO;
443
444 private:
445     typedef enum { 
446         NoneDictionaryKind = 0,
447         CachedDictionaryKind = 1,
448         UncachedDictionaryKind = 2
449     } DictionaryKind;
450
451 public:
452 #define DEFINE_BITFIELD(type, lowerName, upperName, width, offset) \
453     static const uint32_t s_##lowerName##Shift = offset;\
454     static const uint32_t s_##lowerName##Mask = ((1 << (width - 1)) | ((1 << (width - 1)) - 1));\
455     type lowerName() const { return static_cast<type>((m_bitField >> offset) & s_##lowerName##Mask); }\
456     void set##upperName(type newValue) \
457     {\
458         m_bitField &= ~(s_##lowerName##Mask << offset);\
459         m_bitField |= (newValue & s_##lowerName##Mask) << offset;\
460     }
461
462     DEFINE_BITFIELD(DictionaryKind, dictionaryKind, DictionaryKind, 2, 0);
463     DEFINE_BITFIELD(bool, isPinnedPropertyTable, IsPinnedPropertyTable, 1, 2);
464     DEFINE_BITFIELD(bool, hasGetterSetterProperties, HasGetterSetterProperties, 1, 3);
465     DEFINE_BITFIELD(bool, hasReadOnlyOrGetterSetterPropertiesExcludingProto, HasReadOnlyOrGetterSetterPropertiesExcludingProto, 1, 4);
466     DEFINE_BITFIELD(bool, hasNonEnumerableProperties, HasNonEnumerableProperties, 1, 5);
467     DEFINE_BITFIELD(unsigned, attributesInPrevious, AttributesInPrevious, 14, 6);
468     DEFINE_BITFIELD(bool, preventExtensions, PreventExtensions, 1, 20);
469     DEFINE_BITFIELD(bool, didTransition, DidTransition, 1, 21);
470     DEFINE_BITFIELD(bool, staticFunctionsReified, StaticFunctionsReified, 1, 22);
471     DEFINE_BITFIELD(bool, hasRareData, HasRareData, 1, 23);
472     DEFINE_BITFIELD(bool, hasBeenFlattenedBefore, HasBeenFlattenedBefore, 1, 24);
473     DEFINE_BITFIELD(bool, hasCustomGetterSetterProperties, HasCustomGetterSetterProperties, 1, 25);
474     DEFINE_BITFIELD(bool, didWatchInternalProperties, DidWatchInternalProperties, 1, 26);
475
476 private:
477     friend class LLIntOffsetsExtractor;
478
479     JS_EXPORT_PRIVATE Structure(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, unsigned inlineCapacity);
480     Structure(VM&);
481     Structure(VM&, Structure*);
482
483     static Structure* create(VM&, Structure*);
484     
485     static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, AtomicStringImpl* uid, unsigned attributes, PropertyOffset&);
486
487     // This will return the structure that has a usable property table, that property table,
488     // and the list of structures that we visited before we got to it. If it returns a
489     // non-null structure, it will also lock the structure that it returns; it is your job
490     // to unlock it.
491     void findStructuresAndMapForMaterialization(Vector<Structure*, 8>& structures, Structure*&, PropertyTable*&);
492     
493     static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind);
494
495     PropertyOffset add(VM&, PropertyName, unsigned attributes);
496     PropertyOffset remove(PropertyName);
497
498     void createPropertyMap(const GCSafeConcurrentJITLocker&, VM&, unsigned keyCount = 0);
499     void checkConsistency();
500
501     WriteBarrier<PropertyTable>& propertyTable();
502     PropertyTable* takePropertyTableOrCloneIfPinned(VM&);
503     PropertyTable* copyPropertyTable(VM&);
504     PropertyTable* copyPropertyTableForPinning(VM&);
505     JS_EXPORT_PRIVATE void materializePropertyMap(VM&);
506     ALWAYS_INLINE void materializePropertyMapIfNecessary(VM& vm, DeferGC&)
507     {
508         ASSERT(!isCompilationThread());
509         ASSERT(structure()->classInfo() == info());
510         ASSERT(checkOffsetConsistency());
511         if (!propertyTable() && previousID())
512             materializePropertyMap(vm);
513     }
514     ALWAYS_INLINE void materializePropertyMapIfNecessary(VM& vm, PropertyTable*& table)
515     {
516         ASSERT(!isCompilationThread());
517         ASSERT(structure()->classInfo() == info());
518         ASSERT(checkOffsetConsistency());
519         table = propertyTable().get();
520         if (!table && previousID()) {
521             DeferGC deferGC(vm.heap);
522             materializePropertyMap(vm);
523             table = propertyTable().get();
524         }
525     }
526     void materializePropertyMapIfNecessaryForPinning(VM& vm, DeferGC&)
527     {
528         ASSERT(structure()->classInfo() == info());
529         checkOffsetConsistency();
530         if (!propertyTable())
531             materializePropertyMap(vm);
532     }
533
534     void setPreviousID(VM& vm, Structure* structure)
535     {
536         if (hasRareData())
537             rareData()->setPreviousID(vm, structure);
538         else
539             m_previousOrRareData.set(vm, this, structure);
540     }
541
542     void clearPreviousID()
543     {
544         if (hasRareData())
545             rareData()->clearPreviousID();
546         else
547             m_previousOrRareData.clear();
548     }
549
550     int transitionCount() const
551     {
552         // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
553         return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
554     }
555
556     bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain) const;
557     bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
558         
559     void pin();
560
561     Structure* previous() const
562     {
563         ASSERT(!hasRareData());
564         return static_cast<Structure*>(m_previousOrRareData.get());
565     }
566
567     StructureRareData* rareData() const
568     {
569         ASSERT(hasRareData());
570         return static_cast<StructureRareData*>(m_previousOrRareData.get());
571     }
572         
573     bool checkOffsetConsistency() const;
574
575     JS_EXPORT_PRIVATE void allocateRareData(VM&);
576     
577     void startWatchingInternalProperties(VM&);
578
579     static const int s_maxTransitionLength = 64;
580     static const int s_maxTransitionLengthForNonEvalPutById = 512;
581
582     // These need to be properly aligned at the beginning of the 'Structure'
583     // part of the object.
584     StructureIDBlob m_blob;
585     TypeInfo::OutOfLineTypeFlags m_outOfLineTypeFlags;
586
587     WriteBarrier<JSGlobalObject> m_globalObject;
588     WriteBarrier<Unknown> m_prototype;
589     mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
590
591     WriteBarrier<JSCell> m_previousOrRareData;
592
593     RefPtr<AtomicStringImpl> m_nameInPrevious;
594
595     const ClassInfo* m_classInfo;
596
597     StructureTransitionTable m_transitionTable;
598
599     // Should be accessed through propertyTable(). During GC, it may be set to 0 by another thread.
600     WriteBarrier<PropertyTable> m_propertyTableUnsafe;
601
602     mutable InlineWatchpointSet m_transitionWatchpointSet;
603
604     COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits);
605
606     // m_offset does not account for anonymous slots
607     PropertyOffset m_offset;
608
609     uint8_t m_inlineCapacity;
610     
611     ConcurrentJITLock m_lock;
612     
613     uint32_t m_bitField;
614 };
615
616 } // namespace JSC
617
618 #endif // Structure_h