JavaScriptCore:
[WebKit-https.git] / JavaScriptCore / bindings / runtime_object.cpp
1 /*
2  * Copyright (C) 2003 Apple Computer, 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 "error_object.h"
30 #include "operations.h"
31 #include "runtime_method.h"
32 #include "runtime_root.h"
33
34 using namespace KJS;
35 using namespace Bindings;
36
37 const ClassInfo RuntimeObjectImp::info = { "RuntimeObject", 0, 0 };
38
39 RuntimeObjectImp::RuntimeObjectImp(Bindings::Instance *i)
40 : instance(i)
41 {
42     instance->rootObject()->addRuntimeObject(this);
43 }
44
45 RuntimeObjectImp::~RuntimeObjectImp()
46 {
47     if (instance)
48         instance->rootObject()->removeRuntimeObject(this);
49 }
50
51 void RuntimeObjectImp::invalidate()
52 {
53     ASSERT(instance);
54     instance = 0;
55 }
56
57 JSValue *RuntimeObjectImp::fallbackObjectGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
58 {
59     RuntimeObjectImp *thisObj = static_cast<RuntimeObjectImp *>(slot.slotBase());
60     RefPtr<Bindings::Instance> instance = thisObj->instance;
61
62     if (!instance)
63         return throwInvalidAccessError(exec);
64     
65     instance->begin();
66
67     Class *aClass = instance->getClass();
68     JSValue* result = aClass->fallbackObject(exec, instance.get(), propertyName);
69
70     instance->end();
71             
72     return result;
73 }
74
75 JSValue *RuntimeObjectImp::fieldGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
76 {    
77     RuntimeObjectImp *thisObj = static_cast<RuntimeObjectImp *>(slot.slotBase());
78     RefPtr<Bindings::Instance> instance = thisObj->instance;
79
80     if (!instance)
81         return throwInvalidAccessError(exec);
82     
83     instance->begin();
84
85     Class *aClass = instance->getClass();
86     Field* aField = aClass->fieldNamed(propertyName, instance.get());
87     JSValue *result = instance->getValueOfField(exec, aField); 
88     
89     instance->end();
90             
91     return result;
92 }
93
94 JSValue *RuntimeObjectImp::methodGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
95 {
96     RuntimeObjectImp *thisObj = static_cast<RuntimeObjectImp *>(slot.slotBase());
97     RefPtr<Bindings::Instance> instance = thisObj->instance;
98
99     if (!instance)
100         return throwInvalidAccessError(exec);
101     
102     instance->begin();
103
104     Class *aClass = instance->getClass();
105     MethodList methodList = aClass->methodsNamed(propertyName, instance.get());
106     JSValue *result = new RuntimeMethod(exec, propertyName, methodList);
107
108     instance->end();
109             
110     return result;
111 }
112
113 bool RuntimeObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
114 {
115     if (!instance) {
116         throwInvalidAccessError(exec);
117         return false;
118     }
119     
120     instance->begin();
121     
122     Class *aClass = instance->getClass();
123     
124     if (aClass) {
125         // See if the instance has a field with the specified name.
126         Field *aField = aClass->fieldNamed(propertyName, instance.get());
127         if (aField) {
128             slot.setCustom(this, fieldGetter);
129             instance->end();
130             return true;
131         } else {
132             // Now check if a method with specified name exists, if so return a function object for
133             // that method.
134             MethodList methodList = aClass->methodsNamed(propertyName, instance.get());
135             if (methodList.size() > 0) {
136                 slot.setCustom(this, methodGetter);
137                 
138                 instance->end();
139                 return true;
140             }
141         }
142
143         // Try a fallback object.
144         if (!aClass->fallbackObject(exec, instance.get(), propertyName)->isUndefined()) {
145             slot.setCustom(this, fallbackObjectGetter);
146             instance->end();
147             return true;
148         }
149     }
150         
151     instance->end();
152
153     // don't call superclass, because runtime objects can't have custom properties or a prototype
154     return false;
155 }
156
157 void RuntimeObjectImp::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int)
158 {
159     if (!instance) {
160         throwInvalidAccessError(exec);
161         return;
162     }
163     
164     RefPtr<Bindings::Instance> protector(instance);
165     instance->begin();
166
167     // Set the value of the property.
168     Field *aField = instance->getClass()->fieldNamed(propertyName, instance.get());
169     if (aField)
170         instance->setValueOfField(exec, aField, value);
171     else if (instance->supportsSetValueOfUndefinedField())
172         instance->setValueOfUndefinedField(exec, propertyName, value);
173
174     instance->end();
175 }
176
177 bool RuntimeObjectImp::canPut(ExecState* exec, const Identifier& propertyName) const
178 {
179     if (!instance) {
180         throwInvalidAccessError(exec);
181         return false;
182     }
183     
184     instance->begin();
185
186     Field *aField = instance->getClass()->fieldNamed(propertyName, instance.get());
187
188     instance->end();
189
190     return !!aField;
191 }
192
193 bool RuntimeObjectImp::deleteProperty(ExecState*, const Identifier&)
194 {
195     // Can never remove a property of a RuntimeObject.
196     return false;
197 }
198
199 JSValue *RuntimeObjectImp::defaultValue(ExecState* exec, JSType hint) const
200 {
201     if (!instance)
202         return throwInvalidAccessError(exec);
203     
204     JSValue *result;
205     
206     RefPtr<Bindings::Instance> protector(instance);
207     instance->begin();
208
209     result = instance->defaultValue(hint);
210     
211     instance->end();
212     
213     return result;
214 }
215     
216 bool RuntimeObjectImp::implementsCall() const
217 {
218     if (!instance)
219         return false;
220     
221     return instance->implementsCall();
222 }
223
224 JSValue *RuntimeObjectImp::callAsFunction(ExecState* exec, JSObject*, const List& args)
225 {
226     if (!instance)
227         return throwInvalidAccessError(exec);
228
229     RefPtr<Bindings::Instance> protector(instance);
230     instance->begin();
231
232     JSValue *aValue = instance->invokeDefaultMethod(exec, args);
233     
234     instance->end();
235     
236     return aValue;
237 }
238
239 void RuntimeObjectImp::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
240 {
241     if (!instance) {
242         throwInvalidAccessError(exec);
243         return;
244     }
245     
246     instance->begin();
247     instance->getPropertyNames(exec, propertyNames);
248     instance->end();
249 }
250
251 JSObject* RuntimeObjectImp::throwInvalidAccessError(ExecState* exec)
252 {
253     return throwError(exec, ReferenceError, "Trying to access object from destroyed plug-in.");
254 }