X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174..refs/heads/master:/runtime/JSCell.h diff --git a/runtime/JSCell.h b/runtime/JSCell.h index 431e671..6d648ad 100644 --- a/runtime/JSCell.h +++ b/runtime/JSCell.h @@ -24,354 +24,255 @@ #define JSCell_h #include "CallData.h" -#include "CallFrame.h" #include "ConstructData.h" +#include "EnumerationMode.h" #include "Heap.h" +#include "IndexingType.h" #include "JSLock.h" -#include "JSValueInlineMethods.h" +#include "JSTypeInfo.h" #include "SlotVisitor.h" +#include "TypedArrayType.h" #include "WriteBarrier.h" #include namespace JSC { - class JSGlobalObject; - class LLIntOffsetsExtractor; - class PropertyDescriptor; - class PropertyNameArray; - class Structure; - - enum EnumerationMode { - ExcludeDontEnumProperties, - IncludeDontEnumProperties - }; - - enum TypedArrayType { - TypedArrayNone, - TypedArrayInt8, - TypedArrayInt16, - TypedArrayInt32, - TypedArrayUint8, - TypedArrayUint8Clamped, - TypedArrayUint16, - TypedArrayUint32, - TypedArrayFloat32, - TypedArrayFloat64 - }; - - class JSCell { - friend class JSValue; - friend class MarkedBlock; - template friend void* allocateCell(Heap&); - - public: - enum CreatingEarlyCellTag { CreatingEarlyCell }; - JSCell(CreatingEarlyCellTag); - - protected: - JSCell(JSGlobalData&, Structure*); - JS_EXPORT_PRIVATE static void destroy(JSCell*); - - public: - // Querying the type. - bool isString() const; - bool isObject() const; - bool isGetterSetter() const; - bool inherits(const ClassInfo*) const; - bool isAPIValueWrapper() const; - - Structure* structure() const; - void setStructure(JSGlobalData&, Structure*); - void clearStructure() { m_structure.clear(); } - - // Extracting the value. - JS_EXPORT_PRIVATE bool getString(ExecState* exec, UString&) const; - JS_EXPORT_PRIVATE UString getString(ExecState* exec) 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 +class CopyVisitor; +class ExecState; +class Identifier; +class JSArrayBufferView; +class JSDestructibleObject; +class JSGlobalObject; +class LLIntOffsetsExtractor; +class PropertyDescriptor; +class PropertyNameArray; +class Structure; + +template void* allocateCell(Heap&); +template void* allocateCell(Heap&, size_t); + +#define DECLARE_EXPORT_INFO \ + protected: \ + static JS_EXPORTDATA const ::JSC::ClassInfo s_info; \ + public: \ + static const ::JSC::ClassInfo* info() { return &s_info; } + +#define DECLARE_INFO \ + protected: \ + static const ::JSC::ClassInfo s_info; \ + public: \ + static const ::JSC::ClassInfo* info() { return &s_info; } + +class JSCell { + friend class JSValue; + friend class MarkedBlock; + template friend void* allocateCell(Heap&); + template friend void* allocateCell(Heap&, size_t); + +public: + static const unsigned StructureFlags = 0; + + static const bool needsDestruction = false; + + static JSCell* seenMultipleCalleeObjects() { return bitwise_cast(static_cast(1)); } + + enum CreatingEarlyCellTag { CreatingEarlyCell }; + JSCell(CreatingEarlyCellTag); + +protected: + JSCell(VM&, Structure*); + JS_EXPORT_PRIVATE static void destroy(JSCell*); + +public: + // Querying the type. + bool isString() const; + bool isSymbol() const; + bool isObject() const; + bool isGetterSetter() const; + bool isCustomGetterSetter() const; + bool isProxy() const; + bool inherits(const ClassInfo*) const; + bool isAPIValueWrapper() const; + + JSType type() const; + IndexingType indexingType() const; + StructureID structureID() const { return m_structureID; } + Structure* structure() const; + Structure* structure(VM&) const; + void setStructure(VM&, Structure*); + void clearStructure() { m_structureID = 0; } + + TypeInfo::InlineTypeFlags inlineTypeFlags() const { return m_flags; } + + const char* className() const; + + VM* vm() const; + + // 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 getCallData(JSCell*, CallData&); - JS_EXPORT_PRIVATE static ConstructType getConstructData(JSCell*, ConstructData&); - - // 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&); - - // Object operations, with the toObject operation included. - const ClassInfo* classInfo() const; - const ClassInfo* validatedClassInfo() const; - const MethodTable* methodTable() const; - static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); - static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); + // Returns information about how to call/construct this cell as a function/constructor. May tell + // you that the cell is not callable or constructor (default is that it's not either). If it + // says that the function is callable, and the TypeOfShouldCallGetCallData type flag is set, and + // this is an object, then typeof will return "function" instead of "object". These methods + // cannot change their minds and must be thread-safe. They are sometimes called from compiler + // threads. + JS_EXPORT_PRIVATE static CallType getCallData(JSCell*, CallData&); + JS_EXPORT_PRIVATE static ConstructType getConstructData(JSCell*, ConstructData&); + + // Basic conversions. + JS_EXPORT_PRIVATE JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; + bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; + bool toBoolean(ExecState*) const; + TriState pureToBoolean() const; + JS_EXPORT_PRIVATE double toNumber(ExecState*) const; + JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const; + + void dump(PrintStream&) const; + JS_EXPORT_PRIVATE static void dumpToStream(const JSCell*, PrintStream&); + static void visitChildren(JSCell*, SlotVisitor&); + JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken); + + // Object operations, with the toObject operation included. + const ClassInfo* classInfo() const; + const MethodTable* methodTable() const; + const MethodTable* methodTable(VM&) const; + static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); - static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName); - static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); + static bool deleteProperty(JSCell*, ExecState*, PropertyName); + static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); - static JSObject* toThisObject(JSCell*, ExecState*); + static JSValue toThis(JSCell*, ExecState*, ECMAMode); - void zap() { *reinterpret_cast(this) = 0; } - bool isZapped() const { return !*reinterpret_cast(this); } + void zap() { *reinterpret_cast(this) = 0; } + bool isZapped() const { return !*reinterpret_cast(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*, const Identifier& propertyName, PropertySlot&); - JSValue fastGetOwnProperty(ExecState*, const UString&); + static bool canUseFastGetOwnProperty(const Structure&); + JSValue fastGetOwnProperty(VM&, Structure&, PropertyName); - static ptrdiff_t structureOffset() - { - return OBJECT_OFFSETOF(JSCell, m_structure); - } - - static ptrdiff_t classInfoOffset() - { - return OBJECT_OFFSETOF(JSCell, m_classInfo); - } - - void* structureAddress() - { - return &m_structure; - } + enum GCData : uint8_t { + Marked = 0, // The object has survived a GC and is in the old gen. + NotMarked = 1, // The object is new and in the eden gen. + MarkedAndRemembered = 2, // The object is in the GC's remembered set. -#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*, const Identifier& 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 getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static UString className(const JSObject*); - static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue prototypeProperty); - static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes); - static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow); - static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); - - private: - friend class LLIntOffsetsExtractor; - - const ClassInfo* m_classInfo; - WriteBarrier m_structure; + // The object being in the GC's remembered set implies that it is also + // Marked. This is because objects are only added to the remembered sets + // by write barriers, and write barriers are only interested in old gen + // objects that point to potential eden gen objects. }; - 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 const ClassInfo* JSCell::classInfo() const - { - return m_classInfo; - } - - inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor) - { - 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 + void setMarked() { m_gcData = Marked; } + void setRemembered(bool remembered) { - return isCell() && asCell()->isObject(); + ASSERT(m_gcData == (remembered ? Marked : MarkedAndRemembered)); + m_gcData = remembered ? MarkedAndRemembered : Marked; } - - inline bool JSValue::getString(ExecState* exec, UString& s) const + bool isMarked() const { - return isCell() && asCell()->getString(exec, s); - } - - inline UString JSValue::getString(ExecState* exec) const - { - return isCell() ? asCell()->getString(exec) : UString(); - } - - template UString HandleConverter::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(i); - return i >= 0; - } - if (isDouble()) { - double d = asDouble(); - v = static_cast(d); - return v == d; + switch (m_gcData) { + case Marked: + case MarkedAndRemembered: + return true; + case NotMarked: + return false; } + RELEASE_ASSERT_NOT_REACHED(); return false; } + bool isRemembered() const { return m_gcData == MarkedAndRemembered; } - inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const + static ptrdiff_t structureIDOffset() { - return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue(); + return OBJECT_OFFSETOF(JSCell, m_structureID); } - inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value) + static ptrdiff_t typeInfoFlagsOffset() { - 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 = std::numeric_limits::quiet_NaN(); - value = *this; - return true; + return OBJECT_OFFSETOF(JSCell, m_flags); } - ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const + static ptrdiff_t typeInfoTypeOffset() { - if (isInt32()) - return asInt32(); - if (isDouble()) - return asDouble(); - return toNumberSlowCase(exec); + return OBJECT_OFFSETOF(JSCell, m_type); } - inline JSObject* JSValue::toObject(ExecState* exec) const + static ptrdiff_t indexingTypeOffset() { - return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject()); + return OBJECT_OFFSETOF(JSCell, m_indexingType); } - inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const + static ptrdiff_t gcDataOffset() { - return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject); + return OBJECT_OFFSETOF(JSCell, m_gcData); } -#if COMPILER(CLANG) - template - struct NeedsDestructor { - static const bool value = !__has_trivial_destructor(T); - }; -#else - // Write manual specializations for this struct template if you care about non-clang compilers. - template - struct NeedsDestructor { - static const bool value = true; - }; -#endif - - template - void* allocateCell(Heap& heap) - { -#if ENABLE(GC_VALIDATION) - ASSERT(!heap.globalData()->isInitializingObject()); - heap.globalData()->setInitializingObjectClass(&T::s_info); -#endif - JSCell* result = 0; - if (NeedsDestructor::value) - result = static_cast(heap.allocateWithDestructor(sizeof(T))); - else { - ASSERT(T::s_info.methodTable.destroy == JSCell::destroy); - result = static_cast(heap.allocateWithoutDestructor(sizeof(T))); - } - result->clearStructure(); - return result; - } + static const TypedArrayType TypedArrayStorageType = NotTypedArray; +protected: + + void finishCreation(VM&); + void finishCreation(VM&, Structure*, CreatingEarlyCellTag); + + // 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_CRASH void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static NO_RETURN_DUE_TO_CRASH void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static NO_RETURN_DUE_TO_CRASH void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + + static uint32_t getEnumerableLength(ExecState*, JSObject*); + static NO_RETURN_DUE_TO_CRASH void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static NO_RETURN_DUE_TO_CRASH void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + + static String className(const JSObject*); + JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue); + static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&); + JS_EXPORT_PRIVATE static ArrayBuffer* slowDownAndWasteMemory(JSArrayBufferView*); + JS_EXPORT_PRIVATE static PassRefPtr getTypedArrayImpl(JSArrayBufferView*); + +private: + friend class LLIntOffsetsExtractor; + + StructureID m_structureID; + IndexingType m_indexingType; + JSType m_type; + TypeInfo::InlineTypeFlags m_flags; + uint8_t m_gcData; +}; + +template +inline To jsCast(From* from) +{ + ASSERT_WITH_SECURITY_IMPLICATION(!from || from->JSCell::inherits(std::remove_pointer::type::info())); + return static_cast(from); +} - inline bool isZapped(const JSCell* cell) - { - return cell->isZapped(); - } - - template - inline To jsCast(From* from) - { - ASSERT(!from || from->JSCell::inherits(&WTF::RemovePointer::Type::s_info)); +template +inline To jsCast(JSValue from) +{ + ASSERT_WITH_SECURITY_IMPLICATION(from.isCell() && from.asCell()->JSCell::inherits(std::remove_pointer::type::info())); + return static_cast(from.asCell()); +} + +template +inline To jsDynamicCast(From* from) +{ + if (LIKELY(from->inherits(std::remove_pointer::type::info()))) return static_cast(from); - } + return nullptr; +} - template - inline To jsCast(JSValue from) - { - ASSERT(from.isCell() && from.asCell()->JSCell::inherits(&WTF::RemovePointer::Type::s_info)); +template +inline To jsDynamicCast(JSValue from) +{ + if (LIKELY(from.isCell() && from.asCell()->inherits(std::remove_pointer::type::info()))) return static_cast(from.asCell()); - } - - template - inline To jsDynamicCast(From* from) - { - return from->inherits(&WTF::RemovePointer::Type::s_info) ? static_cast(from) : 0; - } - - template - inline To jsDynamicCast(JSValue from) - { - return from.isCell() && from.asCell()->inherits(&WTF::RemovePointer::Type::s_info) ? static_cast(from.asCell()) : 0; - } + return nullptr; +} } // namespace JSC