]> git.saurik.com Git - apple/javascriptcore.git/blame - bindings/objc/objc_runtime.mm
JavaScriptCore-461.tar.gz
[apple/javascriptcore.git] / bindings / objc / objc_runtime.mm
CommitLineData
b37bf2e1
A
1/*
2 * Copyright (C) 2004 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 "objc_runtime.h"
28
29#include "objc_instance.h"
30#include "runtime_array.h"
31#include "runtime_object.h"
32#include "WebScriptObject.h"
33
34using namespace KJS;
35using namespace KJS::Bindings;
36
37extern ClassStructPtr KJS::Bindings::webScriptObjectClass()
38{
39 static ClassStructPtr<WebScriptObject> webScriptObjectClass = NSClassFromString(@"WebScriptObject");
40 return webScriptObjectClass;
41}
42
43extern ClassStructPtr KJS::Bindings::webUndefinedClass()
44{
45 static ClassStructPtr<WebUndefined> webUndefinedClass = NSClassFromString(@"WebUndefined");
46 return webUndefinedClass;
47}
48
49// ---------------------- ObjcMethod ----------------------
50
51ObjcMethod::ObjcMethod(ClassStructPtr aClass, const char* name)
52{
53 _objcClass = aClass;
54 _selector = name; // Assume ObjC runtime keeps these around forever.
55 _javaScriptName = 0;
56}
57
58const char* ObjcMethod::name() const
59{
60 return _selector;
61}
62
63int ObjcMethod::numParameters() const
64{
65 return [getMethodSignature() numberOfArguments] - 2;
66}
67
68NSMethodSignature* ObjcMethod::getMethodSignature() const
69{
70#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2
71 return [_objcClass instanceMethodSignatureForSelector:sel_registerName(_selector)];
72#else
73 return [_objcClass instanceMethodSignatureForSelector:(SEL)_selector];
74#endif
75}
76
77// ---------------------- ObjcField ----------------------
78
79ObjcField::ObjcField(Ivar ivar)
80{
81 _ivar = ivar; // Assume ObjectiveC runtime will keep this alive forever
82 _name = 0;
83}
84
85ObjcField::ObjcField(CFStringRef name)
86{
87 _ivar = 0;
88 _name = (CFStringRef)CFRetain(name);
89}
90
91const char* ObjcField::name() const
92{
93#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2
94 if (_ivar)
95 return ivar_getName(_ivar);
96#else
97 if (_ivar)
98 return _ivar->ivar_name;
99#endif
100 return [(NSString*)_name.get() UTF8String];
101}
102
103JSValue* ObjcField::valueFromInstance(ExecState* exec, const Instance* instance) const
104{
105 JSValue* result = jsUndefined();
106
107 id targetObject = (static_cast<const ObjcInstance*>(instance))->getObject();
108
109 JSLock::DropAllLocks dropAllLocks; // Can't put this inside the @try scope because it unwinds incorrectly.
110
111 @try {
112 NSString* key = [NSString stringWithCString:name() encoding:NSASCIIStringEncoding];
113 if (id objcValue = [targetObject valueForKey:key])
114 result = convertObjcValueToValue(exec, &objcValue, ObjcObjectType, instance->rootObject());
115 } @catch(NSException* localException) {
116 JSLock::lock();
117 throwError(exec, GeneralError, [localException reason]);
118 JSLock::unlock();
119 }
120
121 return result;
122}
123
124static id convertValueToObjcObject(ExecState* exec, JSValue* value)
125{
126 RefPtr<RootObject> rootObject = findRootObject(exec->dynamicGlobalObject());
127 if (!rootObject)
128 return nil;
129 return [webScriptObjectClass() _convertValueToObjcValue:value originRootObject:rootObject.get() rootObject:rootObject.get()];
130}
131
132void ObjcField::setValueToInstance(ExecState* exec, const Instance* instance, JSValue* aValue) const
133{
134 id targetObject = (static_cast<const ObjcInstance*>(instance))->getObject();
135 id value = convertValueToObjcObject(exec, aValue);
136
137 JSLock::DropAllLocks dropAllLocks; // Can't put this inside the @try scope because it unwinds incorrectly.
138
139 @try {
140 NSString* key = [NSString stringWithCString:name() encoding:NSASCIIStringEncoding];
141 [targetObject setValue:value forKey:key];
142 } @catch(NSException* localException) {
143 JSLock::lock();
144 throwError(exec, GeneralError, [localException reason]);
145 JSLock::unlock();
146 }
147}
148
149// ---------------------- ObjcArray ----------------------
150
151ObjcArray::ObjcArray(ObjectStructPtr a, PassRefPtr<RootObject> rootObject)
152 : Array(rootObject)
153 , _array(a)
154{
155}
156
157void ObjcArray::setValueAt(ExecState* exec, unsigned int index, JSValue* aValue) const
158{
159 if (![_array.get() respondsToSelector:@selector(insertObject:atIndex:)]) {
160 throwError(exec, TypeError, "Array is not mutable.");
161 return;
162 }
163
164 if (index > [_array.get() count]) {
165 throwError(exec, RangeError, "Index exceeds array size.");
166 return;
167 }
168
169 // Always try to convert the value to an ObjC object, so it can be placed in the
170 // array.
171 ObjcValue oValue = convertValueToObjcValue (exec, aValue, ObjcObjectType);
172
173 @try {
174 [_array.get() insertObject:oValue.objectValue atIndex:index];
175 } @catch(NSException* localException) {
176 throwError(exec, GeneralError, "Objective-C exception.");
177 }
178}
179
180JSValue* ObjcArray::valueAt(ExecState* exec, unsigned int index) const
181{
182 if (index > [_array.get() count])
183 return throwError(exec, RangeError, "Index exceeds array size.");
184 @try {
185 id obj = [_array.get() objectAtIndex:index];
186 if (obj)
187 return convertObjcValueToValue (exec, &obj, ObjcObjectType, _rootObject.get());
188 } @catch(NSException* localException) {
189 return throwError(exec, GeneralError, "Objective-C exception.");
190 }
191 return jsUndefined();
192}
193
194unsigned int ObjcArray::getLength() const
195{
196 return [_array.get() count];
197}
198
199const ClassInfo ObjcFallbackObjectImp::info = { "ObjcFallbackObject", 0, 0 };
200
201ObjcFallbackObjectImp::ObjcFallbackObjectImp(ObjcInstance* i, const KJS::Identifier propertyName)
202: _instance(i)
203, _item(propertyName)
204{
205}
206
207bool ObjcFallbackObjectImp::getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot& slot)
208{
209 // keep the prototype from getting called instead of just returning false
210 slot.setUndefined(this);
211 return true;
212}
213
214void ObjcFallbackObjectImp::put(ExecState*, const Identifier&, JSValue*, int)
215{
216}
217
218bool ObjcFallbackObjectImp::canPut(ExecState*, const Identifier&) const
219{
220 return false;
221}
222
223
224JSType ObjcFallbackObjectImp::type() const
225{
226 id targetObject = _instance->getObject();
227
228 if ([targetObject respondsToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)])
229 return ObjectType;
230
231 return UndefinedType;
232}
233
234bool ObjcFallbackObjectImp::implementsCall() const
235{
236 id targetObject = _instance->getObject();
237
238 if ([targetObject respondsToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)])
239 return true;
240
241 return false;
242}
243
244JSValue* ObjcFallbackObjectImp::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args)
245{
246 if (thisObj->classInfo() != &KJS::RuntimeObjectImp::info)
247 return throwError(exec, TypeError);
248
249 JSValue* result = jsUndefined();
250
251 RuntimeObjectImp* imp = static_cast<RuntimeObjectImp*>(thisObj);
252 Instance* instance = imp->getInternalInstance();
253
254 if (!instance)
255 return RuntimeObjectImp::throwInvalidAccessError(exec);
256
257 instance->begin();
258
259 ObjcInstance* objcInstance = static_cast<ObjcInstance*>(instance);
260 id targetObject = objcInstance->getObject();
261
262 if ([targetObject respondsToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)]){
263 MethodList methodList;
264 ObjcClass* objcClass = static_cast<ObjcClass*>(instance->getClass());
265 ObjcMethod* fallbackMethod = new ObjcMethod (objcClass->isa(), sel_getName(@selector(invokeUndefinedMethodFromWebScript:withArguments:)));
266 fallbackMethod->setJavaScriptName((CFStringRef)[NSString stringWithCString:_item.ascii() encoding:NSASCIIStringEncoding]);
267 methodList.append(fallbackMethod);
268 result = instance->invokeMethod(exec, methodList, args);
269 delete fallbackMethod;
270 }
271
272 instance->end();
273
274 return result;
275}
276
277bool ObjcFallbackObjectImp::deleteProperty(ExecState*, const Identifier&)
278{
279 return false;
280}
281
282JSValue* ObjcFallbackObjectImp::defaultValue(ExecState* exec, JSType hint) const
283{
284 return _instance->getValueOfUndefinedField(exec, _item, hint);
285}
286
287bool ObjcFallbackObjectImp::toBoolean(ExecState *) const
288{
289 id targetObject = _instance->getObject();
290
291 if ([targetObject respondsToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)])
292 return true;
293
294 return false;
295}