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