]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/StructureInlines.h
JavaScriptCore-7600.1.4.17.5.tar.gz
[apple/javascriptcore.git] / 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 ALWAYS_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 ALWAYS_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 ALWAYS_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 (!m_hasRareData)
158 allocateRareData(vm);
159 rareData()->setEnumerationCache(vm, enumerationCache);
160 }
161
162 inline JSPropertyNameIterator* Structure::enumerationCache()
163 {
164 if (!m_hasRareData)
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