7d454a1a8a6b67e701c8282716ca06a13a3f263f
[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     Structure* structure = cell->structure(visitor.vm());
121     visitor.appendUnbarrieredPointer(&structure);
122 }
123
124 ALWAYS_INLINE VM& ExecState::vm() const
125 {
126     ASSERT(callee());
127     ASSERT(callee()->vm());
128     ASSERT(!callee()->isLargeAllocation());
129     // This is an important optimization since we access this so often.
130     return *callee()->markedBlock().vm();
131 }
132
133 template<typename T>
134 void* allocateCell(Heap& heap, size_t size)
135 {
136     ASSERT(!DisallowGC::isGCDisallowedOnCurrentThread());
137     ASSERT(size >= sizeof(T));
138     JSCell* result = static_cast<JSCell*>(heap.allocateObjectOfType<T>(size));
139 #if ENABLE(GC_VALIDATION)
140     ASSERT(!heap.vm()->isInitializingObject());
141     heap.vm()->setInitializingObjectClass(T::info());
142 #endif
143     result->clearStructure();
144     return result;
145 }
146     
147 template<typename T>
148 void* allocateCell(Heap& heap)
149 {
150     return allocateCell<T>(heap, sizeof(T));
151 }
152     
153 template<typename T>
154 void* allocateCell(Heap& heap, GCDeferralContext* deferralContext, size_t size)
155 {
156     ASSERT(size >= sizeof(T));
157     JSCell* result = static_cast<JSCell*>(heap.allocateObjectOfType<T>(deferralContext, size));
158 #if ENABLE(GC_VALIDATION)
159     ASSERT(!heap.vm()->isInitializingObject());
160     heap.vm()->setInitializingObjectClass(T::info());
161 #endif
162     result->clearStructure();
163     return result;
164 }
165     
166 template<typename T>
167 void* allocateCell(Heap& heap, GCDeferralContext* deferralContext)
168 {
169     return allocateCell<T>(heap, deferralContext, sizeof(T));
170 }
171     
172 inline bool JSCell::isObject() const
173 {
174     return TypeInfo::isObject(m_type);
175 }
176
177 inline bool JSCell::isString() const
178 {
179     return m_type == StringType;
180 }
181
182 inline bool JSCell::isSymbol() const
183 {
184     return m_type == SymbolType;
185 }
186
187 inline bool JSCell::isGetterSetter() const
188 {
189     return m_type == GetterSetterType;
190 }
191
192 inline bool JSCell::isCustomGetterSetter() const
193 {
194     return m_type == CustomGetterSetterType;
195 }
196
197 inline bool JSCell::isProxy() const
198 {
199     return m_type == ImpureProxyType || m_type == PureForwardingProxyType;
200 }
201
202 inline bool JSCell::isAPIValueWrapper() const
203 {
204     return m_type == APIValueWrapperType;
205 }
206
207 ALWAYS_INLINE void JSCell::setStructure(VM& vm, Structure* structure)
208 {
209     ASSERT(structure->classInfo() == this->structure()->classInfo());
210     ASSERT(!this->structure()
211         || this->structure()->transitionWatchpointSetHasBeenInvalidated()
212         || Heap::heap(this)->structureIDTable().get(structure->id()) == structure);
213     m_structureID = structure->id();
214     m_flags = structure->typeInfo().inlineTypeFlags();
215     m_type = structure->typeInfo().type();
216     IndexingType newIndexingType = structure->indexingTypeIncludingHistory();
217     if (m_indexingTypeAndMisc != newIndexingType) {
218         ASSERT(!(newIndexingType & ~AllArrayTypesAndHistory));
219         for (;;) {
220             IndexingType oldValue = m_indexingTypeAndMisc;
221             IndexingType newValue = (oldValue & ~AllArrayTypesAndHistory) | structure->indexingTypeIncludingHistory();
222             if (WTF::atomicCompareExchangeWeakRelaxed(&m_indexingTypeAndMisc, oldValue, newValue))
223                 break;
224         }
225     }
226     vm.heap.writeBarrier(this, structure);
227 }
228
229 inline const MethodTable* JSCell::methodTable() const
230 {
231     VM& vm = *Heap::heap(this)->vm();
232     Structure* structure = this->structure(vm);
233     if (Structure* rootStructure = structure->structure(vm))
234         RELEASE_ASSERT(rootStructure == rootStructure->structure(vm));
235
236     return &structure->classInfo()->methodTable;
237 }
238
239 inline const MethodTable* JSCell::methodTable(VM& vm) const
240 {
241     Structure* structure = this->structure(vm);
242     if (Structure* rootStructure = structure->structure(vm))
243         RELEASE_ASSERT(rootStructure == rootStructure->structure(vm));
244
245     return &structure->classInfo()->methodTable;
246 }
247
248 inline bool JSCell::inherits(const ClassInfo* info) const
249 {
250     return classInfo()->isSubClassOf(info);
251 }
252
253 ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(VM& vm, Structure& structure, PropertyName name)
254 {
255     ASSERT(canUseFastGetOwnProperty(structure));
256     PropertyOffset offset = structure.get(vm, name);
257     if (offset != invalidOffset)
258         return asObject(this)->locationForOffset(offset)->get();
259     return JSValue();
260 }
261
262 inline bool JSCell::canUseFastGetOwnProperty(const Structure& structure)
263 {
264     return !structure.hasGetterSetterProperties() 
265         && !structure.hasCustomGetterSetterProperties()
266         && !structure.typeInfo().overridesGetOwnPropertySlot();
267 }
268
269 ALWAYS_INLINE const ClassInfo* JSCell::classInfo() const
270 {
271     if (isLargeAllocation()) {
272         LargeAllocation& allocation = largeAllocation();
273         if (allocation.attributes().destruction == NeedsDestruction
274             && !(inlineTypeFlags() & StructureIsImmortal))
275             return static_cast<const JSDestructibleObject*>(this)->classInfo();
276         return structure(*allocation.vm())->classInfo();
277     }
278     MarkedBlock& block = markedBlock();
279     if (block.needsDestruction() && !(inlineTypeFlags() & StructureIsImmortal))
280         return static_cast<const JSDestructibleObject*>(this)->classInfo();
281     return structure(*block.vm())->classInfo();
282 }
283
284 inline bool JSCell::toBoolean(ExecState* exec) const
285 {
286     if (isString())
287         return static_cast<const JSString*>(this)->toBoolean();
288     return !structure()->masqueradesAsUndefined(exec->lexicalGlobalObject());
289 }
290
291 inline TriState JSCell::pureToBoolean() const
292 {
293     if (isString())
294         return static_cast<const JSString*>(this)->toBoolean() ? TrueTriState : FalseTriState;
295     if (isSymbol())
296         return TrueTriState;
297     return MixedTriState;
298 }
299
300 inline void JSCell::callDestructor(VM& vm)
301 {
302     if (isZapped())
303         return;
304     ASSERT(structureID());
305     if (inlineTypeFlags() & StructureIsImmortal) {
306         Structure* structure = this->structure(vm);
307         const ClassInfo* classInfo = structure->classInfo();
308         MethodTable::DestroyFunctionPtr destroy = classInfo->methodTable.destroy;
309         destroy(this);
310     } else
311         jsCast<JSDestructibleObject*>(this)->classInfo()->methodTable.destroy(this);
312     zap();
313 }
314
315 inline void JSCell::lock()
316 {
317     Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc);
318     IndexingTypeLockAlgorithm::lock(*lock);
319 }
320
321 inline bool JSCell::tryLock()
322 {
323     Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc);
324     return IndexingTypeLockAlgorithm::tryLock(*lock);
325 }
326
327 inline void JSCell::unlock()
328 {
329     Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc);
330     IndexingTypeLockAlgorithm::unlock(*lock);
331 }
332
333 inline bool JSCell::isLocked() const
334 {
335     Atomic<IndexingType>* lock = bitwise_cast<Atomic<IndexingType>*>(&m_indexingTypeAndMisc);
336     return IndexingTypeLockAlgorithm::isLocked(*lock);
337 }
338
339 inline JSObject* JSCell::toObject(ExecState* exec, JSGlobalObject* globalObject) const
340 {
341     if (isObject())
342         return jsCast<JSObject*>(const_cast<JSCell*>(this));
343     return toObjectSlow(exec, globalObject);
344 }
345
346 } // namespace JSC