| /* |
| * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) |
| * Copyright (C) 2001 Peter Kelly (pmk@post.com) |
| * 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 |
| * 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 |
| |
| #include "CallData.h" |
| #include "CallFrame.h" |
| #include "ConstructData.h" |
| #include "Heap.h" |
| #include "JSLock.h" |
| #include "JSValueInlines.h" |
| #include "SlotVisitor.h" |
| #include "TypedArrayDescriptor.h" |
| #include "WriteBarrier.h" |
| #include <wtf/Noncopyable.h> |
| #include <wtf/TypeTraits.h> |
| |
| namespace JSC { |
| |
| class CopyVisitor; |
| class JSDestructibleObject; |
| class JSGlobalObject; |
| class LLIntOffsetsExtractor; |
| class PropertyDescriptor; |
| class PropertyNameArray; |
| class Structure; |
| |
| enum EnumerationMode { |
| ExcludeDontEnumProperties, |
| IncludeDontEnumProperties |
| }; |
| |
| class JSCell { |
| friend class JSValue; |
| friend class MarkedBlock; |
| template<typename T> friend void* allocateCell(Heap&); |
| template<typename T> friend void* allocateCell(Heap&, size_t); |
| |
| public: |
| static const unsigned StructureFlags = 0; |
| |
| static const bool needsDestruction = false; |
| static const bool hasImmortalStructure = false; |
| |
| enum CreatingEarlyCellTag { CreatingEarlyCell }; |
| JSCell(CreatingEarlyCellTag); |
| |
| protected: |
| JSCell(JSGlobalData&, Structure*); |
| JS_EXPORT_PRIVATE static void destroyInternal(JSCell*); |
| static void destroy(JSCell* cell) { |
| return destroyInternal(cell); |
| } |
| |
| public: |
| // Querying the type. |
| bool isString() const; |
| bool isObject() const; |
| bool isGetterSetter() const; |
| bool isProxy() const; |
| bool inherits(const ClassInfo*) const; |
| bool isAPIValueWrapper() const; |
| |
| Structure* structure() const; |
| void setStructure(JSGlobalData&, Structure*); |
| void clearStructure() { m_structure.clear(); } |
| |
| JS_EXPORT_PRIVATE const char* className(); |
| |
| // Extracting the value. |
| JS_EXPORT_PRIVATE bool getString(ExecState*, String&) const; |
| JS_EXPORT_PRIVATE String getString(ExecState*) const; // null string if not a string |
| JS_EXPORT_PRIVATE JSObject* getObject(); // NULL if not an object |
| const JSObject* getObject() const; // NULL if not an object |
| |
| JS_EXPORT_PRIVATE static CallType getCallDataInternal(JSCell*, CallData&); |
| static CallType getCallData(JSCell* cell, CallData& data) { |
| return getCallDataInternal(cell, data); |
| } |
| JS_EXPORT_PRIVATE static ConstructType getConstructDataInternal(JSCell*, ConstructData&); |
| static ConstructType getConstructData(JSCell* cell, ConstructData& data) { |
| return getConstructDataInternal(cell, data); |
| } |
| |
| // Basic conversions. |
| JS_EXPORT_PRIVATE JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; |
| bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; |
| bool toBoolean(ExecState*) const; |
| JS_EXPORT_PRIVATE double toNumber(ExecState*) const; |
| JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const; |
| |
| static void visitChildren(JSCell*, SlotVisitor&); |
| JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&); |
| |
| // Object operations, with the toObject operation included. |
| JS_EXPORT_PRIVATE const ClassInfo* classInfo() const; |
| const MethodTable* methodTable() const; |
| static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); |
| static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); |
| |
| static bool deleteProperty(JSCell*, ExecState*, PropertyName); |
| static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); |
| |
| static JSObject* toThisObject(JSCell*, ExecState*); |
| |
| void zap() { *reinterpret_cast<uintptr_t**>(this) = 0; } |
| bool isZapped() const { return !*reinterpret_cast<uintptr_t* const*>(this); } |
| |
| // 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*, PropertyName, PropertySlot&); |
| JSValue fastGetOwnProperty(ExecState*, const String&); |
| |
| static ptrdiff_t structureOffset() |
| { |
| return OBJECT_OFFSETOF(JSCell, m_structure); |
| } |
| |
| void* structureAddress() |
| { |
| return &m_structure; |
| } |
| |
| #if ENABLE(GC_VALIDATION) |
| Structure* unvalidatedStructure() { return m_structure.unvalidatedGet(); } |
| #endif |
| |
| static const TypedArrayType TypedArrayStorageType = TypedArrayNone; |
| protected: |
| |
| void finishCreation(JSGlobalData&); |
| void finishCreation(JSGlobalData&, Structure*, CreatingEarlyCellTag); |
| |
| // Base implementation; for non-object classes implements getPropertySlot. |
| static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); |
| static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); |
| |
| // Dummy implementations of override-able static functions for classes to put in their MethodTable |
| static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); |
| static NO_RETURN_DUE_TO_ASSERT void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); |
| static NO_RETURN_DUE_TO_ASSERT void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); |
| static NO_RETURN_DUE_TO_ASSERT void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); |
| static String className(const JSObject*); |
| JS_EXPORT_PRIVATE static bool customHasInstanceInternal(JSObject*, ExecState*, JSValue); |
| static bool customHasInstance(JSObject* object, ExecState* exec, JSValue value) { |
| return customHasInstanceInternal(object, exec, value); |
| } |
| 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&); |
| |
| private: |
| friend class LLIntOffsetsExtractor; |
| |
| WriteBarrier<Structure> m_structure; |
| }; |
| |
| inline JSCell::JSCell(CreatingEarlyCellTag) |
| { |
| } |
| |
| inline void JSCell::finishCreation(JSGlobalData& globalData) |
| { |
| #if ENABLE(GC_VALIDATION) |
| ASSERT(globalData.isInitializingObject()); |
| globalData.setInitializingObjectClass(0); |
| #else |
| UNUSED_PARAM(globalData); |
| #endif |
| ASSERT(m_structure); |
| } |
| |
| inline Structure* JSCell::structure() const |
| { |
| return m_structure.get(); |
| } |
| |
| inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor) |
| { |
| MARK_LOG_PARENT(visitor, cell); |
| |
| visitor.append(&cell->m_structure); |
| } |
| |
| // --- JSValue inlines ---------------------------- |
| |
| inline bool JSValue::isString() const |
| { |
| return isCell() && asCell()->isString(); |
| } |
| |
| inline bool JSValue::isPrimitive() const |
| { |
| return !isCell() || asCell()->isString(); |
| } |
| |
| inline bool JSValue::isGetterSetter() const |
| { |
| return isCell() && asCell()->isGetterSetter(); |
| } |
| |
| inline bool JSValue::isObject() const |
| { |
| return isCell() && asCell()->isObject(); |
| } |
| |
| inline bool JSValue::getString(ExecState* exec, String& s) const |
| { |
| return isCell() && asCell()->getString(exec, s); |
| } |
| |
| inline String JSValue::getString(ExecState* exec) const |
| { |
| return isCell() ? asCell()->getString(exec) : String(); |
| } |
| |
| template <typename Base> String HandleConverter<Base, Unknown>::getString(ExecState* exec) const |
| { |
| return jsValue().getString(exec); |
| } |
| |
| inline JSObject* JSValue::getObject() const |
| { |
| return isCell() ? asCell()->getObject() : 0; |
| } |
| |
| ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const |
| { |
| 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 JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const |
| { |
| return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue(); |
| } |
| |
| inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value) |
| { |
| 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 = QNaN; |
| value = *this; |
| return true; |
| } |
| |
| ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const |
| { |
| if (isInt32()) |
| return asInt32(); |
| if (isDouble()) |
| return asDouble(); |
| return toNumberSlowCase(exec); |
| } |
| |
| inline JSObject* JSValue::toObject(ExecState* exec) const |
| { |
| 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); |
| } |
| |
| template<typename T> |
| void* allocateCell(Heap& heap, size_t size) |
| { |
| ASSERT(size >= sizeof(T)); |
| #if ENABLE(GC_VALIDATION) |
| ASSERT(!heap.globalData()->isInitializingObject()); |
| heap.globalData()->setInitializingObjectClass(T::s_classinfo()); |
| #endif |
| JSCell* result = 0; |
| 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)); |
| result->clearStructure(); |
| return result; |
| } |
| |
| template<typename T> |
| void* allocateCell(Heap& heap) |
| { |
| return allocateCell<T>(heap, sizeof(T)); |
| } |
| |
| inline bool isZapped(const JSCell* cell) |
| { |
| return cell->isZapped(); |
| } |
| |
| template<typename To, typename From> |
| inline To jsCast(From* from) |
| { |
| ASSERT(!from || from->JSCell::inherits(WTF::RemovePointer<To>::Type::s_classinfo())); |
| return static_cast<To>(from); |
| } |
| |
| template<typename To> |
| inline To jsCast(JSValue from) |
| { |
| ASSERT(from.isCell() && from.asCell()->JSCell::inherits(WTF::RemovePointer<To>::Type::s_classinfo())); |
| return static_cast<To>(from.asCell()); |
| } |
| |
| template<typename To, typename From> |
| inline To jsDynamicCast(From* from) |
| { |
| return from->inherits(WTF::RemovePointer<To>::Type::s_classinfo()) ? static_cast<To>(from) : 0; |
| } |
| |
| template<typename To> |
| inline To jsDynamicCast(JSValue from) |
| { |
| return from.isCell() && from.asCell()->inherits(WTF::RemovePointer<To>::Type::s_classinfo()) ? static_cast<To>(from.asCell()) : 0; |
| } |
| |
| } // namespace JSC |
| |
| #endif // JSCell_h |