JSCell.h 12.1 KB
Newer Older
weinig@apple.com's avatar
weinig@apple.com committed
1 2 3
/*
 *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
 *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
4
 *  Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Apple Inc. All rights reserved.
weinig@apple.com's avatar
weinig@apple.com committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
 *
 */

#ifndef JSCell_h
#define JSCell_h

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 "SlotVisitor.h"
33
#include "SlotVisitorInlineMethods.h"
34
#include "TypedArrayDescriptor.h"
35
#include "WriteBarrier.h"
36
#include <wtf/Noncopyable.h>
37
#include <wtf/TypeTraits.h>
weinig@apple.com's avatar
weinig@apple.com committed
38

39
namespace JSC {
weinig@apple.com's avatar
weinig@apple.com committed
40

41
    class CopyVisitor;
42
    class JSDestructibleObject;
43
    class JSGlobalObject;
44
    class LLIntOffsetsExtractor;
45
    class PropertyDescriptor;
46
    class PropertyNameArray;
47
    class Structure;
48 49 50 51 52

    enum EnumerationMode {
        ExcludeDontEnumProperties,
        IncludeDontEnumProperties
    };
53

54
    class JSCell {
ggaren@apple.com's avatar
ggaren@apple.com committed
55
        friend class JSValue;
56
        friend class MarkedBlock;
57
        template<typename T> friend void* allocateCell(Heap&);
58
        template<typename T> friend void* allocateCell(Heap&, size_t);
59

60
    public:
61 62
        static const unsigned StructureFlags = 0;

63 64 65
        static const bool needsDestruction = false;
        static const bool hasImmortalStructure = false;

66
        enum CreatingEarlyCellTag { CreatingEarlyCell };
67
        JSCell(CreatingEarlyCellTag);
68

69
    protected:
70
        JSCell(JSGlobalData&, Structure*);
71
        JS_EXPORT_PRIVATE static void destroy(JSCell*);
72 73 74

    public:
        // Querying the type.
75 76
        bool isString() const;
        bool isObject() const;
77
        bool isGetterSetter() const;
78
        bool inherits(const ClassInfo*) const;
79
        bool isAPIValueWrapper() const;
80

darin@apple.com's avatar
darin@apple.com committed
81
        Structure* structure() const;
82
        void setStructure(JSGlobalData&, Structure*);
83
        void clearStructure() { m_structure.clear(); }
weinig@apple.com's avatar
weinig@apple.com committed
84

85 86
        const char* className();

87
        // Extracting the value.
88 89
        JS_EXPORT_PRIVATE bool getString(ExecState*, String&) const;
        JS_EXPORT_PRIVATE String getString(ExecState*) const; // null string if not a string
90
        JS_EXPORT_PRIVATE JSObject* getObject(); // NULL if not an object
91 92
        const JSObject* getObject() const; // NULL if not an object
        
93 94
        JS_EXPORT_PRIVATE static CallType getCallData(JSCell*, CallData&);
        JS_EXPORT_PRIVATE static ConstructType getConstructData(JSCell*, ConstructData&);
95 96

        // Basic conversions.
97
        JS_EXPORT_PRIVATE JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
98
        bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
99
        bool toBoolean(ExecState*) const;
100 101
        JS_EXPORT_PRIVATE double toNumber(ExecState*) const;
        JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const;
102

103
        static void visitChildren(JSCell*, SlotVisitor&);
104
        JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&);
105 106

        // Object operations, with the toObject operation included.
107
        const ClassInfo* classInfo() const;
108
        const MethodTable* methodTable() const;
109
        static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
110
        static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
111
        
112
        static bool deleteProperty(JSCell*, ExecState*, PropertyName);
113
        static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
114

115
        static JSObject* toThisObject(JSCell*, ExecState*);
116 117 118

