Get rid of HeapRootVisitor and make SlotVisitor less painful to use
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSCellInlines.h
1 /*
2  * Copyright (C) 2012-2016 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 #pragma once
27
28 #include "CPU.h"
29 #include "CallFrame.h"
30 #include "DeferGC.h"
31 #include "Handle.h"
32 #include "JSCell.h"
33 #include "JSDestructibleObject.h"
34 #include "JSObject.h"
35 #include "JSString.h"
36 #include "MarkedBlock.h"
37 #include "Structure.h"
38 #include "Symbol.h"
39 #include <wtf/CompilationThread.h>
40
41 namespace JSC {
42
43 inline JSCell::JSCell(CreatingEarlyCellTag)
44     : m_cellState(CellState::NewWhite)
45 {
46     ASSERT(!isCompilationThread());
47 }
48
49 inline JSCell::JSCell(VM&, Structure* structure)
50     : m_structureID(structure->id())
51     , m_indexingTypeAndMisc(structure->indexingTypeIncludingHistory())
52     , m_type(structure->typeInfo().type())
53     , m_flags(structure->typeInfo().inlineTypeFlags())
54     , m_cellState(CellState::NewWhite)
55 {
56     ASSERT(!isCompilationThread());
57 }
58
59 inline void JSCell::finishCreation(VM& vm)
60 {
61     // This object is ready to be escaped so the concurrent GC may see it at any time. We have
62     // to make sure that none of our stores sink below here.
63     vm.heap.mutatorFence();
64 #if ENABLE(GC_VALIDATION)
65     ASSERT(vm.isInitializingObject());
66     vm.setInitializingObjectClass(0);
67 #else
68     UNUSED_PARAM(vm);
69 #endif
70     ASSERT(m_structureID);
71 }
72
73 inline void JSCell::finishCreation(VM& vm, Structure* structure, CreatingEarlyCellTag)
74 {
75 #if ENABLE(GC_VALIDATION)
76     ASSERT(vm.isInitializingObject());
77     vm.setInitializingObjectClass(0);
78     if (structure) {
79 #endif
80         m_structureID = structure->id();
81         m_indexingTypeAndMisc = structure->indexingTypeIncludingHistory();
82         m_type = structure->typeInfo().type();
83         m_flags = structure->typeInfo().inlineTypeFlags();
84 #if ENABLE(GC_VALIDATION)
85     }
86 #else
87     UNUSED_PARAM(vm);
88 #endif
89     // Very first set of allocations won't have a real structure.
90     ASSERT(m_structureID || !vm.structureStructure);
91 }
92
93 inline JSType JSCell::type() const
94 {
95     return m_type;
96 }
97
98 inline IndexingType JSCell::indexingTypeAndMisc() const
99 {
100     return m_indexingTypeAndMisc;
101 }
102
103 inline IndexingType JSCell::indexingType() const
104 {
105     return indexingTypeAndMisc() & AllArrayTypes;
106 }
107
108 ALWAYS_INLINE Structure* JSCell::structure() const
109 {
110     return structure(*vm());
111 }
112
113 ALWAYS_INLINE Structure* JSCell::structure(VM& vm) const
114 {
115     return vm.getStructure(m_structureID);
116 }
117
118 inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor)
119 {
120     visitor.appendUnbarriered(cell->structure(visitor.vm()));
121 }
122
123 ALWAYS_INLINE VM& ExecState::vm() const
124 {
125     ASSERT(callee());
126     ASSERT(callee()->vm());
127     ASSERT(!callee()->isLargeAllocation());
128     // This is an important optimization since we access this so often.
129     return *callee()->markedBlock().vm();
130 }
131
132 template<typename T>
133 void* allocateCell(Heap& heap, size_t size)
134 {
135     ASSERT(!DisallowGC::isGCDisallowedOnCurrentThread());
136     ASSERT(size >= sizeof(T));
137     JSCell* result = static_cast<JSCell*>(heap.allocateObjectOfType<T>(size));
138 #if ENABLE(GC_VALIDATION)
139     ASSERT(!heap.vm()->isInitializingObject());
140     heap.vm()->setInitializingObjectClass(T::info());
141 #endif
142     result->clearStructure();
143     return result;
144 }
145     
146 template<typename T>
147 void* allocateCell(Heap& heap)
148 {
149     return allocateCell<T>(heap, sizeof(T));
150 }
151     
152 template<typename T>
153 void* allocateCell(Heap& heap, GCDeferralContext* deferralContext, size_t size)
154 {
155     ASSERT(size >= sizeof(T));
156     JSCell* result = static_cast<JSCell*>(heap.allocateObjectOfType<T>(deferralContext, size));
157 #if ENABLE(GC_VALIDATION)
158     ASSERT(!heap.vm()->isInitializingObject());
159     heap.vm()->setInitializingObjectClass(T::info());
160 #endif
161     result->clearStructure();
162     return result;
163 }
164     
165 template<typename T>
166 void* allocateCell(Heap& heap, GCDeferralContext* deferralContext)
167 {
168     return allocateCell<T>(heap, deferralContext, sizeof(T));
169 }
170     
171 inline bool JSCell::isObject() const
172 {
173     return TypeInfo::isObject(m_type);
174 }
175
176 inline bool JSCell::isString() const
177 {
178     return m_type == StringType;
179 }
180
181 inline bool JSCell::isSymbol() const
182 {
183     return m_type == SymbolType;
184 }
185
186 inline bool JSCell::isGetterSetter() const
187 {
188     return m_type == GetterSetterType;
189 }
190
191 inline bool JSCell::isCustomGetterSetter() const
192 {
193     return m_type == CustomGetterSetterType;
194 }
195
196 inline bool JSCell::isProxy() const
197 {
198     return m_type == ImpureProxyType || m_type == PureForwardingProxyType;
199 }
200
201 inline bool JSCell::isAPIValueWrapper() const
202 {
203     return m_type == APIValueWrapperType;
204 }
205
206 ALWAYS_INLINE void JSCell::setStructure(VM& vm, Structure* structure)
207 {
208     ASSERT(structure->classInfo() == this->structure()->classInfo());
209     ASSERT(!this->structure()
210         || this->structure()->transitionWatchpointSetHasBeenInvalidated()
211         || Heap::heap(this)->structureIDTable().get(structure->id()) == structure);
212     m_structureID = structure->id();
213     m_flags = structure->typeInfo().inlineTypeFlags();
214     m_type = structure->typeInfo().type();
215     IndexingType newIndexingType = structure->indexingTypeIncludingHistory();
216     if (m_indexingTypeAndMisc != newIndexingType) {
217         ASSERT(!(newIndexingType & ~AllArrayTypesAndHistory));
218         for (;;) {
219             IndexingType oldValue = m_indexingTypeAndMisc;
220             IndexingType newValue = (oldValue & ~AllArrayTypesAndHistory) | structure->indexingTypeIncludingHistory();
221             if (WTF::atomicCompareExchangeWeakRelaxed(&m_indexingTypeAndMisc, oldValue, newValue))
222                 break;
223         }
224     }
225     vm.heap.writeBarrier(this, structure);
226 }
227
228 inline const MethodTable* JSCell::methodTable() const
229 {
230     VM& vm = *Heap::heap(this)->vm();
231     Structure* structure = this->structure(vm);
232     if (Structure* rootStructure = structure->structure(vm))
233         RELEASE_ASSERT(rootStructure == rootStructure->structure(vm));
234
235     return &structure->classInfo()->methodTable;
236 }
237
238 inline const MethodTable* JSCell::methodTable(VM& vm) const
239 {
240     Structure* structure = this->structure(vm);
241     if (Structure* rootStructure = structure->structure(vm))
242         RELEASE_ASSERT(rootStructure == rootStructure->structure(vm));
243
244     return &structure->classInfo()->methodTable;
245 }
246
247 inline bool JSCell::inherits(const ClassInfo* info) const
248 {
249     return classInfo()->isSubClassOf(info);
250 }
251
252 ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(VM& vm, Structure& structure, PropertyName name)
253 {
254     ASSERT(canUseFastGetOwnProperty(structure));
255     PropertyOffset offset = structure.get(vm, name);
256     if (offset != invalidOffset)
257         return asObject(this)->locationForOffset(offset)->get();
258     return JSValue();
259 }
260
261 inline bool JSCell::canUseFastGetOwnProperty(const Structure& structure)
262 {
263     return !structure.hasGetterSetterProperties() 
264         && !structure.hasCustomGetterSetterProperties()
265         && !structure.typeInfo().overridesGetOwnPropertySlot();
266 }
267
268 ALWAYS_INLINE const ClassInfo* JSCell::classInfo() const
269 {
270     if (isLargeAllocation()) {
271         LargeAllocation& allocation = largeAllocation();
272         if (allocation.attributes().destruction == NeedsDestruction
273             && !(inlineTypeFlags() & StructureIsImmortal))
274             return static_cast<const JSDestructibleObject*>(this)->classInfo();
275         return structure(*allocation.vm())->classInfo();
276     }
277     MarkedBlock& block = markedBlock();
278     if (block.needsDestruction() && !(inlineTypeFlags() & StructureIsImmortal))
279         return static_cast<const JSDestructibleObject*>(this)->classInfo();
280     return structure(*block.vm())->classInfo();
281 }
282
283 inline bool JSCell::toBoolean(ExecState* exec) const
284 {
285     if (isString())
286         return static_cast<const JSString*>(this)->toBoolean();
287     return !structure()->masqueradesAsUndefined(exec->lexicalGlobalObject());
288 }
289
290 inline TriState JSCell::pureToBoolean() const
291 {
292     if (isString())
293         return static_cast<const JSString*>(this)->toBoolean() ? TrueTriState : FalseTriState;
294     if (isSymbol())
295         return TrueTriState;
296     return MixedTriState;
297 }
298
299 inline void JSCell::callDestructor(VM& vm)
300 {
301     if (isZapped())
302         return;
303     ASSERT(structureID());
304     if (inlineTypeFlags() & StructureIsImmortal) {
305         Structure* structure = this->structure(vm);
306         const ClassInfo* classInfo = structure->classInfo();
307         MethodTable::DestroyFunctionPtr destroy = classInfo->methodTable.destroy;
308         destroy(this);
309     } else
310         jsCast<JSDestructibleObject*>(this)->classInfo()->methodTable.destroy(this);
311     zap();
312 }
313
314 inline void JSCell::lock()
315 {
316     Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc);
317     IndexingTypeLockAlgorithm::lock(*lock);
318 }
319
320 inline bool JSCell::tryLock()
321 {
322     Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc);
323     return IndexingTypeLockAlgorithm::tryLock(*lock);
324 }
325
326 inline void JSCell::unlock()
327 {
328     Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc);
329     IndexingTypeLockAlgorithm::unlock(*lock);
330 }
331
332 inline bool JSCell::isLocked() const
333 {
334     Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc);
335     return IndexingTypeLockAlgorithm::isLocked(*lock);
336 }
337
338 inline JSObject* JSCell::toObject(ExecState* exec, JSGlobalObject* globalObject) const
339 {
340     if (isObject())
341         return jsCast<JSObject*>(const_cast<JSCell*>(this));
342     return toObjectSlow(exec, globalObject);
343 }
344
345 } // namespace JSC