1cc5b814f6e4c4590af71af6c91ed38f875b32bb
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSCell.h
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
4  *  Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Apple Inc. All rights reserved.
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public License
17  *  along with this library; see the file COPYING.LIB.  If not, write to
18  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #ifndef JSCell_h
24 #define JSCell_h
25
26 #include "CallData.h"
27 #include "CallFrame.h"
28 #include "ConstructData.h"
29 #include "Heap.h"
30 #include "JSLock.h"
31 #include "JSValueInlineMethods.h"
32 #include "SlotVisitor.h"
33 #include "SlotVisitorInlineMethods.h"
34 #include "TypedArrayDescriptor.h"
35 #include "WriteBarrier.h"
36 #include <wtf/Noncopyable.h>
37 #include <wtf/TypeTraits.h>
38
39 namespace JSC {
40
41     class JSDestructibleObject;
42     class JSGlobalObject;
43     class LLIntOffsetsExtractor;
44     class PropertyDescriptor;
45     class PropertyNameArray;
46     class Structure;
47
48     enum EnumerationMode {
49         ExcludeDontEnumProperties,
50         IncludeDontEnumProperties
51     };
52
53     class JSCell {
54         friend class JSValue;
55         friend class MarkedBlock;
56         template<typename T> friend void* allocateCell(Heap&);
57         template<typename T> friend void* allocateCell(Heap&, size_t);
58
59     public:
60         static const unsigned StructureFlags = 0;
61
62         static const bool needsDestruction = false;
63         static const bool hasImmortalStructure = false;
64
65         enum CreatingEarlyCellTag { CreatingEarlyCell };
66         JSCell(CreatingEarlyCellTag);
67
68     protected:
69         JSCell(JSGlobalData&, Structure*);
70         JS_EXPORT_PRIVATE static void destroy(JSCell*);
71
72     public:
73         // Querying the type.
74         bool isString() const;
75         bool isObject() const;
76         bool isGetterSetter() const;
77         bool inherits(const ClassInfo*) const;
78         bool isAPIValueWrapper() const;
79
80         Structure* structure() const;
81         void setStructure(JSGlobalData&, Structure*);
82         void clearStructure() { m_structure.clear(); }
83
84         const char* className();
85
86         // Extracting the value.
87         JS_EXPORT_PRIVATE bool getString(ExecState*, String&) const;
88         JS_EXPORT_PRIVATE String getString(ExecState*) const; // null string if not a string
89         JS_EXPORT_PRIVATE JSObject* getObject(); // NULL if not an object
90         const JSObject* getObject() const; // NULL if not an object
91         
92         JS_EXPORT_PRIVATE static CallType getCallData(JSCell*, CallData&);
93         JS_EXPORT_PRIVATE static ConstructType getConstructData(JSCell*, ConstructData&);
94
95         // Basic conversions.
96         JS_EXPORT_PRIVATE JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
97         bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
98         bool toBoolean(ExecState*) const;
99         JS_EXPORT_PRIVATE double toNumber(ExecState*) const;
100         JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const;
101
102         static void visitChildren(JSCell*, SlotVisitor&);
103
104         // Object operations, with the toObject operation included.
105         const ClassInfo* classInfo() const;
106         const MethodTable* methodTable() const;
107         static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
108         static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
109         
110         static bool deleteProperty(JSCell*, ExecState*, PropertyName);
111         static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
112
113         static JSObject* toThisObject(JSCell*, ExecState*);
114
115         void zap() { *reinterpret_cast<uintptr_t**>(this) = 0; }
116         bool isZapped() const { return !*reinterpret_cast<uintptr_t* const*>(this); }
117
118         // FIXME: Rename getOwnPropertySlot to virtualGetOwnPropertySlot, and
119         // fastGetOwnPropertySlot to getOwnPropertySlot. Callers should always
120         // call this function, not its slower virtual counterpart. (For integer
121         // property names, we want a similar interface with appropriate optimizations.)
122         bool fastGetOwnPropertySlot(ExecState*, PropertyName, PropertySlot&);
123         JSValue fastGetOwnProperty(ExecState*, const String&);
124
125         static ptrdiff_t structureOffset()
126         {
127             return OBJECT_OFFSETOF(JSCell, m_structure);
128         }
129
130         void* structureAddress()
131         {
132             return &m_structure;
133         }
134         
135 #if ENABLE(GC_VALIDATION)
136         Structure* unvalidatedStructure() { return m_structure.unvalidatedGet(); }
137 #endif
138         
139         static const TypedArrayType TypedArrayStorageType = TypedArrayNone;
140     protected:
141
142         void finishCreation(JSGlobalData&);
143         void finishCreation(JSGlobalData&, Structure*, CreatingEarlyCellTag);
144
145         // Base implementation; for non-object classes implements getPropertySlot.
146         static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
147         static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
148
149         // Dummy implementations of override-able static functions for classes to put in their MethodTable
150         static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
151         static NO_RETURN_DUE_TO_ASSERT void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
152         static NO_RETURN_DUE_TO_ASSERT void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
153         static NO_RETURN_DUE_TO_ASSERT void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
154         static String className(const JSObject*);
155         JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue);
156         static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes);
157         static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow);
158         static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
159
160     private:
161         friend class LLIntOffsetsExtractor;
162         
163         WriteBarrier<Structure> m_structure;
164     };
165
166     inline JSCell::JSCell(CreatingEarlyCellTag)
167     {
168     }
169
170     inline void JSCell::finishCreation(JSGlobalData& globalData)
171     {
172 #if ENABLE(GC_VALIDATION)
173         ASSERT(globalData.isInitializingObject());
174         globalData.setInitializingObjectClass(0);
175 #else
176         UNUSED_PARAM(globalData);
177 #endif
178         ASSERT(m_structure);
179     }
180
181     inline Structure* JSCell::structure() const
182     {
183         return m_structure.get();
184     }
185
186     inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor)
187     {
188         MARK_LOG_PARENT(visitor, cell);
189
190         visitor.append(&cell->m_structure);
191     }
192
193     // --- JSValue inlines ----------------------------
194
195     inline bool JSValue::isString() const
196     {
197         return isCell() && asCell()->isString();
198     }
199
200     inline bool JSValue::isPrimitive() const
201     {
202         return !isCell() || asCell()->isString();
203     }
204
205     inline bool JSValue::isGetterSetter() const
206     {
207         return isCell() && asCell()->isGetterSetter();
208     }
209
210     inline bool JSValue::isObject() const
211     {
212         return isCell() && asCell()->isObject();
213     }
214
215     inline bool JSValue::getString(ExecState* exec, String& s) const
216     {
217         return isCell() && asCell()->getString(exec, s);
218     }
219
220     inline String JSValue::getString(ExecState* exec) const
221     {
222         return isCell() ? asCell()->getString(exec) : String();
223     }
224
225     template <typename Base> String HandleConverter<Base, Unknown>::getString(ExecState* exec) const
226     {
227         return jsValue().getString(exec);
228     }
229
230     inline JSObject* JSValue::getObject() const
231     {
232         return isCell() ? asCell()->getObject() : 0;
233     }
234
235     ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
236     {
237         if (isInt32()) {
238             int32_t i = asInt32();
239             v = static_cast<uint32_t>(i);
240             return i >= 0;
241         }
242         if (isDouble()) {
243             double d = asDouble();
244             v = static_cast<uint32_t>(d);
245             return v == d;
246         }
247         return false;
248     }
249
250     inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
251     {
252         return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
253     }
254
255     inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value)
256     {
257         if (isInt32()) {
258             number = asInt32();
259             value = *this;
260             return true;
261         }
262         if (isDouble()) {
263             number = asDouble();
264             value = *this;
265             return true;
266         }
267         if (isCell())
268             return asCell()->getPrimitiveNumber(exec, number, value);
269         if (isTrue()) {
270             number = 1.0;
271             value = *this;
272             return true;
273         }
274         if (isFalse() || isNull()) {
275             number = 0.0;
276             value = *this;
277             return true;
278         }
279         ASSERT(isUndefined());
280         number = std::numeric_limits<double>::quiet_NaN();
281         value = *this;
282         return true;
283     }
284
285     ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const
286     {
287         if (isInt32())
288             return asInt32();
289         if (isDouble())
290             return asDouble();
291         return toNumberSlowCase(exec);
292     }
293
294     inline JSObject* JSValue::toObject(ExecState* exec) const
295     {
296         return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject());
297     }
298
299     inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const
300     {
301         return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject);
302     }
303
304     template<typename T>
305     void* allocateCell(Heap& heap, size_t size)
306     {
307         ASSERT(size >= sizeof(T));
308 #if ENABLE(GC_VALIDATION)
309         ASSERT(!heap.globalData()->isInitializingObject());
310         heap.globalData()->setInitializingObjectClass(&T::s_info);
311 #endif
312         JSCell* result = 0;
313         if (T::needsDestruction && T::hasImmortalStructure)
314             result = static_cast<JSCell*>(heap.allocateWithImmortalStructureDestructor(size));
315         else if (T::needsDestruction && !T::hasImmortalStructure)
316             result = static_cast<JSCell*>(heap.allocateWithNormalDestructor(size));
317         else 
318             result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size));
319         result->clearStructure();
320         return result;
321     }
322     
323     template<typename T>
324     void* allocateCell(Heap& heap)
325     {
326         return allocateCell<T>(heap, sizeof(T));
327     }
328     
329     inline bool isZapped(const JSCell* cell)
330     {
331         return cell->isZapped();
332     }
333
334     template<typename To, typename From>
335     inline To jsCast(From* from)
336     {
337         ASSERT(!from || from->JSCell::inherits(&WTF::RemovePointer<To>::Type::s_info));
338         return static_cast<To>(from);
339     }
340     
341     template<typename To>
342     inline To jsCast(JSValue from)
343     {
344         ASSERT(from.isCell() && from.asCell()->JSCell::inherits(&WTF::RemovePointer<To>::Type::s_info));
345         return static_cast<To>(from.asCell());
346     }
347
348     template<typename To, typename From>
349     inline To jsDynamicCast(From* from)
350     {
351         return from->inherits(&WTF::RemovePointer<To>::Type::s_info) ? static_cast<To>(from) : 0;
352     }
353
354     template<typename To>
355     inline To jsDynamicCast(JSValue from)
356     {
357         return from.isCell() && from.asCell()->inherits(&WTF::RemovePointer<To>::Type::s_info) ? static_cast<To>(from.asCell()) : 0;
358     }
359
360 } // namespace JSC
361
362 #endif // JSCell_h