]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/JSCell.h
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / runtime / JSCell.h
CommitLineData
9dae56ea
A
1/*
2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
f9bf01c6 4 * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Apple Inc. All rights reserved.
9dae56ea
A
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
14957cd0
A
26#include "CallData.h"
27#include "CallFrame.h"
28#include "ConstructData.h"
29#include "Heap.h"
30#include "JSLock.h"
31#include "JSValueInlineMethods.h"
f9bf01c6 32#include "MarkStack.h"
14957cd0 33#include "WriteBarrier.h"
f9bf01c6 34#include <wtf/Noncopyable.h>
9dae56ea
A
35
36namespace JSC {
37
14957cd0
A
38 class JSGlobalObject;
39 class Structure;
40
41#if COMPILER(MSVC)
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);
47
48 protected:
49 MSVCBugWorkaround() { }
50 ~MSVCBugWorkaround() { }
51 };
52
53 class JSCell : MSVCBugWorkaround {
54#else
55 class JSCell {
56 WTF_MAKE_NONCOPYABLE(JSCell);
57#endif
58
59 friend class ExecutableBase;
9dae56ea
A
60 friend class GetterSetter;
61 friend class Heap;
9dae56ea
A
62 friend class JSObject;
63 friend class JSPropertyNameIterator;
64 friend class JSString;
ba379fdc
A
65 friend class JSValue;
66 friend class JSAPIValueWrapper;
f9bf01c6
A
67 friend class JSZombie;
68 friend class JSGlobalData;
14957cd0
A
69 friend class MarkedSpace;
70 friend class MarkedBlock;
71 friend class ScopeChainNode;
72 friend class Structure;
73 friend class StructureChain;
74 friend class RegExp;
75 enum CreatingEarlyCellTag { CreatingEarlyCell };
76
77 protected:
78 enum VPtrStealingHackType { VPtrStealingHack };
9dae56ea
A
79
80 private:
14957cd0
A
81 explicit JSCell(VPtrStealingHackType) { }
82 JSCell(JSGlobalData&, Structure*);
83 JSCell(JSGlobalData&, Structure*, CreatingEarlyCellTag);
9dae56ea 84 virtual ~JSCell();
14957cd0 85 static const ClassInfo s_dummyCellInfo;
9dae56ea
A
86
87 public:
14957cd0 88 static Structure* createDummyStructure(JSGlobalData&);
f9bf01c6 89
9dae56ea 90 // Querying the type.
9dae56ea
A
91 bool isString() const;
92 bool isObject() const;
93 virtual bool isGetterSetter() const;
f9bf01c6 94 bool inherits(const ClassInfo*) const;
ba379fdc 95 virtual bool isAPIValueWrapper() const { return false; }
f9bf01c6 96 virtual bool isPropertyNameIterator() const { return false; }
9dae56ea
A
97
98 Structure* structure() const;
99
100 // Extracting the value.
f9bf01c6
A
101 bool getString(ExecState* exec, UString&) const;
102 UString getString(ExecState* exec) const; // null string if not a string
9dae56ea
A
103 JSObject* getObject(); // NULL if not an object
104 const JSObject* getObject() const; // NULL if not an object
105
106 virtual CallType getCallData(CallData&);
107 virtual ConstructType getConstructData(ConstructData&);
108
109 // Extracting integer values.
ba379fdc 110 // FIXME: remove these methods, can check isNumberCell in JSValue && then call asNumberCell::*.
9dae56ea 111 virtual bool getUInt32(uint32_t&) const;
9dae56ea
A
112
113 // Basic conversions.
f9bf01c6
A
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;
14957cd0 119 virtual JSObject* toObject(ExecState*, JSGlobalObject*) const;
9dae56ea
A
120
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; }
f9bf01c6 125
14957cd0 126 virtual void visitChildren(SlotVisitor&);
f9bf01c6
A
127#if ENABLE(JSC_ZOMBIES)
128 virtual bool isZombie() const { return false; }
129#endif
9dae56ea
A
130
131 // Object operations, with the toObject operation included.
14957cd0 132 const ClassInfo* classInfo() const;
ba379fdc
A
133 virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
134 virtual void put(ExecState*, unsigned propertyName, JSValue);
9dae56ea
A
135 virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
136 virtual bool deleteProperty(ExecState*, unsigned propertyName);
137
138 virtual JSObject* toThisObject(ExecState*) const;
ba379fdc 139 virtual JSValue getJSNumber();
9dae56ea 140 void* vptr() { return *reinterpret_cast<void**>(this); }
f9bf01c6
A
141 void setVPtr(void* vptr) { *reinterpret_cast<void**>(this) = vptr; }
142
4e4e5a6f
A
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&);
148
14957cd0
A
149 static ptrdiff_t structureOffset()
150 {
151 return OBJECT_OFFSETOF(JSCell, m_structure);
152 }
153
154#if ENABLE(GC_VALIDATION)
155 Structure* unvalidatedStructure() { return m_structure.unvalidatedGet(); }
156#endif
157
f9bf01c6
A
158 protected:
159 static const unsigned AnonymousSlotCount = 0;
9dae56ea
A
160
161 private:
162 // Base implementation; for non-object classes implements getPropertySlot.
9dae56ea
A
163 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
164 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
165
14957cd0 166 WriteBarrier<Structure> m_structure;
9dae56ea
A
167 };
168
14957cd0
A
169 inline JSCell::JSCell(JSGlobalData& globalData, Structure* structure)
170 : m_structure(globalData, this, structure)
9dae56ea 171 {
14957cd0 172 ASSERT(m_structure);
9dae56ea
A
173 }
174
14957cd0 175 inline JSCell::JSCell(JSGlobalData& globalData, Structure* structure, CreatingEarlyCellTag)
9dae56ea 176 {
14957cd0
A
177#if ENABLE(GC_VALIDATION)
178 if (structure)
ba379fdc 179#endif
14957cd0
A
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);
9dae56ea
A
183 }
184
14957cd0 185 inline JSCell::~JSCell()
9dae56ea 186 {
14957cd0
A
187#if ENABLE(GC_VALIDATION)
188 m_structure.clear();
189#endif
9dae56ea
A
190 }
191
192 inline Structure* JSCell::structure() const
193 {
14957cd0 194 return m_structure.get();
9dae56ea
A
195 }
196
14957cd0 197 inline void JSCell::visitChildren(SlotVisitor& visitor)
9dae56ea 198 {
14957cd0 199 visitor.append(&m_structure);
9dae56ea
A
200 }
201
202 // --- JSValue inlines ----------------------------
203
ba379fdc 204 inline bool JSValue::isString() const
9dae56ea 205 {
ba379fdc 206 return isCell() && asCell()->isString();
9dae56ea
A
207 }
208
ba379fdc 209 inline bool JSValue::isGetterSetter() const
9dae56ea 210 {
ba379fdc 211 return isCell() && asCell()->isGetterSetter();
9dae56ea
A
212 }
213
ba379fdc 214 inline bool JSValue::isObject() const
9dae56ea 215 {
ba379fdc 216 return isCell() && asCell()->isObject();
9dae56ea
A
217 }
218
f9bf01c6 219 inline bool JSValue::getString(ExecState* exec, UString& s) const
9dae56ea 220 {
f9bf01c6 221 return isCell() && asCell()->getString(exec, s);
9dae56ea
A
222 }
223
f9bf01c6 224 inline UString JSValue::getString(ExecState* exec) const
9dae56ea 225 {
f9bf01c6 226 return isCell() ? asCell()->getString(exec) : UString();
9dae56ea
A
227 }
228
14957cd0
A
229 template <typename Base> UString HandleConverter<Base, Unknown>::getString(ExecState* exec) const
230 {
231 return jsValue().getString(exec);
232 }
233
ba379fdc 234 inline JSObject* JSValue::getObject() const
9dae56ea 235 {
ba379fdc 236 return isCell() ? asCell()->getObject() : 0;
9dae56ea
A
237 }
238
14957cd0 239 inline CallType getCallData(JSValue value, CallData& callData)
9dae56ea 240 {
14957cd0
A
241 CallType result = value.isCell() ? value.asCell()->getCallData(callData) : CallTypeNone;
242 ASSERT(result == CallTypeNone || value.isValidCallee());
243 return result;
9dae56ea
A
244 }
245
14957cd0 246 inline ConstructType getConstructData(JSValue value, ConstructData& constructData)
9dae56ea 247 {
14957cd0
A
248 ConstructType result = value.isCell() ? value.asCell()->getConstructData(constructData) : ConstructTypeNone;
249 ASSERT(result == ConstructTypeNone || value.isValidCallee());
250 return result;
9dae56ea
A
251 }
252
ba379fdc 253 ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
9dae56ea 254 {
ba379fdc
A
255 if (isInt32()) {
256 int32_t i = asInt32();
257 v = static_cast<uint32_t>(i);
258 return i >= 0;
259 }
260 if (isDouble()) {
261 double d = asDouble();
262 v = static_cast<uint32_t>(d);
263 return v == d;
264 }
265 return false;
9dae56ea
A
266 }
267
ba379fdc 268 inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
9dae56ea 269 {
ba379fdc 270 return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
9dae56ea
A
271 }
272
ba379fdc 273 inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value)
9dae56ea 274 {
ba379fdc
A
275 if (isInt32()) {
276 number = asInt32();
277 value = *this;
278 return true;
279 }
280 if (isDouble()) {
281 number = asDouble();
282 value = *this;
283 return true;
284 }
285 if (isCell())
286 return asCell()->getPrimitiveNumber(exec, number, value);
287 if (isTrue()) {
288 number = 1.0;
289 value = *this;
290 return true;
291 }
292 if (isFalse() || isNull()) {
293 number = 0.0;
294 value = *this;
9dae56ea
A
295 return true;
296 }
ba379fdc
A
297 ASSERT(isUndefined());
298 number = nonInlineNaN();
299 value = *this;
300 return true;
9dae56ea
A
301 }
302
ba379fdc 303 inline bool JSValue::toBoolean(ExecState* exec) const
9dae56ea 304 {
ba379fdc
A
305 if (isInt32())
306 return asInt32() != 0;
307 if (isDouble())
308 return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
309 if (isCell())
310 return asCell()->toBoolean(exec);
311 return isTrue(); // false, null, and undefined all convert to false.
9dae56ea
A
312 }
313
ba379fdc 314 ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const
9dae56ea 315 {
ba379fdc
A
316 if (isInt32())
317 return asInt32();
318 if (isDouble())
319 return asDouble();
320 if (isCell())
321 return asCell()->toNumber(exec);
322 if (isTrue())
323 return 1.0;
324 return isUndefined() ? nonInlineNaN() : 0; // null and false both convert to 0.
9dae56ea
A
325 }
326
ba379fdc 327 inline JSValue JSValue::getJSNumber()
9dae56ea 328 {
ba379fdc
A
329 if (isInt32() || isDouble())
330 return *this;
331 if (isCell())
332 return asCell()->getJSNumber();
333 return JSValue();
9dae56ea
A
334 }
335
ba379fdc 336 inline JSObject* JSValue::toObject(ExecState* exec) const
9dae56ea 337 {
14957cd0 338 return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject());
9dae56ea
A
339 }
340
14957cd0 341 inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const
9dae56ea 342 {
14957cd0 343 return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject);
9dae56ea
A
344 }
345
14957cd0 346 inline JSObject* JSValue::toThisObject(ExecState* exec) const
f9bf01c6 347 {
14957cd0 348 return isCell() ? asCell()->toThisObject(exec) : toThisObjectSlowCase(exec);
f9bf01c6
A
349 }
350
351 inline Heap* Heap::heap(JSValue v)
352 {
353 if (!v.isCell())
354 return 0;
355 return heap(v.asCell());
356 }
357
358 inline Heap* Heap::heap(JSCell* c)
359 {
14957cd0 360 return MarkedSpace::heap(c);
f9bf01c6
A
361 }
362
363#if ENABLE(JSC_ZOMBIES)
364 inline bool JSValue::isZombie() const
365 {
14957cd0 366 return isCell() && asCell() > (JSCell*)0x1ffffffffL && asCell()->isZombie();
f9bf01c6
A
367 }
368#endif
14957cd0
A
369
370 inline void* MarkedBlock::allocate()
371 {
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;
376 cell->~JSCell();
377 return cell;
378 }
379 m_nextAtom += m_atomsPerCell;
380 }
381
382 return 0;
383 }
384
385 inline MarkedSpace::SizeClass& MarkedSpace::sizeClassFor(size_t bytes)
386 {
387 ASSERT(bytes && bytes < maxCellSize);
388 if (bytes < preciseCutoff)
389 return m_preciseSizeClasses[(bytes - 1) / preciseStep];
390 return m_impreciseSizeClasses[(bytes - 1) / impreciseStep];
391 }
392
393 inline void* MarkedSpace::allocate(size_t bytes)
394 {
395 SizeClass& sizeClass = sizeClassFor(bytes);
396 return allocateFromSizeClass(sizeClass);
397 }
398
399 inline void* Heap::allocate(size_t bytes)
400 {
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);
406
407 m_operationInProgress = Allocation;
408 void* result = m_markedSpace.allocate(bytes);
409 m_operationInProgress = NoOperation;
410 if (result)
411 return result;
412
413 return allocateSlowCase(bytes);
414 }
415
416 inline void* JSCell::operator new(size_t size, JSGlobalData* globalData)
417 {
418 JSCell* result = static_cast<JSCell*>(globalData->heap.allocate(size));
419 result->m_structure.clear();
420 return result;
421 }
422
423 inline void* JSCell::operator new(size_t size, ExecState* exec)
424 {
425 JSCell* result = static_cast<JSCell*>(exec->heap()->allocate(size));
426 result->m_structure.clear();
427 return result;
428 }
429
9dae56ea
A
430} // namespace JSC
431
432#endif // JSCell_h