1 /*
2 * Copyright (C) 2003, 2008 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_root.h"
32 #include <runtime/Error.h>
33 #include <runtime/ObjectPrototype.h>
34
35 using namespace WebCore;
36
37 namespace JSC {
38
39 using namespace Bindings;
40
41 const ClassInfo RuntimeObjectImp::s_info = { "RuntimeObject", 0, 0, 0 };
42
RuntimeObjectImp(ExecState * exec,PassRefPtr<Instance> i)43 RuntimeObjectImp::RuntimeObjectImp(ExecState* exec, PassRefPtr<Instance> i)
44 // FIXME: deprecatedGetDOMStructure uses the prototype off of the wrong global object
45 // We need to pass in the right global object for "i".
46 : JSObject(deprecatedGetDOMStructure<RuntimeObjectImp>(exec))
47 , instance(i)
48 {
49 instance->rootObject()->addRuntimeObject(this);
50 }
51
RuntimeObjectImp(ExecState *,PassRefPtr<Structure> structure,PassRefPtr<Instance> i)52 RuntimeObjectImp::RuntimeObjectImp(ExecState*, PassRefPtr<Structure> structure, PassRefPtr<Instance> i)
53 : JSObject(structure)
54 , instance(i)
55 {
56 instance->rootObject()->addRuntimeObject(this);
57 }
58
~RuntimeObjectImp()59 RuntimeObjectImp::~RuntimeObjectImp()
60 {
61 if (instance)
62 instance->rootObject()->removeRuntimeObject(this);
63 }
64
invalidate()65 void RuntimeObjectImp::invalidate()
66 {
67 ASSERT(instance);
68 instance = 0;
69 }
70
fallbackObjectGetter(ExecState * exec,const Identifier & propertyName,const PropertySlot & slot)71 JSValue RuntimeObjectImp::fallbackObjectGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
72 {
73 RuntimeObjectImp* thisObj = static_cast<RuntimeObjectImp*>(asObject(slot.slotBase()));
74 RefPtr<Instance> instance = thisObj->instance;
75
76 if (!instance)
77 return throwInvalidAccessError(exec);
78
79 instance->begin();
80
81 Class *aClass = instance->getClass();
82 JSValue result = aClass->fallbackObject(exec, instance.get(), propertyName);
83
84 instance->end();
85
86 return result;
87 }
88
fieldGetter(ExecState * exec,const Identifier & propertyName,const PropertySlot & slot)89 JSValue RuntimeObjectImp::fieldGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
90 {
91 RuntimeObjectImp* thisObj = static_cast<RuntimeObjectImp*>(asObject(slot.slotBase()));
92 RefPtr<Instance> instance = thisObj->instance;
93
94 if (!instance)
95 return throwInvalidAccessError(exec);
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 result;
106 }
107
methodGetter(ExecState * exec,const Identifier & propertyName,const PropertySlot & slot)108 JSValue RuntimeObjectImp::methodGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
109 {
110 RuntimeObjectImp* thisObj = static_cast<RuntimeObjectImp*>(asObject(slot.slotBase()));
111 RefPtr<Instance> instance = thisObj->instance;
112
113 if (!instance)
114 return throwInvalidAccessError(exec);
115
116 instance->begin();
117
118 Class *aClass = instance->getClass();
119 MethodList methodList = aClass->methodsNamed(propertyName, instance.get());
120 JSValue result = new (exec) RuntimeMethod(exec, propertyName, methodList);
121
122 instance->end();
123
124 return result;
125 }
126
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)127 bool RuntimeObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
128 {
129 if (!instance) {
130 throwInvalidAccessError(exec);
131 return false;
132 }
133
134 instance->begin();
135
136 Class *aClass = instance->getClass();
137
138 if (aClass) {
139 // See if the instance has a field with the specified name.
140 Field *aField = aClass->fieldNamed(propertyName, instance.get());
141 if (aField) {
142 slot.setCustom(this, fieldGetter);
143 instance->end();
144 return true;
145 } else {
146 // Now check if a method with specified name exists, if so return a function object for
147 // that method.
148 MethodList methodList = aClass->methodsNamed(propertyName, instance.get());
149 if (methodList.size() > 0) {
150 slot.setCustom(this, methodGetter);
151
152 instance->end();
153 return true;
154 }
155 }
156
157 // Try a fallback object.
158 if (!aClass->fallbackObject(exec, instance.get(), propertyName).isUndefined()) {
159 slot.setCustom(this, fallbackObjectGetter);
160 instance->end();
161 return true;
162 }
163 }
164
165 instance->end();
166
167 return instance->getOwnPropertySlot(this, exec, propertyName, slot);
168 }
169
put(ExecState * exec,const Identifier & propertyName,JSValue value,PutPropertySlot & slot)170 void RuntimeObjectImp::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
171 {
172 if (!instance) {
173 throwInvalidAccessError(exec);
174 return;
175 }
176
177 RefPtr<Instance> protector(instance);
178 instance->begin();
179
180 // Set the value of the property.
181 Field *aField = instance->getClass()->fieldNamed(propertyName, instance.get());
182 if (aField)
183 aField->setValueToInstance(exec, instance.get(), value);
184 else if (!instance->setValueOfUndefinedField(exec, propertyName, value))
185 instance->put(this, exec, propertyName, value, slot);
186
187 instance->end();
188 }
189
deleteProperty(ExecState *,const Identifier &)190 bool RuntimeObjectImp::deleteProperty(ExecState*, const Identifier&)
191 {
192 // Can never remove a property of a RuntimeObject.
193 return false;
194 }
195
defaultValue(ExecState * exec,PreferredPrimitiveType hint) const196 JSValue RuntimeObjectImp::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
197 {
198 if (!instance)
199 return throwInvalidAccessError(exec);
200
201 RefPtr<Instance> protector(instance);
202 instance->begin();
203 JSValue result = instance->defaultValue(exec, hint);
204 instance->end();
205 return result;
206 }
207
callRuntimeObject(ExecState * exec,JSObject * function,JSValue,const ArgList & args)208 static JSValue JSC_HOST_CALL callRuntimeObject(ExecState* exec, JSObject* function, JSValue, const ArgList& args)
209 {
210 RefPtr<Instance> instance(static_cast<RuntimeObjectImp*>(function)->getInternalInstance());
211 instance->begin();
212 JSValue result = instance->invokeDefaultMethod(exec, args);
213 instance->end();
214 return result;
215 }
216
getCallData(CallData & callData)217 CallType RuntimeObjectImp::getCallData(CallData& callData)
218 {
219 if (!instance || !instance->supportsInvokeDefaultMethod())
220 return CallTypeNone;
221 callData.native.function = callRuntimeObject;
222 return CallTypeHost;
223 }
224
callRuntimeConstructor(ExecState * exec,JSObject * constructor,const ArgList & args)225 static JSObject* callRuntimeConstructor(ExecState* exec, JSObject* constructor, const ArgList& args)
226 {
227 RefPtr<Instance> instance(static_cast<RuntimeObjectImp*>(constructor)->getInternalInstance());
228 instance->begin();
229 JSValue result = instance->invokeConstruct(exec, args);
230 instance->end();
231
232 ASSERT(result);
233 return result.isObject() ? static_cast<JSObject*>(result.asCell()) : constructor;
234 }
235
getConstructData(ConstructData & constructData)236 ConstructType RuntimeObjectImp::getConstructData(ConstructData& constructData)
237 {
238 if (!instance || !instance->supportsConstruct())
239 return ConstructTypeNone;
240 constructData.native.function = callRuntimeConstructor;
241 return ConstructTypeHost;
242 }
243
getPropertyNames(ExecState * exec,PropertyNameArray & propertyNames)244 void RuntimeObjectImp::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
245 {
246 if (!instance) {
247 throwInvalidAccessError(exec);
248 return;
249 }
250
251 instance->begin();
252 instance->getPropertyNames(exec, propertyNames);
253 instance->end();
254 }
255
throwInvalidAccessError(ExecState * exec)256 JSObject* RuntimeObjectImp::throwInvalidAccessError(ExecState* exec)
257 {
258 return throwError(exec, ReferenceError, "Trying to access object from destroyed plug-in.");
259 }
260
261 }
262