1/*
2 * Copyright (C) 2006-2019 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#ifndef JSCallbackObject_h
28#define JSCallbackObject_h
29
30#include "JSObjectRef.h"
31#include "JSValueRef.h"
32#include "JSObject.h"
33
34namespace JSC {
35
36struct JSCallbackObjectData {
37 WTF_MAKE_FAST_ALLOCATED;
38public:
39 JSCallbackObjectData(void* privateData, JSClassRef jsClass)
40 : privateData(privateData)
41 , jsClass(jsClass)
42 {
43 JSClassRetain(jsClass);
44 }
45
46 ~JSCallbackObjectData()
47 {
48 JSClassRelease(jsClass);
49 }
50
51 JSValue getPrivateProperty(const Identifier& propertyName) const
52 {
53 if (!m_privateProperties)
54 return JSValue();
55 return m_privateProperties->getPrivateProperty(propertyName);
56 }
57
58 void setPrivateProperty(VM& vm, JSCell* owner, const Identifier& propertyName, JSValue value)
59 {
60 if (!m_privateProperties)
61 m_privateProperties = std::make_unique<JSPrivatePropertyMap>();
62 m_privateProperties->setPrivateProperty(vm, owner, propertyName, value);
63 }
64
65 void deletePrivateProperty(const Identifier& propertyName)
66 {
67 if (!m_privateProperties)
68 return;
69 m_privateProperties->deletePrivateProperty(propertyName);
70 }
71
72 void visitChildren(SlotVisitor& visitor)
73 {
74 JSPrivatePropertyMap* properties = m_privateProperties.get();
75 if (!properties)
76 return;
77 properties->visitChildren(visitor);
78 }
79
80 void* privateData;
81 JSClassRef jsClass;
82 struct JSPrivatePropertyMap {
83 WTF_MAKE_FAST_ALLOCATED;
84 public:
85 JSValue getPrivateProperty(const Identifier& propertyName) const
86 {
87 PrivatePropertyMap::const_iterator location = m_propertyMap.find(propertyName.impl());
88 if (location == m_propertyMap.end())
89 return JSValue();
90 return location->value.get();
91 }
92
93 void setPrivateProperty(VM& vm, JSCell* owner, const Identifier& propertyName, JSValue value)
94 {
95 LockHolder locker(m_lock);
96 WriteBarrier<Unknown> empty;
97 m_propertyMap.add(propertyName.impl(), empty).iterator->value.set(vm, owner, value);
98 }
99
100 void deletePrivateProperty(const Identifier& propertyName)
101 {
102 LockHolder locker(m_lock);
103 m_propertyMap.remove(propertyName.impl());
104 }
105
106 void visitChildren(SlotVisitor& visitor)
107 {
108 LockHolder locker(m_lock);
109 for (auto& pair : m_propertyMap) {
110 if (pair.value)
111 visitor.append(pair.value);
112 }
113 }
114
115 private:
116 typedef HashMap<RefPtr<UniquedStringImpl>, WriteBarrier<Unknown>, IdentifierRepHash> PrivatePropertyMap;
117 PrivatePropertyMap m_propertyMap;
118 Lock m_lock;
119 };
120 std::unique_ptr<JSPrivatePropertyMap> m_privateProperties;
121};
122
123
124template <class Parent>
125class JSCallbackObject final : public Parent {
126protected:
127 JSCallbackObject(ExecState*, Structure*, JSClassRef, void* data);
128 JSCallbackObject(VM&, JSClassRef, Structure*);
129
130 void finishCreation(ExecState*);
131 void finishCreation(VM&);
132
133public:
134 typedef Parent Base;
135 static const unsigned StructureFlags = Base::StructureFlags | ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | OverridesGetPropertyNames | OverridesGetCallData;
136 static_assert(!(StructureFlags & ImplementsDefaultHasInstance), "using customHasInstance");
137
138 ~JSCallbackObject();
139
140 static JSCallbackObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef classRef, void* data)
141 {
142 VM& vm = exec->vm();
143 ASSERT_UNUSED(globalObject, !structure->globalObject() || structure->globalObject() == globalObject);
144 JSCallbackObject* callbackObject = new (NotNull, allocateCell<JSCallbackObject>(vm.heap)) JSCallbackObject(exec, structure, classRef, data);
145 callbackObject->finishCreation(exec);
146 return callbackObject;
147 }
148 static JSCallbackObject<Parent>* create(VM&, JSClassRef, Structure*);
149
150 static const bool needsDestruction;
151 static void destroy(JSCell* cell)
152 {
153 static_cast<JSCallbackObject*>(cell)->JSCallbackObject::~JSCallbackObject();
154 }
155
156 void setPrivate(void* data);
157 void* getPrivate();
158
159 // FIXME: We should fix the warnings for extern-template in JSObject template classes: https://bugs.webkit.org/show_bug.cgi?id=161979
160 IGNORE_CLANG_WARNINGS_BEGIN("undefined-var-template")
161 DECLARE_INFO;
162 IGNORE_CLANG_WARNINGS_END
163
164 JSClassRef classRef() const { return m_callbackObjectData->jsClass; }
165 bool inherits(JSClassRef) const;
166
167 static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
168
169 JSValue getPrivateProperty(const Identifier& propertyName) const
170 {
171 return m_callbackObjectData->getPrivateProperty(propertyName);
172 }
173
174 void setPrivateProperty(VM& vm, const Identifier& propertyName, JSValue value)
175 {
176 m_callbackObjectData->setPrivateProperty(vm, this, propertyName, value);
177 }
178
179 void deletePrivateProperty(const Identifier& propertyName)
180 {
181 m_callbackObjectData->deletePrivateProperty(propertyName);
182 }
183
184 using Parent::methodTable;
185
186private:
187 static String className(const JSObject*, VM&);
188 static String toStringName(const JSObject*, ExecState*);
189
190 static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
191
192 static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
193 static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
194
195 static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
196 static bool putByIndex(JSCell*, ExecState*, unsigned, JSValue, bool shouldThrow);
197
198 static bool deleteProperty(JSCell*, ExecState*, PropertyName);
199 static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned);
200
201 static bool customHasInstance(JSObject*, ExecState*, JSValue);
202
203 static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
204
205 static ConstructType getConstructData(JSCell*, ConstructData&);
206 static CallType getCallData(JSCell*, CallData&);
207
208 static void visitChildren(JSCell* cell, SlotVisitor& visitor)
209 {
210 JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell);
211 ASSERT_GC_OBJECT_INHERITS((static_cast<Parent*>(thisObject)), JSCallbackObject<Parent>::info());
212 Parent::visitChildren(thisObject, visitor);
213 thisObject->m_callbackObjectData->visitChildren(visitor);
214 }
215
216 void init(ExecState*);
217
218 static JSCallbackObject* asCallbackObject(JSValue);
219 static JSCallbackObject* asCallbackObject(EncodedJSValue);
220
221 static EncodedJSValue JSC_HOST_CALL call(ExecState*);
222 static EncodedJSValue JSC_HOST_CALL construct(ExecState*);
223
224 JSValue getStaticValue(ExecState*, PropertyName);
225 static EncodedJSValue staticFunctionGetter(ExecState*, EncodedJSValue, PropertyName);
226 static EncodedJSValue callbackGetter(ExecState*, EncodedJSValue, PropertyName);
227
228 std::unique_ptr<JSCallbackObjectData> m_callbackObjectData;
229 const ClassInfo* m_classInfo { nullptr };
230};
231
232} // namespace JSC
233
234// include the actual template class implementation
235#include "JSCallbackObjectFunctions.h"
236
237#endif // JSCallbackObject_h
238