]>
Commit | Line | Data |
---|---|---|
9dae56ea | 1 | /* |
93a37866 | 2 | * Copyright (C) 2008, 2009, 2012, 2013 Apple Inc. All rights reserved. |
9dae56ea A |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions | |
6 | * are met: | |
7 | * 1. Redistributions of source code must retain the above copyright | |
8 | * notice, this list of conditions and the following disclaimer. | |
9 | * 2. Redistributions in binary form must reproduce the above copyright | |
10 | * notice, this list of conditions and the following disclaimer in the | |
11 | * documentation and/or other materials provided with the distribution. | |
12 | * | |
81345200 | 13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
9dae56ea A |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
81345200 | 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
9dae56ea A |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | */ | |
25 | ||
26 | #ifndef Structure_h | |
27 | #define Structure_h | |
28 | ||
6fe7ccc8 | 29 | #include "ClassInfo.h" |
81345200 | 30 | #include "ConcurrentJITLock.h" |
93a37866 A |
31 | #include "IndexingType.h" |
32 | #include "JSCJSValue.h" | |
14957cd0 | 33 | #include "JSCell.h" |
9dae56ea | 34 | #include "JSType.h" |
93a37866 | 35 | #include "PropertyName.h" |
f9bf01c6 | 36 | #include "PropertyNameArray.h" |
93a37866 | 37 | #include "PropertyOffset.h" |
f9bf01c6 | 38 | #include "Protect.h" |
81345200 A |
39 | #include "PutPropertySlot.h" |
40 | #include "StructureIDBlob.h" | |
93a37866 | 41 | #include "StructureRareData.h" |
9dae56ea | 42 | #include "StructureTransitionTable.h" |
f9bf01c6 | 43 | #include "JSTypeInfo.h" |
93a37866 | 44 | #include "Watchpoint.h" |
81345200 A |
45 | #include "Weak.h" |
46 | #include "WriteBarrierInlines.h" | |
47 | #include <wtf/CompilationThread.h> | |
9dae56ea | 48 | #include <wtf/PassRefPtr.h> |
81345200 | 49 | #include <wtf/PrintStream.h> |
9dae56ea | 50 | #include <wtf/RefCounted.h> |
93a37866 | 51 | #include <wtf/text/StringImpl.h> |
9dae56ea | 52 | |
9dae56ea A |
53 | |
54 | namespace JSC { | |
55 | ||
81345200 | 56 | class DeferGC; |
93a37866 A |
57 | class LLIntOffsetsExtractor; |
58 | class PropertyNameArray; | |
59 | class PropertyNameArrayData; | |
60 | class PropertyTable; | |
61 | class StructureChain; | |
62 | class SlotVisitor; | |
63 | class JSString; | |
81345200 | 64 | struct DumpContext; |
93a37866 A |
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 | class Structure : public JSCell { | |
76 | public: | |
77 | friend class StructureTransitionTable; | |
9dae56ea | 78 | |
93a37866 | 79 | typedef JSCell Base; |
81345200 | 80 | |
93a37866 A |
81 | static Structure* create(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0); |
82 | ||
81345200 A |
83 | ~Structure(); |
84 | ||
93a37866 A |
85 | protected: |
86 | void finishCreation(VM& vm) | |
87 | { | |
88 | Base::finishCreation(vm); | |
89 | ASSERT(m_prototype); | |
90 | ASSERT(m_prototype.isObject() || m_prototype.isNull()); | |
91 | } | |
9dae56ea | 92 | |
93a37866 A |
93 | void finishCreation(VM& vm, CreatingEarlyCellTag) |
94 | { | |
95 | Base::finishCreation(vm, this, CreatingEarlyCell); | |
96 | ASSERT(m_prototype); | |
97 | ASSERT(m_prototype.isNull()); | |
98 | ASSERT(!vm.structureStructure); | |
99 | } | |
6fe7ccc8 | 100 | |
93a37866 | 101 | public: |
81345200 A |
102 | StructureID id() const { return m_blob.structureID(); } |
103 | int32_t objectInitializationBlob() const { return m_blob.blobExcludingStructureID(); } | |
104 | int64_t idBlob() const { return m_blob.blob(); } | |
105 | ||
106 | bool isProxy() const | |
107 | { | |
108 | JSType type = m_blob.type(); | |
109 | return type == ImpureProxyType || type == PureForwardingProxyType; | |
110 | } | |
111 | ||
93a37866 A |
112 | static void dumpStatistics(); |
113 | ||
81345200 A |
114 | JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext); |
115 | static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset&); | |
93a37866 A |
116 | JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&); |
117 | static Structure* removePropertyTransition(VM&, Structure*, PropertyName, PropertyOffset&); | |
118 | JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(VM&, Structure*, JSValue prototype); | |
119 | JS_EXPORT_PRIVATE static Structure* despecifyFunctionTransition(VM&, Structure*, PropertyName); | |
120 | static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes); | |
81345200 | 121 | JS_EXPORT_PRIVATE static Structure* toCacheableDictionaryTransition(VM&, Structure*); |
93a37866 A |
122 | static Structure* toUncacheableDictionaryTransition(VM&, Structure*); |
123 | static Structure* sealTransition(VM&, Structure*); | |
124 | static Structure* freezeTransition(VM&, Structure*); | |
125 | static Structure* preventExtensionsTransition(VM&, Structure*); | |
126 | static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition); | |
127 | ||
128 | bool isSealed(VM&); | |
129 | bool isFrozen(VM&); | |
130 | bool isExtensible() const { return !m_preventExtensions; } | |
131 | bool didTransition() const { return m_didTransition; } | |
132 | bool putWillGrowOutOfLineStorage(); | |
81345200 | 133 | size_t suggestedNewOutOfLineStorageCapacity(); |
93a37866 | 134 | |
81345200 | 135 | JS_EXPORT_PRIVATE Structure* flattenDictionaryStructure(VM&, JSObject*); |
93a37866 A |
136 | |
137 | static const bool needsDestruction = true; | |
138 | static const bool hasImmortalStructure = true; | |
139 | static void destroy(JSCell*); | |
140 | ||
141 | // These should be used with caution. | |
142 | JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(VM&, PropertyName, unsigned attributes, JSCell* specificValue); | |
143 | PropertyOffset removePropertyWithoutTransition(VM&, PropertyName); | |
144 | void setPrototypeWithoutTransition(VM& vm, JSValue prototype) { m_prototype.set(vm, this, prototype); } | |
6fe7ccc8 | 145 | |
93a37866 A |
146 | bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; } |
147 | bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; } | |
9dae56ea | 148 | |
81345200 A |
149 | bool hasBeenFlattenedBefore() const { return m_hasBeenFlattenedBefore; } |
150 | ||
93a37866 A |
151 | bool propertyAccessesAreCacheable() { return m_dictionaryKind != UncachedDictionaryKind && !typeInfo().prohibitsPropertyCaching(); } |
152 | ||
81345200 A |
153 | // We use SlowPath in GetByIdStatus for structures that may get new impure properties later to prevent |
154 | // DFG from inlining property accesses since structures don't transition when a new impure property appears. | |
155 | bool takesSlowPathInDFGForImpureProperty() | |
156 | { | |
157 | return typeInfo().hasImpureGetOwnPropertySlot(); | |
158 | } | |
159 | ||
93a37866 | 160 | // Type accessors. |
81345200 | 161 | TypeInfo typeInfo() const { ASSERT(structure()->classInfo() == info()); return m_blob.typeInfo(m_outOfLineTypeFlags); } |
93a37866 A |
162 | bool isObject() const { return typeInfo().isObject(); } |
163 | ||
81345200 A |
164 | IndexingType indexingType() const { return m_blob.indexingType() & AllArrayTypes; } |
165 | IndexingType indexingTypeIncludingHistory() const { return m_blob.indexingType(); } | |
f9bf01c6 | 166 | |
93a37866 A |
167 | bool mayInterceptIndexedAccesses() const |
168 | { | |
169 | return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors); | |
170 | } | |
f9bf01c6 | 171 | |
93a37866 | 172 | bool anyObjectInChainMayInterceptIndexedAccesses() const; |
81345200 | 173 | bool holesMustForwardToPrototype(VM&) const; |
6fe7ccc8 | 174 | |
93a37866 A |
175 | bool needsSlowPutIndexing() const; |
176 | NonPropertyTransition suggestedArrayStorageTransition() const; | |
ba379fdc | 177 | |
93a37866 A |
178 | JSGlobalObject* globalObject() const { return m_globalObject.get(); } |
179 | void setGlobalObject(VM& vm, JSGlobalObject* globalObject) { m_globalObject.set(vm, this, globalObject); } | |
6fe7ccc8 | 180 | |
93a37866 | 181 | JSValue storedPrototype() const { return m_prototype.get(); } |
81345200 A |
182 | JSObject* storedPrototypeObject() const; |
183 | Structure* storedPrototypeStructure() const; | |
93a37866 A |
184 | JSValue prototypeForLookup(ExecState*) const; |
185 | JSValue prototypeForLookup(JSGlobalObject*) const; | |
186 | JSValue prototypeForLookup(CodeBlock*) const; | |
187 | StructureChain* prototypeChain(VM&, JSGlobalObject*) const; | |
188 | StructureChain* prototypeChain(ExecState*) const; | |
189 | static void visitChildren(JSCell*, SlotVisitor&); | |
190 | ||
191 | // Will just the prototype chain intercept this property access? | |
192 | bool prototypeChainMayInterceptStoreTo(VM&, PropertyName); | |
193 | ||
194 | bool transitionDidInvolveSpecificValue() const { return !!m_specificValueInPrevious; } | |
195 | ||
196 | Structure* previousID() const | |
197 | { | |
81345200 A |
198 | ASSERT(structure()->classInfo() == info()); |
199 | if (m_hasRareData) | |
93a37866 A |
200 | return rareData()->previousID(); |
201 | return previous(); | |
202 | } | |
203 | bool transitivelyTransitionedFrom(Structure* structureToFind); | |
9dae56ea | 204 | |
93a37866 A |
205 | unsigned outOfLineCapacity() const |
206 | { | |
207 | ASSERT(checkOffsetConsistency()); | |
208 | ||
209 | unsigned outOfLineSize = this->outOfLineSize(); | |
f9bf01c6 | 210 | |
93a37866 A |
211 | if (!outOfLineSize) |
212 | return 0; | |
9dae56ea | 213 | |
93a37866 A |
214 | if (outOfLineSize <= initialOutOfLineCapacity) |
215 | return initialOutOfLineCapacity; | |
9dae56ea | 216 | |
93a37866 A |
217 | ASSERT(outOfLineSize > initialOutOfLineCapacity); |
218 | COMPILE_ASSERT(outOfLineGrowthFactor == 2, outOfLineGrowthFactor_is_two); | |
219 | return WTF::roundUpToPowerOfTwo(outOfLineSize); | |
220 | } | |
221 | unsigned outOfLineSize() const | |
222 | { | |
223 | ASSERT(checkOffsetConsistency()); | |
81345200 | 224 | ASSERT(structure()->classInfo() == info()); |
93a37866 A |
225 | |
226 | return numberOfOutOfLineSlotsForLastOffset(m_offset); | |
227 | } | |
228 | bool hasInlineStorage() const | |
229 | { | |
230 | return !!m_inlineCapacity; | |
231 | } | |
232 | unsigned inlineCapacity() const | |
233 | { | |
234 | return m_inlineCapacity; | |
235 | } | |
236 | unsigned inlineSize() const | |
237 | { | |
238 | return std::min<unsigned>(m_offset + 1, m_inlineCapacity); | |
239 | } | |
240 | unsigned totalStorageSize() const | |
241 | { | |
242 | return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity); | |
243 | } | |
244 | unsigned totalStorageCapacity() const | |
245 | { | |
81345200 | 246 | ASSERT(structure()->classInfo() == info()); |
93a37866 A |
247 | return outOfLineCapacity() + inlineCapacity(); |
248 | } | |
9dae56ea | 249 | |
81345200 | 250 | bool isValidOffset(PropertyOffset offset) const |
93a37866 | 251 | { |
81345200 A |
252 | return JSC::isValidOffset(offset) |
253 | && offset <= m_offset | |
254 | && (offset < m_inlineCapacity || offset >= firstOutOfLineOffset); | |
93a37866 | 255 | } |
81345200 A |
256 | |
257 | bool couldHaveIndexingHeader() const | |
93a37866 | 258 | { |
81345200 A |
259 | return hasIndexedProperties(indexingType()) |
260 | || isTypedView(m_classInfo->typedArrayStorageType); | |
93a37866 | 261 | } |
81345200 A |
262 | |
263 | bool hasIndexingHeader(const JSCell*) const; | |
264 | ||
93a37866 | 265 | bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject); |
14957cd0 | 266 | |
93a37866 A |
267 | PropertyOffset get(VM&, PropertyName); |
268 | PropertyOffset get(VM&, const WTF::String& name); | |
81345200 A |
269 | PropertyOffset get(VM&, PropertyName, unsigned& attributes, JSCell*& specificValue); |
270 | ||
271 | PropertyOffset getConcurrently(VM&, StringImpl* uid); | |
272 | PropertyOffset getConcurrently(VM&, StringImpl* uid, unsigned& attributes, JSCell*& specificValue); | |
9dae56ea | 273 | |
93a37866 A |
274 | bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; } |
275 | bool hasReadOnlyOrGetterSetterPropertiesExcludingProto() const { return m_hasReadOnlyOrGetterSetterPropertiesExcludingProto; } | |
276 | void setHasGetterSetterProperties(bool is__proto__) | |
277 | { | |
278 | m_hasGetterSetterProperties = true; | |
279 | if (!is__proto__) | |
280 | m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; | |
281 | } | |
81345200 A |
282 | |
283 | bool hasCustomGetterSetterProperties() const { return m_hasCustomGetterSetterProperties; } | |
284 | void setHasCustomGetterSetterProperties(bool is__proto__) | |
285 | { | |
286 | m_hasCustomGetterSetterProperties = true; | |
287 | if (!is__proto__) | |
288 | m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; | |
289 | } | |
290 | ||
93a37866 A |
291 | void setContainsReadOnlyProperties() |
292 | { | |
293 | m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; | |
294 | } | |
f9bf01c6 | 295 | |
93a37866 A |
296 | bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; } |
297 | ||
298 | bool isEmpty() const | |
299 | { | |
300 | ASSERT(checkOffsetConsistency()); | |
301 | return !JSC::isValidOffset(m_offset); | |
302 | } | |
6fe7ccc8 | 303 | |
93a37866 A |
304 | JS_EXPORT_PRIVATE void despecifyDictionaryFunction(VM&, PropertyName); |
305 | void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; } | |
9dae56ea | 306 | |
93a37866 A |
307 | void setEnumerationCache(VM&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h. |
308 | JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h. | |
309 | void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode); | |
9dae56ea | 310 | |
93a37866 | 311 | JSString* objectToStringValue() |
9dae56ea | 312 | { |
81345200 | 313 | if (!m_hasRareData) |
93a37866 A |
314 | return 0; |
315 | return rareData()->objectToStringValue(); | |
14957cd0 | 316 | } |
9dae56ea | 317 | |
81345200 | 318 | void setObjectToStringValue(VM& vm, JSString* value) |
6fe7ccc8 | 319 | { |
81345200 | 320 | if (!m_hasRareData) |
93a37866 | 321 | allocateRareData(vm); |
81345200 | 322 | rareData()->setObjectToStringValue(vm, value); |
6fe7ccc8 | 323 | } |
93a37866 A |
324 | |
325 | bool staticFunctionsReified() | |
14957cd0 | 326 | { |
93a37866 | 327 | return m_staticFunctionReified; |
14957cd0 | 328 | } |
9dae56ea | 329 | |
93a37866 | 330 | void setStaticFunctionsReified() |
14957cd0 | 331 | { |
93a37866 | 332 | m_staticFunctionReified = true; |
14957cd0 | 333 | } |
9dae56ea | 334 | |
93a37866 A |
335 | const ClassInfo* classInfo() const { return m_classInfo; } |
336 | ||
81345200 A |
337 | static ptrdiff_t structureIDOffset() |
338 | { | |
339 | return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::structureIDOffset(); | |
340 | } | |
341 | ||
93a37866 | 342 | static ptrdiff_t prototypeOffset() |
14957cd0 | 343 | { |
93a37866 | 344 | return OBJECT_OFFSETOF(Structure, m_prototype); |
14957cd0 | 345 | } |
9dae56ea | 346 | |
93a37866 | 347 | static ptrdiff_t globalObjectOffset() |
14957cd0 | 348 | { |
93a37866 | 349 | return OBJECT_OFFSETOF(Structure, m_globalObject); |
14957cd0 | 350 | } |
9dae56ea | 351 | |
93a37866 A |
352 | static ptrdiff_t classInfoOffset() |
353 | { | |
354 | return OBJECT_OFFSETOF(Structure, m_classInfo); | |
355 | } | |
356 | ||
357 | static ptrdiff_t indexingTypeOffset() | |
6fe7ccc8 | 358 | { |
81345200 | 359 | return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingTypeOffset(); |
14957cd0 | 360 | } |
9dae56ea | 361 | |
93a37866 A |
362 | static Structure* createStructure(VM&); |
363 | ||
364 | bool transitionWatchpointSetHasBeenInvalidated() const | |
14957cd0 | 365 | { |
93a37866 A |
366 | return m_transitionWatchpointSet.hasBeenInvalidated(); |
367 | } | |
6fe7ccc8 | 368 | |
93a37866 A |
369 | bool transitionWatchpointSetIsStillValid() const |
370 | { | |
371 | return m_transitionWatchpointSet.isStillValid(); | |
372 | } | |
6fe7ccc8 | 373 | |
93a37866 A |
374 | void addTransitionWatchpoint(Watchpoint* watchpoint) const |
375 | { | |
376 | ASSERT(transitionWatchpointSetIsStillValid()); | |
377 | m_transitionWatchpointSet.add(watchpoint); | |
14957cd0 | 378 | } |
93a37866 A |
379 | |
380 | void notifyTransitionFromThisStructure() const | |
381 | { | |
81345200 | 382 | m_transitionWatchpointSet.fireAll(); |
93a37866 | 383 | } |
81345200 A |
384 | |
385 | InlineWatchpointSet& transitionWatchpointSet() const | |
386 | { | |
387 | return m_transitionWatchpointSet; | |
388 | } | |
389 | ||
390 | void dump(PrintStream&) const; | |
391 | void dumpInContext(PrintStream&, DumpContext*) const; | |
392 | void dumpBrief(PrintStream&, const CString&) const; | |
393 | ||
394 | static void dumpContextHeader(PrintStream&); | |
395 | ||
396 | DECLARE_EXPORT_INFO; | |
93a37866 A |
397 | |
398 | private: | |
399 | friend class LLIntOffsetsExtractor; | |
9dae56ea | 400 | |
93a37866 A |
401 | JS_EXPORT_PRIVATE Structure(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, unsigned inlineCapacity); |
402 | Structure(VM&); | |
81345200 A |
403 | Structure(VM&, Structure*); |
404 | ||
405 | static Structure* create(VM&, Structure*); | |
406 | ||
407 | static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset&); | |
408 | ||
409 | // This will return the structure that has a usable property table, that property table, | |
410 | // and the list of structures that we visited before we got to it. If it returns a | |
411 | // non-null structure, it will also lock the structure that it returns; it is your job | |
412 | // to unlock it. | |
413 | void findStructuresAndMapForMaterialization(Vector<Structure*, 8>& structures, Structure*&, PropertyTable*&); | |
414 | ||
93a37866 A |
415 | typedef enum { |
416 | NoneDictionaryKind = 0, | |
417 | CachedDictionaryKind = 1, | |
418 | UncachedDictionaryKind = 2 | |
419 | } DictionaryKind; | |
420 | static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind); | |
421 | ||
422 | PropertyOffset putSpecificValue(VM&, PropertyName, unsigned attributes, JSCell* specificValue); | |
423 | PropertyOffset remove(PropertyName); | |
424 | ||
81345200 | 425 | void createPropertyMap(const GCSafeConcurrentJITLocker&, VM&, unsigned keyCount = 0); |
93a37866 A |
426 | void checkConsistency(); |
427 | ||
428 | bool despecifyFunction(VM&, PropertyName); | |
429 | void despecifyAllFunctions(VM&); | |
430 | ||
431 | WriteBarrier<PropertyTable>& propertyTable(); | |
81345200 A |
432 | PropertyTable* takePropertyTableOrCloneIfPinned(VM&); |
433 | PropertyTable* copyPropertyTable(VM&); | |
434 | PropertyTable* copyPropertyTableForPinning(VM&); | |
93a37866 | 435 | JS_EXPORT_PRIVATE void materializePropertyMap(VM&); |
81345200 | 436 | ALWAYS_INLINE void materializePropertyMapIfNecessary(VM& vm, DeferGC&) |
14957cd0 | 437 | { |
81345200 A |
438 | ASSERT(!isCompilationThread()); |
439 | ASSERT(structure()->classInfo() == info()); | |
93a37866 A |
440 | ASSERT(checkOffsetConsistency()); |
441 | if (!propertyTable() && previousID()) | |
442 | materializePropertyMap(vm); | |
443 | } | |
81345200 | 444 | ALWAYS_INLINE void materializePropertyMapIfNecessary(VM& vm, PropertyTable*& table) |
93a37866 | 445 | { |
81345200 A |
446 | ASSERT(!isCompilationThread()); |
447 | ASSERT(structure()->classInfo() == info()); | |
448 | ASSERT(checkOffsetConsistency()); | |
449 | table = propertyTable().get(); | |
450 | if (!table && previousID()) { | |
451 | DeferGC deferGC(vm.heap); | |
452 | materializePropertyMap(vm); | |
453 | table = propertyTable().get(); | |
454 | } | |
455 | } | |
456 | void materializePropertyMapIfNecessaryForPinning(VM& vm, DeferGC&) | |
457 | { | |
458 | ASSERT(structure()->classInfo() == info()); | |
93a37866 A |
459 | checkOffsetConsistency(); |
460 | if (!propertyTable()) | |
461 | materializePropertyMap(vm); | |
9dae56ea A |
462 | } |
463 | ||
81345200 | 464 | void setPreviousID(VM& vm, Structure* structure) |
6fe7ccc8 | 465 | { |
81345200 A |
466 | if (m_hasRareData) |
467 | rareData()->setPreviousID(vm, structure); | |
93a37866 | 468 | else |
81345200 | 469 | m_previousOrRareData.set(vm, this, structure); |
6fe7ccc8 A |
470 | } |
471 | ||
93a37866 | 472 | void clearPreviousID() |
6fe7ccc8 | 473 | { |
81345200 | 474 | if (m_hasRareData) |
93a37866 A |
475 | rareData()->clearPreviousID(); |
476 | else | |
477 | m_previousOrRareData.clear(); | |
6fe7ccc8 A |
478 | } |
479 | ||
93a37866 | 480 | int transitionCount() const |
6fe7ccc8 | 481 | { |
93a37866 A |
482 | // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both. |
483 | return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity); | |
6fe7ccc8 A |
484 | } |
485 | ||
93a37866 A |
486 | bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain) const; |
487 | bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const; | |
488 | ||
489 | void pin(); | |
490 | ||
491 | Structure* previous() const | |
492 | { | |
81345200 | 493 | ASSERT(!m_hasRareData); |
93a37866 A |
494 | return static_cast<Structure*>(m_previousOrRareData.get()); |
495 | } | |
496 | ||
497 | StructureRareData* rareData() const | |
498 | { | |
81345200 | 499 | ASSERT(m_hasRareData); |
93a37866 A |
500 | return static_cast<StructureRareData*>(m_previousOrRareData.get()); |
501 | } | |
502 | ||
503 | bool checkOffsetConsistency() const; | |
504 | ||
505 | void allocateRareData(VM&); | |
506 | void cloneRareDataFrom(VM&, const Structure*); | |
507 | ||
508 | static const int s_maxTransitionLength = 64; | |
81345200 | 509 | static const int s_maxTransitionLengthForNonEvalPutById = 512; |
93a37866 A |
510 | |
511 | static const unsigned maxSpecificFunctionThrashCount = 3; | |
81345200 A |
512 | |
513 | // These need to be properly aligned at the beginning of the 'Structure' | |
514 | // part of the object. | |
515 | StructureIDBlob m_blob; | |
516 | TypeInfo::OutOfLineTypeFlags m_outOfLineTypeFlags; | |
517 | ||
93a37866 A |
518 | WriteBarrier<JSGlobalObject> m_globalObject; |
519 | WriteBarrier<Unknown> m_prototype; | |
520 | mutable WriteBarrier<StructureChain> m_cachedPrototypeChain; | |
521 | ||
522 | WriteBarrier<JSCell> m_previousOrRareData; | |
523 | ||
524 | RefPtr<StringImpl> m_nameInPrevious; | |
525 | WriteBarrier<JSCell> m_specificValueInPrevious; | |
526 | ||
527 | const ClassInfo* m_classInfo; | |
528 | ||
529 | StructureTransitionTable m_transitionTable; | |
530 | ||
531 | // Should be accessed through propertyTable(). During GC, it may be set to 0 by another thread. | |
532 | WriteBarrier<PropertyTable> m_propertyTableUnsafe; | |
533 | ||
534 | mutable InlineWatchpointSet m_transitionWatchpointSet; | |
535 | ||
536 | COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits); | |
537 | ||
538 | // m_offset does not account for anonymous slots | |
539 | PropertyOffset m_offset; | |
540 | ||
93a37866 | 541 | uint8_t m_inlineCapacity; |
81345200 A |
542 | |
543 | ConcurrentJITLock m_lock; | |
544 | ||
93a37866 | 545 | unsigned m_dictionaryKind : 2; |
81345200 | 546 | bool m_hasBeenFlattenedBefore : 1; |
93a37866 A |
547 | bool m_isPinnedPropertyTable : 1; |
548 | bool m_hasGetterSetterProperties : 1; | |
81345200 | 549 | bool m_hasCustomGetterSetterProperties : 1; |
93a37866 A |
550 | bool m_hasReadOnlyOrGetterSetterPropertiesExcludingProto : 1; |
551 | bool m_hasNonEnumerableProperties : 1; | |
552 | unsigned m_attributesInPrevious : 14; | |
553 | unsigned m_specificFunctionThrashCount : 2; | |
554 | unsigned m_preventExtensions : 1; | |
555 | unsigned m_didTransition : 1; | |
81345200 A |
556 | unsigned m_staticFunctionReified : 1; |
557 | bool m_hasRareData : 1; | |
93a37866 A |
558 | }; |
559 | ||
9dae56ea A |
560 | } // namespace JSC |
561 | ||
562 | #endif // Structure_h |