• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2003, 2008, 2009 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 COMPUTER, 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 COMPUTER, 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 #include <runtime/ObjectPrototype.h>
33 
34 using namespace WebCore;
35 
36 namespace JSC {
37 namespace Bindings {
38 
39 const ClassInfo RuntimeObject::s_info = { "RuntimeObject", &JSObjectWithGlobalObject::s_info, 0, 0 };
40 
RuntimeObject(ExecState *,JSGlobalObject * globalObject,Structure * structure,PassRefPtr<Instance> instance)41 RuntimeObject::RuntimeObject(ExecState*, JSGlobalObject* globalObject, Structure* structure, PassRefPtr<Instance> instance)
42     : JSObjectWithGlobalObject(globalObject, structure)
43     , m_instance(instance)
44 {
45     ASSERT(inherits(&s_info));
46 }
47 
~RuntimeObject()48 RuntimeObject::~RuntimeObject()
49 {
50 }
51 
invalidate()52 void RuntimeObject::invalidate()
53 {
54     ASSERT(m_instance);
55     if (m_instance)
56         m_instance->willInvalidateRuntimeObject();
57     m_instance = 0;
58 }
59 
fallbackObjectGetter(ExecState * exec,JSValue slotBase,const Identifier & propertyName)60 JSValue RuntimeObject::fallbackObjectGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
61 {
62     RuntimeObject* thisObj = static_cast<RuntimeObject*>(asObject(slotBase));
63     RefPtr<Instance> instance = thisObj->m_instance;
64 
65     if (!instance)
66         return throwInvalidAccessError(exec);
67 
68     instance->begin();
69 
70     Class *aClass = instance->getClass();
71     JSValue result = aClass->fallbackObject(exec, instance.get(), propertyName);
72 
73     instance->end();
74 
75     return result;
76 }
77 
fieldGetter(ExecState * exec,JSValue slotBase,const Identifier & propertyName)78 JSValue RuntimeObject::fieldGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
79 {
80     RuntimeObject* thisObj = static_cast<RuntimeObject*>(asObject(slotBase));
81     RefPtr<Instance> instance = thisObj->m_instance;
82 
83     if (!instance)
84         return throwInvalidAccessError(exec);
85 
86     instance->begin();
87 
88     Class *aClass = instance->getClass();
89     Field* aField = aClass->fieldNamed(propertyName, instance.get());
90     JSValue result = aField->valueFromInstance(exec, instance.get());
91 
92     instance->end();
93 
94     return result;
95 }
96 
methodGetter(ExecState * exec,JSValue slotBase,const Identifier & propertyName)97 JSValue RuntimeObject::methodGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
98 {
99     RuntimeObject* thisObj = static_cast<RuntimeObject*>(asObject(slotBase));
100     RefPtr<Instance> instance = thisObj->m_instance;
101 
102     if (!instance)
103         return throwInvalidAccessError(exec);
104 
105     instance->begin();
106 
107     JSValue method = instance->getMethod(exec, propertyName);
108 
109     instance->end();
110 
111     return method;
112 }
113 
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)114 bool RuntimeObject::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
115 {
116     if (!m_instance) {
117         throwInvalidAccessError(exec);
118         return false;
119     }
120 
121     RefPtr<Instance> instance = m_instance;
122 
123     instance->begin();
124 
125     Class *aClass = instance->getClass();
126 
127     if (aClass) {
128         // See if the instance has a field with the specified name.
129         Field *aField = aClass->fieldNamed(propertyName, instance.get());
130         if (aField) {
131             slot.setCustom(this, fieldGetter);
132             instance->end();
133             return true;
134         } else {
135             // Now check if a method with specified name exists, if so return a function object for
136             // that method.
137             MethodList methodList = aClass->methodsNamed(propertyName, instance.get());
138             if (methodList.size() > 0) {
139                 slot.setCustom(this, methodGetter);
140 
141                 instance->end();
142                 return true;
143             }
144         }
145 
146         // Try a fallback object.
147         if (!aClass->fallbackObject(exec, instance.get(), propertyName).isUndefined()) {
148             slot.setCustom(this, fallbackObjectGetter);
149             instance->end();
150             return true;
151         }
152     }
153 
154     instance->end();
155 
156     return instance->getOwnPropertySlot(this, exec, propertyName, slot);
157 }
158 
getOwnPropertyDescriptor(ExecState * exec,const Identifier & propertyName,PropertyDescriptor & descriptor)159 bool RuntimeObject::getOwnPropertyDescriptor(ExecState *exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
160 {
161     if (!m_instance) {
162         throwInvalidAccessError(exec);
163         return false;
164     }
165 
166     RefPtr<Instance> instance = m_instance;
167     instance->begin();
168 
169     Class *aClass = instance->getClass();
170 
171     if (aClass) {
172         // See if the instance has a field with the specified name.
173         Field *aField = aClass->fieldNamed(propertyName, instance.get());
174         if (aField) {
175             PropertySlot slot;
176             slot.setCustom(this, fieldGetter);
177             instance->end();
178             descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete);
179             return true;
180         } else {
181             // Now check if a method with specified name exists, if so return a function object for
182             // that method.
183             MethodList methodList = aClass->methodsNamed(propertyName, instance.get());
184             if (methodList.size() > 0) {
185                 PropertySlot slot;
186                 slot.setCustom(this, methodGetter);
187                 instance->end();
188                 descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly);
189                 return true;
190             }
191         }
192 
193         // Try a fallback object.
194         if (!aClass->fallbackObject(exec, instance.get(), propertyName).isUndefined()) {
195             PropertySlot slot;
196             slot.setCustom(this, fallbackObjectGetter);
197             instance->end();
198             descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
199             return true;
200         }
201     }
202 
203     instance->end();
204 
205     return instance->getOwnPropertyDescriptor(this, exec, propertyName, descriptor);
206 }
207 
put(ExecState * exec,const Identifier & propertyName,JSValue value,PutPropertySlot & slot)208 void RuntimeObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
209 {
210     if (!m_instance) {
211         throwInvalidAccessError(exec);
212         return;
213     }
214 
215     RefPtr<Instance> instance = m_instance;
216     instance->begin();
217 
218     // Set the value of the property.
219     Field *aField = instance->getClass()->fieldNamed(propertyName, instance.get());
220     if (aField)
221         aField->setValueToInstance(exec, instance.get(), value);
222     else if (!instance->setValueOfUndefinedField(exec, propertyName, value))
223         instance->put(this, exec, propertyName, value, slot);
224 
225     instance->end();
226 }
227 
deleteProperty(ExecState *,const Identifier &)228 bool RuntimeObject::deleteProperty(ExecState*, const Identifier&)
229 {
230     // Can never remove a property of a RuntimeObject.
231     return false;
232 }
233 
defaultValue(ExecState * exec,PreferredPrimitiveType hint) const234 JSValue RuntimeObject::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
235 {
236     if (!m_instance)
237         return throwInvalidAccessError(exec);
238 
239     RefPtr<Instance> instance = m_instance;
240 
241     instance->begin();
242     JSValue result = instance->defaultValue(exec, hint);
243     instance->end();
244     return result;
245 }
246 
callRuntimeObject(ExecState * exec)247 static EncodedJSValue JSC_HOST_CALL callRuntimeObject(ExecState* exec)
248 {
249     ASSERT(exec->callee()->inherits(&RuntimeObject::s_info));
250     RefPtr<Instance> instance(static_cast<RuntimeObject*>(exec->callee())->getInternalInstance());
251     instance->begin();
252     JSValue result = instance->invokeDefaultMethod(exec);
253     instance->end();
254     return JSValue::encode(result);
255 }
256 
getCallData(CallData & callData)257 CallType RuntimeObject::getCallData(CallData& callData)
258 {
259     if (!m_instance)
260         return CallTypeNone;
261 
262     RefPtr<Instance> instance = m_instance;
263     if (!instance->supportsInvokeDefaultMethod())
264         return CallTypeNone;
265 
266     callData.native.function = callRuntimeObject;
267     return CallTypeHost;
268 }
269 
callRuntimeConstructor(ExecState * exec)270 static EncodedJSValue JSC_HOST_CALL callRuntimeConstructor(ExecState* exec)
271 {
272     JSObject* constructor = exec->callee();
273     ASSERT(constructor->inherits(&RuntimeObject::s_info));
274     RefPtr<Instance> instance(static_cast<RuntimeObject*>(exec->callee())->getInternalInstance());
275     instance->begin();
276     ArgList args(exec);
277     JSValue result = instance->invokeConstruct(exec, args);
278     instance->end();
279 
280     ASSERT(result);
281     return JSValue::encode(result.isObject() ? static_cast<JSObject*>(result.asCell()) : constructor);
282 }
283 
getConstructData(ConstructData & constructData)284 ConstructType RuntimeObject::getConstructData(ConstructData& constructData)
285 {
286     if (!m_instance)
287         return ConstructTypeNone;
288 
289     RefPtr<Instance> instance = m_instance;
290     if (!instance->supportsConstruct())
291         return ConstructTypeNone;
292 
293     constructData.native.function = callRuntimeConstructor;
294     return ConstructTypeHost;
295 }
296 
getOwnPropertyNames(ExecState * exec,PropertyNameArray & propertyNames,EnumerationMode)297 void RuntimeObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode)
298 {
299     if (!m_instance) {
300         throwInvalidAccessError(exec);
301         return;
302     }
303 
304     RefPtr<Instance> instance = m_instance;
305 
306     instance->begin();
307     instance->getPropertyNames(exec, propertyNames);
308     instance->end();
309 }
310 
throwInvalidAccessError(ExecState * exec)311 JSObject* RuntimeObject::throwInvalidAccessError(ExecState* exec)
312 {
313     return throwError(exec, createReferenceError(exec, "Trying to access object from destroyed plug-in."));
314 }
315 
316 }
317 }
318