]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/JSCell.h
JavaScriptCore-903.5.tar.gz
[apple/javascriptcore.git] / runtime / JSCell.h
index 43d81a55563dbae2738aa9c857db84fcbb4e0ff9..e30bc183ff69ce2396acef956e15ca566d15777d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
- *  Copyright (C) 2003, 2004, 2005, 2007, 2008 Apple Inc. All rights reserved.
+ *  Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
 #ifndef JSCell_h
 #define JSCell_h
 
+#include "CallData.h"
+#include "CallFrame.h"
+#include "ConstructData.h"
+#include "Heap.h"
+#include "JSLock.h"
+#include "JSValueInlineMethods.h"
+#include "MarkStack.h"
+#include "WriteBarrier.h"
 #include <wtf/Noncopyable.h>
-#include "Structure.h"
-#include "JSValue.h"
-#include "JSImmediate.h"
-#include "Collector.h"
 
 namespace JSC {
 
-    class JSCell : Noncopyable {
-        friend class JIT;
+    class JSGlobalObject;
+    class Structure;
+
+#if COMPILER(MSVC)
+    // If WTF_MAKE_NONCOPYABLE is applied to JSCell we end up with a bunch of
+    // undefined references to the JSCell copy constructor and assignment operator
+    // when linking JavaScriptCore.
+    class MSVCBugWorkaround {
+        WTF_MAKE_NONCOPYABLE(MSVCBugWorkaround);
+
+    protected:
+        MSVCBugWorkaround() { }
+        ~MSVCBugWorkaround() { }
+    };
+
+    class JSCell : MSVCBugWorkaround {
+#else
+    class JSCell {
+        WTF_MAKE_NONCOPYABLE(JSCell);
+#endif
+
+        friend class ExecutableBase;
         friend class GetterSetter;
         friend class Heap;
-        friend class JSNumberCell;
         friend class JSObject;
         friend class JSPropertyNameIterator;
         friend class JSString;
-        friend class JSValuePtr;
-        friend class Interpreter;
+        friend class JSValue;
+        friend class JSAPIValueWrapper;
+        friend class JSZombie;
+        friend class JSGlobalData;
+        friend class MarkedSpace;
+        friend class MarkedBlock;
+        friend class ScopeChainNode;
+        friend class Structure;
+        friend class StructureChain;
+        friend class RegExp;
+        enum CreatingEarlyCellTag { CreatingEarlyCell };
+
+    protected:
+        enum VPtrStealingHackType { VPtrStealingHack };
 
     private:
-        explicit JSCell(Structure*);
+        explicit JSCell(VPtrStealingHackType) { }
+        JSCell(JSGlobalData&, Structure*);
+        JSCell(JSGlobalData&, Structure*, CreatingEarlyCellTag);
         virtual ~JSCell();
+        static const ClassInfo s_dummyCellInfo;
 
     public:
+        static Structure* createDummyStructure(JSGlobalData&);
+
         // Querying the type.
-        bool isNumber() const;
         bool isString() const;
         bool isObject() const;
         virtual bool isGetterSetter() const;
-        virtual bool isObject(const ClassInfo*) const;
+        bool inherits(const ClassInfo*) const;
+        virtual bool isAPIValueWrapper() const { return false; }
+        virtual bool isPropertyNameIterator() const { return false; }
 
         Structure* structure() const;
 
         // Extracting the value.
-        bool getString(UString&) const;
-        UString getString() const; // null string if not a string
+        bool getString(ExecState* exec, UString&) const;
+        UString getString(ExecState* exec) const; // null string if not a string
         JSObject* getObject(); // NULL if not an object
         const JSObject* getObject() const; // NULL if not an object
         
@@ -66,233 +107,324 @@ namespace JSC {
         virtual ConstructType getConstructData(ConstructData&);
 
         // Extracting integer values.
-        // FIXME: remove these methods, can check isNumberCell in JSValuePtr && then call asNumberCell::*.
+        // FIXME: remove these methods, can check isNumberCell in JSValue && then call asNumberCell::*.
         virtual bool getUInt32(uint32_t&) const;
-        virtual bool getTruncatedInt32(int32_t&) const;
-        virtual bool getTruncatedUInt32(uint32_t&) const;
 
         // Basic conversions.
-        virtual JSValuePtr toPrimitive(ExecState*, PreferredPrimitiveType) const = 0;
-        virtual bool getPrimitiveNumber(ExecState*, double& number, JSValuePtr&) = 0;
-        virtual bool toBoolean(ExecState*) const = 0;
-        virtual double toNumber(ExecState*) const = 0;
-        virtual UString toString(ExecState*) const = 0;
-        virtual JSObject* toObject(ExecState*) const = 0;
+        virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
+        virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue&);
+        virtual bool toBoolean(ExecState*) const;
+        virtual double toNumber(ExecState*) const;
+        virtual UString toString(ExecState*) const;
+        virtual JSObject* toObject(ExecState*, JSGlobalObject*) const;
 
         // Garbage collection.
         void* operator new(size_t, ExecState*);
         void* operator new(size_t, JSGlobalData*);
         void* operator new(size_t, void* placementNewDestination) { return placementNewDestination; }
-        virtual void mark();
-        bool marked() const;
+
+        virtual void visitChildren(SlotVisitor&);
+#if ENABLE(JSC_ZOMBIES)
+        virtual bool isZombie() const { return false; }
+#endif
 
         // Object operations, with the toObject operation included.
-        virtual const ClassInfo* classInfo() const;
-        virtual void put(ExecState*, const Identifier& propertyName, JSValuePtr, PutPropertySlot&);
-        virtual void put(ExecState*, unsigned propertyName, JSValuePtr);
+        const ClassInfo* classInfo() const;
+        virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
+        virtual void put(ExecState*, unsigned propertyName, JSValue);
         virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
         virtual bool deleteProperty(ExecState*, unsigned propertyName);
 
         virtual JSObject* toThisObject(ExecState*) const;
-        virtual UString toThisString(ExecState*) const;
-        virtual JSString* toThisJSString(ExecState*);
-        virtual JSValuePtr getJSNumber();
+        virtual JSValue getJSNumber();
         void* vptr() { return *reinterpret_cast<void**>(this); }
+        void setVPtr(void* vptr) { *reinterpret_cast<void**>(this) = vptr; }
+
+        // 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.)
+        bool fastGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
+
+        static ptrdiff_t structureOffset()
+        {
+            return OBJECT_OFFSETOF(JSCell, m_structure);
+        }
+
+#if ENABLE(GC_VALIDATION)
+        Structure* unvalidatedStructure() { return m_structure.unvalidatedGet(); }
+#endif
+        
+    protected:
+        static const unsigned AnonymousSlotCount = 0;
 
     private:
         // Base implementation; for non-object classes implements getPropertySlot.
-        bool fastGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
         virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
         virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
         
-        Structure* m_structure;
+        WriteBarrier<Structure> m_structure;
     };
 
-    JSCell* asCell(JSValuePtr);
-
-    inline JSCell* asCell(JSValuePtr value)
+    inline JSCell::JSCell(JSGlobalData& globalData, Structure* structure)
+        : m_structure(globalData, this, structure)
     {
-        return value.asCell();
+        ASSERT(m_structure);
     }
 
-    inline JSCell::JSCell(Structure* structure)
-        : m_structure(structure)
+    inline JSCell::JSCell(JSGlobalData& globalData, Structure* structure, CreatingEarlyCellTag)
     {
+#if ENABLE(GC_VALIDATION)
+        if (structure)
+#endif
+            m_structure.setEarlyValue(globalData, this, structure);
+        // Very first set of allocations won't have a real structure.
+        ASSERT(m_structure || !globalData.dummyMarkableCellStructure);
     }
 
     inline JSCell::~JSCell()
     {
+#if ENABLE(GC_VALIDATION)
+        m_structure.clear();
+#endif
     }
 
-    inline bool JSCell::isNumber() const
+    inline Structure* JSCell::structure() const
     {
-        return Heap::isNumber(const_cast<JSCell*>(this));
+        return m_structure.get();
     }
 
-    inline bool JSCell::isObject() const
+    inline void JSCell::visitChildren(SlotVisitor& visitor)
     {
-        return m_structure->typeInfo().type() == ObjectType;
+        visitor.append(&m_structure);
     }
 
-    inline bool JSCell::isString() const
-    {
-        return m_structure->typeInfo().type() == StringType;
-    }
+    // --- JSValue inlines ----------------------------
 
-    inline Structure* JSCell::structure() const
+    inline bool JSValue::isString() const
     {
-        return m_structure;
+        return isCell() && asCell()->isString();
     }
 
-    inline bool JSCell::marked() const
+    inline bool JSValue::isGetterSetter() const
     {
-        return Heap::isCellMarked(this);
+        return isCell() && asCell()->isGetterSetter();
     }
 
-    inline void JSCell::mark()
+    inline bool JSValue::isObject() const
     {
-        return Heap::markCell(this);
+        return isCell() && asCell()->isObject();
     }
 
-    ALWAYS_INLINE JSCell* JSValuePtr::asCell() const
+    inline bool JSValue::getString(ExecState* exec, UString& s) const
     {
-        ASSERT(isCell());
-        return m_ptr;
+        return isCell() && asCell()->getString(exec, s);
     }
 
-    inline void* JSCell::operator new(size_t size, JSGlobalData* globalData)
+    inline UString JSValue::getString(ExecState* exec) const
     {
-#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE
-        return globalData->heap.inlineAllocate(size);
-#else
-        return globalData->heap.allocate(size);
-#endif
+        return isCell() ? asCell()->getString(exec) : UString();
     }
 
-    // --- JSValue inlines ----------------------------
-
-    inline bool JSValuePtr::isString() const
+    template <typename Base> UString HandleConverter<Base, Unknown>::getString(ExecState* exec) const
     {
-        return !JSImmediate::isImmediate(asValue()) && asCell()->isString();
+        return jsValue().getString(exec);
     }
 
-    inline bool JSValuePtr::isGetterSetter() const
+    inline JSObject* JSValue::getObject() const
     {
-        return !JSImmediate::isImmediate(asValue()) && asCell()->isGetterSetter();
+        return isCell() ? asCell()->getObject() : 0;
     }
 
-    inline bool JSValuePtr::isObject() const
+    inline CallType getCallData(JSValue value, CallData& callData)
     {
-        return !JSImmediate::isImmediate(asValue()) && asCell()->isObject();
+        CallType result = value.isCell() ? value.asCell()->getCallData(callData) : CallTypeNone;
+        ASSERT(result == CallTypeNone || value.isValidCallee());
+        return result;
     }
 
-    inline bool JSValuePtr::getString(UString& s) const
+    inline ConstructType getConstructData(JSValue value, ConstructData& constructData)
     {
-        return !JSImmediate::isImmediate(asValue()) && asCell()->getString(s);
+        ConstructType result = value.isCell() ? value.asCell()->getConstructData(constructData) : ConstructTypeNone;
+        ASSERT(result == ConstructTypeNone || value.isValidCallee());
+        return result;
     }
 
-    inline UString JSValuePtr::getString() const
+    ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
     {
-        return JSImmediate::isImmediate(asValue()) ? UString() : asCell()->getString();
+        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;
     }
 
-    inline JSObject* JSValuePtr::getObject() const
+    inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
     {
-        return JSImmediate::isImmediate(asValue()) ? 0 : asCell()->getObject();
+        return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
     }
 
-    inline CallType JSValuePtr::getCallData(CallData& callData)
+    inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value)
     {
-        return JSImmediate::isImmediate(asValue()) ? CallTypeNone : asCell()->getCallData(callData);
+        if (isInt32()) {
+            number = asInt32();
+            value = *this;
+            return true;
+        }
+        if (isDouble()) {
+            number = asDouble();
+            value = *this;
+            return true;
+        }
+        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());
+        number = nonInlineNaN();
+        value = *this;
+        return true;
     }
 
-    inline ConstructType JSValuePtr::getConstructData(ConstructData& constructData)
+    inline bool JSValue::toBoolean(ExecState* exec) const
     {
-        return JSImmediate::isImmediate(asValue()) ? ConstructTypeNone : asCell()->getConstructData(constructData);
+        if (isInt32())
+            return asInt32() != 0;
+        if (isDouble())
+            return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
+        if (isCell())
+            return asCell()->toBoolean(exec);
+        return isTrue(); // false, null, and undefined all convert to false.
     }
 
-    ALWAYS_INLINE bool JSValuePtr::getUInt32(uint32_t& v) const
+    ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const
     {
-        return JSImmediate::isImmediate(asValue()) ? JSImmediate::getUInt32(asValue(), v) : asCell()->getUInt32(v);
+        if (isInt32())
+            return asInt32();
+        if (isDouble())
+            return asDouble();
+        if (isCell())
+            return asCell()->toNumber(exec);
+        if (isTrue())
+            return 1.0;
+        return isUndefined() ? nonInlineNaN() : 0; // null and false both convert to 0.
     }
 
-    ALWAYS_INLINE bool JSValuePtr::getTruncatedInt32(int32_t& v) const
+    inline JSValue JSValue::getJSNumber()
     {
-        return JSImmediate::isImmediate(asValue()) ? JSImmediate::getTruncatedInt32(asValue(), v) : asCell()->getTruncatedInt32(v);
+        if (isInt32() || isDouble())
+            return *this;
+        if (isCell())
+            return asCell()->getJSNumber();
+        return JSValue();
     }
 
-    inline bool JSValuePtr::getTruncatedUInt32(uint32_t& v) const
+    inline JSObject* JSValue::toObject(ExecState* exec) const
     {
-        return JSImmediate::isImmediate(asValue()) ? JSImmediate::getTruncatedUInt32(asValue(), v) : asCell()->getTruncatedUInt32(v);
+        return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject());
     }
 
