Optimize own property GetByVals with rope string subscripts.
[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 nullptr;
65     return asObject(value);
66 }
67
68 inline Structure* Structure::storedPrototypeStructure() const
69 {
70     JSObject* object = storedPrototypeObject();
71     if (!object)
72         return nullptr;
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, PropertyName propertyName, unsigned& attributes)
90 {
91     ASSERT(!isCompilationThread());
92     ASSERT(structure()->classInfo() == info());
93
94     PropertyTable* propertyTable;
95     materializePropertyMapIfNecessary(vm, propertyTable);
96     if (!propertyTable)
97         return invalidOffset;
98
99     PropertyMapEntry* entry = propertyTable->get(propertyName.uid());
100     if (!entry)
101         return invalidOffset;
102
103     attributes = entry->attributes;
104     return entry->offset;
105 }
106
107 inline PropertyOffset Structure::getConcurrently(VM& vm, StringImpl* uid)
108 {
109     unsigned attributesIgnored;
110     return getConcurrently(vm, uid, attributesIgnored);
111 }
112
113 inline bool Structure::hasIndexingHeader(const JSCell* cell) const
114 {
115     if (hasIndexedProperties(indexingType()))
116         return true;
117     
118     if (!isTypedView(m_classInfo->typedArrayStorageType))
119         return false;
120     
121     return jsCast<const JSArrayBufferView*>(cell)->mode() == WastefulTypedArray;
122 }
123
124 inline bool Structure::masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject)
125 {
126     return typeInfo().masqueradesAsUndefined() && globalObject() == lexicalGlobalObject;
127 }
128
129 inline bool Structure::transitivelyTransitionedFrom(Structure* structureToFind)
130 {
131     for (Structure* current = this; current; current = current->previousID()) {
132         if (current == structureToFind)
133             return true;
134     }
135     return false;
136 }
137
138 inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject) const
139 {
140     if (isObject())
141         return m_prototype.get();
142
143     ASSERT(typeInfo().type() == StringType);
144     return globalObject->stringPrototype();
145 }
146
147 inline JSValue Structure::prototypeForLookup(ExecState* exec) const
148 {
149     return prototypeForLookup(exec->lexicalGlobalObject());
150 }
151
152 inline StructureChain* Structure::prototypeChain(VM& vm, JSGlobalObject* globalObject) const
153 {
154     // We cache our prototype chain so our clients can share it.
155     if (!isValid(globalObject, m_cachedPrototypeChain.get())) {
156         JSValue prototype = prototypeForLookup(globalObject);
157         m_cachedPrototypeChain.set(vm, this, StructureChain::create(vm, prototype.isNull() ? 0 : asObject(prototype)->structure()));
158     }
159     return m_cachedPrototypeChain.get();
160 }
161
162 inline StructureChain* Structure::prototypeChain(ExecState* exec) const
163 {
164     return prototypeChain(exec->vm(), exec->lexicalGlobalObject());
165 }
166
167 inline bool Structure::isValid(JSGlobalObject* globalObject, StructureChain* cachedPrototypeChain) const
168 {
169     if (!cachedPrototypeChain)
170         return false;
171
172     JSValue prototype = prototypeForLookup(globalObject);
173     WriteBarrier<Structure>* cachedStructure = cachedPrototypeChain->head();
174     while (*cachedStructure && !prototype.isNull()) {
175         if (asObject(prototype)->structure() != cachedStructure->get())
176             return false;
177         ++cachedStructure;
178         prototype = asObject(prototype)->prototype();
179     }
180     return prototype.isNull() && !*cachedStructure;
181 }
182
183 inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
184 {
185     return isValid(exec->lexicalGlobalObject(), cachedPrototypeChain);
186 }
187
188 inline bool Structure::putWillGrowOutOfLineStorage()
189 {
190     checkOffsetConsistency();
191
192     ASSERT(outOfLineCapacity() >= outOfLineSize());
193
194     if (!propertyTable()) {
195         unsigned currentSize = numberOfOutOfLineSlotsForLastOffset(m_offset);
196         ASSERT(outOfLineCapacity() >= currentSize);
197         return currentSize == outOfLineCapacity();
198     }
199
200     ASSERT(totalStorageCapacity() >= propertyTable()->propertyStorageSize());
201     if (propertyTable()->hasDeletedOffset())
202         return false;
203
204     ASSERT(totalStorageCapacity() >= propertyTable()->size());
205     return propertyTable()->size() == totalStorageCapacity();
206 }
207
208 ALWAYS_INLINE WriteBarrier<PropertyTable>& Structure::propertyTable()
209 {
210     ASSERT(!globalObject() || !globalObject()->vm().heap.isCollecting());
211     return m_propertyTableUnsafe;
212 }
213
214 inline void Structure::didReplaceProperty(PropertyOffset offset)
215 {
216     if (LIKELY(!hasRareData()))
217         return;
218     StructureRareData::PropertyWatchpointMap* map = rareData()->m_replacementWatchpointSets.get();
219     if (LIKELY(!map))
220         return;
221     WatchpointSet* set = map->get(offset);
222     if (LIKELY(!set))
223         return;
224     set->fireAll("Property did get replaced");
225 }
226
227 inline WatchpointSet* Structure::propertyReplacementWatchpointSet(PropertyOffset offset)
228 {
229     ConcurrentJITLocker locker(m_lock);
230     if (!hasRareData())
231         return nullptr;
232     WTF::loadLoadFence();
233     StructureRareData::PropertyWatchpointMap* map = rareData()->m_replacementWatchpointSets.get();
234     if (!map)
235         return nullptr;
236     return map->get(offset);
237 }
238
239 ALWAYS_INLINE bool Structure::checkOffsetConsistency() const
240 {
241     PropertyTable* propertyTable = m_propertyTableUnsafe.get();
242
243     if (!propertyTable) {
244         ASSERT(!isPinnedPropertyTable());
245         return true;
246     }
247
248     // We cannot reliably assert things about the property table in the concurrent
249     // compilation thread. It is possible for the table to be stolen and then have
250     // things added to it, which leads to the offsets being all messed up. We could
251     // get around this by grabbing a lock here, but I think that would be overkill.
252     if (isCompilationThread())
253         return true;
254     
255     RELEASE_ASSERT(numberOfSlotsForLastOffset(m_offset, m_inlineCapacity) == propertyTable->propertyStorageSize());
256     unsigned totalSize = propertyTable->propertyStorageSize();
257     RELEASE_ASSERT((totalSize < inlineCapacity() ? 0 : totalSize - inlineCapacity()) == numberOfOutOfLineSlotsForLastOffset(m_offset));
258
259     return true;
260 }
261
262 inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity)
263 {
264     if (!currentCapacity)
265         return initialOutOfLineCapacity;
266     return currentCapacity * outOfLineGrowthFactor;
267 }
268
269 inline size_t Structure::suggestedNewOutOfLineStorageCapacity()
270 {
271     return nextOutOfLineStorageCapacity(outOfLineCapacity());
272 }
273
274 } // namespace JSC
275
276 #endif // StructureInlines_h
277