]>
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" | |
6fe7ccc8 | 32 | #include "SlotVisitor.h" |
14957cd0 | 33 | #include "WriteBarrier.h" |
f9bf01c6 | 34 | #include <wtf/Noncopyable.h> |
9dae56ea A |
35 | |
36 | namespace JSC { | |
37 | ||
14957cd0 | 38 | class JSGlobalObject; |
6fe7ccc8 A |
39 | class LLIntOffsetsExtractor; |
40 | class PropertyDescriptor; | |
41 | class PropertyNameArray; | |
14957cd0 A |
42 | class Structure; |
43 | ||
6fe7ccc8 A |
44 | enum EnumerationMode { |
45 | ExcludeDontEnumProperties, | |
46 | IncludeDontEnumProperties | |
47 | }; | |
14957cd0 | 48 | |
6fe7ccc8 A |
49 | enum TypedArrayType { |
50 | TypedArrayNone, | |
51 | TypedArrayInt8, | |
52 | TypedArrayInt16, | |
53 | TypedArrayInt32, | |
54 | TypedArrayUint8, | |
55 | TypedArrayUint8Clamped, | |
56 | TypedArrayUint16, | |
57 | TypedArrayUint32, | |
58 | TypedArrayFloat32, | |
59 | TypedArrayFloat64 | |
14957cd0 A |
60 | }; |
61 | ||
14957cd0 | 62 | class JSCell { |
ba379fdc | 63 | friend class JSValue; |
14957cd0 | 64 | friend class MarkedBlock; |
6fe7ccc8 A |
65 | template<typename T> friend void* allocateCell(Heap&); |
66 | ||
67 | public: | |
14957cd0 | 68 | enum CreatingEarlyCellTag { CreatingEarlyCell }; |
6fe7ccc8 | 69 | JSCell(CreatingEarlyCellTag); |
14957cd0 A |
70 | |
71 | protected: | |
14957cd0 | 72 | JSCell(JSGlobalData&, Structure*); |
6fe7ccc8 | 73 | JS_EXPORT_PRIVATE static void destroy(JSCell*); |
9dae56ea A |
74 | |
75 | public: | |
76 | // Querying the type. | |
9dae56ea A |
77 | bool isString() const; |
78 | bool isObject() const; | |
6fe7ccc8 | 79 | bool isGetterSetter() const; |
f9bf01c6 | 80 | bool inherits(const ClassInfo*) const; |
6fe7ccc8 | 81 | bool isAPIValueWrapper() const; |
9dae56ea A |
82 | |
83 | Structure* structure() const; | |
6fe7ccc8 A |
84 | void setStructure(JSGlobalData&, Structure*); |
85 | void clearStructure() { m_structure.clear(); } | |
9dae56ea A |
86 | |
87 | // Extracting the value. | |
6fe7ccc8 A |
88 | JS_EXPORT_PRIVATE bool getString(ExecState* exec, UString&) const; |
89 | JS_EXPORT_PRIVATE UString getString(ExecState* exec) const; // null string if not a string | |
90 | JS_EXPORT_PRIVATE JSObject* getObject(); // NULL if not an object | |
9dae56ea A |
91 | const JSObject* getObject() const; // NULL if not an object |
92 | ||
6fe7ccc8 A |
93 | JS_EXPORT_PRIVATE static CallType getCallData(JSCell*, CallData&); |
94 | JS_EXPORT_PRIVATE static ConstructType getConstructData(JSCell*, ConstructData&); | |
9dae56ea A |
95 | |
96 | // Basic conversions. | |
6fe7ccc8 A |
97 | JS_EXPORT_PRIVATE JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; |
98 | bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; | |
99 | bool toBoolean(ExecState*) const; | |
100 | JS_EXPORT_PRIVATE double toNumber(ExecState*) const; | |
101 | JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const; | |
102 | ||
103 | static void visitChildren(JSCell*, SlotVisitor&); | |
9dae56ea A |
104 | |
105 | // Object operations, with the toObject operation included. | |
14957cd0 | 106 | const ClassInfo* classInfo() const; |
6fe7ccc8 A |
107 | const ClassInfo* validatedClassInfo() const; |
108 | const MethodTable* methodTable() const; | |
109 | static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); | |
110 | static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); | |
111 | ||
112 | static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName); | |
113 | static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); | |
114 | ||
115 | static JSObject* toThisObject(JSCell*, ExecState*); | |
9dae56ea | 116 | |
6fe7ccc8 A |
117 | void zap() { *reinterpret_cast<uintptr_t**>(this) = 0; } |
118 | bool isZapped() const { return !*reinterpret_cast<uintptr_t* const*>(this); } | |
f9bf01c6 | 119 | |
4e4e5a6f A |
120 | // FIXME: Rename getOwnPropertySlot to virtualGetOwnPropertySlot, and |
121 | // fastGetOwnPropertySlot to getOwnPropertySlot. Callers should always | |
122 | // call this function, not its slower virtual counterpart. (For integer | |
123 | // property names, we want a similar interface with appropriate optimizations.) | |
124 | bool fastGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); | |
6fe7ccc8 | 125 | JSValue fastGetOwnProperty(ExecState*, const UString&); |
4e4e5a6f | 126 | |
14957cd0 A |
127 | static ptrdiff_t structureOffset() |
128 | { | |
129 | return OBJECT_OFFSETOF(JSCell, m_structure); | |
130 | } | |
131 | ||
6fe7ccc8 A |
132 | static ptrdiff_t classInfoOffset() |
133 | { | |
134 | return OBJECT_OFFSETOF(JSCell, m_classInfo); | |
135 | } | |
136 | ||
137 | void* structureAddress() | |
138 | { | |
139 | return &m_structure; | |
140 | } | |
141 | ||
14957cd0 A |
142 | #if ENABLE(GC_VALIDATION) |
143 | Structure* unvalidatedStructure() { return m_structure.unvalidatedGet(); } | |
144 | #endif | |
145 | ||
6fe7ccc8 | 146 | static const TypedArrayType TypedArrayStorageType = TypedArrayNone; |
f9bf01c6 | 147 | protected: |
9dae56ea | 148 | |
6fe7ccc8 A |
149 | void finishCreation(JSGlobalData&); |
150 | void finishCreation(JSGlobalData&, Structure*, CreatingEarlyCellTag); | |
151 | ||
9dae56ea | 152 | // Base implementation; for non-object classes implements getPropertySlot. |
6fe7ccc8 A |
153 | static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&); |
154 | static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); | |
155 | ||
156 | // Dummy implementations of override-able static functions for classes to put in their MethodTable | |
157 | static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); | |
158 | static NO_RETURN_DUE_TO_ASSERT void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); | |
159 | static NO_RETURN_DUE_TO_ASSERT void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); | |
160 | static UString className(const JSObject*); | |
161 | static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue prototypeProperty); | |
162 | static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes); | |
163 | static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow); | |
164 | static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); | |
165 | ||
166 | private: | |
167 | friend class LLIntOffsetsExtractor; | |
9dae56ea | 168 | |
6fe7ccc8 | 169 | const ClassInfo* m_classInfo; |
14957cd0 | 170 | WriteBarrier<Structure> m_structure; |
9dae56ea A |
171 | }; |
172 | ||
6fe7ccc8 | 173 | inline JSCell::JSCell(CreatingEarlyCellTag) |
9dae56ea A |
174 | { |
175 | } | |
176 | ||
6fe7ccc8 | 177 | inline void JSCell::finishCreation(JSGlobalData& globalData) |
9dae56ea | 178 | { |
14957cd0 | 179 | #if ENABLE(GC_VALIDATION) |
6fe7ccc8 A |
180 | ASSERT(globalData.isInitializingObject()); |
181 | globalData.setInitializingObjectClass(0); | |
182 | #else | |
183 | UNUSED_PARAM(globalData); | |
ba379fdc | 184 | #endif |
6fe7ccc8 | 185 | ASSERT(m_structure); |
9dae56ea A |
186 | } |
187 | ||
6fe7ccc8 | 188 | inline Structure* JSCell::structure() const |
9dae56ea | 189 | { |
6fe7ccc8 | 190 | return m_structure.get(); |
9dae56ea A |
191 | } |
192 | ||
6fe7ccc8 | 193 | inline const ClassInfo* JSCell::classInfo() const |
9dae56ea | 194 | { |
6fe7ccc8 | 195 | return m_classInfo; |
9dae56ea A |
196 | } |
197 | ||
6fe7ccc8 | 198 | inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor) |
9dae56ea | 199 | { |
6fe7ccc8 | 200 | visitor.append(&cell->m_structure); |
9dae56ea A |
201 | } |
202 | ||
203 | // --- JSValue inlines ---------------------------- | |
204 | ||
ba379fdc | 205 | inline bool JSValue::isString() const |
9dae56ea | 206 | { |
ba379fdc | 207 | return isCell() && asCell()->isString(); |
9dae56ea A |
208 | } |
209 | ||
6fe7ccc8 A |
210 | inline bool JSValue::isPrimitive() const |
211 | { | |
212 | return !isCell() || asCell()->isString(); | |
213 | } | |
214 | ||
ba379fdc | 215 | inline bool JSValue::isGetterSetter() const |
9dae56ea | 216 | { |
ba379fdc | 217 | return isCell() && asCell()->isGetterSetter(); |
9dae56ea A |
218 | } |
219 | ||
ba379fdc | 220 | inline bool JSValue::isObject() const |
9dae56ea | 221 | { |
ba379fdc | 222 | return isCell() && asCell()->isObject(); |
9dae56ea A |
223 | } |
224 | ||
f9bf01c6 | 225 | inline bool JSValue::getString(ExecState* exec, UString& s) const |
9dae56ea | 226 | { |
f9bf01c6 | 227 | return isCell() && asCell()->getString(exec, s); |
9dae56ea A |
228 | } |
229 | ||
f9bf01c6 | 230 | inline UString JSValue::getString(ExecState* exec) const |
9dae56ea | 231 | { |
f9bf01c6 | 232 | return isCell() ? asCell()->getString(exec) : UString(); |
9dae56ea A |
233 | } |
234 | ||
14957cd0 A |
235 | template <typename Base> UString HandleConverter<Base, Unknown>::getString(ExecState* exec) const |
236 | { | |
237 | return jsValue().getString(exec); | |
238 | } | |
239 | ||
ba379fdc | 240 | inline JSObject* JSValue::getObject() const |
9dae56ea | 241 | { |
ba379fdc | 242 | return isCell() ? asCell()->getObject() : 0; |
9dae56ea A |
243 | } |
244 | ||
ba379fdc | 245 | ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const |
9dae56ea | 246 | { |
ba379fdc A |
247 | if (isInt32()) { |
248 | int32_t i = asInt32(); | |
249 | v = static_cast<uint32_t>(i); | |
250 | return i >= 0; | |
251 | } | |
252 | if (isDouble()) { | |
253 | double d = asDouble(); | |
254 | v = static_cast<uint32_t>(d); | |
255 | return v == d; | |
256 | } | |
257 | return false; | |
9dae56ea A |
258 | } |
259 | ||
ba379fdc | 260 | inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const |
9dae56ea | 261 | { |
ba379fdc | 262 | return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue(); |
9dae56ea A |
263 | } |
264 | ||
ba379fdc | 265 | inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value) |
9dae56ea | 266 | { |
ba379fdc A |
267 | if (isInt32()) { |
268 | number = asInt32(); | |
269 | value = *this; | |
270 | return true; | |
271 | } | |
272 | if (isDouble()) { | |
273 | number = asDouble(); | |
274 | value = *this; | |
275 | return true; | |
276 | } | |
277 | if (isCell()) | |
278 | return asCell()->getPrimitiveNumber(exec, number, value); | |
279 | if (isTrue()) { | |
280 | number = 1.0; | |
281 | value = *this; | |
282 | return true; | |
283 | } | |
284 | if (isFalse() || isNull()) { | |
285 | number = 0.0; | |
286 | value = *this; | |
9dae56ea A |
287 | return true; |
288 | } | |
ba379fdc | 289 | ASSERT(isUndefined()); |
6fe7ccc8 | 290 | number = std::numeric_limits<double>::quiet_NaN(); |
ba379fdc A |
291 | value = *this; |
292 | return true; | |
9dae56ea A |
293 | } |
294 | ||
ba379fdc | 295 | ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const |
9dae56ea | 296 | { |
ba379fdc A |
297 | if (isInt32()) |
298 | return asInt32(); | |
299 | if (isDouble()) | |
300 | return asDouble(); | |
6fe7ccc8 | 301 | return toNumberSlowCase(exec); |
9dae56ea A |
302 | } |
303 | ||
ba379fdc | 304 | inline JSObject* JSValue::toObject(ExecState* exec) const |
9dae56ea | 305 | { |
14957cd0 | 306 | return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject()); |
9dae56ea A |
307 | } |
308 | ||
14957cd0 | 309 | inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const |
9dae56ea | 310 | { |
14957cd0 | 311 | return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject); |
9dae56ea A |
312 | } |
313 | ||
6fe7ccc8 A |
314 | #if COMPILER(CLANG) |
315 | template<class T> | |
316 | struct NeedsDestructor { | |
317 | static const bool value = !__has_trivial_destructor(T); | |
318 | }; | |
319 | #else | |
320 | // Write manual specializations for this struct template if you care about non-clang compilers. | |
321 | template<class T> | |
322 | struct NeedsDestructor { | |
323 | static const bool value = true; | |
324 | }; | |
f9bf01c6 | 325 | #endif |
14957cd0 | 326 | |
6fe7ccc8 A |
327 | template<typename T> |
328 | void* allocateCell(Heap& heap) | |
14957cd0 | 329 | { |
6fe7ccc8 A |
330 | #if ENABLE(GC_VALIDATION) |
331 | ASSERT(!heap.globalData()->isInitializingObject()); | |
332 | heap.globalData()->setInitializingObjectClass(&T::s_info); | |
333 | #endif | |
334 | JSCell* result = 0; | |
335 | if (NeedsDestructor<T>::value) | |
336 | result = static_cast<JSCell*>(heap.allocateWithDestructor(sizeof(T))); | |
337 | else { | |
338 | ASSERT(T::s_info.methodTable.destroy == JSCell::destroy); | |
339 | result = static_cast<JSCell*>(heap.allocateWithoutDestructor(sizeof(T))); | |
14957cd0 | 340 | } |
6fe7ccc8 A |
341 | result->clearStructure(); |
342 | return result; | |
14957cd0 A |
343 | } |
344 | ||
6fe7ccc8 | 345 | inline bool isZapped(const JSCell* cell) |
14957cd0 | 346 | { |
6fe7ccc8 | 347 | return cell->isZapped(); |
14957cd0 A |
348 | } |
349 | ||
6fe7ccc8 A |
350 | template<typename To, typename From> |
351 | inline To jsCast(From* from) | |
14957cd0 | 352 | { |
6fe7ccc8 A |
353 | ASSERT(!from || from->JSCell::inherits(&WTF::RemovePointer<To>::Type::s_info)); |
354 | return static_cast<To>(from); | |
14957cd0 | 355 | } |
6fe7ccc8 A |
356 | |
357 | template<typename To> | |
358 | inline To jsCast(JSValue from) | |
14957cd0 | 359 | { |
6fe7ccc8 A |
360 | ASSERT(from.isCell() && from.asCell()->JSCell::inherits(&WTF::RemovePointer<To>::Type::s_info)); |
361 | return static_cast<To>(from.asCell()); | |
14957cd0 A |
362 | } |
363 | ||
6fe7ccc8 A |
364 | template<typename To, typename From> |
365 | inline To jsDynamicCast(From* from) | |
14957cd0 | 366 | { |
6fe7ccc8 | 367 | return from->inherits(&WTF::RemovePointer<To>::Type::s_info) ? static_cast<To>(from) : 0; |
14957cd0 A |
368 | } |
369 | ||
6fe7ccc8 A |
370 | template<typename To> |
371 | inline To jsDynamicCast(JSValue from) | |
14957cd0 | 372 | { |
6fe7ccc8 | 373 | return from.isCell() && from.asCell()->inherits(&WTF::RemovePointer<To>::Type::s_info) ? static_cast<To>(from.asCell()) : 0; |
14957cd0 A |
374 | } |
375 | ||
9dae56ea A |
376 | } // namespace JSC |
377 | ||
378 | #endif // JSCell_h |