f615ce98d1a397c23d6b3f2a3a61490670e6ae06
[WebKit-https.git] / Source / JavaScriptCore / API / JSCallbackObject.h
1 /*
2  * Copyright (C) 2006-2016 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
34 namespace JSC {
35
36 struct JSCallbackObjectData {
37     WTF_MAKE_FAST_ALLOCATED;
38 public:
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 (PrivatePropertyMap::iterator ptr = m_propertyMap.begin(); ptr != m_propertyMap.end(); ++ptr) {
110                 if (ptr->value)
111                     visitor.append(ptr->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     
124 template <class Parent>
125 class JSCallbackObject : public Parent {
126 protected:
127     JSCallbackObject(ExecState*, Structure*, JSClassRef, void* data);
128     JSCallbackObject(VM&, JSClassRef, Structure*);
129
130     void finishCreation(ExecState*);
131     void finishCreation(VM&);
132
133 public:
134     typedef Parent Base;
135     static const unsigned StructureFlags = Base::StructureFlags | ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | OverridesGetPropertyNames | TypeOfShouldCallGetCallData;
136
137     ~JSCallbackObject();
138
139     static JSCallbackObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef classRef, void* data)
140     {
141         ASSERT_UNUSED(globalObject, !structure->globalObject() || structure->globalObject() == globalObject);
142         JSCallbackObject* callbackObject = new (NotNull, allocateCell<JSCallbackObject>(*exec->heap())) JSCallbackObject(exec, structure, classRef, data);
143         callbackObject->finishCreation(exec);
144         return callbackObject;
145     }
146     static JSCallbackObject<Parent>* create(VM&, JSClassRef, Structure*);
147
148     static const bool needsDestruction;
149     static void destroy(JSCell* cell)
150     {
151         static_cast<JSCallbackObject*>(cell)->JSCallbackObject::~JSCallbackObject();
152     }
153
154     void setPrivate(void* data);
155     void* getPrivate();
156
157     // FIXME: We should fix the warnings for extern-template in JSObject template classes: https://bugs.webkit.org/show_bug.cgi?id=161979
158 #if COMPILER(CLANG)
159 #if __has_warning("-Wundefined-var-template")
160 #pragma clang diagnostic push
161 #pragma clang diagnostic ignored "-Wundefined-var-template"
162 #endif
163 #endif
164     DECLARE_INFO;
165 #if COMPILER(CLANG)
166 #if __has_warning("-Wundefined-var-template")
167 #pragma clang diagnostic pop
168 #endif
169 #endif
170
171     JSClassRef classRef() const { return m_callbackObjectData->jsClass; }
172     bool inherits(JSClassRef) const;
173
174     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
175     
176     JSValue getPrivateProperty(const Identifier& propertyName) const
177     {
178         return m_callbackObjectData->getPrivateProperty(propertyName);
179     }
180     
181     void setPrivateProperty(VM& vm, const Identifier& propertyName, JSValue value)
182     {
183         m_callbackObjectData->setPrivateProperty(vm, this, propertyName, value);
184     }
185     
186     void deletePrivateProperty(const Identifier& propertyName)
187     {
188         m_callbackObjectData->deletePrivateProperty(propertyName);
189     }
190
191     using Parent::methodTable;
192
193 private:
194     static String className(const JSObject*);
195
196     static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
197
198     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
199     static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
200     
201     static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
202     static bool putByIndex(JSCell*, ExecState*, unsigned, JSValue, bool shouldThrow);
203
204     static bool deleteProperty(JSCell*, ExecState*, PropertyName);
205     static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned);
206
207     static bool customHasInstance(JSObject*, ExecState*, JSValue);
208
209     static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
210
211     static ConstructType getConstructData(JSCell*, ConstructData&);
212     static CallType getCallData(JSCell*, CallData&);
213
214     static void visitChildren(JSCell* cell, SlotVisitor& visitor)
215     {
216         JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell);
217         ASSERT_GC_OBJECT_INHERITS((static_cast<Parent*>(thisObject)), JSCallbackObject<Parent>::info());
218         Parent::visitChildren(thisObject, visitor);
219         thisObject->m_callbackObjectData->visitChildren(visitor);
220     }
221
222     void init(ExecState*);
223  
224     static JSCallbackObject* asCallbackObject(JSValue);
225     static JSCallbackObject* asCallbackObject(EncodedJSValue);
226  
227     static EncodedJSValue JSC_HOST_CALL call(ExecState*);
228     static EncodedJSValue JSC_HOST_CALL construct(ExecState*);
229    
230     JSValue getStaticValue(ExecState*, PropertyName);
231     static EncodedJSValue staticFunctionGetter(ExecState*, EncodedJSValue, PropertyName);
232     static EncodedJSValue callbackGetter(ExecState*, EncodedJSValue, PropertyName);
233
234     std::unique_ptr<JSCallbackObjectData> m_callbackObjectData;
235 };
236
237 } // namespace JSC
238
239 // include the actual template class implementation
240 #include "JSCallbackObjectFunctions.h"
241
242 #endif // JSCallbackObject_h