2 * Copyright (C) 2013 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.
26 #ifndef StructureInlines_h
27 #define StructureInlines_h
29 #include "JSArrayBufferView.h"
30 #include "PropertyMapHashTable.h"
31 #include "Structure.h"
35 inline Structure
* Structure::create(VM
& vm
, JSGlobalObject
* globalObject
, JSValue prototype
, const TypeInfo
& typeInfo
, const ClassInfo
* classInfo
, IndexingType indexingType
, unsigned inlineCapacity
)
37 ASSERT(vm
.structureStructure
);
39 Structure
* structure
= new (NotNull
, allocateCell
<Structure
>(vm
.heap
)) Structure(vm
, globalObject
, prototype
, typeInfo
, classInfo
, indexingType
, inlineCapacity
);
40 structure
->finishCreation(vm
);
44 inline Structure
* Structure::createStructure(VM
& vm
)
46 ASSERT(!vm
.structureStructure
);
47 Structure
* structure
= new (NotNull
, allocateCell
<Structure
>(vm
.heap
)) Structure(vm
);
48 structure
->finishCreation(vm
, CreatingEarlyCell
);
52 inline Structure
* Structure::create(VM
& vm
, Structure
* structure
)
54 ASSERT(vm
.structureStructure
);
55 Structure
* newStructure
= new (NotNull
, allocateCell
<Structure
>(vm
.heap
)) Structure(vm
, structure
);
56 newStructure
->finishCreation(vm
);
60 inline JSObject
* Structure::storedPrototypeObject() const
62 JSValue value
= m_prototype
.get();
65 return asObject(value
);
68 inline Structure
* Structure::storedPrototypeStructure() const
70 JSObject
* object
= storedPrototypeObject();
73 return object
->structure();
76 ALWAYS_INLINE PropertyOffset
Structure::get(VM
& vm
, PropertyName propertyName
)
78 ASSERT(!isCompilationThread());
79 ASSERT(structure()->classInfo() == info());
80 PropertyTable
* propertyTable
;
81 materializePropertyMapIfNecessary(vm
, propertyTable
);
85 PropertyMapEntry
* entry
= propertyTable
->get(propertyName
.uid());
86 return entry
? entry
->offset
: invalidOffset
;
89 ALWAYS_INLINE PropertyOffset
Structure::get(VM
& vm
, const WTF::String
& name
)
91 ASSERT(!isCompilationThread());
92 ASSERT(structure()->classInfo() == info());
93 PropertyTable
* propertyTable
;
94 materializePropertyMapIfNecessary(vm
, propertyTable
);
98 PropertyMapEntry
* entry
= propertyTable
->findWithString(name
.impl()).first
;
99 return entry
? entry
->offset
: invalidOffset
;
102 ALWAYS_INLINE PropertyOffset
Structure::get(VM
& vm
, PropertyName propertyName
, unsigned& attributes
, JSCell
*& specificValue
)
104 ASSERT(!isCompilationThread());
105 ASSERT(structure()->classInfo() == info());
107 PropertyTable
* propertyTable
;
108 materializePropertyMapIfNecessary(vm
, propertyTable
);
110 return invalidOffset
;
112 PropertyMapEntry
* entry
= propertyTable
->get(propertyName
.uid());
114 return invalidOffset
;
116 attributes
= entry
->attributes
;
117 specificValue
= entry
->specificValue
.get();
118 return entry
->offset
;
121 inline PropertyOffset
Structure::getConcurrently(VM
& vm
, StringImpl
* uid
)
123 unsigned attributesIgnored
;
124 JSCell
* specificValueIgnored
;
125 return getConcurrently(
126 vm
, uid
, attributesIgnored
, specificValueIgnored
);
129 inline bool Structure::hasIndexingHeader(const JSCell
* cell
) const
131 if (hasIndexedProperties(indexingType()))
134 if (!isTypedView(m_classInfo
->typedArrayStorageType
))
137 return jsCast
<const JSArrayBufferView
*>(cell
)->mode() == WastefulTypedArray
;
140 inline bool Structure::masqueradesAsUndefined(JSGlobalObject
* lexicalGlobalObject
)
142 return typeInfo().masqueradesAsUndefined() && globalObject() == lexicalGlobalObject
;
145 inline bool Structure::transitivelyTransitionedFrom(Structure
* structureToFind
)
147 for (Structure
* current
= this; current
; current
= current
->previousID()) {
148 if (current
== structureToFind
)
154 inline void Structure::setEnumerationCache(VM
& vm
, JSPropertyNameIterator
* enumerationCache
)
156 ASSERT(!isDictionary());
158 allocateRareData(vm
);
159 rareData()->setEnumerationCache(vm
, enumerationCache
);
162 inline JSPropertyNameIterator
* Structure::enumerationCache()
166 return rareData()->enumerationCache();
169 inline JSValue
Structure::prototypeForLookup(JSGlobalObject
* globalObject
) const
172 return m_prototype
.get();
174 ASSERT(typeInfo().type() == StringType
);
175 return globalObject
->stringPrototype();
178 inline JSValue
Structure::prototypeForLookup(ExecState
* exec
) const
180 return prototypeForLookup(exec
->lexicalGlobalObject());
183 inline StructureChain
* Structure::prototypeChain(VM
& vm
, JSGlobalObject
* globalObject
) const
185 // We cache our prototype chain so our clients can share it.
186 if (!isValid(globalObject
, m_cachedPrototypeChain
.get())) {
187 JSValue prototype
= prototypeForLookup(globalObject
);
188 m_cachedPrototypeChain
.set(vm
, this, StructureChain::create(vm
, prototype
.isNull() ? 0 : asObject(prototype
)->structure()));
190 return m_cachedPrototypeChain
.get();
193 inline StructureChain
* Structure::prototypeChain(ExecState
* exec
) const
195 return prototypeChain(exec
->vm(), exec
->lexicalGlobalObject());
198 inline bool Structure::isValid(JSGlobalObject
* globalObject
, StructureChain
* cachedPrototypeChain
) const
200 if (!cachedPrototypeChain
)
203 JSValue prototype
= prototypeForLookup(globalObject
);
204 WriteBarrier
<Structure
>* cachedStructure
= cachedPrototypeChain
->head();
205 while (*cachedStructure
&& !prototype
.isNull()) {
206 if (asObject(prototype
)->structure() != cachedStructure
->get())
209 prototype
= asObject(prototype
)->prototype();
211 return prototype
.isNull() && !*cachedStructure
;
214 inline bool Structure::isValid(ExecState
* exec
, StructureChain
* cachedPrototypeChain
) const
216 return isValid(exec
->lexicalGlobalObject(), cachedPrototypeChain
);
219 inline bool Structure::putWillGrowOutOfLineStorage()
221 checkOffsetConsistency();
223 ASSERT(outOfLineCapacity() >= outOfLineSize());
225 if (!propertyTable()) {
226 unsigned currentSize
= numberOfOutOfLineSlotsForLastOffset(m_offset
);
227 ASSERT(outOfLineCapacity() >= currentSize
);
228 return currentSize
== outOfLineCapacity();
231 ASSERT(totalStorageCapacity() >= propertyTable()->propertyStorageSize());
232 if (propertyTable()->hasDeletedOffset())
235 ASSERT(totalStorageCapacity() >= propertyTable()->size());
236 return propertyTable()->size() == totalStorageCapacity();
239 ALWAYS_INLINE WriteBarrier
<PropertyTable
>& Structure::propertyTable()
241 ASSERT(!globalObject() || !globalObject()->vm().heap
.isCollecting());
242 return m_propertyTableUnsafe
;
245 ALWAYS_INLINE
bool Structure::checkOffsetConsistency() const
247 PropertyTable
* propertyTable
= m_propertyTableUnsafe
.get();
249 if (!propertyTable
) {
250 ASSERT(!m_isPinnedPropertyTable
);
254 // We cannot reliably assert things about the property table in the concurrent
255 // compilation thread. It is possible for the table to be stolen and then have
256 // things added to it, which leads to the offsets being all messed up. We could
257 // get around this by grabbing a lock here, but I think that would be overkill.
258 if (isCompilationThread())
261 RELEASE_ASSERT(numberOfSlotsForLastOffset(m_offset
, m_inlineCapacity
) == propertyTable
->propertyStorageSize());
262 unsigned totalSize
= propertyTable
->propertyStorageSize();
263 RELEASE_ASSERT((totalSize
< inlineCapacity() ? 0 : totalSize
- inlineCapacity()) == numberOfOutOfLineSlotsForLastOffset(m_offset
));
268 inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity
)
270 if (!currentCapacity
)
271 return initialOutOfLineCapacity
;
272 return currentCapacity
* outOfLineGrowthFactor
;
275 inline size_t Structure::suggestedNewOutOfLineStorageCapacity()
277 return nextOutOfLineStorageCapacity(outOfLineCapacity());
282 #endif // StructureInlines_h