diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSCell.h')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSCell.h | 211 |
1 files changed, 157 insertions, 54 deletions
diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h index de85a4bdc..1464bb51d 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -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, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003-2017 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 @@ -20,13 +20,17 @@ * */ -#ifndef JSCell_h -#define JSCell_h +#pragma once #include "CallData.h" +#include "CellState.h" #include "ConstructData.h" +#include "EnumerationMode.h" #include "Heap.h" +#include "HeapCell.h" +#include "IndexingType.h" #include "JSLock.h" +#include "JSTypeInfo.h" #include "SlotVisitor.h" #include "TypedArrayType.h" #include "WriteBarrier.h" @@ -35,7 +39,9 @@ namespace JSC { class CopyVisitor; +class GCDeferralContext; class ExecState; +class Identifier; class JSArrayBufferView; class JSDestructibleObject; class JSGlobalObject; @@ -44,41 +50,48 @@ class PropertyDescriptor; class PropertyNameArray; class Structure; -enum EnumerationMode { - ExcludeDontEnumProperties, - IncludeDontEnumProperties -}; - template<typename T> void* allocateCell(Heap&); template<typename T> 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; } +template<typename T> void* allocateCell(Heap&, GCDeferralContext*); +template<typename T> void* allocateCell(Heap&, GCDeferralContext*, size_t); + +#define DECLARE_EXPORT_INFO \ + protected: \ + static JS_EXPORTDATA const ::JSC::ClassInfo s_info; \ + public: \ + static constexpr 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; } +#define DECLARE_INFO \ + protected: \ + static const ::JSC::ClassInfo s_info; \ + public: \ + static constexpr const ::JSC::ClassInfo* info() { return &s_info; } -class JSCell { +class JSCell : public HeapCell { friend class JSValue; friend class MarkedBlock; template<typename T> friend void* allocateCell(Heap&); template<typename T> friend void* allocateCell(Heap&, size_t); + template<typename T> friend void* allocateCell(Heap&, GCDeferralContext*); + template<typename T> friend void* allocateCell(Heap&, GCDeferralContext*, size_t); public: static const unsigned StructureFlags = 0; static const bool needsDestruction = false; - static const bool hasImmortalStructure = false; + + // Don't call this directly. Call JSC::subspaceFor<Type>(vm) instead. + // FIXME: Refer to Subspace by reference. + // https://bugs.webkit.org/show_bug.cgi?id=166988 + template<typename CellType> + static Subspace* subspaceFor(VM&); + + static JSCell* seenMultipleCalleeObjects() { return bitwise_cast<JSCell*>(static_cast<uintptr_t>(1)); } enum CreatingEarlyCellTag { CreatingEarlyCell }; JSCell(CreatingEarlyCellTag); - + protected: JSCell(VM&, Structure*); JS_EXPORT_PRIVATE static void destroy(JSCell*); @@ -86,17 +99,36 @@ protected: public: // Querying the type. bool isString() const; + bool isSymbol() const; bool isObject() const; + bool isAnyWasmCallee(VM&) const; bool isGetterSetter() const; + bool isCustomGetterSetter() const; bool isProxy() const; - bool inherits(const ClassInfo*) const; + bool inherits(VM&, const ClassInfo*) const; bool isAPIValueWrapper() const; - + + // Each cell has a built-in lock. Currently it's simply available for use if you need it. It's + // a full-blown WTF::Lock. Note that this lock is currently used in JSArray and that lock's + // ordering with the Structure lock is that the Structure lock must be acquired first. + void lock(); + bool tryLock(); + void unlock(); + bool isLocked() const; + + JSType type() const; + IndexingType indexingTypeAndMisc() const; + IndexingType indexingType() const; + StructureID structureID() const { return m_structureID; } Structure* structure() const; + Structure* structure(VM&) const; void setStructure(VM&, Structure*); - void clearStructure() { m_structure.clear(); } + void setStructureIDDirectly(StructureID id) { m_structureID = id; } + void clearStructure() { m_structureID = 0; } + + TypeInfo::InlineTypeFlags inlineTypeFlags() const { return m_flags; } - const char* className(); + const char* className(VM&) const; // Extracting the value. JS_EXPORT_PRIVATE bool getString(ExecState*, String&) const; @@ -104,6 +136,12 @@ public: JS_EXPORT_PRIVATE JSObject* getObject(); // NULL if not an object const JSObject* getObject() const; // NULL if not an object + // 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&); @@ -113,42 +151,81 @@ public: bool toBoolean(ExecState*) const; TriState pureToBoolean() const; JS_EXPORT_PRIVATE double toNumber(ExecState*) const; - JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const; + JSObject* toObject(ExecState*, JSGlobalObject*) const; + + void dump(PrintStream&) const; + JS_EXPORT_PRIVATE static void dumpToStream(const JSCell*, PrintStream&); + + size_t estimatedSizeInBytes() const; + JS_EXPORT_PRIVATE static size_t estimatedSize(JSCell*); static void visitChildren(JSCell*, SlotVisitor&); - JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken); + static void visitOutputConstraints(JSCell*, SlotVisitor&); + + JS_EXPORT_PRIVATE static void heapSnapshot(JSCell*, HeapSnapshotBuilder&); // Object operations, with the toObject operation included. - const ClassInfo* classInfo() const; + const ClassInfo* classInfo(VM&) const; const MethodTable* methodTable() const; - const MethodTable* methodTableForDestruction() const; - static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); + const MethodTable* methodTable(VM&) const; + static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + static bool putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); static bool deleteProperty(JSCell*, ExecState*, PropertyName); static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); static JSValue toThis(JSCell*, ExecState*, ECMAMode); - void zap() { *reinterpret_cast<uintptr_t**>(this) = 0; } - bool isZapped() const { return !*reinterpret_cast<uintptr_t* const*>(this); } + static bool canUseFastGetOwnProperty(const Structure&); + JSValue fastGetOwnProperty(VM&, Structure&, PropertyName); - JSValue fastGetOwnProperty(ExecState*, const String&); + // The recommended idiom for using cellState() is to switch on it or perform an == comparison on it + // directly. We deliberately avoid helpers for this, because we want transparency about how the various + // CellState values influences our various algorithms. + CellState cellState() const { return m_cellState; } + + void setCellState(CellState data) const { const_cast<JSCell*>(this)->m_cellState = data; } + + bool atomicCompareExchangeCellStateWeakRelaxed(CellState oldState, CellState newState) + { + return WTF::atomicCompareExchangeWeakRelaxed(&m_cellState, oldState, newState); + } - static ptrdiff_t structureOffset() + CellState atomicCompareExchangeCellStateStrong(CellState oldState, CellState newState) { - return OBJECT_OFFSETOF(JSCell, m_structure); + return WTF::atomicCompareExchangeStrong(&m_cellState, oldState, newState); } - void* structureAddress() + static ptrdiff_t structureIDOffset() { - return &m_structure; + return OBJECT_OFFSETOF(JSCell, m_structureID); } - -#if ENABLE(GC_VALIDATION) - Structure* unvalidatedStructure() const { return m_structure.unvalidatedGet(); } -#endif - + + static ptrdiff_t typeInfoFlagsOffset() + { + return OBJECT_OFFSETOF(JSCell, m_flags); + } + + static ptrdiff_t typeInfoTypeOffset() + { + return OBJECT_OFFSETOF(JSCell, m_type); + } + + // DO NOT store to this field. Always use a CAS loop, since some bits are flipped using CAS + // from other threads due to the internal lock. One exception: you don't need the CAS if the + // object has not escaped yet. + static ptrdiff_t indexingTypeAndMiscOffset() + { + return OBJECT_OFFSETOF(JSCell, m_indexingTypeAndMisc); + } + + static ptrdiff_t cellStateOffset() + { + return OBJECT_OFFSETOF(JSCell, m_cellState); + } + + void callDestructor(VM&); + static const TypedArrayType TypedArrayStorageType = NotTypedArray; protected: @@ -160,46 +237,72 @@ protected: 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 NO_RETURN_DUE_TO_CRASH bool preventExtensions(JSObject*, ExecState*); + static NO_RETURN_DUE_TO_CRASH bool isExtensible(JSObject*, ExecState*); + static NO_RETURN_DUE_TO_CRASH bool setPrototype(JSObject*, ExecState*, JSValue, bool); + static NO_RETURN_DUE_TO_CRASH JSValue getPrototype(JSObject*, ExecState*); + static String className(const JSObject*); + static String toStringName(const JSObject*, ExecState*); 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<ArrayBufferView> getTypedArrayImpl(JSArrayBufferView*); + JS_EXPORT_PRIVATE static RefPtr<ArrayBufferView> getTypedArrayImpl(JSArrayBufferView*); private: friend class LLIntOffsetsExtractor; - - WriteBarrier<Structure> m_structure; + + JS_EXPORT_PRIVATE JSObject* toObjectSlow(ExecState*, JSGlobalObject*) const; + + StructureID m_structureID; + IndexingType m_indexingTypeAndMisc; // DO NOT store to this field. Always CAS. + JSType m_type; + TypeInfo::InlineTypeFlags m_flags; + CellState m_cellState; }; template<typename To, typename From> inline To jsCast(From* from) { - ASSERT(!from || from->JSCell::inherits(std::remove_pointer<To>::type::info())); + ASSERT_WITH_SECURITY_IMPLICATION(!from || from->JSCell::inherits(*from->JSCell::vm(), std::remove_pointer<To>::type::info())); return static_cast<To>(from); } template<typename To> inline To jsCast(JSValue from) { - ASSERT(from.isCell() && from.asCell()->JSCell::inherits(std::remove_pointer<To>::type::info())); + ASSERT_WITH_SECURITY_IMPLICATION(from.isCell() && from.asCell()->JSCell::inherits(*from.asCell()->vm(), std::remove_pointer<To>::type::info())); return static_cast<To>(from.asCell()); } template<typename To, typename From> -inline To jsDynamicCast(From* from) +inline To jsDynamicCast(VM& vm, From* from) { - return from->inherits(std::remove_pointer<To>::type::info()) ? static_cast<To>(from) : 0; + if (LIKELY(from->JSCell::inherits(vm, std::remove_pointer<To>::type::info()))) + return static_cast<To>(from); + return nullptr; } template<typename To> -inline To jsDynamicCast(JSValue from) +inline To jsDynamicCast(VM& vm, JSValue from) { - return from.isCell() && from.asCell()->inherits(std::remove_pointer<To>::type::info()) ? static_cast<To>(from.asCell()) : 0; + if (LIKELY(from.isCell() && from.asCell()->inherits(vm, std::remove_pointer<To>::type::info()))) + return static_cast<To>(from.asCell()); + return nullptr; } -} // namespace JSC +// FIXME: Refer to Subspace by reference. +// https://bugs.webkit.org/show_bug.cgi?id=166988 +template<typename Type> +inline Subspace* subspaceFor(VM& vm) +{ + return Type::template subspaceFor<Type>(vm); +} -#endif // JSCell_h +} // namespace JSC |