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.
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.
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.
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.
27 #include "CallFrame.h"
28 #include "ConstructData.h"
31 #include "JSValueInlineMethods.h"
32 #include "MarkStack.h"
33 #include "WriteBarrier.h"
34 #include <wtf/Noncopyable.h>
42 // If WTF_MAKE_NONCOPYABLE is applied to JSCell we end up with a bunch of
43 // undefined references to the JSCell copy constructor and assignment operator
44 // when linking JavaScriptCore.
45 class MSVCBugWorkaround
{
46 WTF_MAKE_NONCOPYABLE(MSVCBugWorkaround
);
49 MSVCBugWorkaround() { }
50 ~MSVCBugWorkaround() { }
53 class JSCell
: MSVCBugWorkaround
{
56 WTF_MAKE_NONCOPYABLE(JSCell
);
59 friend class ExecutableBase
;
60 friend class GetterSetter
;
62 friend class JSObject
;
63 friend class JSPropertyNameIterator
;
64 friend class JSString
;
66 friend class JSAPIValueWrapper
;
67 friend class JSZombie
;
68 friend class JSGlobalData
;
69 friend class MarkedSpace
;
70 friend class MarkedBlock
;
71 friend class ScopeChainNode
;
72 friend class Structure
;
73 friend class StructureChain
;
75 enum CreatingEarlyCellTag
{ CreatingEarlyCell
};
78 enum VPtrStealingHackType
{ VPtrStealingHack
};
81 explicit JSCell(VPtrStealingHackType
) { }
82 JSCell(JSGlobalData
&, Structure
*);
83 JSCell(JSGlobalData
&, Structure
*, CreatingEarlyCellTag
);
85 static const ClassInfo s_dummyCellInfo
;
88 static Structure
* createDummyStructure(JSGlobalData
&);
91 bool isString() const;
92 bool isObject() const;
93 virtual bool isGetterSetter() const;
94 bool inherits(const ClassInfo
*) const;
95 virtual bool isAPIValueWrapper() const { return false; }
96 virtual bool isPropertyNameIterator() const { return false; }
98 Structure
* structure() const;
100 // Extracting the value.
101 bool getString(ExecState
* exec
, UString
&) const;
102 UString
getString(ExecState
* exec
) const; // null string if not a string
103 JSObject
* getObject(); // NULL if not an object
104 const JSObject
* getObject() const; // NULL if not an object
106 virtual CallType
getCallData(CallData
&);
107 virtual ConstructType
getConstructData(ConstructData
&);
109 // Extracting integer values.
110 // FIXME: remove these methods, can check isNumberCell in JSValue && then call asNumberCell::*.
111 virtual bool getUInt32(uint32_t&) const;
113 // Basic conversions.
114 virtual JSValue
toPrimitive(ExecState
*, PreferredPrimitiveType
) const;
115 virtual bool getPrimitiveNumber(ExecState
*, double& number
, JSValue
&);
116 virtual bool toBoolean(ExecState
*) const;
117 virtual double toNumber(ExecState
*) const;
118 virtual UString
toString(ExecState
*) const;
119 virtual JSObject
* toObject(ExecState
*, JSGlobalObject
*) const;
121 // Garbage collection.
122 void* operator new(size_t, ExecState
*);
123 void* operator new(size_t, JSGlobalData
*);
124 void* operator new(size_t, void* placementNewDestination
) { return placementNewDestination
; }
126 virtual void visitChildren(SlotVisitor
&);
127 #if ENABLE(JSC_ZOMBIES)
128 virtual bool isZombie() const { return false; }
131 // Object operations, with the toObject operation included.
132 const ClassInfo
* classInfo() const;
133 virtual void put(ExecState
*, const Identifier
& propertyName
, JSValue
, PutPropertySlot
&);
134 virtual void put(ExecState
*, unsigned propertyName
, JSValue
);
135 virtual bool deleteProperty(ExecState
*, const Identifier
& propertyName
);
136 virtual bool deleteProperty(ExecState
*, unsigned propertyName
);
138 virtual JSObject
* toThisObject(ExecState
*) const;
139 virtual JSValue
getJSNumber();
140 void* vptr() { return *reinterpret_cast<void**>(this); }
141 void setVPtr(void* vptr
) { *reinterpret_cast<void**>(this) = vptr
; }
143 // FIXME: Rename getOwnPropertySlot to virtualGetOwnPropertySlot, and
144 // fastGetOwnPropertySlot to getOwnPropertySlot. Callers should always
145 // call this function, not its slower virtual counterpart. (For integer
146 // property names, we want a similar interface with appropriate optimizations.)
147 bool fastGetOwnPropertySlot(ExecState
*, const Identifier
& propertyName
, PropertySlot
&);
149 static ptrdiff_t structureOffset()
151 return OBJECT_OFFSETOF(JSCell
, m_structure
);
154 #if ENABLE(GC_VALIDATION)
155 Structure
* unvalidatedStructure() { return m_structure
.unvalidatedGet(); }
159 static const unsigned AnonymousSlotCount
= 0;
162 // Base implementation; for non-object classes implements getPropertySlot.
163 virtual bool getOwnPropertySlot(ExecState
*, const Identifier
& propertyName
, PropertySlot
&);
164 virtual bool getOwnPropertySlot(ExecState
*, unsigned propertyName
, PropertySlot
&);
166 WriteBarrier
<Structure
> m_structure
;
169 inline JSCell::JSCell(JSGlobalData
& globalData
, Structure
* structure
)
170 : m_structure(globalData
, this, structure
)
175 inline JSCell::JSCell(JSGlobalData
& globalData
, Structure
* structure
, CreatingEarlyCellTag
)
177 #if ENABLE(GC_VALIDATION)
180 m_structure
.setEarlyValue(globalData
, this, structure
);
181 // Very first set of allocations won't have a real structure.
182 ASSERT(m_structure
|| !globalData
.dummyMarkableCellStructure
);
185 inline JSCell::~JSCell()
187 #if ENABLE(GC_VALIDATION)
192 inline Structure
* JSCell::structure() const
194 return m_structure
.get();
197 inline void JSCell::visitChildren(SlotVisitor
& visitor
)
199 visitor
.append(&m_structure
);
202 // --- JSValue inlines ----------------------------
204 inline bool JSValue::isString() const
206 return isCell() && asCell()->isString();
209 inline bool JSValue::isGetterSetter() const
211 return isCell() && asCell()->isGetterSetter();
214 inline bool JSValue::isObject() const
216 return isCell() && asCell()->isObject();
219 inline bool JSValue::getString(ExecState
* exec
, UString
& s
) const
221 return isCell() && asCell()->getString(exec
, s
);
224 inline UString
JSValue::getString(ExecState
* exec
) const
226 return isCell() ? asCell()->getString(exec
) : UString();
229 template <typename Base
> UString HandleConverter
<Base
, Unknown
>::getString(ExecState
* exec
) const
231 return jsValue().getString(exec
);
234 inline JSObject
* JSValue::getObject() const
236 return isCell() ? asCell()->getObject() : 0;
239 inline CallType
getCallData(JSValue value
, CallData
& callData
)
241 CallType result
= value
.isCell() ? value
.asCell()->getCallData(callData
) : CallTypeNone
;
242 ASSERT(result
== CallTypeNone
|| value
.isValidCallee());
246 inline ConstructType
getConstructData(JSValue value
, ConstructData
& constructData
)
248 ConstructType result
= value
.isCell() ? value
.asCell()->getConstructData(constructData
) : ConstructTypeNone
;
249 ASSERT(result
== ConstructTypeNone
|| value
.isValidCallee());
253 ALWAYS_INLINE
bool JSValue::getUInt32(uint32_t& v
) const
256 int32_t i
= asInt32();
257 v
= static_cast<uint32_t>(i
);
261 double d
= asDouble();
262 v
= static_cast<uint32_t>(d
);
268 inline JSValue
JSValue::toPrimitive(ExecState
* exec
, PreferredPrimitiveType preferredType
) const
270 return isCell() ? asCell()->toPrimitive(exec
, preferredType
) : asValue();
273 inline bool JSValue::getPrimitiveNumber(ExecState
* exec
, double& number
, JSValue
& value
)
286 return asCell()->getPrimitiveNumber(exec
, number
, value
);
292 if (isFalse() || isNull()) {
297 ASSERT(isUndefined());
298 number
= nonInlineNaN();
303 inline bool JSValue::toBoolean(ExecState
* exec
) const
306 return asInt32() != 0;
308 return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
310 return asCell()->toBoolean(exec
);
311 return isTrue(); // false, null, and undefined all convert to false.
314 ALWAYS_INLINE
double JSValue::toNumber(ExecState
* exec
) const
321 return asCell()->toNumber(exec
);
324 return isUndefined() ? nonInlineNaN() : 0; // null and false both convert to 0.
327 inline JSValue
JSValue::getJSNumber()
329 if (isInt32() || isDouble())
332 return asCell()->getJSNumber();
336 inline JSObject
* JSValue::toObject(ExecState
* exec
) const
338 return isCell() ? asCell()->toObject(exec
, exec
->lexicalGlobalObject()) : toObjectSlowCase(exec
, exec
->lexicalGlobalObject());
341 inline JSObject
* JSValue::toObject(ExecState
* exec
, JSGlobalObject
* globalObject
) const
343 return isCell() ? asCell()->toObject(exec
, globalObject
) : toObjectSlowCase(exec
, globalObject
);
346 inline JSObject
* JSValue::toThisObject(ExecState
* exec
) const
348 return isCell() ? asCell()->toThisObject(exec
) : toThisObjectSlowCase(exec
);
351 inline Heap
* Heap::heap(JSValue v
)
355 return heap(v
.asCell());
358 inline Heap
* Heap::heap(JSCell
* c
)
360 return MarkedSpace::heap(c
);
363 #if ENABLE(JSC_ZOMBIES)
364 inline bool JSValue::isZombie() const
366 return isCell() && asCell() > (JSCell
*)0x1ffffffffL
&& asCell()->isZombie();
370 inline void* MarkedBlock::allocate()
372 while (m_nextAtom
< m_endAtom
) {
373 if (!m_marks
.testAndSet(m_nextAtom
)) {
374 JSCell
* cell
= reinterpret_cast<JSCell
*>(&atoms()[m_nextAtom
]);
375 m_nextAtom
+= m_atomsPerCell
;
379 m_nextAtom
+= m_atomsPerCell
;
385 inline MarkedSpace::SizeClass
& MarkedSpace::sizeClassFor(size_t bytes
)
387 ASSERT(bytes
&& bytes
< maxCellSize
);
388 if (bytes
< preciseCutoff
)
389 return m_preciseSizeClasses
[(bytes
- 1) / preciseStep
];
390 return m_impreciseSizeClasses
[(bytes
- 1) / impreciseStep
];
393 inline void* MarkedSpace::allocate(size_t bytes
)
395 SizeClass
& sizeClass
= sizeClassFor(bytes
);
396 return allocateFromSizeClass(sizeClass
);
399 inline void* Heap::allocate(size_t bytes
)
401 ASSERT(globalData()->identifierTable
== wtfThreadData().currentIdentifierTable());
402 ASSERT(JSLock::lockCount() > 0);
403 ASSERT(JSLock::currentThreadIsHoldingLock());
404 ASSERT(bytes
<= MarkedSpace::maxCellSize
);
405 ASSERT(m_operationInProgress
== NoOperation
);
407 m_operationInProgress
= Allocation
;
408 void* result
= m_markedSpace
.allocate(bytes
);
409 m_operationInProgress
= NoOperation
;
413 return allocateSlowCase(bytes
);
416 inline void* JSCell::operator new(size_t size
, JSGlobalData
* globalData
)
418 JSCell
* result
= static_cast<JSCell
*>(globalData
->heap
.allocate(size
));
419 result
->m_structure
.clear();
423 inline void* JSCell::operator new(size_t size
, ExecState
* exec
)
425 JSCell
* result
= static_cast<JSCell
*>(exec
->heap()->allocate(size
));
426 result
->m_structure
.clear();