1/*
2 * Copyright (C) 2012, 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 JSCellInlines_h
27#define JSCellInlines_h
28
29#include "CallFrame.h"
30#include "DeferGC.h"
31#include "Handle.h"
32#include "JSCell.h"
33#include "JSObject.h"
34#include "JSString.h"
35#include "Structure.h"
36#include <wtf/CompilationThread.h>
37
38namespace JSC {
39
40inline JSCell::JSCell(CreatingEarlyCellTag)
41    : m_gcData(NotMarked)
42{
43    ASSERT(!isCompilationThread());
44}
45
46inline JSCell::JSCell(VM&, Structure* structure)
47    : m_structureID(structure->id())
48    , m_indexingType(structure->indexingType())
49    , m_type(structure->typeInfo().type())
50    , m_flags(structure->typeInfo().inlineTypeFlags())
51    , m_gcData(NotMarked)
52{
53    ASSERT(!isCompilationThread());
54}
55
56inline void JSCell::finishCreation(VM& vm)
57{
58#if ENABLE(GC_VALIDATION)
59    ASSERT(vm.isInitializingObject());
60    vm.setInitializingObjectClass(0);
61#else
62    UNUSED_PARAM(vm);
63#endif
64    ASSERT(m_structureID);
65}
66
67inline void JSCell::finishCreation(VM& vm, Structure* structure, CreatingEarlyCellTag)
68{
69#if ENABLE(GC_VALIDATION)
70    ASSERT(vm.isInitializingObject());
71    vm.setInitializingObjectClass(0);
72    if (structure) {
73#endif
74        m_structureID = structure->id();
75        m_indexingType = structure->indexingType();
76        m_type = structure->typeInfo().type();
77        m_flags = structure->typeInfo().inlineTypeFlags();
78#if ENABLE(GC_VALIDATION)
79    }
80#else
81    UNUSED_PARAM(vm);
82#endif
83    // Very first set of allocations won't have a real structure.
84    ASSERT(m_structureID || !vm.structureStructure);
85}
86
87inline JSType JSCell::type() const
88{
89    return m_type;
90}
91
92inline IndexingType JSCell::indexingType() const
93{
94    return m_indexingType;
95}
96
97inline Structure* JSCell::structure() const
98{
99    return Heap::heap(this)->structureIDTable().get(m_structureID);
100}
101
102inline Structure* JSCell::structure(VM& vm) const
103{
104    return vm.heap.structureIDTable().get(m_structureID);
105}
106
107inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor)
108{
109    Structure* structure = cell->structure(visitor.vm());
110    visitor.appendUnbarrieredPointer(&structure);
111}
112
113template<typename T>
114void* allocateCell(Heap& heap, size_t size)
115{
116    ASSERT(!DisallowGC::isGCDisallowedOnCurrentThread());
117    ASSERT(size >= sizeof(T));
118    JSCell* result = 0;
119    if (T::needsDestruction && T::hasImmortalStructure)
120        result = static_cast<JSCell*>(heap.allocateWithImmortalStructureDestructor(size));
121    else if (T::needsDestruction)
122        result = static_cast<JSCell*>(heap.allocateWithNormalDestructor(size));
123    else
124        result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size));
125#if ENABLE(GC_VALIDATION)
126    ASSERT(!heap.vm()->isInitializingObject());
127    heap.vm()->setInitializingObjectClass(T::info());
128#endif
129    result->clearStructure();
130    return result;
131}
132
133template<typename T>
134void* allocateCell(Heap& heap)
135{
136    return allocateCell<T>(heap, sizeof(T));
137}
138
139inline bool isZapped(const JSCell* cell)
140{
141    return cell->isZapped();
142}
143
144inline bool JSCell::isObject() const
145{
146    return TypeInfo::isObject(m_type);
147}
148
149inline bool JSCell::isString() const
150{
151    return m_type == StringType;
152}
153
154inline bool JSCell::isGetterSetter() const
155{
156    return m_type == GetterSetterType;
157}
158
159inline bool JSCell::isCustomGetterSetter() const
160{
161    return m_type == CustomGetterSetterType;
162}
163
164inline bool JSCell::isProxy() const
165{
166    return m_type == ImpureProxyType || m_type == PureForwardingProxyType;
167}
168
169inline bool JSCell::isAPIValueWrapper() const
170{
171    return m_type == APIValueWrapperType;
172}
173
174inline void JSCell::setStructure(VM& vm, Structure* structure)
175{
176    ASSERT(structure->typeInfo().overridesVisitChildren() == this->structure()->typeInfo().overridesVisitChildren());
177    ASSERT(structure->classInfo() == this->structure()->classInfo());
178    ASSERT(!this->structure()
179        || this->structure()->transitionWatchpointSetHasBeenInvalidated()
180        || Heap::heap(this)->structureIDTable().get(structure->id()) == structure);
181    vm.heap.writeBarrier(this, structure);
182    m_structureID = structure->id();
183    m_flags = structure->typeInfo().inlineTypeFlags();
184    m_type = structure->typeInfo().type();
185    m_indexingType = structure->indexingType();
186}
187
188inline const MethodTable* JSCell::methodTable() const
189{
190    VM& vm = *Heap::heap(this)->vm();
191    Structure* structure = this->structure(vm);
192    if (Structure* rootStructure = structure->structure(vm))
193        RELEASE_ASSERT(rootStructure == rootStructure->structure(vm));
194
195    return &structure->classInfo()->methodTable;
196}
197
198inline const MethodTable* JSCell::methodTable(VM& vm) const
199{
200    Structure* structure = this->structure(vm);
201    if (Structure* rootStructure = structure->structure(vm))
202        RELEASE_ASSERT(rootStructure == rootStructure->structure(vm));
203
204    return &structure->classInfo()->methodTable;
205}
206
207inline bool JSCell::inherits(const ClassInfo* info) const
208{
209    return classInfo()->isSubClassOf(info);
210}
211
212// Fast call to get a property where we may not yet have converted the string to an
213// identifier. The first time we perform a property access with a given string, try
214// performing the property map lookup without forming an identifier. We detect this
215// case by checking whether the hash has yet been set for this string.
216ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(VM& vm, Structure& structure, const String& name)
217{
218    ASSERT(canUseFastGetOwnProperty(structure));
219    PropertyOffset offset = name.impl()->hasHash()
220        ? structure.get(vm, Identifier(&vm, name))
221        : structure.get(vm, name);
222    if (offset != invalidOffset)
223        return asObject(this)->locationForOffset(offset)->get();
224    return JSValue();
225}
226
227inline bool JSCell::canUseFastGetOwnProperty(const Structure& structure)
228{
229    return !structure.hasGetterSetterProperties()
230        && !structure.hasCustomGetterSetterProperties()
231        && !structure.typeInfo().overridesGetOwnPropertySlot();
232}
233
234inline bool JSCell::toBoolean(ExecState* exec) const
235{
236    if (isString())
237        return static_cast<const JSString*>(this)->toBoolean();
238    return !structure()->masqueradesAsUndefined(exec->lexicalGlobalObject());
239}
240
241inline TriState JSCell::pureToBoolean() const
242{
243    if (isString())
244        return static_cast<const JSString*>(this)->toBoolean() ? TrueTriState : FalseTriState;
245    return MixedTriState;
246}
247
248} // namespace JSC
249
250#endif // JSCellInlines_h
251