/* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2003-2019 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. * */ #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 "SubspaceAccess.h" #include "TypedArrayType.h" #include "WriteBarrier.h" namespace JSC { class CallFrame; class CompleteSubspace; class CopyVisitor; class GCDeferralContext; class Identifier; class JSArrayBufferView; class JSDestructibleObject; class JSGlobalObject; class LLIntOffsetsExtractor; class PropertyDescriptor; class PropertyName; class PropertyNameArray; class Structure; class JSCellLock; enum class GCDeferralContextArgPresense { HasArg, DoesNotHaveArg }; template void* allocateCell(Heap&, size_t = sizeof(T)); template void* tryAllocateCell(Heap&, size_t = sizeof(T)); template void* allocateCell(Heap&, GCDeferralContext*, size_t = sizeof(T)); template void* tryAllocateCell(Heap&, GCDeferralContext*, size_t = sizeof(T)); #define DECLARE_EXPORT_INFO \ protected: \ static JS_EXPORT_PRIVATE 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 constexpr const ::JSC::ClassInfo* info() { return &s_info; } class JSCell : public HeapCell { friend class JSValue; friend class MarkedBlock; template friend void* tryAllocateCellHelper(Heap&, size_t, GCDeferralContext*, AllocationFailureMode); public: static constexpr unsigned StructureFlags = 0; static constexpr bool needsDestruction = false; static constexpr uint8_t numberOfLowerTierCells = 8; static JSCell* seenMultipleCalleeObjects() { return bitwise_cast(static_cast(1)); } enum CreatingEarlyCellTag { CreatingEarlyCell }; JSCell(CreatingEarlyCellTag); JS_EXPORT_PRIVATE static void destroy(JSCell*); protected: JSCell(VM&, Structure*); public: // Querying the type. bool isString() const; bool isHeapBigInt() const; bool isSymbol() const; bool isObject() const; bool isGetterSetter() const; bool isCustomGetterSetter() const; bool isProxy() const; bool isCallable(VM&); bool isConstructor(VM&); template TriState isCallableWithConcurrency(VM&); template TriState isConstructorWithConcurrency(VM&); bool inherits(VM&, const ClassInfo*) const; template bool inherits(VM&) 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. // We use this abstraction to make it easier to grep for places where we lock cells. // to lock a cell you can just do: // auto locker = holdLock(cell->cellLocker()); JSCellLock& cellLock() { return *reinterpret_cast(this); } JSType type() const; IndexingType indexingTypeAndMisc() const; IndexingType indexingMode() const; IndexingType indexingType() const; StructureID structureID() const { return m_structureID; } Structure* structure() const; Structure* structure(VM&) const; void setStructure(VM&, Structure*); void setStructureIDDirectly(StructureID id) { m_structureID = id; } void clearStructure() { m_structureID = 0; } TypeInfo::InlineTypeFlags inlineTypeFlags() const { return m_flags; } const char* className(VM&) const; // Extracting the value. JS_EXPORT_PRIVATE bool getString(JSGlobalObject*, String&) const; JS_EXPORT_PRIVATE String getString(JSGlobalObject*) 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 // 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 OverridesGetCallData 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 CallData getCallData(JSCell*); JS_EXPORT_PRIVATE static CallData getConstructData(JSCell*); // Basic conversions. JS_EXPORT_PRIVATE JSValue toPrimitive(JSGlobalObject*, PreferredPrimitiveType) const; bool toBoolean(JSGlobalObject*) const; TriState pureToBoolean() const; JS_EXPORT_PRIVATE double toNumber(JSGlobalObject*) const; JSObject* toObject(JSGlobalObject*) const; void dump(PrintStream&) const; JS_EXPORT_PRIVATE static void dumpToStream(const JSCell*, PrintStream&); size_t estimatedSizeInBytes(VM&) const; JS_EXPORT_PRIVATE static size_t estimatedSize(JSCell*, VM&); static void visitChildren(JSCell*, SlotVisitor&); static void visitOutputConstraints(JSCell*, SlotVisitor&); JS_EXPORT_PRIVATE static void analyzeHeap(JSCell*, HeapAnalyzer&); // Object operations, with the toObject operation included. const ClassInfo* classInfo(VM&) const; const MethodTable* methodTable(VM&) const; static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&); static bool putByIndex(JSCell*, JSGlobalObject*, unsigned propertyName, JSValue, bool shouldThrow); bool putInline(JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&); static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&); JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName); static bool deletePropertyByIndex(JSCell*, JSGlobalObject*, unsigned propertyName); static JSValue toThis(JSCell*, JSGlobalObject*, ECMAMode); static bool canUseFastGetOwnProperty(const Structure&); JSValue fastGetOwnProperty(VM&, Structure&, PropertyName); // 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(this)->m_cellState = data; } bool atomicCompareExchangeCellStateWeakRelaxed(CellState oldState, CellState newState) { return WTF::atomicCompareExchangeWeakRelaxed(&m_cellState, oldState, newState); } CellState atomicCompareExchangeCellStateStrong(CellState oldState, CellState newState) { return WTF::atomicCompareExchangeStrong(&m_cellState, oldState, newState); } static ptrdiff_t structureIDOffset() { return OBJECT_OFFSETOF(JSCell, m_structureID); } 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); } static const TypedArrayType TypedArrayStorageType = NotTypedArray; void setPerCellBit(bool); bool perCellBit() const; 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*, JSGlobalObject*, PreferredPrimitiveType); static NO_RETURN_DUE_TO_CRASH void getOwnPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, DontEnumPropertiesMode); static NO_RETURN_DUE_TO_CRASH void getOwnSpecialPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, DontEnumPropertiesMode); static uint32_t getEnumerableLength(JSGlobalObject*, JSObject*); static NO_RETURN_DUE_TO_CRASH bool preventExtensions(JSObject*, JSGlobalObject*); static NO_RETURN_DUE_TO_CRASH bool isExtensible(JSObject*, JSGlobalObject*); static NO_RETURN_DUE_TO_CRASH bool setPrototype(JSObject*, JSGlobalObject*, JSValue, bool); static NO_RETURN_DUE_TO_CRASH JSValue getPrototype(JSObject*, JSGlobalObject*); static String className(const JSObject*, VM&); static String toStringName(const JSObject*, JSGlobalObject*); JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, JSGlobalObject*, JSValue); static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool shouldThrow); static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&); static bool getOwnPropertySlotByIndex(JSObject*, JSGlobalObject*, unsigned propertyName, PropertySlot&); static NO_RETURN_DUE_TO_CRASH void doPutPropertySecurityCheck(JSObject*, JSGlobalObject*, PropertyName, PutPropertySlot&); private: friend class LLIntOffsetsExtractor; friend class JSCellLock; JS_EXPORT_PRIVATE JSObject* toObjectSlow(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; }; class JSCellLock : public JSCell { public: void lock(); bool tryLock(); void unlock(); bool isLocked() const; private: JS_EXPORT_PRIVATE void lockSlow(); JS_EXPORT_PRIVATE void unlockSlow(); }; // FIXME: Refer to Subspace by reference. // https://bugs.webkit.org/show_bug.cgi?id=166988 template inline auto subspaceFor(VM& vm) { return Type::template subspaceFor(vm); } template inline auto subspaceForConcurrently(VM& vm) { return Type::template subspaceFor(vm); } #if CPU(X86_64) JS_EXPORT_PRIVATE NEVER_INLINE NO_RETURN_DUE_TO_CRASH NOT_TAIL_CALLED void reportZappedCellAndCrash(Heap&, const JSCell*); #endif } // namespace JSC