]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/JSCell.h
JavaScriptCore-903.5.tar.gz
[apple/javascriptcore.git] / 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 "CallFrame.h"
28 #include "ConstructData.h"
29 #include "Heap.h"
30 #include "JSLock.h"
31 #include "JSValueInlineMethods.h"
32 #include "MarkStack.h"
33 #include "WriteBarrier.h"
34 #include <wtf/Noncopyable.h>
35
36 namespace JSC {
37
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;
60 friend class GetterSetter;
61 friend class Heap;
62 friend class JSObject;
63 friend class JSPropertyNameIterator;
64 friend class JSString;
65 friend class JSValue;
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;
74 friend class RegExp;
75 enum CreatingEarlyCellTag { CreatingEarlyCell };
76
77 protected:
78 enum VPtrStealingHackType { VPtrStealingHack };
79
80 private:
81 explicit JSCell(VPtrStealingHackType) { }
82 JSCell(JSGlobalData&, Structure*);
83 JSCell(JSGlobalData&, Structure*, CreatingEarlyCellTag);
84 virtual ~JSCell();
85 static const ClassInfo s_dummyCellInfo;
86
87 public:
88 static Structure* createDummyStructure(JSGlobalData&);
89
90 // Querying the type.
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; }
97
98 Structure* structure() const;
99
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
105
106 virtual CallType getCallData(CallData&);
107 virtual ConstructType getConstructData(ConstructData&);
108
109 // Extracting integer values.
110 // FIXME: remove these methods, can check isNumberCell in JSValue && then call asNumberCell::*.
111 virtual bool getUInt32(uint32_t&) const;
112
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;
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; }
125
126 virtual void visitChildren(SlotVisitor&);
127 #if ENABLE(JSC_ZOMBIES)
128 virtual bool isZombie() const { return false; }
129 #endif
130
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);
137
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; }
142
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
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
158 protected:
159 static const unsigned AnonymousSlotCount = 0;
160
161 private:
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&);
165
166 WriteBarrier<Structure> m_structure;
167 };
168
169 inline JSCell::JSCell(JSGlobalData& globalData, Structure* structure)
170 : m_structure(globalData, this, structure)
171 {
172 ASSERT(m_structure);
173 }
174
175 inline JSCell::JSCell(JSGlobalData& globalData, Structure* structure, CreatingEarlyCellTag)
176 {
177 #if ENABLE(GC_VALIDATION)
178 if (structure)
179 #endif
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);
183 }
184
185 inline JSCell::~JSCell()
186 {
187 #if ENABLE(GC_VALIDATION)
188 m_structure.clear();
189 #endif
190 }
191
192 inline Structure* JSCell::structure() const
193 {
194 return m_structure.get();
195 }
196
197 inline void JSCell::visitChildren(SlotVisitor& visitor)
198 {
199 visitor.append(&m_structure);
200 }
201
202 // --- JSValue inlines ----------------------------
203
204 inline bool JSValue::isString() const
205 {
206 return isCell() && asCell()->isString();
207 }
208
209 inline bool JSValue::isGetterSetter() const
210 {
211 return isCell() && asCell()->isGetterSetter();
212 }
213
214 inline bool JSValue::isObject() const
215 {
216 return isCell() && asCell()->isObject();
217 }
218
219 inline bool JSValue::getString(ExecState* exec, UString& s) const
220 {
221 return isCell() && asCell()->getString(exec, s);
222 }
223
224 inline UString JSValue::getString(ExecState* exec) const
225 {
226 return isCell() ? asCell()->getString(exec) : UString();
227 }
228
229 template <typename Base> UString HandleConverter<Base, Unknown>::getString(ExecState* exec) const
230 {
231 return jsValue().getString(exec);
232 }
233
234 inline JSObject* JSValue::getObject() const
235 {
236 return isCell() ? asCell()->getObject() : 0;
237 }
238
239 inline CallType getCallData(JSValue value, CallData& callData)
240 {
241 CallType result = value.isCell() ? value.asCell()->getCallData(callData) : CallTypeNone;
242 ASSERT(result == CallTypeNone || value.isValidCallee());
243 return result;
244 }
245
246 inline ConstructType getConstructData(JSValue value, ConstructData& constructData)
247 {
248 ConstructType result = value.isCell() ? value.asCell()->getConstructData(constructData) : ConstructTypeNone;
249 ASSERT(result == ConstructTypeNone || value.isValidCallee());
250 return result;
251 }
252
253 ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
254 {
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;
266 }
267
268 inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
269 {
270 return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
271 }
272
273 inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value)
274 {
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;
295 return true;
296 }
297 ASSERT(isUndefined());
298 number = nonInlineNaN();
299 value = *this;
300 return true;
301 }
302
303 inline bool JSValue::toBoolean(ExecState* exec) const
304 {
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.
312 }
313
314 ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const
315 {
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.
325 }
326
327 inline JSValue JSValue::getJSNumber()
328 {
329 if (isInt32() || isDouble())
330 return *this;
331 if (isCell())
332 return asCell()->getJSNumber();
333 return JSValue();
334 }
335
336 inline JSObject* JSValue::toObject(ExecState* exec) const
337 {
338 return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject());
339 }
340
341 inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const
342 {
343 return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject);
344 }
345
346 inline JSObject* JSValue::toThisObject(ExecState* exec) const
347 {
348 return isCell() ? asCell()->toThisObject(exec) : toThisObjectSlowCase(exec);
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 {
360 return MarkedSpace::heap(c);
361 }
362
363 #if ENABLE(JSC_ZOMBIES)
364 inline bool JSValue::isZombie() const
365 {
366 return isCell() && asCell() > (JSCell*)0x1ffffffffL && asCell()->isZombie();
367 }
368 #endif
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
430 } // namespace JSC
431
432 #endif // JSCell_h