-    inline void JSValuePtr::mark()
+    inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const
     {
-        asCell()->mark(); // callers should check !marked() before calling mark(), so this should only be called with cells
+        return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject);
     }
 
-    inline bool JSValuePtr::marked() const
+    inline JSObject* JSValue::toThisObject(ExecState* exec) const
     {
-        return JSImmediate::isImmediate(asValue()) || asCell()->marked();
+        return isCell() ? asCell()->toThisObject(exec) : toThisObjectSlowCase(exec);
     }
 
-    inline JSValuePtr JSValuePtr::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
+    inline Heap* Heap::heap(JSValue v)
     {
-        return JSImmediate::isImmediate(asValue()) ? asValue() : asCell()->toPrimitive(exec, preferredType);
+        if (!v.isCell())
+            return 0;
+        return heap(v.asCell());
     }
 
-    inline bool JSValuePtr::getPrimitiveNumber(ExecState* exec, double& number, JSValuePtr& value)
+    inline Heap* Heap::heap(JSCell* c)
     {
-        if (JSImmediate::isImmediate(asValue())) {
-            number = JSImmediate::toDouble(asValue());
-            value = asValue();
-            return true;
-        }
-        return asCell()->getPrimitiveNumber(exec, number, value);
+        return MarkedSpace::heap(c);
     }