        void zap() { *reinterpret_cast<uintptr_t**>(this) = 0; }
        bool isZapped() const { return !*reinterpret_cast<uintptr_t* const*>(this); }
119

120 121 122 123
        // FIXME: Rename getOwnPropertySlot to virtualGetOwnPropertySlot, and
        // fastGetOwnPropertySlot to getOwnPropertySlot. Callers should always
        // call this function, not its slower virtual counterpart. (For integer
        // property names, we want a similar interface with appropriate optimizations.)
124
        bool fastGetOwnPropertySlot(ExecState*, PropertyName, PropertySlot&);
125
        JSValue fastGetOwnProperty(ExecState*, const String&);
126

127 128 129 130
        static ptrdiff_t structureOffset()
        {
            return OBJECT_OFFSETOF(JSCell, m_structure);
        }
131

132 133 134 135
        void* structureAddress()
        {
            return &m_structure;
        }
136
        
137 138 139 140
#if ENABLE(GC_VALIDATION)
        Structure* unvalidatedStructure() { return m_structure.unvalidatedGet(); }
#endif
        
141
        static const TypedArrayType TypedArrayStorageType = TypedArrayNone;
142 143
    protected:

144 145
        void finishCreation(JSGlobalData&);
        void finishCreation(JSGlobalData&, Structure*, CreatingEarlyCellTag);
146

darin@apple.com's avatar
darin@apple.com committed
147
        // Base implementation; for non-object classes implements getPropertySlot.
148
        static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
149
        static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
150 151

        // Dummy implementations of override-able static functions for classes to put in their MethodTable
152
        static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
153
        static NO_RETURN_DUE_TO_ASSERT void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
154
        static NO_RETURN_DUE_TO_ASSERT void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
155
        static NO_RETURN_DUE_TO_ASSERT void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
156
        static String className(const JSObject*);
157
        JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue);
158 159 160
        static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes);
        static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow);
        static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
161

162
    private:
163 164
        friend class LLIntOffsetsExtractor;
        
165
        WriteBarrier<Structure> m_structure;
166
    };
167

168
    inline JSCell::JSCell(CreatingEarlyCellTag)
169 170 171
    {
    }

172
    inline void JSCell::finishCreation(JSGlobalData& globalData)
173 174 175
    {
#if ENABLE(GC_VALIDATION)
        ASSERT(globalData.isInitializingObject());
176
        globalData.setInitializingObjectClass(0);
177 178 179 180 181 182
#else
        UNUSED_PARAM(globalData);
#endif
        ASSERT(m_structure);
    }

183
    inline Structure* JSCell::structure() const
184
    {
185
        return m_structure.get();
186 187
    }

188 189
    inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor)
    {
190 191
        MARK_LOG_PARENT(visitor, cell);

192
        visitor.append(&cell->m_structure);
193 194 195 196
    }

    // --- JSValue inlines ----------------------------

ggaren@apple.com's avatar
ggaren@apple.com committed
197
    inline bool JSValue::isString() const
198
    {
199
        return isCell() && asCell()->isString();
200 201
    }

202 203 204 205 206
    inline bool JSValue::isPrimitive() const
    {
        return !isCell() || asCell()->isString();
    }

ggaren@apple.com's avatar
ggaren@apple.com committed
207
    inline bool JSValue::isGetterSetter() const
darin@apple.com's avatar
darin@apple.com committed
208
    {
209
        return isCell() && asCell()->isGetterSetter();
darin@apple.com's avatar
darin@apple.com committed
210 211
    }

ggaren@apple.com's avatar
ggaren@apple.com committed
212
    inline bool JSValue::isObject() const
213
    {
214
        return isCell() && asCell()->isObject();
215 216
    }

217
    inline bool JSValue::getString(ExecState* exec, String& s) const
218
    {
219
        return isCell() && asCell()->getString(exec, s);
220 221
    }

222
    inline String JSValue::getString(ExecState* exec) const
223
    {
224
        return isCell() ? asCell()->getString(exec) : String();
225 226
    }

227
    template <typename Base> String HandleConverter<Base, Unknown>::getString(ExecState* exec) const
228 229 230 231
    {
        return jsValue().getString(exec);
    }

ggaren@apple.com's avatar
ggaren@apple.com committed
232
    inline JSObject* JSValue::getObject() const
233
    {
234
        return isCell() ? asCell()->getObject() : 0;
235 236
    }

