Structure::get should instantiate DeferGC only when materializing property map
[WebKit-https.git] / Source / JavaScriptCore / runtime / StructureInlines.h
1 /*
2  * Copyright (C) 2013 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 #ifndef StructureInlines_h
27 #define StructureInlines_h
28
29 #include "JSArrayBufferView.h"
30 #include "PropertyMapHashTable.h"
31 #include "Structure.h"
32
33 namespace JSC {
34
35 inline Structure* Structure::create(VM& vm, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity)
36 {
37     ASSERT(vm.structureStructure);
38     ASSERT(classInfo);
39     Structure* structure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, globalObject, prototype, typeInfo, classInfo, indexingType, inlineCapacity);
40     structure->finishCreation(vm);
41     return structure;
42 }
43
44 inline Structure* Structure::createStructure(VM& vm)
45 {
46     ASSERT(!vm.structureStructure);
47     Structure* structure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm);
48     structure->finishCreation(vm, CreatingEarlyCell);
49     return structure;
50 }
51
52 inline Structure* Structure::create(VM& vm, Structure* structure)
53 {
54     ASSERT(vm.structureStructure);
55     Structure* newStructure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, structure);
56     newStructure->finishCreation(vm);
57     return newStructure;
58 }
59
60 inline JSObject* Structure::storedPrototypeObject() const
61 {
62     JSValue value = m_prototype.get();
63     if (value.isNull())
64         return 0;
65     return asObject(value);
66 }
67
68 inline Structure* Structure::storedPrototypeStructure() const
69 {
70     JSObject* object = storedPrototypeObject();
71     if (!object)
72         return 0;
73     return object->structure();
74 }
75
76 inline PropertyOffset Structure::get(VM& vm, PropertyName propertyName)
77 {
78     ASSERT(!isCompilationThread());
79     ASSERT(structure()->classInfo() == info());
80     PropertyTable* propertyTable;
81     materializePropertyMapIfNecessary(vm, propertyTable);
82     if (!propertyTable)
83         return invalidOffset;
84
85     PropertyMapEntry* entry = propertyTable->get(propertyName.uid());
86     return entry ? entry->offset : invalidOffset;
87 }
88
89 inline PropertyOffset Structure::get(VM& vm, const WTF::String& name)
90 {
91     ASSERT(!isCompilationThread());
92     ASSERT(structure()->classInfo() == info());
93     PropertyTable* propertyTable;
94     materializePropertyMapIfNecessary(vm, propertyTable);
95     if (!propertyTable)
96         return invalidOffset;
97
98     PropertyMapEntry* entry = propertyTable->findWithString(name.impl()).first;
99     return entry ? entry->offset : invalidOffset;
100 }
101     
102 inline PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attributes, JSCell*& specificValue)
103 {
104     ASSERT(!isCompilationThread());
105     ASSERT(structure()->classInfo() == info());
106
107     PropertyTable* propertyTable;
108     materializePropertyMapIfNecessary(vm, propertyTable);
109     if (!propertyTable)
110         return invalidOffset;
111
112     PropertyMapEntry* entry = propertyTable->get(propertyName.uid());
113     if (!entry)
114         return invalidOffset;
115
116     attributes = entry->attributes;
117     specificValue = entry->specificValue.get();
118     return entry->offset;
119 }
120
121 inline PropertyOffset Structure::getConcurrently(VM& vm, StringImpl* uid)
122 {
123     unsigned attributesIgnored;
124     JSCell* specificValueIgnored;
125     return getConcurrently(
126         vm, uid, attributesIgnored, specificValueIgnored);
127 }
128
129 inline bool Structure::hasIndexingHeader(const JSCell* cell) const
130 {
131     if (hasIndexedProperties(indexingType()))
132         return true;
133     
134     if (!isTypedView(m_classInfo->typedArrayStorageType))
135         return false;
136     
137     return jsCast<const JSArrayBufferView*>(cell)->mode() == WastefulTypedArray;
138 }
139
140 inline bool Structure::masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject)
141 {
142     return typeInfo().masqueradesAsUndefined() && globalObject() == lexicalGlobalObject;
143 }
144
145 inline bool Structure::transitivelyTransitionedFrom(Structure* structureToFind)
146 {
147     for (Structure* current = this; current; current = current->previousID()) {
148         if (current == structureToFind)
149             return true;
150     }
151     return false;
152 }
153
154 inline void Structure::setEnumerationCache(VM& vm, JSPropertyNameIterator* enumerationCache)
155 {
156     ASSERT(!isDictionary());
157     if (!typeInfo().structureHasRareData())
158         allocateRareData(vm);
159     rareData()->setEnumerationCache(vm, this, enumerationCache);
160 }
161
162 inline JSPropertyNameIterator* Structure::enumerationCache()
163 {
164     if (!typeInfo().structureHasRareData())
165         return 0;
166     return rareData()->enumerationCache();
167 }
168
169 inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject) const
170 {
171     if (isObject())
172         return m_prototype.get();
173
174     ASSERT(typeInfo().type() == StringType);
175     return globalObject->stringPrototype();
176 }
177
178 inline JSValue Structure::prototypeForLookup(ExecState* exec) const
179 {
180     return prototypeForLookup(exec->lexicalGlobalObject());
181 }
182
183 inline StructureChain* Structure::prototypeChain(VM& vm, JSGlobalObject* globalObject) const
184 {
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()));
189     }
190     return m_cachedPrototypeChain.get();
191 }
192
193 inline StructureChain* Structure::prototypeChain(ExecState* exec) const
194 {
195     return prototypeChain(exec->vm(), exec->lexicalGlobalObject());
196 }
197
198 inline bool Structure::isValid(JSGlobalObject* globalObject, StructureChain* cachedPrototypeChain) const
199 {
200     if (!cachedPrototypeChain)
201         return false;
202
203     JSValue prototype = prototypeForLookup(globalObject);
204     WriteBarrier<Structure>* cachedStructure = cachedPrototypeChain->head();
205     while (*cachedStructure && !prototype.isNull()) {
206         if (asObject(prototype)->structure() != cachedStructure->get())
207             return false;
208         ++cachedStructure;
209         prototype = asObject(prototype)->prototype();
210     }
211     return prototype.isNull() && !*cachedStructure;
212 }
213
214 inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
215 {
216     return isValid(exec->lexicalGlobalObject(), cachedPrototypeChain);
217 }
218
219 inline bool Structure::putWillGrowOutOfLineStorage()
220 {
221     checkOffsetConsistency();
222
223     ASSERT(outOfLineCapacity() >= outOfLineSize());
224
225     if (!propertyTable()) {
226         unsigned currentSize = numberOfOutOfLineSlotsForLastOffset(m_offset);
227         ASSERT(outOfLineCapacity() >= currentSize);
228         return currentSize == outOfLineCapacity();
229     }
230
231     ASSERT(totalStorageCapacity() >= propertyTable()->propertyStorageSize());
232     if (propertyTable()->hasDeletedOffset())
233         return false;
234
235     ASSERT(totalStorageCapacity() >= propertyTable()->size());
236     return propertyTable()->size() == totalStorageCapacity();
237 }
238
239 ALWAYS_INLINE WriteBarrier<PropertyTable>& Structure::propertyTable()
240 {
241     ASSERT(!globalObject() || !globalObject()->vm().heap.isCollecting());
242     return m_propertyTableUnsafe;
243 }
244
245 ALWAYS_INLINE bool Structure::checkOffsetConsistency() const
246 {
247     PropertyTable* propertyTable = m_propertyTableUnsafe.get();
248
249     if (!propertyTable) {
250         ASSERT(!m_isPinnedPropertyTable);
251         return true;
252     }
253
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())
259         return true;
260     
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));
264
265     return true;
266 }
267
268 inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity)
269 {
270     if (!currentCapacity)
271         return initialOutOfLineCapacity;
272     return currentCapacity * outOfLineGrowthFactor;
273 }
274
275 inline size_t Structure::suggestedNewOutOfLineStorageCapacity()
276 {
277     return nextOutOfLineStorageCapacity(outOfLineCapacity());
278 }
279
280 } // namespace JSC
281
282 #endif // StructureInlines_h
283