2010-05-09 Maciej Stachowiak <mjs@apple.com>
[WebKit.git] / 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 "Collector.h"
27 #include "JSImmediate.h"
28 #include "JSValue.h"
29 #include "MarkStack.h"
30 #include "Structure.h"
31 #include <wtf/Noncopyable.h>
32
33 namespace JSC {
34
35     class JSCell : public NoncopyableCustomAllocated {
36         friend class GetterSetter;
37         friend class Heap;
38         friend class JIT;
39         friend class JSNumberCell;
40         friend class JSObject;
41         friend class JSPropertyNameIterator;
42         friend class JSString;
43         friend class JSValue;
44         friend class JSAPIValueWrapper;
45         friend class JSZombie;
46         friend class JSGlobalData;
47
48     private:
49         explicit JSCell(Structure*);
50         virtual ~JSCell();
51
52     public:
53         static PassRefPtr<Structure> createDummyStructure()
54         {
55             return Structure::create(jsNull(), TypeInfo(UnspecifiedType), AnonymousSlotCount);
56         }
57
58         // Querying the type.
59 #if USE(JSVALUE32)
60         bool isNumber() const;
61 #endif
62         bool isString() const;
63         bool isObject() const;
64         virtual bool isGetterSetter() const;
65         bool inherits(const ClassInfo*) const;
66         virtual bool isAPIValueWrapper() const { return false; }
67         virtual bool isPropertyNameIterator() const { return false; }
68
69         Structure* structure() const;
70
71         // Extracting the value.
72         bool getString(ExecState* exec, UString&) const;
73         UString getString(ExecState* exec) const; // null string if not a string
74         JSObject* getObject(); // NULL if not an object
75         const JSObject* getObject() const; // NULL if not an object
76         
77         virtual CallType getCallData(CallData&);
78         virtual ConstructType getConstructData(ConstructData&);
79
80         // Extracting integer values.
81         // FIXME: remove these methods, can check isNumberCell in JSValue && then call asNumberCell::*.
82         virtual bool getUInt32(uint32_t&) const;
83
84         // Basic conversions.
85         virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
86         virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue&);
87         virtual bool toBoolean(ExecState*) const;
88         virtual double toNumber(ExecState*) const;
89         virtual UString toString(ExecState*) const;
90         virtual JSObject* toObject(ExecState*) const;
91
92         // Garbage collection.
93         void* operator new(size_t, ExecState*);
94         void* operator new(size_t, JSGlobalData*);
95         void* operator new(size_t, void* placementNewDestination) { return placementNewDestination; }
96
97         virtual void markChildren(MarkStack&);
98 #if ENABLE(JSC_ZOMBIES)
99         virtual bool isZombie() const { return false; }
100 #endif
101
102         // Object operations, with the toObject operation included.
103         virtual const ClassInfo* classInfo() const;
104         virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
105         virtual void put(ExecState*, unsigned propertyName, JSValue);
106         virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
107         virtual bool deleteProperty(ExecState*, unsigned propertyName);
108
109         virtual JSObject* toThisObject(ExecState*) const;
110         virtual JSValue getJSNumber();
111         void* vptr() { return *reinterpret_cast<void**>(this); }
112         void setVPtr(void* vptr) { *reinterpret_cast<void**>(this) = vptr; }
113
114         // FIXME: Rename getOwnPropertySlot to virtualGetOwnPropertySlot, and
115         // fastGetOwnPropertySlot to getOwnPropertySlot. Callers should always
116         // call this function, not its slower virtual counterpart. (For integer
117         // property names, we want a similar interface with appropriate optimizations.)
118         bool fastGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
119
120     protected:
121         static const unsigned AnonymousSlotCount = 0;
122
123     private:
124         // Base implementation; for non-object classes implements getPropertySlot.
125         virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
126         virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
127         
128         Structure* m_structure;
129     };
130
131     inline JSCell::JSCell(Structure* structure)
132         : m_structure(structure)
133     {
134     }
135
136     inline JSCell::~JSCell()
137     {
138     }
139
140 #if USE(JSVALUE32)
141     inline bool JSCell::isNumber() const
142     {
143         return m_structure->typeInfo().type() == NumberType;
144     }
145 #endif
146
147     inline bool JSCell::isObject() const
148     {
149         return m_structure->typeInfo().type() == ObjectType;
150     }
151
152     inline bool JSCell::isString() const
153     {
154         return m_structure->typeInfo().type() == StringType;
155     }
156
157     inline Structure* JSCell::structure() const
158     {
159         return m_structure;
160     }
161
162     inline void JSCell::markChildren(MarkStack&)
163     {
164     }
165
166     inline void* JSCell::operator new(size_t size, JSGlobalData* globalData)
167     {
168         return globalData->heap.allocate(size);
169     }
170
171     inline void* JSCell::operator new(size_t size, ExecState* exec)
172     {
173         return exec->heap()->allocate(size);
174     }
175
176     // --- JSValue inlines ----------------------------
177
178     inline bool JSValue::isString() const
179     {
180         return isCell() && asCell()->isString();
181     }
182
183     inline bool JSValue::isGetterSetter() const
184     {
185         return isCell() && asCell()->isGetterSetter();
186     }
187
188     inline bool JSValue::isObject() const
189     {
190         return isCell() && asCell()->isObject();
191     }
192
193     inline bool JSValue::getString(ExecState* exec, UString& s) const
194     {
195         return isCell() && asCell()->getString(exec, s);
196     }
197
198     inline UString JSValue::getString(ExecState* exec) const
199     {
200         return isCell() ? asCell()->getString(exec) : UString();
201     }
202
203     inline JSObject* JSValue::getObject() const
204     {
205         return isCell() ? asCell()->getObject() : 0;
206     }
207
208     inline CallType JSValue::getCallData(CallData& callData)
209     {
210         return isCell() ? asCell()->getCallData(callData) : CallTypeNone;
211     }
212
213     inline ConstructType JSValue::getConstructData(ConstructData& constructData)
214     {
215         return isCell() ? asCell()->getConstructData(constructData) : ConstructTypeNone;
216     }
217
218     ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
219     {
220         if (isInt32()) {
221             int32_t i = asInt32();
222             v = static_cast<uint32_t>(i);
223             return i >= 0;
224         }
225         if (isDouble()) {
226             double d = asDouble();
227             v = static_cast<uint32_t>(d);
228             return v == d;
229         }
230         return false;
231     }
232
233 #if !USE(JSVALUE32_64)
234     ALWAYS_INLINE JSCell* JSValue::asCell() const
235     {
236         ASSERT(isCell());
237         return m_ptr;
238     }
239 #endif // !USE(JSVALUE32_64)
240
241     inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
242     {
243         return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
244     }
245
246     inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value)
247     {
248         if (isInt32()) {
249             number = asInt32();
250             value = *this;
251             return true;
252         }
253         if (isDouble()) {
254             number = asDouble();
255             value = *this;
256             return true;
257         }
258         if (isCell())
259             return asCell()->getPrimitiveNumber(exec, number, value);
260         if (isTrue()) {
261             number = 1.0;
262             value = *this;
263             return true;
264         }
265         if (isFalse() || isNull()) {
266             number = 0.0;
267             value = *this;
268             return true;
269         }
270         ASSERT(isUndefined());
271         number = nonInlineNaN();
272         value = *this;
273         return true;
274     }
275
276     inline bool JSValue::toBoolean(ExecState* exec) const
277     {
278         if (isInt32())
279             return asInt32() != 0;
280         if (isDouble())
281             return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
282         if (isCell())
283             return asCell()->toBoolean(exec);
284         return isTrue(); // false, null, and undefined all convert to false.
285     }
286
287     ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const
288     {
289         if (isInt32())
290             return asInt32();
291         if (isDouble())
292             return asDouble();
293         if (isCell())
294             return asCell()->toNumber(exec);
295         if (isTrue())
296             return 1.0;
297         return isUndefined() ? nonInlineNaN() : 0; // null and false both convert to 0.
298     }
299
300     inline bool JSValue::needsThisConversion() const
301     {
302         if (UNLIKELY(!isCell()))
303             return true;
304         return asCell()->structure()->typeInfo().needsThisConversion();
305     }
306
307     inline JSValue JSValue::getJSNumber()
308     {
309         if (isInt32() || isDouble())
310             return *this;
311         if (isCell())
312             return asCell()->getJSNumber();
313         return JSValue();
314     }
315
316     inline JSObject* JSValue::toObject(ExecState* exec) const
317     {
318         return isCell() ? asCell()->toObject(exec) : toObjectSlowCase(exec);
319     }
320
321     inline JSObject* JSValue::toThisObject(ExecState* exec) const
322     {
323         return isCell() ? asCell()->toThisObject(exec) : toThisObjectSlowCase(exec);
324     }
325
326     ALWAYS_INLINE void MarkStack::append(JSCell* cell)
327     {
328         ASSERT(!m_isCheckingForDefaultMarkViolation);
329         ASSERT(cell);
330         if (Heap::isCellMarked(cell))
331             return;
332         Heap::markCell(cell);
333         if (cell->structure()->typeInfo().type() >= CompoundType)
334             m_values.append(cell);
335     }
336
337     ALWAYS_INLINE void MarkStack::append(JSValue value)
338     {
339         ASSERT(value);
340         if (value.isCell())
341             append(value.asCell());
342     }
343
344     inline Heap* Heap::heap(JSValue v)
345     {
346         if (!v.isCell())
347             return 0;
348         return heap(v.asCell());
349     }
350
351     inline Heap* Heap::heap(JSCell* c)
352     {
353         return cellBlock(c)->heap;
354     }
355     
356 #if ENABLE(JSC_ZOMBIES)
357     inline bool JSValue::isZombie() const
358     {
359         return isCell() && asCell() && asCell()->isZombie();
360     }
361 #endif
362 } // namespace JSC
363
364 #endif // JSCell_h