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