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 | |
39 | namespace JSC { |
40 | |
41 | class CallFrame; |
42 | class CompleteSubspace; |
43 | class CopyVisitor; |
44 | class GCDeferralContext; |
45 | class Identifier; |
46 | class JSArrayBufferView; |
47 | class JSDestructibleObject; |
48 | class JSGlobalObject; |
49 | class ; |
50 | class PropertyDescriptor; |
51 | class PropertyName; |
52 | class PropertyNameArray; |
53 | class Structure; |
54 | class JSCellLock; |
55 | |
56 | enum class GCDeferralContextArgPresense { |
57 | HasArg, |
58 | DoesNotHaveArg |
59 | }; |
60 | |
61 | template<typename T> void* allocateCell(Heap&, size_t = sizeof(T)); |
62 | template<typename T> void* tryAllocateCell(Heap&, size_t = sizeof(T)); |
63 | template<typename T> void* allocateCell(Heap&, GCDeferralContext*, size_t = sizeof(T)); |
64 | template<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 | |
78 | class 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 | |
84 | public: |
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 | |
101 | protected: |
102 | JSCell(VM&, Structure*); |
103 | JS_EXPORT_PRIVATE static void destroy(JSCell*); |
104 | |
105 | public: |
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; |
244 | protected: |
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 | |
271 | private: |
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 | |
284 | class JSCellLock : public JSCell { |
285 | public: |
286 | void lock(); |
287 | bool tryLock(); |
288 | void unlock(); |
289 | bool isLocked() const; |
290 | private: |
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 |
297 | template<typename Type> |
298 | inline auto subspaceFor(VM& vm) |
299 | { |
300 | return Type::template subspaceFor<Type, SubspaceAccess::OnMainThread>(vm); |
301 | } |
302 | |
303 | template<typename Type> |
304 | inline auto subspaceForConcurrently(VM& vm) |
305 | { |
306 | return Type::template subspaceFor<Type, SubspaceAccess::Concurrently>(vm); |
307 | } |
308 | |
309 | } // namespace JSC |
310 | |