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