1 | /* |
2 | * Copyright (C) 1999-2001 Harri Porten ([email protected]) |
3 | * Copyright (C) 2001 Peter Kelly ([email protected]) |
4 | * Copyright (C) 2003-2017 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 CompleteSubspace; |
42 | class CopyVisitor; |
43 | class GCDeferralContext; |
44 | class ExecState; |
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 const unsigned StructureFlags = 0; |
86 | |
87 | static const 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 | |
95 | static JSCell* seenMultipleCalleeObjects() { return bitwise_cast<JSCell*>(static_cast<uintptr_t>(1)); } |
96 | |
97 | enum CreatingEarlyCellTag { CreatingEarlyCell }; |
98 | JSCell(CreatingEarlyCellTag); |
99 | |
100 | protected: |
101 | JSCell(VM&, Structure*); |
102 | JS_EXPORT_PRIVATE static void destroy(JSCell*); |
103 | |
104 | public: |
105 | // Querying the type. |
106 | bool isString() const; |
107 | bool isBigInt() const; |
108 | bool isSymbol() const; |
109 | bool isObject() const; |
110 | bool isGetterSetter() const; |
111 | bool isCustomGetterSetter() const; |
112 | bool isProxy() const; |
113 | bool isFunction(VM&); |
114 | bool isCallable(VM&, CallType&, CallData&); |
115 | bool isConstructor(VM&); |
116 | bool isConstructor(VM&, ConstructType&, ConstructData&); |
117 | bool inherits(VM&, const ClassInfo*) const; |
118 | template<typename Target> bool inherits(VM&) const; |
119 | bool isAPIValueWrapper() const; |
120 | |
121 | // Each cell has a built-in lock. Currently it's simply available for use if you need it. It's |
122 | // a full-blown WTF::Lock. Note that this lock is currently used in JSArray and that lock's |
123 | // ordering with the Structure lock is that the Structure lock must be acquired first. |
124 | |
125 | // We use this abstraction to make it easier to grep for places where we lock cells. |
126 | // to lock a cell you can just do: |
127 | // auto locker = holdLock(cell->cellLocker()); |
128 | JSCellLock& cellLock() { return *reinterpret_cast<JSCellLock*>(this); } |
129 | |
130 | JSType type() const; |
131 | IndexingType indexingTypeAndMisc() const; |
132 | IndexingType indexingMode() const; |
133 | IndexingType indexingType() const; |
134 | StructureID structureID() const { return m_structureID; } |
135 | Structure* structure() const; |
136 | Structure* structure(VM&) const; |
137 | void setStructure(VM&, Structure*); |
138 | void setStructureIDDirectly(StructureID id) { m_structureID = id; } |
139 | void clearStructure() { m_structureID = 0; } |
140 | |
141 | TypeInfo::InlineTypeFlags inlineTypeFlags() const { return m_flags; } |
142 | |
143 | const char* className(VM&) const; |
144 | |
145 | // Extracting the value. |
146 | JS_EXPORT_PRIVATE bool getString(ExecState*, String&) const; |
147 | JS_EXPORT_PRIVATE String getString(ExecState*) const; // null string if not a string |
148 | JS_EXPORT_PRIVATE JSObject* getObject(); // NULL if not an object |
149 | const JSObject* getObject() const; // NULL if not an object |
150 | |
151 | // Returns information about how to call/construct this cell as a function/constructor. May tell |
152 | // you that the cell is not callable or constructor (default is that it's not either). If it |
153 | // says that the function is callable, and the OverridesGetCallData type flag is set, and |
154 | // this is an object, then typeof will return "function" instead of "object". These methods |
155 | // cannot change their minds and must be thread-safe. They are sometimes called from compiler |
156 | // threads. |
157 | JS_EXPORT_PRIVATE static CallType getCallData(JSCell*, CallData&); |
158 | JS_EXPORT_PRIVATE static ConstructType getConstructData(JSCell*, ConstructData&); |
159 | |
160 | // Basic conversions. |
161 | JS_EXPORT_PRIVATE JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; |
162 | bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; |
163 | bool toBoolean(ExecState*) const; |
164 | TriState pureToBoolean() const; |
165 | JS_EXPORT_PRIVATE double toNumber(ExecState*) const; |
166 | JSObject* toObject(ExecState*, JSGlobalObject*) const; |
167 | |
168 | void dump(PrintStream&) const; |
169 | JS_EXPORT_PRIVATE static void dumpToStream(const JSCell*, PrintStream&); |
170 | |
171 | size_t estimatedSizeInBytes(VM&) const; |
172 | JS_EXPORT_PRIVATE static size_t estimatedSize(JSCell*, VM&); |
173 | |
174 | static void visitChildren(JSCell*, SlotVisitor&); |
175 | static void visitOutputConstraints(JSCell*, SlotVisitor&); |
176 | |
177 | JS_EXPORT_PRIVATE static void heapSnapshot(JSCell*, HeapSnapshotBuilder&); |
178 | |
179 | // Object operations, with the toObject operation included. |
180 | const ClassInfo* classInfo(VM&) const; |
181 | const MethodTable* methodTable(VM&) const; |
182 | static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); |
183 | static bool putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); |
184 | bool putInline(ExecState*, PropertyName, JSValue, PutPropertySlot&); |
185 | |
186 | static bool deleteProperty(JSCell*, ExecState*, PropertyName); |
187 | static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); |
188 | |
189 | static JSValue toThis(JSCell*, ExecState*, ECMAMode); |
190 | |
191 | static bool canUseFastGetOwnProperty(const Structure&); |
192 | JSValue fastGetOwnProperty(VM&, Structure&, PropertyName); |
193 | |
194 | // The recommended idiom for using cellState() is to switch on it or perform an == comparison on it |
195 | // directly. We deliberately avoid helpers for this, because we want transparency about how the various |
196 | // CellState values influences our various algorithms. |
197 | CellState cellState() const { return m_cellState; } |
198 | |
199 | void setCellState(CellState data) const { const_cast<JSCell*>(this)->m_cellState = data; } |
200 | |
201 | bool atomicCompareExchangeCellStateWeakRelaxed(CellState oldState, CellState newState) |
202 | { |
203 | return WTF::atomicCompareExchangeWeakRelaxed(&m_cellState, oldState, newState); |
204 | } |
205 | |
206 | CellState atomicCompareExchangeCellStateStrong(CellState oldState, CellState newState) |
207 | { |
208 | return WTF::atomicCompareExchangeStrong(&m_cellState, oldState, newState); |
209 | } |
210 | |
211 | static ptrdiff_t structureIDOffset() |
212 | { |
213 | return OBJECT_OFFSETOF(JSCell, m_structureID); |
214 | } |
215 | |
216 | static ptrdiff_t typeInfoFlagsOffset() |
217 | { |
218 | return OBJECT_OFFSETOF(JSCell, m_flags); |
219 | } |
220 | |
221 | static ptrdiff_t typeInfoTypeOffset() |
222 | { |
223 | return OBJECT_OFFSETOF(JSCell, m_type); |
224 | } |
225 | |
226 | // DO NOT store to this field. Always use a CAS loop, since some bits are flipped using CAS |
227 | // from other threads due to the internal lock. One exception: you don't need the CAS if the |
228 | // object has not escaped yet. |
229 | static ptrdiff_t indexingTypeAndMiscOffset() |
230 | { |
231 | return OBJECT_OFFSETOF(JSCell, m_indexingTypeAndMisc); |
232 | } |
233 | |
234 | static ptrdiff_t cellStateOffset() |
235 | { |
236 | return OBJECT_OFFSETOF(JSCell, m_cellState); |
237 | } |
238 | |
239 | static const TypedArrayType TypedArrayStorageType = NotTypedArray; |
240 | |
241 | void setPerCellBit(bool); |
242 | bool perCellBit() const; |
243 | protected: |
244 | |
245 | void finishCreation(VM&); |
246 | void finishCreation(VM&, Structure*, CreatingEarlyCellTag); |
247 | |
248 | // Dummy implementations of override-able static functions for classes to put in their MethodTable |
249 | static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); |
250 | static NO_RETURN_DUE_TO_CRASH void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); |
251 | static NO_RETURN_DUE_TO_CRASH void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); |
252 | static NO_RETURN_DUE_TO_CRASH void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); |
253 | |
254 | static uint32_t getEnumerableLength(ExecState*, JSObject*); |
255 | static NO_RETURN_DUE_TO_CRASH void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); |
256 | static NO_RETURN_DUE_TO_CRASH void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); |
257 | static NO_RETURN_DUE_TO_CRASH bool preventExtensions(JSObject*, ExecState*); |
258 | static NO_RETURN_DUE_TO_CRASH bool isExtensible(JSObject*, ExecState*); |
259 | static NO_RETURN_DUE_TO_CRASH bool setPrototype(JSObject*, ExecState*, JSValue, bool); |
260 | static NO_RETURN_DUE_TO_CRASH JSValue getPrototype(JSObject*, ExecState*); |
261 | |
262 | static String className(const JSObject*, VM&); |
263 | static String toStringName(const JSObject*, ExecState*); |
264 | JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue); |
265 | static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); |
266 | static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); |
267 | static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&); |
268 | |
269 | private: |
270 | friend class LLIntOffsetsExtractor; |
271 | friend class JSCellLock; |
272 | |
273 | JS_EXPORT_PRIVATE JSObject* toObjectSlow(ExecState*, JSGlobalObject*) const; |
274 | |
275 | StructureID m_structureID; |
276 | IndexingType m_indexingTypeAndMisc; // DO NOT store to this field. Always CAS. |
277 | JSType m_type; |
278 | TypeInfo::InlineTypeFlags m_flags; |
279 | CellState m_cellState; |
280 | }; |
281 | |
282 | class JSCellLock : public JSCell { |
283 | public: |
284 | void lock(); |
285 | bool tryLock(); |
286 | void unlock(); |
287 | bool isLocked() const; |
288 | private: |
289 | JS_EXPORT_PRIVATE void lockSlow(); |
290 | JS_EXPORT_PRIVATE void unlockSlow(); |
291 | }; |
292 | |
293 | // FIXME: Refer to Subspace by reference. |
294 | // https://bugs.webkit.org/show_bug.cgi?id=166988 |
295 | template<typename Type> |
296 | inline auto subspaceFor(VM& vm) |
297 | { |
298 | return Type::template subspaceFor<Type, SubspaceAccess::OnMainThread>(vm); |
299 | } |
300 | |
301 | template<typename Type> |
302 | inline auto subspaceForConcurrently(VM& vm) |
303 | { |
304 | return Type::template subspaceFor<Type, SubspaceAccess::Concurrently>(vm); |
305 | } |
306 | |
307 | } // namespace JSC |
308 | |