Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / bridge / runtime_object.cpp
1 /*
2  * Copyright (C) 2003, 2008-2009, 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "runtime_object.h"
28
29 #include "JSDOMBinding.h"
30 #include "runtime_method.h"
31 #include <runtime/Error.h>
32
33 using namespace WebCore;
34
35 namespace JSC {
36 namespace Bindings {
37
38 WEBCORE_EXPORT const ClassInfo RuntimeObject::s_info = { "RuntimeObject", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(RuntimeObject) };
39
40 RuntimeObject::RuntimeObject(VM& vm, Structure* structure, RefPtr<Instance>&& instance)
41     : JSDestructibleObject(vm, structure)
42     , m_instance(WTFMove(instance))
43 {
44 }
45
46 void RuntimeObject::finishCreation(VM& vm)
47 {
48     Base::finishCreation(vm);
49     ASSERT(inherits(vm, info()));
50 }
51
52 void RuntimeObject::destroy(JSCell* cell)
53 {
54     static_cast<RuntimeObject*>(cell)->RuntimeObject::~RuntimeObject();
55 }
56
57 void RuntimeObject::invalidate()
58 {
59     ASSERT(m_instance);
60     if (m_instance)
61         m_instance->willInvalidateRuntimeObject();
62     m_instance = nullptr;
63 }
64
65 EncodedJSValue RuntimeObject::fallbackObjectGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName propertyName)
66 {
67     VM& vm = exec->vm();
68     auto scope = DECLARE_THROW_SCOPE(vm);
69
70     RuntimeObject* thisObj = jsCast<RuntimeObject*>(JSValue::decode(thisValue));
71     RefPtr<Instance> instance = thisObj->m_instance;
72
73     if (!instance)
74         return JSValue::encode(throwInvalidAccessError(exec, scope));
75     
76     instance->begin();
77
78     Class *aClass = instance->getClass();
79     JSValue result = aClass->fallbackObject(exec, instance.get(), propertyName);
80
81     instance->end();
82             
83     return JSValue::encode(result);
84 }
85
86 EncodedJSValue RuntimeObject::fieldGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName propertyName)
87 {    
88     VM& vm = exec->vm();
89     auto scope = DECLARE_THROW_SCOPE(vm);
90
91     RuntimeObject* thisObj = jsCast<RuntimeObject*>(JSValue::decode(thisValue));
92     RefPtr<Instance> instance = thisObj->m_instance;
93
94     if (!instance)
95         return JSValue::encode(throwInvalidAccessError(exec, scope));
96     
97     instance->begin();
98
99     Class *aClass = instance->getClass();
100     Field* aField = aClass->fieldNamed(propertyName, instance.get());
101     JSValue result = aField->valueFromInstance(exec, instance.get());
102     
103     instance->end();
104             
105     return JSValue::encode(result);
106 }
107
108 EncodedJSValue RuntimeObject::methodGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName propertyName)
109 {
110     VM& vm = exec->vm();
111     auto scope = DECLARE_THROW_SCOPE(vm);
112
113     RuntimeObject* thisObj = jsCast<RuntimeObject*>(JSValue::decode(thisValue));
114     RefPtr<Instance> instance = thisObj->m_instance;
115
116     if (!instance)
117         return JSValue::encode(throwInvalidAccessError(exec, scope));
118     
119     instance->begin();
120
121     JSValue method = instance->getMethod(exec, propertyName);
122
123     instance->end();
124             
125     return JSValue::encode(method);
126 }
127
128 bool RuntimeObject::getOwnPropertySlot(JSObject* object, ExecState *exec, PropertyName propertyName, PropertySlot& slot)
129 {
130     VM& vm = exec->vm();
131     auto scope = DECLARE_THROW_SCOPE(vm);
132
133     RuntimeObject* thisObject = jsCast<RuntimeObject*>(object);
134     if (!thisObject->m_instance) {
135         throwInvalidAccessError(exec, scope);
136         return false;
137     }
138     
139     RefPtr<Instance> instance = thisObject->m_instance;
140
141     instance->begin();
142     
143     Class *aClass = instance->getClass();
144     
145     if (aClass) {
146         // See if the instance has a field with the specified name.
147         Field *aField = aClass->fieldNamed(propertyName, instance.get());
148         if (aField) {
149             slot.setCustom(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::DontDelete), thisObject->fieldGetter);
150             instance->end();
151             return true;
152         } else {
153             // Now check if a method with specified name exists, if so return a function object for
154             // that method.
155             if (aClass->methodNamed(propertyName, instance.get())) {
156                 slot.setCustom(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly, thisObject->methodGetter);
157                 
158                 instance->end();
159                 return true;
160             }
161         }
162
163         // Try a fallback object.
164         if (!aClass->fallbackObject(exec, instance.get(), propertyName).isUndefined()) {
165             slot.setCustom(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum, thisObject->fallbackObjectGetter);
166             instance->end();
167             return true;
168         }
169     }
170         
171     instance->end();
172     
173     return instance->getOwnPropertySlot(thisObject, exec, propertyName, slot);
174 }
175
176 bool RuntimeObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
177 {
178     VM& vm = exec->vm();
179     auto scope = DECLARE_THROW_SCOPE(vm);
180
181     RuntimeObject* thisObject = jsCast<RuntimeObject*>(cell);
182     if (!thisObject->m_instance) {
183         throwInvalidAccessError(exec, scope);
184         return false;
185     }
186     
187     RefPtr<Instance> instance = thisObject->m_instance;
188     instance->begin();
189
190     // Set the value of the property.
191     bool result = false;
192     Field *aField = instance->getClass()->fieldNamed(propertyName, instance.get());
193     if (aField)
194         result = aField->setValueToInstance(exec, instance.get(), value);
195     else if (!instance->setValueOfUndefinedField(exec, propertyName, value))
196         result = instance->put(thisObject, exec, propertyName, value, slot);
197
198     instance->end();
199     return result;
200 }
201
202 bool RuntimeObject::deleteProperty(JSCell*, ExecState*, PropertyName)
203 {
204     // Can never remove a property of a RuntimeObject.
205     return false;
206 }
207
208 JSValue RuntimeObject::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint)
209 {
210     VM& vm = exec->vm();
211     auto scope = DECLARE_THROW_SCOPE(vm);
212
213     const RuntimeObject* thisObject = jsCast<const RuntimeObject*>(object);
214     if (!thisObject->m_instance)
215         return throwInvalidAccessError(exec, scope);
216     
217     RefPtr<Instance> instance = thisObject->m_instance;
218
219     instance->begin();
220     JSValue result = instance->defaultValue(exec, hint);
221     instance->end();
222     return result;
223 }
224
225 static EncodedJSValue JSC_HOST_CALL callRuntimeObject(ExecState* exec)
226 {
227     ASSERT(exec->jsCallee()->inherits(exec->vm(), RuntimeObject::info()));
228     RefPtr<Instance> instance(static_cast<RuntimeObject*>(exec->jsCallee())->getInternalInstance());
229     instance->begin();
230     JSValue result = instance->invokeDefaultMethod(exec);
231     instance->end();
232     return JSValue::encode(result);
233 }
234
235 CallType RuntimeObject::getCallData(JSCell* cell, CallData& callData)
236 {
237     RuntimeObject* thisObject = jsCast<RuntimeObject*>(cell);
238     if (!thisObject->m_instance)
239         return CallType::None;
240     
241     RefPtr<Instance> instance = thisObject->m_instance;
242     if (!instance->supportsInvokeDefaultMethod())
243         return CallType::None;
244     
245     callData.native.function = callRuntimeObject;
246     return CallType::Host;
247 }
248
249 static EncodedJSValue JSC_HOST_CALL callRuntimeConstructor(ExecState* exec)
250 {
251     JSObject* constructor = exec->jsCallee();
252     ASSERT(constructor->inherits(exec->vm(), RuntimeObject::info()));
253     RefPtr<Instance> instance(static_cast<RuntimeObject*>(exec->jsCallee())->getInternalInstance());
254     instance->begin();
255     ArgList args(exec);
256     JSValue result = instance->invokeConstruct(exec, args);
257     instance->end();
258     
259     ASSERT(result);
260     return JSValue::encode(result.isObject() ? jsCast<JSObject*>(result.asCell()) : constructor);
261 }
262
263 ConstructType RuntimeObject::getConstructData(JSCell* cell, ConstructData& constructData)
264 {
265     RuntimeObject* thisObject = jsCast<RuntimeObject*>(cell);
266     if (!thisObject->m_instance)
267         return ConstructType::None;
268     
269     RefPtr<Instance> instance = thisObject->m_instance;
270     if (!instance->supportsConstruct())
271         return ConstructType::None;
272     
273     constructData.native.function = callRuntimeConstructor;
274     return ConstructType::Host;
275 }
276
277 void RuntimeObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode)
278 {
279     VM& vm = exec->vm();
280     auto scope = DECLARE_THROW_SCOPE(vm);
281
282     RuntimeObject* thisObject = jsCast<RuntimeObject*>(object);
283     if (!thisObject->m_instance) {
284         throwInvalidAccessError(exec, scope);
285         return;
286     }
287
288     RefPtr<Instance> instance = thisObject->m_instance;
289     
290     instance->begin();
291     instance->getPropertyNames(exec, propertyNames);
292     instance->end();
293 }
294
295 JSObject* RuntimeObject::throwInvalidAccessError(ExecState* exec, ThrowScope& scope)
296 {
297     return throwException(exec, scope, createReferenceError(exec, "Trying to access object from destroyed plug-in."));
298 }
299
300 }
301 }