-
-    inline bool JSValuePtr::toBoolean(ExecState* exec) const
+    
+#if ENABLE(JSC_ZOMBIES)
+    inline bool JSValue::isZombie() const
     {
-        return JSImmediate::isImmediate(asValue()) ? JSImmediate::toBoolean(asValue()) : asCell()->toBoolean(exec);
+        return isCell() && asCell() > (JSCell*)0x1ffffffffL && asCell()->isZombie();
     }
+#endif
 
-    ALWAYS_INLINE double JSValuePtr::toNumber(ExecState* exec) const
+    inline void* MarkedBlock::allocate()
     {
-        return JSImmediate::isImmediate(asValue()) ? JSImmediate::toDouble(asValue()) : asCell()->toNumber(exec);
-    }
+        while (m_nextAtom < m_endAtom) {
+            if (!m_marks.testAndSet(m_nextAtom)) {
+                JSCell* cell = reinterpret_cast<JSCell*>(&atoms()[m_nextAtom]);
+                m_nextAtom += m_atomsPerCell;
+                cell->~JSCell();
+                return cell;
+            }
+            m_nextAtom += m_atomsPerCell;
+        }
 
-    inline UString JSValuePtr::toString(ExecState* exec) const
-    {
-        return JSImmediate::isImmediate(asValue()) ? JSImmediate::toString(asValue()) : asCell()->toString(exec);
+        return 0;
     }
