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