]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/JSCell.h
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / runtime / JSCell.h
index 2cb5959a1571005c88223952681d98c1e50111ca..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 {
+    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 JIT;
-        friend class JSNumberCell;
         friend class JSObject;
         friend class JSPropertyNameIterator;
         friend class JSString;
         friend class JSValue;
         friend class JSAPIValueWrapper;
-        friend struct VPtrSet;
+        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.
-#if USE(JSVALUE32)
-        bool isNumber() const;
-#endif
         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
         
@@ -74,97 +111,92 @@ namespace JSC {
         virtual bool getUInt32(uint32_t&) const;
 
         // Basic conversions.
-        virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const = 0;
-        virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue&) = 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;
+        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 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(JSValue);
-
-    inline JSCell* asCell(JSValue 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 USE(JSVALUE32)
-    inline bool JSCell::isNumber() const
-    {
-        return Heap::isNumber(const_cast<JSCell*>(this));
-    }
+#if ENABLE(GC_VALIDATION)
+        m_structure.clear();
 #endif
-
-    inline bool JSCell::isObject() const
-    {
-        return m_structure->typeInfo().type() == ObjectType;
-    }
-
-    inline bool JSCell::isString() const
-    {
-        return m_structure->typeInfo().type() == StringType;
     }
 
     inline Structure* JSCell::structure() const
     {
-        return m_structure;
-    }
-
-    inline bool JSCell::marked() const
-    {
-        return Heap::isCellMarked(this);
-    }
-
-    inline void JSCell::mark()
-    {
-        return Heap::markCell(this);
+        return m_structure.get();
     }
 
-    inline void* JSCell::operator new(size_t size, JSGlobalData* globalData)
+    inline void JSCell::visitChildren(SlotVisitor& visitor)
     {
-#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE
-        return globalData->heap.inlineAllocate(size);
-#else
-        return globalData->heap.allocate(size);
-#endif
+        visitor.append(&m_structure);
     }
 
     // --- JSValue inlines ----------------------------
@@ -184,14 +216,19 @@ namespace JSC {
         return isCell() && asCell()->isObject();
     }
 
-    inline bool JSValue::getString(UString& s) const
+    inline bool JSValue::getString(ExecState* exec, UString& s) const
+    {
+        return isCell() && asCell()->getString(exec, s);
+    }
+
+    inline UString JSValue::getString(ExecState* exec) const
     {
-        return isCell() && asCell()->getString(s);
+        return isCell() ? asCell()->getString(exec) : UString();
     }
 
-    inline UString JSValue::getString() const
+    template <typename Base> UString HandleConverter<Base, Unknown>::getString(ExecState* exec) const
     {
-        return isCell() ? asCell()->getString() : UString();
+        return jsValue().getString(exec);
     }
 
     inline JSObject* JSValue::getObject() const
@@ -199,14 +236,18 @@ namespace JSC {
         return isCell() ? asCell()->getObject() : 0;
     }
 
-    inline CallType JSValue::getCallData(CallData& callData)
+    inline CallType getCallData(JSValue value, CallData& callData)
     {
-        return isCell() ? asCell()->getCallData(callData) : CallTypeNone;
+        CallType result = value.isCell() ? value.asCell()->getCallData(callData) : CallTypeNone;
+        ASSERT(result == CallTypeNone || value.isValidCallee());
+        return result;
     }
 
-    inline ConstructType JSValue::getConstructData(ConstructData& constructData)
+    inline ConstructType getConstructData(JSValue value, ConstructData& constructData)
     {
-        return isCell() ? asCell()->getConstructData(constructData) : ConstructTypeNone;
+        ConstructType result = value.isCell() ? value.asCell()->getConstructData(constructData) : ConstructTypeNone;
+        ASSERT(result == ConstructTypeNone || value.isValidCallee());
+        return result;
     }
 
     ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
@@ -224,24 +265,6 @@ namespace JSC {
         return false;
     }
 
-    inline void JSValue::mark()
-    {
-        asCell()->mark(); // callers should check !marked() before calling mark(), so this should only be called with cells
-    }
-
-    inline bool JSValue::marked() const
-    {
-        return !isCell() || asCell()->marked();
-    }
-
-#if !USE(JSVALUE32_64)
-    ALWAYS_INLINE JSCell* JSValue::asCell() const
-    {
-        ASSERT(isCell());
-        return m_ptr;
-    }
-#endif // !USE(JSVALUE32_64)
-
     inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
     {
         return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
@@ -301,53 +324,107 @@ namespace JSC {
         return isUndefined() ? nonInlineNaN() : 0; // null and false both convert to 0.
     }
 
-    inline UString JSValue::toString(ExecState* exec) const
+    inline JSValue JSValue::getJSNumber()
     {
+        if (isInt32() || isDouble())
+            return *this;
         if (isCell())
-            return asCell()->toString(exec);
-        if (isInt32())
-            return UString::from(asInt32());
-        if (isDouble())
-            return asDouble() == 0.0 ? "0" : UString::from(asDouble());
-        if (isTrue())
-            return "true";
-        if (isFalse())
-            return "false";
-        if (isNull())
-            return "null";
-        ASSERT(isUndefined());
-        return "undefined";
+            return asCell()->getJSNumber();
+        return JSValue();
     }
 
-    inline bool JSValue::needsThisConversion() const
+    inline JSObject* JSValue::toObject(ExecState* exec) const
     {
-        if (UNLIKELY(!isCell()))
-            return true;
-        return asCell()->structure()->typeInfo().needsThisConversion();
+        return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject());
     }
 
-    inline UString JSValue::toThisString(ExecState* exec) const
+    inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const
     {
-        return isCell() ? asCell()->toThisString(exec) : toString(exec);
+        return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject);
     }
 
-    inline JSValue JSValue::getJSNumber()
+    inline JSObject* JSValue::toThisObject(ExecState* exec) const
     {
-        if (isInt32() || isDouble())
-            return *this;
-        if (isCell())
-            return asCell()->getJSNumber();
-        return JSValue();
+        return isCell() ? asCell()->toThisObject(exec) : toThisObjectSlowCase(exec);
     }
 
-    inline JSObject* JSValue::toObject(ExecState* exec) const
+    inline Heap* Heap::heap(JSValue v)
     {
-        return isCell() ? asCell()->toObject(exec) : toObjectSlowCase(exec);
+        if (!v.isCell())
+            return 0;
+        return heap(v.asCell());
     }
 
-    inline JSObject* JSValue::toThisObject(ExecState* exec) const
+    inline Heap* Heap::heap(JSCell* c)
     {
-        return isCell() ? asCell()->toThisObject(exec) : toThisObjectSlowCase(exec);
+        return MarkedSpace::heap(c);
+    }
+    
+#if ENABLE(JSC_ZOMBIES)
+    inline bool JSValue::isZombie() const
+    {
+        return isCell() && asCell() > (JSCell*)0x1ffffffffL && asCell()->isZombie();
+    }
+#endif
+
+    inline void* MarkedBlock::allocate()
+    {
+        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;
+        }
+
+        return 0;
+    }
+    
+    inline MarkedSpace::SizeClass& MarkedSpace::sizeClassFor(size_t bytes)
+    {
+        ASSERT(bytes && bytes < maxCellSize);
+        if (bytes < preciseCutoff)
+            return m_preciseSizeClasses[(bytes - 1) / preciseStep];
+        return m_impreciseSizeClasses[(bytes - 1) / impreciseStep];
+    }
+
+    inline void* MarkedSpace::allocate(size_t bytes)
+    {
+        SizeClass& sizeClass = sizeClassFor(bytes);
+        return allocateFromSizeClass(sizeClass);
+    }
+    
+    inline void* Heap::allocate(size_t bytes)
+    {
+        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 void* JSCell::operator new(size_t size, JSGlobalData* globalData)
+    {
+        JSCell* result = static_cast<JSCell*>(globalData->heap.allocate(size));
+        result->m_structure.clear();
+        return result;
+    }
+
+    inline void* JSCell::operator new(size_t size, ExecState* exec)
+    {
+        JSCell* result = static_cast<JSCell*>(exec->heap()->allocate(size));
+        result->m_structure.clear();
+        return result;
     }
 
 } // namespace JSC