ggaren@apple.com's avatar
ggaren@apple.com committed
237
    ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
238
    {
239 240 241 242 243 244 245 246 247 248 249
        if (isInt32()) {
            int32_t i = asInt32();
            v = static_cast<uint32_t>(i);
            return i >= 0;
        }
        if (isDouble()) {
            double d = asDouble();
            v = static_cast<uint32_t>(d);
            return v == d;
        }
        return false;
250 251
    }

252 253 254 255 256
    inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
    {
        return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
    }

ggaren@apple.com's avatar
ggaren@apple.com committed
257
    inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value)
258
    {
259 260 261 262 263 264 265 266
        if (isInt32()) {
            number = asInt32();
            value = *this;
            return true;
        }
        if (isDouble()) {
            number = asDouble();
            value = *this;
267 268
            return true;
        }
269 270 271 272 273 274 275 276 277 278 279 280 281
        if (isCell())
            return asCell()->getPrimitiveNumber(exec, number, value);
        if (isTrue()) {
            number = 1.0;
            value = *this;
            return true;
        }
        if (isFalse() || isNull()) {
            number = 0.0;
            value = *this;
            return true;
        }
        ASSERT(isUndefined());
282
        number = QNaN;
283 284
        value = *this;
        return true;
285 286
    }

ggaren@apple.com's avatar
ggaren@apple.com committed
287
    ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const
288
    {
289 290 291 292
        if (isInt32())
            return asInt32();
        if (isDouble())
            return asDouble();
293
        return toNumberSlowCase(exec);
294 295
    }

296
    inline JSObject* JSValue::toObject(ExecState* exec) const
297
    {
298 299 300 301 302 303
        return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject());
    }

    inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const
    {
        return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject);
304 305
    }

306
    template<typename T>
307
    void* allocateCell(Heap& heap, size_t size)
308
    {
309
        ASSERT(size >= sizeof(T));
310 311
#if ENABLE(GC_VALIDATION)
        ASSERT(!heap.globalData()->isInitializingObject());
312
        heap.globalData()->setInitializingObjectClass(&T::s_info);
313
#endif
314
        JSCell* result = 0;
315 316 317 318 319 320
        if (T::needsDestruction && T::hasImmortalStructure)
            result = static_cast<JSCell*>(heap.allocateWithImmortalStructureDestructor(size));
        else if (T::needsDestruction && !T::hasImmortalStructure)
            result = static_cast<JSCell*>(heap.allocateWithNormalDestructor(size));
        else 
            result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size));
321
        result->clearStructure();
322 323 324 325
        return result;
    }
    
    template<typename T>
326
    void* allocateCell(Heap& heap)
327
    {
328
        return allocateCell<T>(heap, sizeof(T));
329
    }
330 331 332 333 334
    
    inline bool isZapped(const JSCell* cell)
    {
        return cell->isZapped();
    }
335

336 337 338
    template<typename To, typename From>
    inline To jsCast(From* from)
    {
339
        ASSERT(!from || from->JSCell::inherits(&WTF::RemovePointer<To>::Type::s_info));
340 341
        return static_cast<To>(from);
    }
342
    
343 344 345
    template<typename To>
    inline To jsCast(JSValue from)
    {
346
        ASSERT(from.isCell() && from.asCell()->JSCell::inherits(&WTF::RemovePointer<To>::Type::s_info));
347 348 349
        return static_cast<To>(from.asCell());
    }

350 351 352 353 354 355
    template<typename To, typename From>
    inline To jsDynamicCast(From* from)
    {
        return from->inherits(&WTF::RemovePointer<To>::Type::s_info) ? static_cast<To>(from) : 0;
    }

356 357 358 359 360 361
    template<typename To>
    inline To jsDynamicCast(JSValue from)
    {
        return from.isCell() && from.asCell()->inherits(&WTF::RemovePointer<To>::Type::s_info) ? static_cast<To>(from.asCell()) : 0;
    }

362
} // namespace JSC
weinig@apple.com's avatar
weinig@apple.com committed
363 364

#endif // JSCell_h