2 * Copyright (C) 2013, 2014 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
, PropertyName propertyName
, unsigned& attributes
)
91 ASSERT(!isCompilationThread());
92 ASSERT(structure()->classInfo() == info());
94 PropertyTable
* propertyTable
;
95 materializePropertyMapIfNecessary(vm
, propertyTable
);
99 PropertyMapEntry
* entry
= propertyTable
->get(propertyName
.uid());
101 return invalidOffset
;
103 attributes
= entry
->attributes
;
104 return entry
->offset
;
107 template<typename Functor
>
108 void Structure::forEachPropertyConcurrently(const Functor
& functor
)
110 Vector
<Structure
*, 8> structures
;
111 Structure
* structure
;
112 PropertyTable
* table
;
114 findStructuresAndMapForMaterialization(structures
, structure
, table
);
117 for (auto& entry
: *table
) {
118 if (!functor(entry
)) {
119 structure
->m_lock
.unlock();
123 structure
->m_lock
.unlock();
126 for (unsigned i
= structures
.size(); i
--;) {
127 structure
= structures
[i
];
128 if (!structure
->m_nameInPrevious
)
131 if (!functor(PropertyMapEntry(structure
->m_nameInPrevious
.get(), structure
->m_offset
, structure
->attributesInPrevious())))
136 inline PropertyOffset
Structure::getConcurrently(UniquedStringImpl
* uid
)
138 unsigned attributesIgnored
;
139 return getConcurrently(uid
, attributesIgnored
);
142 inline bool Structure::hasIndexingHeader(const JSCell
* cell
) const
144 if (hasIndexedProperties(indexingType()))
147 if (!isTypedView(m_classInfo
->typedArrayStorageType
))
150 return jsCast
<const JSArrayBufferView
*>(cell
)->mode() == WastefulTypedArray
;
153 inline bool Structure::masqueradesAsUndefined(JSGlobalObject
* lexicalGlobalObject
)
155 return typeInfo().masqueradesAsUndefined() && globalObject() == lexicalGlobalObject
;
158 inline bool Structure::transitivelyTransitionedFrom(Structure
* structureToFind
)
160 for (Structure
* current
= this; current
; current
= current
->previousID()) {
161 if (current
== structureToFind
)
167 inline JSValue
Structure::prototypeForLookup(JSGlobalObject
* globalObject
) const
170 return m_prototype
.get();
171 if (typeInfo().type() == SymbolType
)
172 return globalObject
->symbolPrototype();
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 inline void Structure::didReplaceProperty(PropertyOffset offset
)
247 if (LIKELY(!hasRareData()))
249 StructureRareData::PropertyWatchpointMap
* map
= rareData()->m_replacementWatchpointSets
.get();
252 WatchpointSet
* set
= map
->get(offset
);
255 set
->fireAll("Property did get replaced");
258 inline WatchpointSet
* Structure::propertyReplacementWatchpointSet(PropertyOffset offset
)
260 ConcurrentJITLocker
locker(m_lock
);
263 WTF::loadLoadFence();
264 StructureRareData::PropertyWatchpointMap
* map
= rareData()->m_replacementWatchpointSets
.get();
267 return map
->get(offset
);
270 ALWAYS_INLINE
bool Structure::checkOffsetConsistency() const
272 PropertyTable
* propertyTable
= m_propertyTableUnsafe
.get();
274 if (!propertyTable
) {
275 ASSERT(!isPinnedPropertyTable());
279 // We cannot reliably assert things about the property table in the concurrent
280 // compilation thread. It is possible for the table to be stolen and then have
281 // things added to it, which leads to the offsets being all messed up. We could
282 // get around this by grabbing a lock here, but I think that would be overkill.
283 if (isCompilationThread())
286 RELEASE_ASSERT(numberOfSlotsForLastOffset(m_offset
, m_inlineCapacity
) == propertyTable
->propertyStorageSize());
287 unsigned totalSize
= propertyTable
->propertyStorageSize();
288 RELEASE_ASSERT((totalSize
< inlineCapacity() ? 0 : totalSize
- inlineCapacity()) == numberOfOutOfLineSlotsForLastOffset(m_offset
));
293 inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity
)
295 if (!currentCapacity
)
296 return initialOutOfLineCapacity
;
297 return currentCapacity
* outOfLineGrowthFactor
;
300 inline size_t Structure::suggestedNewOutOfLineStorageCapacity()
302 return nextOutOfLineStorageCapacity(outOfLineCapacity());
307 #endif // StructureInlines_h