2 * Copyright (C) 2008, 2009, 2012-2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "ClassInfo.h"
30 #include "ConcurrentJITLock.h"
31 #include "IndexingType.h"
32 #include "InferredTypeTable.h"
33 #include "JSCJSValue.h"
36 #include "PropertyName.h"
37 #include "PropertyNameArray.h"
38 #include "PropertyOffset.h"
40 #include "PutPropertySlot.h"
41 #include "StructureIDBlob.h"
42 #include "StructureRareData.h"
43 #include "StructureRareDataInlines.h"
44 #include "StructureTransitionTable.h"
45 #include "JSTypeInfo.h"
46 #include "Watchpoint.h"
48 #include "WriteBarrierInlines.h"
49 #include <wtf/CompilationThread.h>
50 #include <wtf/PassRefPtr.h>
51 #include <wtf/PrintStream.h>
52 #include <wtf/RefCounted.h>
56 class UniquedStringImpl;
63 class LLIntOffsetsExtractor;
64 class PropertyNameArray;
65 class PropertyNameArrayData;
73 // The out-of-line property storage capacity to use when first allocating out-of-line
74 // storage. Note that all objects start out without having any out-of-line storage;
75 // this comes into play only on the first property store that exhausts inline storage.
76 static const unsigned initialOutOfLineCapacity = 4;
78 // The factor by which to grow out-of-line storage when it is exhausted, after the
79 // initial allocation.
80 static const unsigned outOfLineGrowthFactor = 2;
82 struct PropertyMapEntry {
83 UniquedStringImpl* key;
84 PropertyOffset offset;
86 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().
90 , offset(invalidOffset)
92 , hasInferredType(false)
96 PropertyMapEntry(UniquedStringImpl* key, PropertyOffset offset, unsigned attributes)
99 , attributes(attributes)
100 , hasInferredType(false)
102 ASSERT(this->attributes == attributes);
106 class StructureFireDetail : public FireDetail {
108 StructureFireDetail(const Structure* structure)
109 : m_structure(structure)
113 void dump(PrintStream& out) const override;
116 const Structure* m_structure;
119 class DeferredStructureTransitionWatchpointFire {
120 WTF_MAKE_NONCOPYABLE(DeferredStructureTransitionWatchpointFire);
122 JS_EXPORT_PRIVATE DeferredStructureTransitionWatchpointFire();
123 JS_EXPORT_PRIVATE ~DeferredStructureTransitionWatchpointFire();
125 void add(const Structure*);
128 const Structure* m_structure;
131 class Structure final : public JSCell {
133 friend class StructureTransitionTable;
136 static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
138 static Structure* create(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0);
143 void finishCreation(VM& vm)
145 Base::finishCreation(vm);
147 ASSERT(m_prototype.isObject() || m_prototype.isNull());
150 void finishCreation(VM& vm, CreatingEarlyCellTag)
152 Base::finishCreation(vm, this, CreatingEarlyCell);
154 ASSERT(m_prototype.isNull());
155 ASSERT(!vm.structureStructure);
159 StructureID id() const { return m_blob.structureID(); }
160 int32_t objectInitializationBlob() const { return m_blob.blobExcludingStructureID(); }
161 int64_t idBlob() const { return m_blob.blob(); }
165 JSType type = m_blob.type();
166 return type == ImpureProxyType || type == PureForwardingProxyType;
169 static void dumpStatistics();
171 JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, PropertyOffset&);
172 JS_EXPORT_PRIVATE static Structure* addNewPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext, DeferredStructureTransitionWatchpointFire* = nullptr);
173 static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&);
174 JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, PropertyOffset&);
175 static Structure* removePropertyTransition(VM&, Structure*, PropertyName, PropertyOffset&);
176 JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(VM&, Structure*, JSValue prototype);
177 JS_EXPORT_PRIVATE static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes);
178 JS_EXPORT_PRIVATE static Structure* toCacheableDictionaryTransition(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr);
179 static Structure* toUncacheableDictionaryTransition(VM&, Structure*);
180 JS_EXPORT_PRIVATE static Structure* sealTransition(VM&, Structure*);
181 JS_EXPORT_PRIVATE static Structure* freezeTransition(VM&, Structure*);
182 static Structure* preventExtensionsTransition(VM&, Structure*);
183 JS_EXPORT_PRIVATE static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition);
185 JS_EXPORT_PRIVATE bool isSealed(VM&);
186 JS_EXPORT_PRIVATE bool isFrozen(VM&);
187 bool isStructureExtensible() const { return !didPreventExtensions(); }
188 bool putWillGrowOutOfLineStorage();
189 size_t suggestedNewOutOfLineStorageCapacity();
191 JS_EXPORT_PRIVATE Structure* flattenDictionaryStructure(VM&, JSObject*);
193 static const bool needsDestruction = true;
194 static void destroy(JSCell*);
196 // These should be used with caution.
197 JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(VM&, PropertyName, unsigned attributes);
198 PropertyOffset removePropertyWithoutTransition(VM&, PropertyName);
199 void setPrototypeWithoutTransition(VM& vm, JSValue prototype) { m_prototype.set(vm, this, prototype); }
201 bool isDictionary() const { return dictionaryKind() != NoneDictionaryKind; }
202 bool isUncacheableDictionary() const { return dictionaryKind() == UncachedDictionaryKind; }
204 bool propertyAccessesAreCacheable()
206 return dictionaryKind() != UncachedDictionaryKind
207 && !typeInfo().prohibitsPropertyCaching()
208 && !(typeInfo().getOwnPropertySlotIsImpure() && !typeInfo().newImpurePropertyFiresWatchpoints());
211 bool propertyAccessesAreCacheableForAbsence()
213 return !typeInfo().getOwnPropertySlotIsImpureForPropertyAbsence();
216 bool needImpurePropertyWatchpoint()
218 return propertyAccessesAreCacheable()
219 && typeInfo().getOwnPropertySlotIsImpure()
220 && typeInfo().newImpurePropertyFiresWatchpoints();
223 // We use SlowPath in GetByIdStatus for structures that may get new impure properties later to prevent
224 // DFG from inlining property accesses since structures don't transition when a new impure property appears.
225 bool takesSlowPathInDFGForImpureProperty()
227 return typeInfo().getOwnPropertySlotIsImpure();
231 TypeInfo typeInfo() const { ASSERT(structure()->classInfo() == info()); return m_blob.typeInfo(m_outOfLineTypeFlags); }
232 bool isObject() const { return typeInfo().isObject(); }
234 IndexingType indexingType() const { return m_blob.indexingType() & AllArrayTypes; }
235 IndexingType indexingTypeIncludingHistory() const { return m_blob.indexingType(); }
237 bool mayInterceptIndexedAccesses() const
239 return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors);
242 JS_EXPORT_PRIVATE bool anyObjectInChainMayInterceptIndexedAccesses() const;
243 bool holesMustForwardToPrototype(VM&) const;
245 bool needsSlowPutIndexing() const;
246 NonPropertyTransition suggestedArrayStorageTransition() const;
248 JSGlobalObject* globalObject() const { return m_globalObject.get(); }
250 // NOTE: This method should only be called during the creation of structures, since the global
251 // object of a structure is presumed to be immutable in a bunch of places.
252 void setGlobalObject(VM& vm, JSGlobalObject* globalObject) { m_globalObject.set(vm, this, globalObject); }
254 JSValue storedPrototype() const { return m_prototype.get(); }
255 JSObject* storedPrototypeObject() const;
256 Structure* storedPrototypeStructure() const;
257 JSValue prototypeForLookup(ExecState*) const;
258 JSValue prototypeForLookup(JSGlobalObject*) const;
259 JSValue prototypeForLookup(CodeBlock*) const;
260 StructureChain* prototypeChain(VM&, JSGlobalObject*) const;
261 StructureChain* prototypeChain(ExecState*) const;
262 static void visitChildren(JSCell*, SlotVisitor&);
264 // Will just the prototype chain intercept this property access?
265 JS_EXPORT_PRIVATE bool prototypeChainMayInterceptStoreTo(VM&, PropertyName);
267 Structure* previousID() const
269 ASSERT(structure()->classInfo() == info());
271 return rareData()->previousID();
274 bool transitivelyTransitionedFrom(Structure* structureToFind);
276 unsigned outOfLineCapacity() const
278 ASSERT(checkOffsetConsistency());
280 unsigned outOfLineSize = this->outOfLineSize();
285 if (outOfLineSize <= initialOutOfLineCapacity)
286 return initialOutOfLineCapacity;
288 ASSERT(outOfLineSize > initialOutOfLineCapacity);
289 COMPILE_ASSERT(outOfLineGrowthFactor == 2, outOfLineGrowthFactor_is_two);
290 return WTF::roundUpToPowerOfTwo(outOfLineSize);
292 unsigned outOfLineSize() const
294 ASSERT(checkOffsetConsistency());
295 ASSERT(structure()->classInfo() == info());
297 return numberOfOutOfLineSlotsForLastOffset(m_offset);
299 bool hasInlineStorage() const
301 return !!m_inlineCapacity;
303 unsigned inlineCapacity() const
305 return m_inlineCapacity;
307 unsigned inlineSize() const
309 return std::min<unsigned>(m_offset + 1, m_inlineCapacity);
311 unsigned totalStorageSize() const
313 return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
315 unsigned totalStorageCapacity() const
317 ASSERT(structure()->classInfo() == info());
318 return outOfLineCapacity() + inlineCapacity();
321 bool isValidOffset(PropertyOffset offset) const
323 return JSC::isValidOffset(offset)
324 && offset <= m_offset
325 && (offset < m_inlineCapacity || offset >= firstOutOfLineOffset);
328 bool hijacksIndexingHeader() const
330 return isTypedView(m_classInfo->typedArrayStorageType);
333 bool couldHaveIndexingHeader() const
335 return hasIndexedProperties(indexingType())
336 || hijacksIndexingHeader();
339 bool hasIndexingHeader(const JSCell*) const;
341 bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject);
343 PropertyOffset get(VM&, PropertyName);
344 PropertyOffset get(VM&, PropertyName, unsigned& attributes);
345 PropertyOffset get(VM&, PropertyName, unsigned& attributes, bool& hasInferredType);
347 // This is a somewhat internalish method. It will call your functor while possibly holding the
348 // Structure's lock. There is no guarantee whether the lock is held or not in any particular
349 // call. So, you have to assume the worst. Also, the functor returns true if it wishes for you
350 // to continue or false if it's done.
351 template<typename Functor>
352 void forEachPropertyConcurrently(const Functor&);
354 PropertyOffset getConcurrently(UniquedStringImpl* uid);
355 PropertyOffset getConcurrently(UniquedStringImpl* uid, unsigned& attributes);
357 Vector<PropertyMapEntry> getPropertiesConcurrently();
359 void setHasGetterSetterPropertiesWithProtoCheck(bool is__proto__)
361 setHasGetterSetterProperties(true);
363 setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
366 void setContainsReadOnlyProperties() { setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true); }
368 void setHasCustomGetterSetterPropertiesWithProtoCheck(bool is__proto__)
370 setHasCustomGetterSetterProperties(true);
372 setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
377 ASSERT(checkOffsetConsistency());
378 return !JSC::isValidOffset(m_offset);
381 void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
382 JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
383 bool canCachePropertyNameEnumerator() const;
384 bool canAccessPropertiesQuicklyForEnumeration() const;
386 void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode);
388 JSString* objectToStringValue()
392 return rareData()->objectToStringValue();
395 void setObjectToStringValue(ExecState*, VM&, JSString* value, PropertySlot toStringTagSymbolSlot);
397 const ClassInfo* classInfo() const { return m_classInfo; }
399 static ptrdiff_t structureIDOffset()
401 return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::structureIDOffset();
404 static ptrdiff_t prototypeOffset()
406 return OBJECT_OFFSETOF(Structure, m_prototype);
409 static ptrdiff_t globalObjectOffset()
411 return OBJECT_OFFSETOF(Structure, m_globalObject);
414 static ptrdiff_t classInfoOffset()
416 return OBJECT_OFFSETOF(Structure, m_classInfo);
419 static ptrdiff_t indexingTypeOffset()
421 return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingTypeOffset();
424 static ptrdiff_t propertyTableUnsafeOffset()
426 return OBJECT_OFFSETOF(Structure, m_propertyTableUnsafe);
429 static Structure* createStructure(VM&);
431 bool transitionWatchpointSetHasBeenInvalidated() const
433 return m_transitionWatchpointSet.hasBeenInvalidated();
436 bool transitionWatchpointSetIsStillValid() const
438 return m_transitionWatchpointSet.isStillValid();
441 bool dfgShouldWatchIfPossible() const
443 // FIXME: We would like to not watch things that are unprofitable to watch, like
444 // dictionaries. Unfortunately, we can't do such things: a dictionary could get flattened,
445 // in which case it will start to appear watchable and so the DFG will think that it is
446 // watching it. We should come up with a comprehensive story for not watching things that
447 // aren't profitable to watch.
448 // https://bugs.webkit.org/show_bug.cgi?id=133625
450 // - We don't watch Structures that either decided not to be watched, or whose predecessors
451 // decided not to be watched. This happens either when a transition is fired while being
453 if (transitionWatchpointIsLikelyToBeFired())
456 // - Don't watch Structures that had been dictionaries.
457 if (hasBeenDictionary())
463 bool dfgShouldWatch() const
465 return dfgShouldWatchIfPossible() && transitionWatchpointSetIsStillValid();
468 void addTransitionWatchpoint(Watchpoint* watchpoint) const
470 ASSERT(transitionWatchpointSetIsStillValid());
471 m_transitionWatchpointSet.add(watchpoint);
474 void didTransitionFromThisStructure(DeferredStructureTransitionWatchpointFire* = nullptr) const;
476 InlineWatchpointSet& transitionWatchpointSet() const
478 return m_transitionWatchpointSet;
481 WatchpointSet* ensurePropertyReplacementWatchpointSet(VM&, PropertyOffset);
482 void startWatchingPropertyForReplacements(VM& vm, PropertyOffset offset)
484 ensurePropertyReplacementWatchpointSet(vm, offset);
486 void startWatchingPropertyForReplacements(VM&, PropertyName);
487 WatchpointSet* propertyReplacementWatchpointSet(PropertyOffset);
488 void didReplaceProperty(PropertyOffset);
489 void didCachePropertyReplacement(VM&, PropertyOffset);
491 void startWatchingInternalPropertiesIfNecessary(VM& vm)
493 if (LIKELY(didWatchInternalProperties()))
495 startWatchingInternalProperties(vm);
498 void startWatchingInternalPropertiesIfNecessaryForEntireChain(VM& vm)
500 for (Structure* structure = this; structure; structure = structure->storedPrototypeStructure())
501 structure->startWatchingInternalPropertiesIfNecessary(vm);
504 bool hasInferredTypes() const
506 return !!m_inferredTypeTable;
509 InferredType* inferredTypeFor(UniquedStringImpl* uid)
511 if (InferredTypeTable* table = m_inferredTypeTable.get())
512 return table->get(uid);
516 InferredType::Descriptor inferredTypeDescriptorFor(UniquedStringImpl* uid)
518 if (InferredType* result = inferredTypeFor(uid))
519 return result->descriptor();
520 return InferredType::Top;
523 // Call this when we know that this is a brand new property. Note that it's not enough for the
524 // property to be brand new to some object. It has to be brand new to the Structure.
525 ALWAYS_INLINE void willStoreValueForNewTransition(
526 VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize)
528 if (hasBeenDictionary() || (!shouldOptimize && !m_inferredTypeTable))
530 willStoreValueSlow(vm, propertyName, value, shouldOptimize, InferredTypeTable::NewProperty);
533 // Call this when we know that this is a new property for the object, but not new for the
534 // structure. Therefore, under the InferredTypeTable's rules, absence of the property from the
535 // table means Top rather than Bottom.
536 ALWAYS_INLINE void willStoreValueForExistingTransition(
537 VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize)
539 if (hasBeenDictionary() || !m_inferredTypeTable)
541 willStoreValueSlow(vm, propertyName, value, shouldOptimize, InferredTypeTable::NewProperty);
544 // Call this when we know that the inferred type table exists and has an entry for this property.
545 ALWAYS_INLINE void willStoreValueForReplace(
546 VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize)
548 if (hasBeenDictionary())
550 willStoreValueSlow(vm, propertyName, value, shouldOptimize, InferredTypeTable::OldProperty);
553 PassRefPtr<StructureShape> toStructureShape(JSValue);
555 // Determines if the two structures match enough that this one could be used for allocations
557 bool canUseForAllocationsOf(Structure*);
559 void dump(PrintStream&) const;
560 void dumpInContext(PrintStream&, DumpContext*) const;
561 void dumpBrief(PrintStream&, const CString&) const;
563 static void dumpContextHeader(PrintStream&);
569 NoneDictionaryKind = 0,
570 CachedDictionaryKind = 1,
571 UncachedDictionaryKind = 2
575 #define DEFINE_BITFIELD(type, lowerName, upperName, width, offset) \
576 static const uint32_t s_##lowerName##Shift = offset;\
577 static const uint32_t s_##lowerName##Mask = ((1 << (width - 1)) | ((1 << (width - 1)) - 1));\
578 type lowerName() const { return static_cast<type>((m_bitField >> offset) & s_##lowerName##Mask); }\
579 void set##upperName(type newValue) \
581 m_bitField &= ~(s_##lowerName##Mask << offset);\
582 m_bitField |= (newValue & s_##lowerName##Mask) << offset;\
585 DEFINE_BITFIELD(DictionaryKind, dictionaryKind, DictionaryKind, 2, 0);
586 DEFINE_BITFIELD(bool, isPinnedPropertyTable, IsPinnedPropertyTable, 1, 2);
587 DEFINE_BITFIELD(bool, hasGetterSetterProperties, HasGetterSetterProperties, 1, 3);
588 DEFINE_BITFIELD(bool, hasReadOnlyOrGetterSetterPropertiesExcludingProto, HasReadOnlyOrGetterSetterPropertiesExcludingProto, 1, 4);
589 DEFINE_BITFIELD(bool, isQuickPropertyAccessAllowedForEnumeration, IsQuickPropertyAccessAllowedForEnumeration, 1, 5);
590 DEFINE_BITFIELD(unsigned, attributesInPrevious, AttributesInPrevious, 14, 6);
591 DEFINE_BITFIELD(bool, didPreventExtensions, DidPreventExtensions, 1, 20);
592 DEFINE_BITFIELD(bool, didTransition, DidTransition, 1, 21);
593 DEFINE_BITFIELD(bool, staticFunctionsReified, StaticFunctionsReified, 1, 22);
594 DEFINE_BITFIELD(bool, hasRareData, HasRareData, 1, 23);
595 DEFINE_BITFIELD(bool, hasBeenFlattenedBefore, HasBeenFlattenedBefore, 1, 24);
596 DEFINE_BITFIELD(bool, hasCustomGetterSetterProperties, HasCustomGetterSetterProperties, 1, 25);
597 DEFINE_BITFIELD(bool, didWatchInternalProperties, DidWatchInternalProperties, 1, 26);
598 DEFINE_BITFIELD(bool, transitionWatchpointIsLikelyToBeFired, TransitionWatchpointIsLikelyToBeFired, 1, 27);
599 DEFINE_BITFIELD(bool, hasBeenDictionary, HasBeenDictionary, 1, 28);
602 friend class LLIntOffsetsExtractor;
604 JS_EXPORT_PRIVATE Structure(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, unsigned inlineCapacity);
606 Structure(VM&, Structure*, DeferredStructureTransitionWatchpointFire*);
608 static Structure* create(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr);
610 static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&);
612 // This will return the structure that has a usable property table, that property table,
613 // and the list of structures that we visited before we got to it. If it returns a
614 // non-null structure, it will also lock the structure that it returns; it is your job
616 void findStructuresAndMapForMaterialization(Vector<Structure*, 8>& structures, Structure*&, PropertyTable*&);
618 static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind, DeferredStructureTransitionWatchpointFire* = nullptr);
620 PropertyOffset add(VM&, PropertyName, unsigned attributes);
621 PropertyOffset remove(PropertyName);
623 void createPropertyMap(const GCSafeConcurrentJITLocker&, VM&, unsigned keyCount = 0);
624 void checkConsistency();
626 WriteBarrier<PropertyTable>& propertyTable();
627 PropertyTable* takePropertyTableOrCloneIfPinned(VM&);
628 PropertyTable* copyPropertyTable(VM&);
629 PropertyTable* copyPropertyTableForPinning(VM&);
630 JS_EXPORT_PRIVATE void materializePropertyMap(VM&);
631 ALWAYS_INLINE void materializePropertyMapIfNecessary(VM& vm, DeferGC&)
633 ASSERT(!isCompilationThread());
634 ASSERT(structure()->classInfo() == info());
635 ASSERT(checkOffsetConsistency());
636 if (!propertyTable() && previousID())
637 materializePropertyMap(vm);
639 ALWAYS_INLINE void materializePropertyMapIfNecessary(VM& vm, PropertyTable*& table)
641 ASSERT(!isCompilationThread());
642 ASSERT(structure()->classInfo() == info());
643 ASSERT(checkOffsetConsistency());
644 table = propertyTable().get();
645 if (!table && previousID()) {
646 DeferGC deferGC(vm.heap);
647 materializePropertyMap(vm);
648 table = propertyTable().get();
651 void materializePropertyMapIfNecessaryForPinning(VM& vm, DeferGC&)
653 ASSERT(structure()->classInfo() == info());
654 checkOffsetConsistency();
655 if (!propertyTable())
656 materializePropertyMap(vm);
659 void setPreviousID(VM& vm, Structure* structure)
662 rareData()->setPreviousID(vm, structure);
664 m_previousOrRareData.set(vm, this, structure);
667 void clearPreviousID()
670 rareData()->clearPreviousID();
672 m_previousOrRareData.clear();
675 int transitionCount() const
677 // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
678 return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
681 bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain) const;
682 bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
686 Structure* previous() const
688 ASSERT(!hasRareData());
689 return static_cast<Structure*>(m_previousOrRareData.get());
692 StructureRareData* rareData() const
694 ASSERT(hasRareData());
695 return static_cast<StructureRareData*>(m_previousOrRareData.get());
698 bool checkOffsetConsistency() const;
700 JS_EXPORT_PRIVATE void allocateRareData(VM&);
702 void startWatchingInternalProperties(VM&);
704 JS_EXPORT_PRIVATE void willStoreValueSlow(
705 VM&, PropertyName, JSValue, bool, InferredTypeTable::StoredPropertyAge);
707 static const int s_maxTransitionLength = 64;
708 static const int s_maxTransitionLengthForNonEvalPutById = 512;
710 // These need to be properly aligned at the beginning of the 'Structure'
711 // part of the object.
712 StructureIDBlob m_blob;
713 TypeInfo::OutOfLineTypeFlags m_outOfLineTypeFlags;
715 WriteBarrier<JSGlobalObject> m_globalObject;
716 WriteBarrier<Unknown> m_prototype;
717 mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
719 WriteBarrier<JSCell> m_previousOrRareData;
721 RefPtr<UniquedStringImpl> m_nameInPrevious;
723 const ClassInfo* m_classInfo;
725 StructureTransitionTable m_transitionTable;
727 // Should be accessed through propertyTable(). During GC, it may be set to 0 by another thread.
728 // During a Heap Snapshot GC we avoid clearing the table so it is safe to use.
729 WriteBarrier<PropertyTable> m_propertyTableUnsafe;
731 WriteBarrier<InferredTypeTable> m_inferredTypeTable;
733 mutable InlineWatchpointSet m_transitionWatchpointSet;
735 COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits);
737 // m_offset does not account for anonymous slots
738 PropertyOffset m_offset;
740 uint8_t m_inlineCapacity;
742 ConcurrentJITLock m_lock;
749 #endif // Structure_h