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