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