/platform/external/webkit/WebCore/bridge/objc/objc_instance.mm

https://github.com/aharish/totoro-gb-opensource-update2 · Objective C++ · 432 lines · 296 code · 69 blank · 67 comment · 40 complexity · 44b92b5bde9634615abf954b33dd34d8 MD5 · raw file

  1. /*
  2. * Copyright (C) 2004, 2008, 2009 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. #import "config.h"
  26. #import "objc_instance.h"
  27. #import "FoundationExtras.h"
  28. #import "WebScriptObject.h"
  29. #import <objc/objc-auto.h>
  30. #import <runtime/Error.h>
  31. #import <runtime/JSLock.h>
  32. #import <wtf/Assertions.h>
  33. #ifdef NDEBUG
  34. #define OBJC_LOG(formatAndArgs...) ((void)0)
  35. #else
  36. #define OBJC_LOG(formatAndArgs...) { \
  37. fprintf (stderr, "%s:%d -- %s: ", __FILE__, __LINE__, __FUNCTION__); \
  38. fprintf(stderr, formatAndArgs); \
  39. }
  40. #endif
  41. using namespace JSC::Bindings;
  42. using namespace JSC;
  43. static NSString *s_exception;
  44. static JSGlobalObject* s_exceptionEnvironment; // No need to protect this value, since we just use it for a pointer comparison.
  45. static NSMapTable *s_instanceWrapperCache;
  46. static NSMapTable *createInstanceWrapperCache()
  47. {
  48. #ifdef BUILDING_ON_TIGER
  49. return NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks, NSNonOwnedPointerMapValueCallBacks, 0);
  50. #else
  51. // NSMapTable with zeroing weak pointers is the recommended way to build caches like this under garbage collection.
  52. NSPointerFunctionsOptions keyOptions = NSPointerFunctionsZeroingWeakMemory | NSPointerFunctionsObjectPersonality;
  53. NSPointerFunctionsOptions valueOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality;
  54. return [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0];
  55. #endif
  56. }
  57. void ObjcInstance::setGlobalException(NSString* exception, JSGlobalObject* exceptionEnvironment)
  58. {
  59. HardRelease(s_exception);
  60. HardRetain(exception);
  61. s_exception = exception;
  62. s_exceptionEnvironment = exceptionEnvironment;
  63. }
  64. void ObjcInstance::moveGlobalExceptionToExecState(ExecState* exec)
  65. {
  66. if (!s_exception) {
  67. ASSERT(!s_exceptionEnvironment);
  68. return;
  69. }
  70. if (!s_exceptionEnvironment || s_exceptionEnvironment == exec->dynamicGlobalObject()) {
  71. JSLock lock(SilenceAssertionsOnly);
  72. throwError(exec, GeneralError, s_exception);
  73. }
  74. HardRelease(s_exception);
  75. s_exception = 0;
  76. s_exceptionEnvironment = 0;
  77. }
  78. ObjcInstance::ObjcInstance(id instance, PassRefPtr<RootObject> rootObject)
  79. : Instance(rootObject)
  80. , _instance(instance)
  81. , _class(0)
  82. , _pool(0)
  83. , _beginCount(0)
  84. {
  85. }
  86. PassRefPtr<ObjcInstance> ObjcInstance::create(id instance, PassRefPtr<RootObject> rootObject)
  87. {
  88. if (!s_instanceWrapperCache)
  89. s_instanceWrapperCache = createInstanceWrapperCache();
  90. if (void* existingWrapper = NSMapGet(s_instanceWrapperCache, instance))
  91. return static_cast<ObjcInstance*>(existingWrapper);
  92. RefPtr<ObjcInstance> wrapper = adoptRef(new ObjcInstance(instance, rootObject));
  93. NSMapInsert(s_instanceWrapperCache, instance, wrapper.get());
  94. return wrapper.release();
  95. }
  96. ObjcInstance::~ObjcInstance()
  97. {
  98. // Both -finalizeForWebScript and -dealloc/-finalize of _instance may require autorelease pools.
  99. NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
  100. ASSERT(s_instanceWrapperCache);
  101. ASSERT(_instance);
  102. NSMapRemove(s_instanceWrapperCache, _instance.get());
  103. if ([_instance.get() respondsToSelector:@selector(finalizeForWebScript)])
  104. [_instance.get() performSelector:@selector(finalizeForWebScript)];
  105. _instance = 0;
  106. [pool drain];
  107. }
  108. static NSAutoreleasePool* allocateAutoReleasePool()
  109. {
  110. #if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2
  111. // If GC is enabled an autorelease pool is unnecessary, and the
  112. // pool cannot be protected from GC so may be collected leading
  113. // to a crash when we try to drain the release pool.
  114. if (objc_collectingEnabled())
  115. return nil;
  116. #endif
  117. return [[NSAutoreleasePool alloc] init];
  118. }
  119. void ObjcInstance::virtualBegin()
  120. {
  121. if (!_pool)
  122. _pool = allocateAutoReleasePool();
  123. _beginCount++;
  124. }
  125. void ObjcInstance::virtualEnd()
  126. {
  127. _beginCount--;
  128. ASSERT(_beginCount >= 0);
  129. if (!_beginCount) {
  130. [_pool drain];
  131. _pool = 0;
  132. }
  133. }
  134. Bindings::Class* ObjcInstance::getClass() const
  135. {
  136. if (!_instance)
  137. return 0;
  138. if (!_class)
  139. _class = ObjcClass::classForIsA(_instance->isa);
  140. return static_cast<Bindings::Class*>(_class);
  141. }
  142. bool ObjcInstance::supportsInvokeDefaultMethod() const
  143. {
  144. return [_instance.get() respondsToSelector:@selector(invokeDefaultMethodWithArguments:)];
  145. }
  146. JSValue ObjcInstance::invokeMethod(ExecState* exec, const MethodList &methodList, const ArgList &args)
  147. {
  148. JSValue result = jsUndefined();
  149. JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly); // Can't put this inside the @try scope because it unwinds incorrectly.
  150. setGlobalException(nil);
  151. // Overloading methods is not allowed in ObjectiveC. Should only be one
  152. // name match for a particular method.
  153. ASSERT(methodList.size() == 1);
  154. @try {
  155. ObjcMethod* method = 0;
  156. method = static_cast<ObjcMethod*>(methodList[0]);
  157. NSMethodSignature* signature = method->getMethodSignature();
  158. NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
  159. [invocation setSelector:method->selector()];
  160. [invocation setTarget:_instance.get()];
  161. if (method->isFallbackMethod()) {
  162. if (objcValueTypeForType([signature methodReturnType]) != ObjcObjectType) {
  163. NSLog(@"Incorrect signature for invokeUndefinedMethodFromWebScript:withArguments: -- return type must be object.");
  164. return result;
  165. }
  166. // Invoke invokeUndefinedMethodFromWebScript:withArguments:, pass JavaScript function
  167. // name as first (actually at 2) argument and array of args as second.
  168. NSString* jsName = (NSString* )method->javaScriptName();
  169. [invocation setArgument:&jsName atIndex:2];
  170. NSMutableArray* objcArgs = [NSMutableArray array];
  171. int count = args.size();
  172. for (int i = 0; i < count; i++) {
  173. ObjcValue value = convertValueToObjcValue(exec, args.at(i), ObjcObjectType);
  174. [objcArgs addObject:value.objectValue];
  175. }
  176. [invocation setArgument:&objcArgs atIndex:3];
  177. } else {
  178. unsigned count = [signature numberOfArguments];
  179. for (unsigned i = 2; i < count ; i++) {
  180. const char* type = [signature getArgumentTypeAtIndex:i];
  181. ObjcValueType objcValueType = objcValueTypeForType(type);
  182. // Must have a valid argument type. This method signature should have
  183. // been filtered already to ensure that it has acceptable argument
  184. // types.
  185. ASSERT(objcValueType != ObjcInvalidType && objcValueType != ObjcVoidType);
  186. ObjcValue value = convertValueToObjcValue(exec, args.at(i-2), objcValueType);
  187. switch (objcValueType) {
  188. case ObjcObjectType:
  189. [invocation setArgument:&value.objectValue atIndex:i];
  190. break;
  191. case ObjcCharType:
  192. case ObjcUnsignedCharType:
  193. [invocation setArgument:&value.charValue atIndex:i];
  194. break;
  195. case ObjcShortType:
  196. case ObjcUnsignedShortType:
  197. [invocation setArgument:&value.shortValue atIndex:i];
  198. break;
  199. case ObjcIntType:
  200. case ObjcUnsignedIntType:
  201. [invocation setArgument:&value.intValue atIndex:i];
  202. break;
  203. case ObjcLongType:
  204. case ObjcUnsignedLongType:
  205. [invocation setArgument:&value.longValue atIndex:i];
  206. break;
  207. case ObjcLongLongType:
  208. case ObjcUnsignedLongLongType:
  209. [invocation setArgument:&value.longLongValue atIndex:i];
  210. break;
  211. case ObjcFloatType:
  212. [invocation setArgument:&value.floatValue atIndex:i];
  213. break;
  214. case ObjcDoubleType:
  215. [invocation setArgument:&value.doubleValue atIndex:i];
  216. break;
  217. default:
  218. // Should never get here. Argument types are filtered (and
  219. // the assert above should have fired in the impossible case
  220. // of an invalid type anyway).
  221. fprintf(stderr, "%s: invalid type (%d)\n", __PRETTY_FUNCTION__, (int)objcValueType);
  222. ASSERT(false);
  223. }
  224. }
  225. }
  226. [invocation invoke];
  227. // Get the return value type.
  228. const char* type = [signature methodReturnType];
  229. ObjcValueType objcValueType = objcValueTypeForType(type);
  230. // Must have a valid return type. This method signature should have
  231. // been filtered already to ensure that it have an acceptable return
  232. // type.
  233. ASSERT(objcValueType != ObjcInvalidType);
  234. // Get the return value and convert it to a JavaScript value. Length
  235. // of return value will never exceed the size of largest scalar
  236. // or a pointer.
  237. char buffer[1024];
  238. ASSERT([signature methodReturnLength] < 1024);
  239. if (*type != 'v') {
  240. [invocation getReturnValue:buffer];
  241. result = convertObjcValueToValue(exec, buffer, objcValueType, m_rootObject.get());
  242. }
  243. } @catch(NSException* localException) {
  244. }
  245. moveGlobalExceptionToExecState(exec);
  246. // Work around problem in some versions of GCC where result gets marked volatile and
  247. // it can't handle copying from a volatile to non-volatile.
  248. return const_cast<JSValue&>(result);
  249. }
  250. JSValue ObjcInstance::invokeDefaultMethod(ExecState* exec, const ArgList &args)
  251. {
  252. JSValue result = jsUndefined();
  253. JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly); // Can't put this inside the @try scope because it unwinds incorrectly.
  254. setGlobalException(nil);
  255. @try {
  256. if (![_instance.get() respondsToSelector:@selector(invokeDefaultMethodWithArguments:)])
  257. return result;
  258. NSMethodSignature* signature = [_instance.get() methodSignatureForSelector:@selector(invokeDefaultMethodWithArguments:)];
  259. NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
  260. [invocation setSelector:@selector(invokeDefaultMethodWithArguments:)];
  261. [invocation setTarget:_instance.get()];
  262. if (objcValueTypeForType([signature methodReturnType]) != ObjcObjectType) {
  263. NSLog(@"Incorrect signature for invokeDefaultMethodWithArguments: -- return type must be object.");
  264. return result;
  265. }
  266. NSMutableArray* objcArgs = [NSMutableArray array];
  267. unsigned count = args.size();
  268. for (unsigned i = 0; i < count; i++) {
  269. ObjcValue value = convertValueToObjcValue(exec, args.at(i), ObjcObjectType);
  270. [objcArgs addObject:value.objectValue];
  271. }
  272. [invocation setArgument:&objcArgs atIndex:2];
  273. [invocation invoke];
  274. // Get the return value type, should always be "@" because of
  275. // check above.
  276. const char* type = [signature methodReturnType];
  277. ObjcValueType objcValueType = objcValueTypeForType(type);
  278. // Get the return value and convert it to a JavaScript value. Length
  279. // of return value will never exceed the size of a pointer, so we're
  280. // OK with 32 here.
  281. char buffer[32];
  282. [invocation getReturnValue:buffer];
  283. result = convertObjcValueToValue(exec, buffer, objcValueType, m_rootObject.get());
  284. } @catch(NSException* localException) {
  285. }
  286. moveGlobalExceptionToExecState(exec);
  287. // Work around problem in some versions of GCC where result gets marked volatile and
  288. // it can't handle copying from a volatile to non-volatile.
  289. return const_cast<JSValue&>(result);
  290. }
  291. bool ObjcInstance::setValueOfUndefinedField(ExecState* exec, const Identifier& property, JSValue aValue)
  292. {
  293. id targetObject = getObject();
  294. if (![targetObject respondsToSelector:@selector(setValue:forUndefinedKey:)])
  295. return false;
  296. JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly); // Can't put this inside the @try scope because it unwinds incorrectly.
  297. // This check is not really necessary because NSObject implements
  298. // setValue:forUndefinedKey:, and unfortunately the default implementation
  299. // throws an exception.
  300. if ([targetObject respondsToSelector:@selector(setValue:forUndefinedKey:)]){
  301. setGlobalException(nil);
  302. ObjcValue objcValue = convertValueToObjcValue(exec, aValue, ObjcObjectType);
  303. @try {
  304. [targetObject setValue:objcValue.objectValue forUndefinedKey:[NSString stringWithCString:property.ascii() encoding:NSASCIIStringEncoding]];
  305. } @catch(NSException* localException) {
  306. // Do nothing. Class did not override valueForUndefinedKey:.
  307. }
  308. moveGlobalExceptionToExecState(exec);
  309. }
  310. return true;
  311. }
  312. JSValue ObjcInstance::getValueOfUndefinedField(ExecState* exec, const Identifier& property) const
  313. {
  314. JSValue result = jsUndefined();
  315. id targetObject = getObject();
  316. JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly); // Can't put this inside the @try scope because it unwinds incorrectly.
  317. // This check is not really necessary because NSObject implements
  318. // valueForUndefinedKey:, and unfortunately the default implementation
  319. // throws an exception.
  320. if ([targetObject respondsToSelector:@selector(valueForUndefinedKey:)]){
  321. setGlobalException(nil);
  322. @try {
  323. id objcValue = [targetObject valueForUndefinedKey:[NSString stringWithCString:property.ascii() encoding:NSASCIIStringEncoding]];
  324. result = convertObjcValueToValue(exec, &objcValue, ObjcObjectType, m_rootObject.get());
  325. } @catch(NSException* localException) {
  326. // Do nothing. Class did not override valueForUndefinedKey:.
  327. }
  328. moveGlobalExceptionToExecState(exec);
  329. }
  330. // Work around problem in some versions of GCC where result gets marked volatile and
  331. // it can't handle copying from a volatile to non-volatile.
  332. return const_cast<JSValue&>(result);
  333. }
  334. JSValue ObjcInstance::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
  335. {
  336. if (hint == PreferString)
  337. return stringValue(exec);
  338. if (hint == PreferNumber)
  339. return numberValue(exec);
  340. if ([_instance.get() isKindOfClass:[NSString class]])
  341. return stringValue(exec);
  342. if ([_instance.get() isKindOfClass:[NSNumber class]])
  343. return numberValue(exec);
  344. return valueOf(exec);
  345. }
  346. JSValue ObjcInstance::stringValue(ExecState* exec) const
  347. {
  348. return convertNSStringToString(exec, [getObject() description]);
  349. }
  350. JSValue ObjcInstance::numberValue(ExecState* exec) const
  351. {
  352. // FIXME: Implement something sensible
  353. return jsNumber(exec, 0);
  354. }
  355. JSValue ObjcInstance::booleanValue() const
  356. {
  357. // FIXME: Implement something sensible
  358. return jsBoolean(false);
  359. }
  360. JSValue ObjcInstance::valueOf(ExecState* exec) const
  361. {
  362. return stringValue(exec);
  363. }