]>
Commit | Line | Data |
---|---|---|
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 | |
36 | namespace 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 |