Remove excessive headers from JavaScriptCore
[WebKit-https.git] / Source / JavaScriptCore / runtime / Structure.h
1 /*
2  * Copyright (C) 2008, 2009, 2012-2016 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 #pragma once
27
28 #include "ClassInfo.h"
29 #include "ConcurrentJSLock.h"
30 #include "IndexingType.h"
31 #include "InferredTypeTable.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 "PutPropertySlot.h"
39 #include "StructureIDBlob.h"
40 #include "StructureRareData.h"
41 #include "StructureRareDataInlines.h"
42 #include "StructureTransitionTable.h"
43 #include "JSTypeInfo.h"
44 #include "Watchpoint.h"
45 #include "WriteBarrierInlines.h"
46 #include <wtf/PrintStream.h>
47
48 namespace WTF {
49
50 class UniquedStringImpl;
51
52 } // namespace WTF
53
54 namespace JSC {
55
56 class DeferGC;
57 class LLIntOffsetsExtractor;
58 class PropertyNameArray;
59 class PropertyNameArrayData;
60 class PropertyTable;
61 class StructureChain;
62 class StructureShape;
63 class SlotVisitor;
64 class JSString;
65 struct DumpContext;
66
67 // The out-of-line property storage capacity to use when first allocating out-of-line
68 // storage. Note that all objects start out without having any out-of-line storage;
69 // this comes into play only on the first property store that exhausts inline storage.
70 static const unsigned initialOutOfLineCapacity = 4;
71
72 // The factor by which to grow out-of-line storage when it is exhausted, after the
73 // initial allocation.
74 static const unsigned outOfLineGrowthFactor = 2;
75
76 struct PropertyMapEntry {
77     UniquedStringImpl* key;
78     PropertyOffset offset;
79     uint8_t attributes;
80     bool hasInferredType; // This caches whether or not a property has an inferred type in the inferred type table, and is used for a fast check in JSObject::putDirectInternal().
81
82     PropertyMapEntry()
83         : key(nullptr)
84         , offset(invalidOffset)
85         , attributes(0)
86         , hasInferredType(false)
87     {
88     }
89     
90     PropertyMapEntry(UniquedStringImpl* key, PropertyOffset offset, unsigned attributes)
91         : key(key)
92         , offset(offset)
93         , attributes(attributes)
94         , hasInferredType(false)
95     {
96         ASSERT(this->attributes == attributes);
97     }
98 };
99
100 class StructureFireDetail : public FireDetail {
101 public:
102     StructureFireDetail(const Structure* structure)
103         : m_structure(structure)
104     {
105     }
106     
107     void dump(PrintStream& out) const override;
108
109 private:
110     const Structure* m_structure;
111 };
112
113 class DeferredStructureTransitionWatchpointFire {
114     WTF_MAKE_NONCOPYABLE(DeferredStructureTransitionWatchpointFire);
115 public:
116     JS_EXPORT_PRIVATE DeferredStructureTransitionWatchpointFire();
117     JS_EXPORT_PRIVATE ~DeferredStructureTransitionWatchpointFire();
118     
119     void add(const Structure*);
120     
121 private:
122     const Structure* m_structure;
123 };
124
125 class Structure final : public JSCell {
126 public:
127     friend class StructureTransitionTable;
128
129     typedef JSCell Base;
130     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
131     
132     static Structure* create(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0);
133
134     ~Structure();
135
136 protected:
137     void finishCreation(VM& vm)
138     {
139         Base::finishCreation(vm);
140         ASSERT(m_prototype);
141         ASSERT(m_prototype.isObject() || m_prototype.isNull());
142     }
143
144     void finishCreation(VM& vm, CreatingEarlyCellTag)
145     {
146         Base::finishCreation(vm, this, CreatingEarlyCell);
147         ASSERT(m_prototype);
148         ASSERT(m_prototype.isNull());
149         ASSERT(!vm.structureStructure);
150     }
151
152 public:
153     StructureID id() const { return m_blob.structureID(); }
154     int32_t objectInitializationBlob() const { return m_blob.blobExcludingStructureID(); }
155     int64_t idBlob() const { return m_blob.blob(); }
156
157     bool isProxy() const
158     {
159         JSType type = m_blob.type();
160         return type == ImpureProxyType || type == PureForwardingProxyType;
161     }
162
163     static void dumpStatistics();
164
165     JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, PropertyOffset&);
166     JS_EXPORT_PRIVATE static Structure* addNewPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext, DeferredStructureTransitionWatchpointFire* = nullptr);
167     static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&);
168     JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, PropertyOffset&);
169     static Structure* removePropertyTransition(VM&, Structure*, PropertyName, PropertyOffset&);
170     JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(VM&, Structure*, JSValue prototype);
171     JS_EXPORT_PRIVATE static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes);
172     JS_EXPORT_PRIVATE static Structure* toCacheableDictionaryTransition(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr);
173     static Structure* toUncacheableDictionaryTransition(VM&, Structure*);
174     JS_EXPORT_PRIVATE static Structure* sealTransition(VM&, Structure*);
175     JS_EXPORT_PRIVATE static Structure* freezeTransition(VM&, Structure*);
176     static Structure* preventExtensionsTransition(VM&, Structure*);
177     JS_EXPORT_PRIVATE static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition);
178
179     JS_EXPORT_PRIVATE bool isSealed(VM&);
180     JS_EXPORT_PRIVATE bool isFrozen(VM&);
181     bool isStructureExtensible() const { return !didPreventExtensions(); }
182
183     JS_EXPORT_PRIVATE Structure* flattenDictionaryStructure(VM&, JSObject*);
184
185     static const bool needsDestruction = true;
186     static void destroy(JSCell*);
187
188     // Versions that take a func will call it after making the change but while still holding
189     // the lock. The callback is not called if there is no change being made, like if you call
190     // removePropertyWithoutTransition() and the property is not found.
191     template<typename Func>
192     PropertyOffset addPropertyWithoutTransition(VM&, PropertyName, unsigned attributes, const Func&);
193     template<typename Func>
194     PropertyOffset removePropertyWithoutTransition(VM&, PropertyName, const Func&);
195     void setPrototypeWithoutTransition(VM& vm, JSValue prototype) { m_prototype.set(vm, this, prototype); }
196         
197     bool isDictionary() const { return dictionaryKind() != NoneDictionaryKind; }
198     bool isUncacheableDictionary() const { return dictionaryKind() == UncachedDictionaryKind; }
199   
200     bool propertyAccessesAreCacheable()
201     {
202         return dictionaryKind() != UncachedDictionaryKind
203             && !typeInfo().prohibitsPropertyCaching()
204             && !(typeInfo().getOwnPropertySlotIsImpure() && !typeInfo().newImpurePropertyFiresWatchpoints());
205     }
206
207     bool propertyAccessesAreCacheableForAbsence()
208     {
209         return !typeInfo().getOwnPropertySlotIsImpureForPropertyAbsence();
210     }
211     
212     bool needImpurePropertyWatchpoint()
213     {
214         return propertyAccessesAreCacheable()
215             && typeInfo().getOwnPropertySlotIsImpure()
216             && typeInfo().newImpurePropertyFiresWatchpoints();
217     }
218
219     bool isImmutablePrototypeExoticObject()
220     {
221         return typeInfo().isImmutablePrototypeExoticObject();
222     }
223
224     // We use SlowPath in GetByIdStatus for structures that may get new impure properties later to prevent
225     // DFG from inlining property accesses since structures don't transition when a new impure property appears.
226     bool takesSlowPathInDFGForImpureProperty()
227     {
228         return typeInfo().getOwnPropertySlotIsImpure();
229     }
230     
231     // Type accessors.
232     TypeInfo typeInfo() const { ASSERT(structure()->classInfo() == info()); return m_blob.typeInfo(m_outOfLineTypeFlags); }
233     bool isObject() const { return typeInfo().isObject(); }
234
235     IndexingType indexingType() const { return m_blob.indexingTypeIncludingHistory() & AllArrayTypes; }
236     IndexingType indexingTypeIncludingHistory() const { return m_blob.indexingTypeIncludingHistory(); }
237         
238     bool mayInterceptIndexedAccesses() const
239     {
240         return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors);
241     }
242         
243     JS_EXPORT_PRIVATE bool anyObjectInChainMayInterceptIndexedAccesses() const;
244     bool holesMustForwardToPrototype(VM&) const;
245         
246     bool needsSlowPutIndexing() const;
247     NonPropertyTransition suggestedArrayStorageTransition() const;
248         
249     JSGlobalObject* globalObject() const { return m_globalObject.get(); }
250
251     // NOTE: This method should only be called during the creation of structures, since the global
252     // object of a structure is presumed to be immutable in a bunch of places.
253     void setGlobalObject(VM& vm, JSGlobalObject* globalObject) { m_globalObject.set(vm, this, globalObject); }
254         
255     JSValue storedPrototype() const { return m_prototype.get(); }
256     JSObject* storedPrototypeObject() const;
257     Structure* storedPrototypeStructure() const;
258     JSValue prototypeForLookup(ExecState*) const;
259     JSValue prototypeForLookup(JSGlobalObject*) const;
260     JSValue prototypeForLookup(CodeBlock*) const;
261     StructureChain* prototypeChain(VM&, JSGlobalObject*) const;
262     StructureChain* prototypeChain(ExecState*) const;
263     static void visitChildren(JSCell*, SlotVisitor&);
264     
265     // A Structure is cheap to mark during GC if doing so would only add a small and bounded amount
266     // to our heap footprint. For example, if the structure refers to a global object that is not
267     // yet marked, then as far as we know, the decision to mark this Structure would lead to a large
268     // increase in footprint because no other object refers to that global object. This method
269     // returns true if all user-controlled (and hence unbounded in size) objects referenced from the
270     // Structure are already marked.
271     bool isCheapDuringGC();
272     
273     // Returns true if this structure is now marked.
274     bool markIfCheap(SlotVisitor&);
275         
276     // Will just the prototype chain intercept this property access?
277     JS_EXPORT_PRIVATE bool prototypeChainMayInterceptStoreTo(VM&, PropertyName);
278     
279     bool hasRareData() const
280     {
281         return isRareData(m_previousOrRareData.get());
282     }
283     
284     Structure* previousID() const
285     {
286         ASSERT(structure()->classInfo() == info());
287         // This is so written because it's used concurrently. We only load from m_previousOrRareData
288         // once, and this load is guaranteed atomic.
289         JSCell* cell = m_previousOrRareData.get();
290         if (isRareData(cell))
291             return static_cast<StructureRareData*>(cell)->previousID();
292         return static_cast<Structure*>(cell);
293     }
294     bool transitivelyTransitionedFrom(Structure* structureToFind);
295     
296     PropertyOffset lastOffset() const { return m_offset; }
297     
298     void setLastOffset(PropertyOffset offset) { m_offset = offset; }
299
300     static unsigned outOfLineCapacity(PropertyOffset lastOffset)
301     {
302         unsigned outOfLineSize = Structure::outOfLineSize(lastOffset);
303
304         // This algorithm completely determines the out-of-line property storage growth algorithm.
305         // The JSObject code will only trigger a resize if the value returned by this algorithm
306         // changed between the new and old structure. So, it's important to keep this simple because
307         // it's on a fast path.
308         
309         if (!outOfLineSize)
310             return 0;
311
312         if (outOfLineSize <= initialOutOfLineCapacity)
313             return initialOutOfLineCapacity;
314
315         ASSERT(outOfLineSize > initialOutOfLineCapacity);
316         COMPILE_ASSERT(outOfLineGrowthFactor == 2, outOfLineGrowthFactor_is_two);
317         return WTF::roundUpToPowerOfTwo(outOfLineSize);
318     }
319     
320     static unsigned outOfLineSize(PropertyOffset lastOffset)
321     {
322         return numberOfOutOfLineSlotsForLastOffset(lastOffset);
323     }
324
325     unsigned outOfLineCapacity() const
326     {
327         return outOfLineCapacity(m_offset);
328     }
329     unsigned outOfLineSize() const
330     {
331         return outOfLineSize(m_offset);
332     }
333     bool hasInlineStorage() const
334     {
335         return !!m_inlineCapacity;
336     }
337     unsigned inlineCapacity() const
338     {
339         return m_inlineCapacity;
340     }
341     unsigned inlineSize() const
342     {
343         return std::min<unsigned>(m_offset + 1, m_inlineCapacity);
344     }
345     unsigned totalStorageSize() const
346     {
347         return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
348     }
349     unsigned totalStorageCapacity() const
350     {
351         ASSERT(structure()->classInfo() == info());
352         return outOfLineCapacity() + inlineCapacity();
353     }
354
355     bool isValidOffset(PropertyOffset offset) const
356     {
357         return JSC::isValidOffset(offset)
358             && offset <= m_offset
359             && (offset < m_inlineCapacity || offset >= firstOutOfLineOffset);
360     }
361
362     bool hijacksIndexingHeader() const
363     {
364         return isTypedView(m_classInfo->typedArrayStorageType);
365     }
366     
367     bool couldHaveIndexingHeader() const
368     {
369         return hasIndexedProperties(indexingType())
370             || hijacksIndexingHeader();
371     }
372     
373     bool hasIndexingHeader(const JSCell*) const;
374     
375     bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject);
376
377     PropertyOffset get(VM&, PropertyName);
378     PropertyOffset get(VM&, PropertyName, unsigned& attributes);
379     PropertyOffset get(VM&, PropertyName, unsigned& attributes, bool& hasInferredType);
380
381     // This is a somewhat internalish method. It will call your functor while possibly holding the
382     // Structure's lock. There is no guarantee whether the lock is held or not in any particular
383     // call. So, you have to assume the worst. Also, the functor returns true if it wishes for you
384     // to continue or false if it's done.
385     template<typename Functor>
386     void forEachPropertyConcurrently(const Functor&);
387     
388     PropertyOffset getConcurrently(UniquedStringImpl* uid);
389     PropertyOffset getConcurrently(UniquedStringImpl* uid, unsigned& attributes);
390     
391     Vector<PropertyMapEntry> getPropertiesConcurrently();
392     
393     void setHasGetterSetterPropertiesWithProtoCheck(bool is__proto__)
394     {
395         setHasGetterSetterProperties(true);
396         if (!is__proto__)
397             setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
398     }
399     
400     void setContainsReadOnlyProperties() { setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true); }
401     
402     void setHasCustomGetterSetterPropertiesWithProtoCheck(bool is__proto__)
403     {
404         setHasCustomGetterSetterProperties(true);
405         if (!is__proto__)
406             setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
407     }
408     
409     bool isEmpty() const
410     {
411         ASSERT(checkOffsetConsistency());
412         return !JSC::isValidOffset(m_offset);
413     }
414
415     void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
416     JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
417     bool canCachePropertyNameEnumerator() const;
418     bool canAccessPropertiesQuicklyForEnumeration() const;
419
420     void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode);
421
422     JSString* objectToStringValue()
423     {
424         if (!hasRareData())
425             return 0;
426         return rareData()->objectToStringValue();
427     }
428
429     void setObjectToStringValue(ExecState*, VM&, JSString* value, PropertySlot toStringTagSymbolSlot);
430
431     const ClassInfo* classInfo() const { return m_classInfo; }
432
433     static ptrdiff_t structureIDOffset()
434     {
435         return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::structureIDOffset();
436     }
437
438     static ptrdiff_t prototypeOffset()
439     {
440         return OBJECT_OFFSETOF(Structure, m_prototype);
441     }
442
443     static ptrdiff_t globalObjectOffset()
444     {
445         return OBJECT_OFFSETOF(Structure, m_globalObject);
446     }
447
448     static ptrdiff_t classInfoOffset()
449     {
450         return OBJECT_OFFSETOF(Structure, m_classInfo);
451     }
452         
453     static ptrdiff_t indexingTypeIncludingHistoryOffset()
454     {
455         return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingTypeIncludingHistoryOffset();
456     }
457     
458     static ptrdiff_t propertyTableUnsafeOffset()
459     {
460         return OBJECT_OFFSETOF(Structure, m_propertyTableUnsafe);
461     }
462
463     static ptrdiff_t inlineCapacityOffset()
464     {
465         return OBJECT_OFFSETOF(Structure, m_inlineCapacity);
466     }
467
468     static Structure* createStructure(VM&);
469         
470     bool transitionWatchpointSetHasBeenInvalidated() const
471     {
472         return m_transitionWatchpointSet.hasBeenInvalidated();
473     }
474         
475     bool transitionWatchpointSetIsStillValid() const
476     {
477         return m_transitionWatchpointSet.isStillValid();
478     }
479     
480     bool dfgShouldWatchIfPossible() const
481     {
482         // FIXME: We would like to not watch things that are unprofitable to watch, like
483         // dictionaries. Unfortunately, we can't do such things: a dictionary could get flattened,
484         // in which case it will start to appear watchable and so the DFG will think that it is
485         // watching it. We should come up with a comprehensive story for not watching things that
486         // aren't profitable to watch.
487         // https://bugs.webkit.org/show_bug.cgi?id=133625
488         
489         // - We don't watch Structures that either decided not to be watched, or whose predecessors
490         //   decided not to be watched. This happens when a transition is fired while being watched.
491         if (transitionWatchpointIsLikelyToBeFired())
492             return false;
493
494         // - Don't watch Structures that had been dictionaries.
495         if (hasBeenDictionary())
496             return false;
497         
498         return true;
499     }
500     
501     bool dfgShouldWatch() const
502     {
503         return dfgShouldWatchIfPossible() && transitionWatchpointSetIsStillValid();
504     }
505         
506     void addTransitionWatchpoint(Watchpoint* watchpoint) const
507     {
508         ASSERT(transitionWatchpointSetIsStillValid());
509         m_transitionWatchpointSet.add(watchpoint);
510     }
511     
512     void didTransitionFromThisStructure(DeferredStructureTransitionWatchpointFire* = nullptr) const;
513     
514     InlineWatchpointSet& transitionWatchpointSet() const
515     {
516         return m_transitionWatchpointSet;
517     }
518     
519     WatchpointSet* ensurePropertyReplacementWatchpointSet(VM&, PropertyOffset);
520     void startWatchingPropertyForReplacements(VM& vm, PropertyOffset offset)
521     {
522         ensurePropertyReplacementWatchpointSet(vm, offset);
523     }
524     void startWatchingPropertyForReplacements(VM&, PropertyName);
525     WatchpointSet* propertyReplacementWatchpointSet(PropertyOffset);
526     void didReplaceProperty(PropertyOffset);
527     void didCachePropertyReplacement(VM&, PropertyOffset);
528     
529     void startWatchingInternalPropertiesIfNecessary(VM& vm)
530     {
531         if (LIKELY(didWatchInternalProperties()))
532             return;
533         startWatchingInternalProperties(vm);
534     }
535     
536     void startWatchingInternalPropertiesIfNecessaryForEntireChain(VM& vm)
537     {
538         for (Structure* structure = this; structure; structure = structure->storedPrototypeStructure())
539             structure->startWatchingInternalPropertiesIfNecessary(vm);
540     }
541
542     bool hasInferredTypes() const
543     {
544         return !!m_inferredTypeTable;
545     }
546
547     InferredType* inferredTypeFor(UniquedStringImpl* uid)
548     {
549         if (InferredTypeTable* table = m_inferredTypeTable.get())
550             return table->get(uid);
551         return nullptr;
552     }
553
554     InferredType::Descriptor inferredTypeDescriptorFor(UniquedStringImpl* uid)
555     {
556         if (InferredType* result = inferredTypeFor(uid))
557             return result->descriptor();
558         return InferredType::Top;
559     }
560
561     // Call this when we know that this is a brand new property. Note that it's not enough for the
562     // property to be brand new to some object. It has to be brand new to the Structure.
563     ALWAYS_INLINE void willStoreValueForNewTransition(
564         VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize)
565     {
566         if (hasBeenDictionary() || (!shouldOptimize && !m_inferredTypeTable))
567             return;
568         willStoreValueSlow(vm, propertyName, value, shouldOptimize, InferredTypeTable::NewProperty);
569     }
570
571     // Call this when we know that this is a new property for the object, but not new for the
572     // structure. Therefore, under the InferredTypeTable's rules, absence of the property from the
573     // table means Top rather than Bottom.
574     ALWAYS_INLINE void willStoreValueForExistingTransition(
575         VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize)
576     {
577         if (hasBeenDictionary() || !m_inferredTypeTable)
578             return;
579         willStoreValueSlow(vm, propertyName, value, shouldOptimize, InferredTypeTable::NewProperty);
580     }
581
582     // Call this when we know that the inferred type table exists and has an entry for this property.
583     ALWAYS_INLINE void willStoreValueForReplace(
584         VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize)
585     {
586         if (hasBeenDictionary())
587             return;
588         willStoreValueSlow(vm, propertyName, value, shouldOptimize, InferredTypeTable::OldProperty);
589     }
590
591     Ref<StructureShape> toStructureShape(JSValue);
592     
593     // Determines if the two structures match enough that this one could be used for allocations
594     // of the other one.
595     bool canUseForAllocationsOf(Structure*);
596     
597     void dump(PrintStream&) const;
598     void dumpInContext(PrintStream&, DumpContext*) const;
599     void dumpBrief(PrintStream&, const CString&) const;
600     
601     static void dumpContextHeader(PrintStream&);
602     
603     ConcurrentJSLock& lock() { return m_lock; }
604     
605     DECLARE_EXPORT_INFO;
606
607 private:
608     typedef enum { 
609         NoneDictionaryKind = 0,
610         CachedDictionaryKind = 1,
611         UncachedDictionaryKind = 2
612     } DictionaryKind;
613
614 public:
615 #define DEFINE_BITFIELD(type, lowerName, upperName, width, offset) \
616     static const uint32_t s_##lowerName##Shift = offset;\
617     static const uint32_t s_##lowerName##Mask = ((1 << (width - 1)) | ((1 << (width - 1)) - 1));\
618     type lowerName() const { return static_cast<type>((m_bitField >> offset) & s_##lowerName##Mask); }\
619     void set##upperName(type newValue) \
620     {\
621         m_bitField &= ~(s_##lowerName##Mask << offset);\
622         m_bitField |= (newValue & s_##lowerName##Mask) << offset;\
623     }
624
625     DEFINE_BITFIELD(DictionaryKind, dictionaryKind, DictionaryKind, 2, 0);
626     DEFINE_BITFIELD(bool, isPinnedPropertyTable, IsPinnedPropertyTable, 1, 2);
627     DEFINE_BITFIELD(bool, hasGetterSetterProperties, HasGetterSetterProperties, 1, 3);
628     DEFINE_BITFIELD(bool, hasReadOnlyOrGetterSetterPropertiesExcludingProto, HasReadOnlyOrGetterSetterPropertiesExcludingProto, 1, 4);
629     DEFINE_BITFIELD(bool, isQuickPropertyAccessAllowedForEnumeration, IsQuickPropertyAccessAllowedForEnumeration, 1, 5);
630     DEFINE_BITFIELD(unsigned, attributesInPrevious, AttributesInPrevious, 14, 6);
631     DEFINE_BITFIELD(bool, didPreventExtensions, DidPreventExtensions, 1, 20);
632     DEFINE_BITFIELD(bool, didTransition, DidTransition, 1, 21);
633     DEFINE_BITFIELD(bool, staticPropertiesReified, StaticPropertiesReified, 1, 22);
634     DEFINE_BITFIELD(bool, hasBeenFlattenedBefore, HasBeenFlattenedBefore, 1, 23);
635     DEFINE_BITFIELD(bool, hasCustomGetterSetterProperties, HasCustomGetterSetterProperties, 1, 24);
636     DEFINE_BITFIELD(bool, didWatchInternalProperties, DidWatchInternalProperties, 1, 25);
637     DEFINE_BITFIELD(bool, transitionWatchpointIsLikelyToBeFired, TransitionWatchpointIsLikelyToBeFired, 1, 26);
638     DEFINE_BITFIELD(bool, hasBeenDictionary, HasBeenDictionary, 1, 27);
639     DEFINE_BITFIELD(bool, isAddingPropertyForTransition, IsAddingPropertyForTransition, 1, 28);
640
641 private:
642     friend class LLIntOffsetsExtractor;
643
644     JS_EXPORT_PRIVATE Structure(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, unsigned inlineCapacity);
645     Structure(VM&);
646     Structure(VM&, Structure*, DeferredStructureTransitionWatchpointFire*);
647
648     static Structure* create(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr);
649     
650     static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&);
651
652     // This will return the structure that has a usable property table, that property table,
653     // and the list of structures that we visited before we got to it. If it returns a
654     // non-null structure, it will also lock the structure that it returns; it is your job
655     // to unlock it.
656     void findStructuresAndMapForMaterialization(Vector<Structure*, 8>& structures, Structure*&, PropertyTable*&);
657     
658     static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind, DeferredStructureTransitionWatchpointFire* = nullptr);
659
660     enum class ShouldPin { No, Yes };
661     template<ShouldPin, typename Func>
662     PropertyOffset add(VM&, PropertyName, unsigned attributes, const Func&);
663     PropertyOffset add(VM&, PropertyName, unsigned attributes);
664     template<typename Func>
665     PropertyOffset remove(PropertyName, const Func&);
666     PropertyOffset remove(PropertyName);
667
668     void checkConsistency();
669
670     // This may grab the lock, or not. Do not call when holding the Structure's lock.
671     PropertyTable* ensurePropertyTableIfNotEmpty(VM& vm)
672     {
673         if (PropertyTable* result = m_propertyTableUnsafe.get())
674             return result;
675         if (!previousID())
676             return nullptr;
677         return materializePropertyTable(vm);
678     }
679     
680     // This may grab the lock, or not. Do not call when holding the Structure's lock.
681     PropertyTable* ensurePropertyTable(VM& vm)
682     {
683         if (PropertyTable* result = m_propertyTableUnsafe.get())
684             return result;
685         return materializePropertyTable(vm);
686     }
687     
688     PropertyTable* propertyTableOrNull() const
689     {
690         return m_propertyTableUnsafe.get();
691     }
692     
693     // This will grab the lock. Do not call when holding the Structure's lock.
694     JS_EXPORT_PRIVATE PropertyTable* materializePropertyTable(VM&, bool setPropertyTable = true);
695     
696     void setPropertyTable(VM& vm, PropertyTable* table);
697     
698     PropertyTable* takePropertyTableOrCloneIfPinned(VM&);
699     PropertyTable* copyPropertyTableForPinning(VM&);
700
701     void setPreviousID(VM& vm, Structure* structure)
702     {
703         if (hasRareData())
704             rareData()->setPreviousID(vm, structure);
705         else
706             m_previousOrRareData.set(vm, this, structure);
707     }
708
709     void clearPreviousID()
710     {
711         if (hasRareData())
712             rareData()->clearPreviousID();
713         else
714             m_previousOrRareData.clear();
715     }
716
717     int transitionCount() const
718     {
719         // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
720         return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
721     }
722
723     bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain) const;
724     bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
725
726     // You have to hold the structure lock to do these.
727     JS_EXPORT_PRIVATE void pin(const AbstractLocker&, VM&, PropertyTable*);
728     void pinForCaching(const AbstractLocker&, VM&, PropertyTable*);
729     
730     bool isRareData(JSCell* cell) const
731     {
732         return cell && cell->structureID() != structureID();
733     }
734
735     StructureRareData* rareData() const
736     {
737         ASSERT(hasRareData());
738         return static_cast<StructureRareData*>(m_previousOrRareData.get());
739     }
740
741     template<typename DetailsFunc>
742     bool checkOffsetConsistency(PropertyTable*, const DetailsFunc&) const;
743     bool checkOffsetConsistency() const;
744
745     JS_EXPORT_PRIVATE void allocateRareData(VM&);
746     
747     void startWatchingInternalProperties(VM&);
748
749     JS_EXPORT_PRIVATE void willStoreValueSlow(
750         VM&, PropertyName, JSValue, bool, InferredTypeTable::StoredPropertyAge);
751
752     static const int s_maxTransitionLength = 64;
753     static const int s_maxTransitionLengthForNonEvalPutById = 512;
754
755     // These need to be properly aligned at the beginning of the 'Structure'
756     // part of the object.
757     StructureIDBlob m_blob;
758     TypeInfo::OutOfLineTypeFlags m_outOfLineTypeFlags;
759
760     uint8_t m_inlineCapacity;
761
762     ConcurrentJSLock m_lock;
763
764     uint32_t m_bitField;
765
766     WriteBarrier<JSGlobalObject> m_globalObject;
767     WriteBarrier<Unknown> m_prototype;
768     mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
769
770     WriteBarrier<JSCell> m_previousOrRareData;
771
772     RefPtr<UniquedStringImpl> m_nameInPrevious;
773
774     const ClassInfo* m_classInfo;
775
776     StructureTransitionTable m_transitionTable;
777
778     // Should be accessed through ensurePropertyTable(). During GC, it may be set to 0 by another thread.
779     // During a Heap Snapshot GC we avoid clearing the table so it is safe to use.
780     WriteBarrier<PropertyTable> m_propertyTableUnsafe;
781
782     WriteBarrier<InferredTypeTable> m_inferredTypeTable;
783
784     mutable InlineWatchpointSet m_transitionWatchpointSet;
785
786     COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits);
787
788     // m_offset does not account for anonymous slots
789     PropertyOffset m_offset;
790 };
791
792 } // namespace JSC