WebCore:
[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 "error_object.h"
27 #include "function.h"
28 #include "interpreter.h"
29 #include "object.h"
30 #include "operations.h"
31 #include "runtime_method.h"
32 #include "runtime_object.h"
33 #include "types.h"
34 #include "value.h"
35
36
37 #include <assert.h>
38
39 using namespace KJS;
40 using namespace Bindings;
41
42 const ClassInfo RuntimeObjectImp::info = {"RuntimeObject", 0, 0, 0};
43
44 RuntimeObjectImp::RuntimeObjectImp(ObjectImp *proto)
45   : ObjectImp(proto)
46 {
47     instance = 0;
48 }
49
50 RuntimeObjectImp::~RuntimeObjectImp()
51 {
52     if (ownsInstance) {
53         delete instance;
54     }
55 }
56
57 RuntimeObjectImp::RuntimeObjectImp(Bindings::Instance *i, bool oi) : ObjectImp ((ObjectImp *)0)
58 {
59     ownsInstance = oi;
60     instance = i;
61 }
62
63 RuntimeObjectImp::RuntimeObjectImp(Bindings::Instance *i, const Value &fb, bool oi) : ObjectImp ((ObjectImp *)0)
64 {
65     ownsInstance = oi;
66     instance = i;
67     fallback = fb;
68 }
69
70 Value RuntimeObjectImp::get(ExecState *exec, const Identifier &propertyName) const
71 {
72     Value result = Undefined();
73
74     instance->begin();
75     
76     Class *aClass = instance->getClass();
77     
78     if (aClass) {
79         
80         // See if the instance have a field with the specified name.
81         Field *aField = aClass->fieldNamed(propertyName.ascii(), instance);
82         if (aField) {
83             result = instance->getValueOfField (exec, aField); 
84         }
85         else {
86             // Now check if a method with specified name exists, if so return a function object for
87             // that method.
88             MethodList methodList = aClass->methodsNamed(propertyName.ascii(), instance);
89             if (methodList.length() > 0) {
90                 result = Object (new RuntimeMethodImp(exec, propertyName, methodList));
91             }
92             else if (!fallback.isNull() && fallback.type() == ObjectType){
93                 ObjectImp *imp = static_cast<ObjectImp*>(fallback.imp());
94                 imp->setForwardingScriptMessage(true);
95                 result = imp->get (exec, propertyName);
96                 imp->setForwardingScriptMessage(false);
97             }
98         }
99         
100         if (result.type() == UndefinedType) {
101             // Try a fallback object.
102             result = aClass->fallbackObject (exec, instance, propertyName);
103         }
104     }
105         
106     instance->end();
107
108     
109     return result;
110 }
111
112 void RuntimeObjectImp::put(ExecState *exec, const Identifier &propertyName,
113                     const Value &value, int attr)
114 {
115     instance->begin();
116
117     // Set the value of the property.
118     Field *aField = instance->getClass()->fieldNamed(propertyName.ascii(), instance);
119     if (aField) {
120         getInternalInstance()->setValueOfField(exec, aField, value);
121     }
122     else {
123         bool domHasProperty = false;
124         if (!fallback.isNull() && fallback.type() == ObjectType){
125             ObjectImp *imp = static_cast<ObjectImp*>(fallback.imp());
126             imp->setForwardingScriptMessage(true);
127             domHasProperty = imp->hasProperty(exec, propertyName);
128             imp->setForwardingScriptMessage(false);
129         }
130         
131         // If the DOM has the property, give it a crack first (even if it read-only).
132         if (domHasProperty || !getInternalInstance()->supportsSetValueOfUndefinedField()) {
133             ObjectImp *imp = static_cast<ObjectImp*>(fallback.imp());
134             imp->setForwardingScriptMessage(true);
135             imp->put(exec, propertyName, value, attr);
136             imp->setForwardingScriptMessage(false);
137         }
138         // Now let the runtime object attempt to handle the undefined field.
139         else if (getInternalInstance()->supportsSetValueOfUndefinedField()){
140             getInternalInstance()->setValueOfUndefinedField(exec, propertyName, value);
141         }
142     }
143
144     instance->end();
145 }
146
147 bool RuntimeObjectImp::canPut(ExecState *exec, const Identifier &propertyName) const
148 {
149     bool result = false;
150
151     instance->begin();
152
153     Field *aField = instance->getClass()->fieldNamed(propertyName.ascii(), instance);
154
155     instance->end();
156
157     if (aField)
158         return true;
159     
160     if (!fallback.isNull() && fallback.type() == ObjectType) {
161         ObjectImp *imp = static_cast<ObjectImp*>(fallback.imp());
162         imp->setForwardingScriptMessage(true);
163         result = imp->canPut (exec, propertyName);
164         imp->setForwardingScriptMessage(false);
165     }
166         
167     return result;
168 }
169
170 bool RuntimeObjectImp::hasProperty(ExecState *exec,
171                             const Identifier &propertyName) const
172 {
173     bool result = false;
174     
175     instance->begin();
176
177     Field *aField = instance->getClass()->fieldNamed(propertyName.ascii(), instance);
178     if (aField) {
179         instance->end();
180         return true;
181     }
182         
183     MethodList methodList = instance->getClass()->methodsNamed(propertyName.ascii(), instance);
184
185     instance->end();
186
187     if (methodList.length() > 0)
188         return true;
189
190     if (!fallback.isNull() && fallback.type() == ObjectType) {
191         ObjectImp *imp = static_cast<ObjectImp*>(fallback.imp());
192         imp->setForwardingScriptMessage(true);
193         result = imp->hasProperty (exec, propertyName);
194         imp->setForwardingScriptMessage(false);
195     }
196         
197     return result;
198 }
199
200 bool RuntimeObjectImp::deleteProperty(ExecState *exec,
201                             const Identifier &propertyName)
202 {
203     // Can never remove a property of a RuntimeObject.
204     return false;
205 }
206
207 Value RuntimeObjectImp::defaultValue(ExecState *exec, Type hint) const
208 {
209     Value result;
210     
211     instance->begin();
212
213     if (!fallback.isNull() && fallback.type() == ObjectType) {
214         ObjectImp *imp = static_cast<ObjectImp*>(fallback.imp());
215         imp->setForwardingScriptMessage(true);
216         result = imp->defaultValue (exec, hint);
217         imp->setForwardingScriptMessage(false);
218     }
219     else {
220         result = getInternalInstance()->defaultValue(hint);
221     }
222     
223     instance->end();
224     
225     return result;
226 }
227     
228 bool RuntimeObjectImp::implementsCall() const
229 {
230     // Only true for default functions.
231     return true;
232 }
233
234 Value RuntimeObjectImp::call(ExecState *exec, Object &thisObj, const List &args)
235 {
236     instance->begin();
237
238     Value aValue = getInternalInstance()->invokeDefaultMethod(exec, args);
239     
240     instance->end();
241     
242     return aValue;
243 }
244