-
-    inline JSObject* JSValuePtr::toObject(ExecState* exec) const
+    
+    inline MarkedSpace::SizeClass& MarkedSpace::sizeClassFor(size_t bytes)
     {
-        return JSImmediate::isImmediate(asValue()) ? JSImmediate::toObject(asValue(), exec) : asCell()->toObject(exec);
+        ASSERT(bytes && bytes < maxCellSize);
+        if (bytes < preciseCutoff)
+            return m_preciseSizeClasses[(bytes - 1) / preciseStep];
+        return m_impreciseSizeClasses[(bytes - 1) / impreciseStep];
     }
 
-    inline JSObject* JSValuePtr::toThisObject(ExecState* exec) const
+    inline void* MarkedSpace::allocate(size_t bytes)
     {
-        if (UNLIKELY(JSImmediate::isImmediate(asValue())))
-            return JSImmediate::toThisObject(asValue(), exec);
-        return asCell()->toThisObject(exec);
+        SizeClass& sizeClass = sizeClassFor(bytes);
+        return allocateFromSizeClass(sizeClass);
     }
-
-    inline bool JSValuePtr::needsThisConversion() const
+    
+    inline void* Heap::allocate(size_t bytes)
     {
-        if (UNLIKELY(JSImmediate::isImmediate(asValue())))
-            return true;
-        return asCell()->structure()->typeInfo().needsThisConversion();
+        ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
+        ASSERT(JSLock::lockCount() > 0);
+        ASSERT(JSLock::currentThreadIsHoldingLock());
+        ASSERT(bytes <= MarkedSpace::maxCellSize);
+        ASSERT(m_operationInProgress == NoOperation);
+
+        m_operationInProgress = Allocation;
+        void* result = m_markedSpace.allocate(bytes);
+        m_operationInProgress = NoOperation;
+        if (result)
+            return result;
+
+        return allocateSlowCase(bytes);
     }
 
-    inline UString JSValuePtr::toThisString(ExecState* exec) const
+    inline void* JSCell::operator new(size_t size, JSGlobalData* globalData)
     {
-        return JSImmediate::isImmediate(asValue()) ? JSImmediate::toString(asValue()) : asCell()->toThisString(exec);
+        JSCell* result = static_cast<JSCell*>(globalData->heap.allocate(size));
+        result->m_structure.clear();
+        return result;
     }
 
-    inline JSValuePtr JSValuePtr::getJSNumber()
+    inline void* JSCell::operator new(size_t size, ExecState* exec)
     {
-        return JSImmediate::isNumber(asValue()) ? asValue() : JSImmediate::isImmediate(asValue()) ? noValue() : asCell()->getJSNumber();
+        JSCell* result = static_cast<JSCell*>(exec->heap()->allocate(size));
+        result->m_structure.clear();
+        return result;
     }
 
 } // namespace JSC