e79064e0c2ebfb27a80439d44bb436c57f78972b
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSCell.h
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
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 "TypedArrayType.h"
36 #include "WriteBarrier.h"
37 #include <wtf/Noncopyable.h>
38
39 namespace JSC {
40
41 class CopyVisitor;
42 class GCDeferralContext;
43 class ExecState;
44 class Identifier;
45 class JSArrayBufferView;
46 class JSDestructibleObject;
47 class JSGlobalObject;
48 class LLIntOffsetsExtractor;
49 class PropertyDescriptor;
50 class PropertyNameArray;
51 class Structure;
52
53 enum class AllocationFailureMode {
54     ShouldAssertOnFailure,
55     ShouldNotAssertOnFailure
56 };
57
58 enum class GCDeferralContextArgPresense {
59     HasArg,
60     DoesNotHaveArg
61 };
62
63 template<typename T> void* allocateCell(Heap&, size_t = sizeof(T));
64 template<typename T> void* tryAllocateCell(Heap&, size_t = sizeof(T));
65 template<typename T> void* allocateCell(Heap&, GCDeferralContext*, size_t = sizeof(T));
66 template<typename T> void* tryAllocateCell(Heap&, GCDeferralContext*, size_t = sizeof(T));
67
68 #define DECLARE_EXPORT_INFO                                                  \
69     protected:                                                               \
70         static JS_EXPORTDATA const ::JSC::ClassInfo s_info;                  \
71     public:                                                                  \
72         static constexpr const ::JSC::ClassInfo* info() { return &s_info; }
73
74 #define DECLARE_INFO                                                         \
75     protected:                                                               \
76         static const ::JSC::ClassInfo s_info;                                \
77     public:                                                                  \
78         static constexpr const ::JSC::ClassInfo* info() { return &s_info; }
79
80 class JSCell : public HeapCell {
81     friend class JSValue;
82     friend class MarkedBlock;
83     template<typename T, AllocationFailureMode, GCDeferralContextArgPresense>
84     friend void* tryAllocateCellHelper(Heap&, GCDeferralContext*, size_t);
85
86 public:
87     static const unsigned StructureFlags = 0;
88
89     static const bool needsDestruction = false;
90
91     // Don't call this directly. Call JSC::subspaceFor<Type>(vm) instead.
92     // FIXME: Refer to Subspace by reference.
93     // https://bugs.webkit.org/show_bug.cgi?id=166988
94     template<typename CellType>
95     static Subspace* subspaceFor(VM&);
96
97     static JSCell* seenMultipleCalleeObjects() { return bitwise_cast<JSCell*>(static_cast<uintptr_t>(1)); }
98
99     enum CreatingEarlyCellTag { CreatingEarlyCell };
100     JSCell(CreatingEarlyCellTag);
101     
102 protected:
103     JSCell(VM&, Structure*);
104     JS_EXPORT_PRIVATE static void destroy(JSCell*);
105
106 public:
107     // Querying the type.
108     bool isString() const;
109     bool isSymbol() const;
110     bool isObject() const;
111     bool isGetterSetter() const;
112     bool isCustomGetterSetter() const;
113     bool isProxy() const;
114     bool inherits(VM&, const ClassInfo*) const;
115     bool isAPIValueWrapper() const;
116     
117     // Each cell has a built-in lock. Currently it's simply available for use if you need it. It's
118     // a full-blown WTF::Lock. Note that this lock is currently used in JSArray and that lock's
119     // ordering with the Structure lock is that the Structure lock must be acquired first.
120     void lock();
121     bool tryLock();
122     void unlock();
123     bool isLocked() const;
124     
125     JSType type() const;
126     IndexingType indexingTypeAndMisc() const;
127     IndexingType indexingType() const;
128     StructureID structureID() const { return m_structureID; }
129     Structure* structure() const;
130     Structure* structure(VM&) const;
131     void setStructure(VM&, Structure*);
132     void setStructureIDDirectly(StructureID id) { m_structureID = id; }
133     void clearStructure() { m_structureID = 0; }
134
135     TypeInfo::InlineTypeFlags inlineTypeFlags() const { return m_flags; }
136
137     const char* className(VM&) const;
138
139     // Extracting the value.
140     JS_EXPORT_PRIVATE bool getString(ExecState*, String&) const;
141     JS_EXPORT_PRIVATE String getString(ExecState*) const; // null string if not a string
142     JS_EXPORT_PRIVATE JSObject* getObject(); // NULL if not an object
143     const JSObject* getObject() const; // NULL if not an object
144         
145     // Returns information about how to call/construct this cell as a function/constructor. May tell
146     // you that the cell is not callable or constructor (default is that it's not either). If it
147     // says that the function is callable, and the TypeOfShouldCallGetCallData type flag is set, and
148     // this is an object, then typeof will return "function" instead of "object". These methods
149     // cannot change their minds and must be thread-safe. They are sometimes called from compiler
150     // threads.
151     JS_EXPORT_PRIVATE static CallType getCallData(JSCell*, CallData&);
152     JS_EXPORT_PRIVATE static ConstructType getConstructData(JSCell*, ConstructData&);
153
154     // Basic conversions.
155     JS_EXPORT_PRIVATE JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
156     bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
157     bool toBoolean(ExecState*) const;
158     TriState pureToBoolean() const;
159     JS_EXPORT_PRIVATE double toNumber(ExecState*) const;
160     JSObject* toObject(ExecState*, JSGlobalObject*) const;
161
162     void dump(PrintStream&) const;
163     JS_EXPORT_PRIVATE static void dumpToStream(const JSCell*, PrintStream&);
164
165     size_t estimatedSizeInBytes() const;
166     JS_EXPORT_PRIVATE static size_t estimatedSize(JSCell*);
167
168     static void visitChildren(JSCell*, SlotVisitor&);
169     static void visitOutputConstraints(JSCell*, SlotVisitor&);
170
171     JS_EXPORT_PRIVATE static void heapSnapshot(JSCell*, HeapSnapshotBuilder&);
172
173     // Object operations, with the toObject operation included.
174     const ClassInfo* classInfo(VM&) const;
175     const MethodTable* methodTable() const;
176     const MethodTable* methodTable(VM&) const;
177     static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
178     static bool putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
179     bool putInline(ExecState*, PropertyName, JSValue, PutPropertySlot&);
180         
181     static bool deleteProperty(JSCell*, ExecState*, PropertyName);
182     static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
183
184     static JSValue toThis(JSCell*, ExecState*, ECMAMode);
185
186     static bool canUseFastGetOwnProperty(const Structure&);
187     JSValue fastGetOwnProperty(VM&, Structure&, PropertyName);
188
189     // The recommended idiom for using cellState() is to switch on it or perform an == comparison on it
190     // directly. We deliberately avoid helpers for this, because we want transparency about how the various
191     // CellState values influences our various algorithms. 
192     CellState cellState() const { return m_cellState; }
193     
194     void setCellState(CellState data) const { const_cast<JSCell*>(this)->m_cellState = data; }
195     
196     bool atomicCompareExchangeCellStateWeakRelaxed(CellState oldState, CellState newState)
197     {
198         return WTF::atomicCompareExchangeWeakRelaxed(&m_cellState, oldState, newState);
199     }
200
201     CellState atomicCompareExchangeCellStateStrong(CellState oldState, CellState newState)
202     {
203         return WTF::atomicCompareExchangeStrong(&m_cellState, oldState, newState);
204     }
205
206     static ptrdiff_t structureIDOffset()
207     {
208         return OBJECT_OFFSETOF(JSCell, m_structureID);
209     }
210
211     static ptrdiff_t typeInfoFlagsOffset()
212     {
213         return OBJECT_OFFSETOF(JSCell, m_flags);
214     }
215
216     static ptrdiff_t typeInfoTypeOffset()
217     {
218         return OBJECT_OFFSETOF(JSCell, m_type);
219     }
220
221     // DO NOT store to this field. Always use a CAS loop, since some bits are flipped using CAS
222     // from other threads due to the internal lock. One exception: you don't need the CAS if the
223     // object has not escaped yet.
224     static ptrdiff_t indexingTypeAndMiscOffset()
225     {
226         return OBJECT_OFFSETOF(JSCell, m_indexingTypeAndMisc);
227     }
228
229     static ptrdiff_t cellStateOffset()
230     {
231         return OBJECT_OFFSETOF(JSCell, m_cellState);
232     }
233     
234     void callDestructor(VM&);
235
236     static const TypedArrayType TypedArrayStorageType = NotTypedArray;
237 protected:
238
239     void finishCreation(VM&);
240     void finishCreation(VM&, Structure*, CreatingEarlyCellTag);
241
242     // Dummy implementations of override-able static functions for classes to put in their MethodTable
243     static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
244     static NO_RETURN_DUE_TO_CRASH void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
245     static NO_RETURN_DUE_TO_CRASH void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
246     static NO_RETURN_DUE_TO_CRASH void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
247
248     static uint32_t getEnumerableLength(ExecState*, JSObject*);
249     static NO_RETURN_DUE_TO_CRASH void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
250     static NO_RETURN_DUE_TO_CRASH void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
251     static NO_RETURN_DUE_TO_CRASH bool preventExtensions(JSObject*, ExecState*);
252     static NO_RETURN_DUE_TO_CRASH bool isExtensible(JSObject*, ExecState*);
253     static NO_RETURN_DUE_TO_CRASH bool setPrototype(JSObject*, ExecState*, JSValue, bool);
254     static NO_RETURN_DUE_TO_CRASH JSValue getPrototype(JSObject*, ExecState*);
255
256     static String className(const JSObject*);
257     static String toStringName(const JSObject*, ExecState*);
258     JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue);
259     static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
260     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
261     static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
262     JS_EXPORT_PRIVATE static ArrayBuffer* slowDownAndWasteMemory(JSArrayBufferView*);
263     JS_EXPORT_PRIVATE static RefPtr<ArrayBufferView> getTypedArrayImpl(JSArrayBufferView*);
264
265 private:
266     friend class LLIntOffsetsExtractor;
267
268     JS_EXPORT_PRIVATE JSObject* toObjectSlow(ExecState*, JSGlobalObject*) const;
269
270     StructureID m_structureID;
271     IndexingType m_indexingTypeAndMisc; // DO NOT store to this field. Always CAS.
272     JSType m_type;
273     TypeInfo::InlineTypeFlags m_flags;
274     CellState m_cellState;
275 };
276
277 template<typename To, typename From>
278 inline To jsCast(From* from)
279 {
280     ASSERT_WITH_SECURITY_IMPLICATION(!from || from->JSCell::inherits(*from->JSCell::vm(), std::remove_pointer<To>::type::info()));
281     return static_cast<To>(from);
282 }
283     
284 template<typename To>
285 inline To jsCast(JSValue from)
286 {
287     ASSERT_WITH_SECURITY_IMPLICATION(from.isCell() && from.asCell()->JSCell::inherits(*from.asCell()->vm(), std::remove_pointer<To>::type::info()));
288     return static_cast<To>(from.asCell());
289 }
290
291 template<typename To, typename From>
292 inline To jsDynamicCast(VM& vm, From* from)
293 {
294     if (LIKELY(from->JSCell::inherits(vm, std::remove_pointer<To>::type::info())))
295         return static_cast<To>(from);
296     return nullptr;
297 }
298
299 template<typename To>
300 inline To jsDynamicCast(VM& vm, JSValue from)
301 {
302     if (LIKELY(from.isCell() && from.asCell()->inherits(vm, std::remove_pointer<To>::type::info())))
303         return static_cast<To>(from.asCell());
304     return nullptr;
305 }
306
307 // FIXME: Refer to Subspace by reference.
308 // https://bugs.webkit.org/show_bug.cgi?id=166988
309 template<typename Type>
310 inline Subspace* subspaceFor(VM& vm)
311 {
312     return Type::template subspaceFor<Type>(vm);
313 }
314
315 } // namespace JSC