1/*
2 * Copyright (C) 1999-2001 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
4 * Copyright (C) 2003-2019 Apple Inc. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#pragma once
24
25#include "CallData.h"
26#include "CellState.h"
27#include "ConstructData.h"
28#include "EnumerationMode.h"
29#include "Heap.h"
30#include "HeapCell.h"
31#include "IndexingType.h"
32#include "JSLock.h"
33#include "JSTypeInfo.h"
34#include "SlotVisitor.h"
35#include "SubspaceAccess.h"
36#include "TypedArrayType.h"
37#include "WriteBarrier.h"
38
39namespace JSC {
40
41class CallFrame;
42class CompleteSubspace;
43class CopyVisitor;
44class GCDeferralContext;
45class Identifier;
46class JSArrayBufferView;
47class JSDestructibleObject;
48class JSGlobalObject;
49class LLIntOffsetsExtractor;
50class PropertyDescriptor;
51class PropertyName;
52class PropertyNameArray;
53class Structure;
54class JSCellLock;
55
56enum class GCDeferralContextArgPresense {
57 HasArg,
58 DoesNotHaveArg
59};
60
61template<typename T> void* allocateCell(Heap&, size_t = sizeof(T));
62template<typename T> void* tryAllocateCell(Heap&, size_t = sizeof(T));
63template<typename T> void* allocateCell(Heap&, GCDeferralContext*, size_t = sizeof(T));
64template<typename T> void* tryAllocateCell(Heap&, GCDeferralContext*, size_t = sizeof(T));
65
66#define DECLARE_EXPORT_INFO \
67 protected: \
68 static JS_EXPORT_PRIVATE const ::JSC::ClassInfo s_info; \
69 public: \
70 static constexpr const ::JSC::ClassInfo* info() { return &s_info; }
71
72#define DECLARE_INFO \
73 protected: \
74 static const ::JSC::ClassInfo s_info; \
75 public: \
76 static constexpr const ::JSC::ClassInfo* info() { return &s_info; }
77
78class JSCell : public HeapCell {
79 friend class JSValue;
80 friend class MarkedBlock;
81 template<typename T>
82 friend void* tryAllocateCellHelper(Heap&, size_t, GCDeferralContext*, AllocationFailureMode);
83
84public:
85 static constexpr unsigned StructureFlags = 0;
86
87 static constexpr bool needsDestruction = false;
88
89 // Don't call this directly. Call JSC::subspaceFor<Type>(vm) instead.
90 // FIXME: Refer to Subspace by reference.
91 // https://bugs.webkit.org/show_bug.cgi?id=166988
92 template<typename CellType, SubspaceAccess>
93 static CompleteSubspace* subspaceFor(VM&);
94 static constexpr uint8_t numberOfLowerTierCells = 8;
95
96 static JSCell* seenMultipleCalleeObjects() { return bitwise_cast<JSCell*>(static_cast<uintptr_t>(1)); }
97
98 enum CreatingEarlyCellTag { CreatingEarlyCell };
99 JSCell(CreatingEarlyCellTag);
100
101protected:
102 JSCell(VM&, Structure*);
103 JS_EXPORT_PRIVATE static void destroy(JSCell*);
104
105public:
106 // Querying the type.
107 bool isString() const;
108 bool isBigInt() const;
109 bool isSymbol() const;
110 bool isObject() const;
111 bool isGetterSetter() const;
112 bool isCustomGetterSetter() const;
113 bool isProxy() const;
114 bool isFunction(VM&);
115 bool isCallable(VM&, CallType&, CallData&);
116 bool isConstructor(VM&);
117 bool isConstructor(VM&, ConstructType&, ConstructData&);
118 bool inherits(VM&, const ClassInfo*) const;
119 template<typename Target> bool inherits(VM&) const;
120 bool isAPIValueWrapper() const;
121
122 // Each cell has a built-in lock. Currently it's simply available for use if you need it. It's
123 // a full-blown WTF::Lock. Note that this lock is currently used in JSArray and that lock's
124 // ordering with the Structure lock is that the Structure lock must be acquired first.
125
126 // We use this abstraction to make it easier to grep for places where we lock cells.
127 // to lock a cell you can just do:
128 // auto locker = holdLock(cell->cellLocker());
129 JSCellLock& cellLock() { return *reinterpret_cast<JSCellLock*>(this); }
130
131 JSType type() const;
132 IndexingType indexingTypeAndMisc() const;
133 IndexingType indexingMode() const;
134 IndexingType indexingType() const;
135 StructureID structureID() const { return m_structureID; }
136 Structure* structure() const;
137 Structure* structure(VM&) const;
138 void setStructure(VM&, Structure*);
139 void setStructureIDDirectly(StructureID id) { m_structureID = id; }
140 void clearStructure() { m_structureID = 0; }
141
142 TypeInfo::InlineTypeFlags inlineTypeFlags() const { return m_flags; }
143
144 const char* className(VM&) const;
145
146 // Extracting the value.
147 JS_EXPORT_PRIVATE bool getString(JSGlobalObject*, String&) const;
148 JS_EXPORT_PRIVATE String getString(JSGlobalObject*) const; // null string if not a string
149 JS_EXPORT_PRIVATE JSObject* getObject(); // NULL if not an object
150 const JSObject* getObject() const; // NULL if not an object
151
152 // Returns information about how to call/construct this cell as a function/constructor. May tell
153 // you that the cell is not callable or constructor (default is that it's not either). If it
154 // says that the function is callable, and the OverridesGetCallData type flag is set, and
155 // this is an object, then typeof will return "function" instead of "object". These methods
156 // cannot change their minds and must be thread-safe. They are sometimes called from compiler
157 // threads.
158 JS_EXPORT_PRIVATE static CallType getCallData(JSCell*, CallData&);
159 JS_EXPORT_PRIVATE static ConstructType getConstructData(JSCell*, ConstructData&);
160
161 // Basic conversions.
162 JS_EXPORT_PRIVATE JSValue toPrimitive(JSGlobalObject*, PreferredPrimitiveType) const;
163 bool getPrimitiveNumber(JSGlobalObject*, double& number, JSValue&) const;
164 bool toBoolean(JSGlobalObject*) const;
165 TriState pureToBoolean() const;
166 JS_EXPORT_PRIVATE double toNumber(JSGlobalObject*) const;
167 JSObject* toObject(JSGlobalObject*) const;
168
169 void dump(PrintStream&) const;
170 JS_EXPORT_PRIVATE static void dumpToStream(const JSCell*, PrintStream&);
171
172 size_t estimatedSizeInBytes(VM&) const;
173 JS_EXPORT_PRIVATE static size_t estimatedSize(JSCell*, VM&);
174
175 static void visitChildren(JSCell*, SlotVisitor&);
176 static void visitOutputConstraints(JSCell*, SlotVisitor&);
177
178 JS_EXPORT_PRIVATE static void analyzeHeap(JSCell*, HeapAnalyzer&);
179
180 // Object operations, with the toObject operation included.
181 const ClassInfo* classInfo(VM&) const;
182 const MethodTable* methodTable(VM&) const;
183 static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
184 static bool putByIndex(JSCell*, JSGlobalObject*, unsigned propertyName, JSValue, bool shouldThrow);
185 bool putInline(JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
186
187 static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
188 static bool deletePropertyByIndex(JSCell*, JSGlobalObject*, unsigned propertyName);
189
190 static JSValue toThis(JSCell*, JSGlobalObject*, ECMAMode);
191
192 static bool canUseFastGetOwnProperty(const Structure&);
193 JSValue fastGetOwnProperty(VM&, Structure&, PropertyName);
194
195 // The recommended idiom for using cellState() is to switch on it or perform an == comparison on it
196 // directly. We deliberately avoid helpers for this, because we want transparency about how the various
197 // CellState values influences our various algorithms.
198 CellState cellState() const { return m_cellState; }
199
200 void setCellState(CellState data) const { const_cast<JSCell*>(this)->m_cellState = data; }
201
202 bool atomicCompareExchangeCellStateWeakRelaxed(CellState oldState, CellState newState)
203 {
204 return WTF::atomicCompareExchangeWeakRelaxed(&m_cellState, oldState, newState);
205 }
206
207 CellState atomicCompareExchangeCellStateStrong(CellState oldState, CellState newState)
208 {
209 return WTF::atomicCompareExchangeStrong(&m_cellState, oldState, newState);
210 }
211
212 static ptrdiff_t structureIDOffset()
213 {
214 return OBJECT_OFFSETOF(JSCell, m_structureID);
215 }
216
217 static ptrdiff_t typeInfoFlagsOffset()
218 {
219 return OBJECT_OFFSETOF(JSCell, m_flags);
220 }
221
222 static ptrdiff_t typeInfoTypeOffset()
223 {
224 return OBJECT_OFFSETOF(JSCell, m_type);
225 }
226
227 // DO NOT store to this field. Always use a CAS loop, since some bits are flipped using CAS
228 // from other threads due to the internal lock. One exception: you don't need the CAS if the
229 // object has not escaped yet.
230 static ptrdiff_t indexingTypeAndMiscOffset()
231 {
232 return OBJECT_OFFSETOF(JSCell, m_indexingTypeAndMisc);
233 }
234
235 static ptrdiff_t cellStateOffset()
236 {
237 return OBJECT_OFFSETOF(JSCell, m_cellState);
238 }
239
240 static const TypedArrayType TypedArrayStorageType = NotTypedArray;
241
242 void setPerCellBit(bool);
243 bool perCellBit() const;
244protected:
245
246 void finishCreation(VM&);
247 void finishCreation(VM&, Structure*, CreatingEarlyCellTag);
248
249 // Dummy implementations of override-able static functions for classes to put in their MethodTable
250 static JSValue defaultValue(const JSObject*, JSGlobalObject*, PreferredPrimitiveType);
251 static NO_RETURN_DUE_TO_CRASH void getOwnPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
252 static NO_RETURN_DUE_TO_CRASH void getOwnNonIndexPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
253 static NO_RETURN_DUE_TO_CRASH void getPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
254
255 static uint32_t getEnumerableLength(JSGlobalObject*, JSObject*);
256 static NO_RETURN_DUE_TO_CRASH void getStructurePropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
257 static NO_RETURN_DUE_TO_CRASH void getGenericPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
258 static NO_RETURN_DUE_TO_CRASH bool preventExtensions(JSObject*, JSGlobalObject*);
259 static NO_RETURN_DUE_TO_CRASH bool isExtensible(JSObject*, JSGlobalObject*);
260 static NO_RETURN_DUE_TO_CRASH bool setPrototype(JSObject*, JSGlobalObject*, JSValue, bool);
261 static NO_RETURN_DUE_TO_CRASH JSValue getPrototype(JSObject*, JSGlobalObject*);
262
263 static String className(const JSObject*, VM&);
264 static String toStringName(const JSObject*, JSGlobalObject*);
265 JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, JSGlobalObject*, JSValue);
266 static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
267 static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
268 static bool getOwnPropertySlotByIndex(JSObject*, JSGlobalObject*, unsigned propertyName, PropertySlot&);
269 static NO_RETURN_DUE_TO_CRASH void doPutPropertySecurityCheck(JSObject*, JSGlobalObject*, PropertyName, PutPropertySlot&);
270
271private:
272 friend class LLIntOffsetsExtractor;
273 friend class JSCellLock;
274
275 JS_EXPORT_PRIVATE JSObject* toObjectSlow(JSGlobalObject*) const;
276
277 StructureID m_structureID;
278 IndexingType m_indexingTypeAndMisc; // DO NOT store to this field. Always CAS.
279 JSType m_type;
280 TypeInfo::InlineTypeFlags m_flags;
281 CellState m_cellState;
282};
283
284class JSCellLock : public JSCell {
285public:
286 void lock();
287 bool tryLock();
288 void unlock();
289 bool isLocked() const;
290private:
291 JS_EXPORT_PRIVATE void lockSlow();
292 JS_EXPORT_PRIVATE void unlockSlow();
293};
294
295// FIXME: Refer to Subspace by reference.
296// https://bugs.webkit.org/show_bug.cgi?id=166988
297template<typename Type>
298inline auto subspaceFor(VM& vm)
299{
300 return Type::template subspaceFor<Type, SubspaceAccess::OnMainThread>(vm);
301}
302
303template<typename Type>
304inline auto subspaceForConcurrently(VM& vm)
305{
306 return Type::template subspaceFor<Type, SubspaceAccess::Concurrently>(vm);
307}
308
309} // namespace JSC
310