Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / bridge / objc / objc_instance.mm
1 /*
2  * Copyright (C) 2004, 2008, 2009, 2013 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 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 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 #import "config.h"
27 #import "objc_instance.h"
28
29 #import "JSDOMBinding.h"
30 #import "NSPointerFunctionsSPI.h"
31 #import "ObjCRuntimeObject.h"
32 #import "WebScriptObject.h"
33 #import "WebScriptObjectProtocol.h"
34 #import "runtime/FunctionPrototype.h"
35 #import "runtime_method.h"
36 #import <runtime/Error.h>
37 #import <runtime/JSLock.h>
38 #import <runtime/ObjectPrototype.h>
39 #import <wtf/Assertions.h>
40 #import <wtf/spi/cocoa/NSMapTableSPI.h>
41
42 #ifdef NDEBUG
43 #define OBJC_LOG(formatAndArgs...) ((void)0)
44 #else
45 #define OBJC_LOG(formatAndArgs...) { \
46     fprintf (stderr, "%s:%d -- %s:  ", __FILE__, __LINE__, __FUNCTION__); \
47     fprintf(stderr, formatAndArgs); \
48 }
49 #endif
50
51 using namespace JSC::Bindings;
52 using namespace JSC;
53
54 static NSString *s_exception;
55 static JSGlobalObject* s_exceptionEnvironment; // No need to protect this value, since we just use it for a pointer comparison.
56 static NSMapTable *s_instanceWrapperCache;
57
58 #pragma clang diagnostic push
59 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
60
61 static NSMapTable *createInstanceWrapperCache()
62 {
63     // NSMapTable with zeroing weak pointers is the recommended way to build caches like this under garbage collection.
64     NSPointerFunctionsOptions keyOptions = NSPointerFunctionsZeroingWeakMemory | NSPointerFunctionsOpaquePersonality;
65     NSPointerFunctionsOptions valueOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality;
66     return [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0];
67 }
68
69 #pragma clang diagnostic pop
70
71 RuntimeObject* ObjcInstance::newRuntimeObject(ExecState* exec)
72 {
73     // FIXME: deprecatedGetDOMStructure uses the prototype off of the wrong global object.
74     return ObjCRuntimeObject::create(exec->vm(), WebCore::deprecatedGetDOMStructure<ObjCRuntimeObject>(exec), this);
75 }
76
77 void ObjcInstance::setGlobalException(NSString* exception, JSGlobalObject* exceptionEnvironment)
78 {
79     NSString *oldException = s_exception;
80     s_exception = [exception copy];
81     [oldException release];
82
83     s_exceptionEnvironment = exceptionEnvironment;
84 }
85
86 void ObjcInstance::moveGlobalExceptionToExecState(ExecState* exec)
87 {
88     if (!s_exception) {
89         ASSERT(!s_exceptionEnvironment);
90         return;
91     }
92
93     if (!s_exceptionEnvironment || s_exceptionEnvironment == exec->vmEntryGlobalObject()) {
94         JSLockHolder lock(exec);
95         throwError(exec, s_exception);
96     }
97
98     [s_exception release];
99     s_exception = nil;
100     s_exceptionEnvironment = 0;
101 }
102
103 ObjcInstance::ObjcInstance(id instance, RefPtr<RootObject>&& rootObject) 
104     : Instance(WTFMove(rootObject))
105     , _instance(instance)
106     , _class(0)
107     , _pool(0)
108     , _beginCount(0)
109 {
110 }
111
112 RefPtr<ObjcInstance> ObjcInstance::create(id instance, RefPtr<RootObject>&& rootObject)
113 {
114     if (!s_instanceWrapperCache)
115         s_instanceWrapperCache = createInstanceWrapperCache();
116     if (void* existingWrapper = NSMapGet(s_instanceWrapperCache, instance))
117         return static_cast<ObjcInstance*>(existingWrapper);
118     RefPtr<ObjcInstance> wrapper = adoptRef(new ObjcInstance(instance, WTFMove(rootObject)));
119     NSMapInsert(s_instanceWrapperCache, instance, wrapper.get());
120     return wrapper;
121 }
122
123 ObjcInstance::~ObjcInstance() 
124 {
125     // Both -finalizeForWebScript and -dealloc/-finalize of _instance may require autorelease pools.
126     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
127
128     ASSERT(s_instanceWrapperCache);
129     ASSERT(_instance);
130     NSMapRemove(s_instanceWrapperCache, _instance.get());
131
132     if ([_instance.get() respondsToSelector:@selector(finalizeForWebScript)])
133         [_instance.get() performSelector:@selector(finalizeForWebScript)];
134     _instance = 0;
135
136     [pool drain];
137 }
138
139 void ObjcInstance::virtualBegin()
140 {
141     if (!_pool)
142         _pool = [[NSAutoreleasePool alloc] init];
143     _beginCount++;
144 }
145
146 void ObjcInstance::virtualEnd()
147 {
148     _beginCount--;
149     ASSERT(_beginCount >= 0);
150     if (!_beginCount) {
151         [_pool drain];
152         _pool = 0;
153     }
154 }
155
156 Bindings::Class* ObjcInstance::getClass() const 
157 {
158     if (!_instance)
159         return 0;
160     if (!_class)
161         _class = ObjcClass::classForIsA(object_getClass(_instance.get()));
162     return static_cast<Bindings::Class*>(_class);
163 }
164
165 bool ObjcInstance::supportsInvokeDefaultMethod() const
166 {
167     return [_instance.get() respondsToSelector:@selector(invokeDefaultMethodWithArguments:)];
168 }
169
170 class ObjCRuntimeMethod : public RuntimeMethod {
171 public:
172     static ObjCRuntimeMethod* create(ExecState* exec, JSGlobalObject* globalObject, const String& name, Bindings::Method* method)
173     {
174         // FIXME: deprecatedGetDOMStructure uses the prototype off of the wrong global object
175         // We need to pass in the right global object for "i".
176         Structure* domStructure = WebCore::deprecatedGetDOMStructure<ObjCRuntimeMethod>(exec);
177         ObjCRuntimeMethod* runtimeMethod = new (NotNull, allocateCell<ObjCRuntimeMethod>(*exec->heap())) ObjCRuntimeMethod(globalObject, domStructure, method);
178         runtimeMethod->finishCreation(exec->vm(), name);
179         return runtimeMethod;
180     }
181
182     static Structure* createStructure(VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
183     {
184         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
185     }
186
187     DECLARE_INFO;
188
189 private:
190     typedef RuntimeMethod Base;
191
192     ObjCRuntimeMethod(JSGlobalObject* globalObject, Structure* structure, Bindings::Method* method)
193         : RuntimeMethod(globalObject, structure, method)
194     {
195     }
196
197     void finishCreation(VM& vm, const String& name)
198     {
199         Base::finishCreation(vm, name);
200         ASSERT(inherits(info()));
201     }
202 };
203
204 const ClassInfo ObjCRuntimeMethod::s_info = { "ObjCRuntimeMethod", &RuntimeMethod::s_info, 0, CREATE_METHOD_TABLE(ObjCRuntimeMethod) };
205
206 JSC::JSValue ObjcInstance::getMethod(ExecState* exec, PropertyName propertyName)
207 {
208     Method* method = getClass()->methodNamed(propertyName, this);
209     return ObjCRuntimeMethod::create(exec, exec->lexicalGlobalObject(), propertyName.publicName(), method);
210 }
211
212 JSC::JSValue ObjcInstance::invokeMethod(ExecState* exec, RuntimeMethod* runtimeMethod)
213 {
214     if (!asObject(runtimeMethod)->inherits(ObjCRuntimeMethod::info()))
215         return exec->vm().throwException(exec, createTypeError(exec, "Attempt to invoke non-plug-in method on plug-in object."));
216
217     ObjcMethod *method = static_cast<ObjcMethod*>(runtimeMethod->method());
218     ASSERT(method);
219
220     return invokeObjcMethod(exec, method);
221 }
222
223 JSC::JSValue ObjcInstance::invokeObjcMethod(ExecState* exec, ObjcMethod* method)
224 {
225     JSValue result = jsUndefined();
226     
227     JSLock::DropAllLocks dropAllLocks(exec); // Can't put this inside the @try scope because it unwinds incorrectly.
228
229     setGlobalException(nil);
230     
231 @try {
232     NSMethodSignature* signature = method->getMethodSignature();
233     NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
234     [invocation setSelector:method->selector()];
235     [invocation setTarget:_instance.get()];
236
237     if (method->isFallbackMethod()) {
238         if (objcValueTypeForType([signature methodReturnType]) != ObjcObjectType) {
239             NSLog(@"Incorrect signature for invokeUndefinedMethodFromWebScript:withArguments: -- return type must be object.");
240             return result;
241         }
242
243         // Invoke invokeUndefinedMethodFromWebScript:withArguments:, pass JavaScript function
244         // name as first (actually at 2) argument and array of args as second.
245         NSString* jsName = (NSString* )method->javaScriptName();
246         [invocation setArgument:&jsName atIndex:2];
247
248         NSMutableArray* objcArgs = [NSMutableArray array];
249         int count = exec->argumentCount();
250         for (int i = 0; i < count; i++) {
251             ObjcValue value = convertValueToObjcValue(exec, exec->uncheckedArgument(i), ObjcObjectType);
252             [objcArgs addObject:value.objectValue];
253         }
254         [invocation setArgument:&objcArgs atIndex:3];
255     } else {
256         unsigned count = [signature numberOfArguments];
257         for (unsigned i = 2; i < count; ++i) {
258             const char* type = [signature getArgumentTypeAtIndex:i];
259             ObjcValueType objcValueType = objcValueTypeForType(type);
260
261             // Must have a valid argument type.  This method signature should have
262             // been filtered already to ensure that it has acceptable argument
263             // types.
264             ASSERT(objcValueType != ObjcInvalidType && objcValueType != ObjcVoidType);
265
266             ObjcValue value = convertValueToObjcValue(exec, exec->argument(i - 2), objcValueType);
267
268             switch (objcValueType) {
269                 case ObjcObjectType:
270                     [invocation setArgument:&value.objectValue atIndex:i];
271                     break;
272                 case ObjcCharType:
273                 case ObjcUnsignedCharType:
274                     [invocation setArgument:&value.charValue atIndex:i];
275                     break;
276                 case ObjcShortType:
277                 case ObjcUnsignedShortType:
278                     [invocation setArgument:&value.shortValue atIndex:i];
279                     break;
280                 case ObjcBoolType:
281                     [invocation setArgument:&value.booleanValue atIndex:i];
282                     break;
283                 case ObjcIntType:
284                 case ObjcUnsignedIntType:
285                     [invocation setArgument:&value.intValue atIndex:i];
286                     break;
287                 case ObjcLongType:
288                 case ObjcUnsignedLongType:
289                     [invocation setArgument:&value.longValue atIndex:i];
290                     break;
291                 case ObjcLongLongType:
292                 case ObjcUnsignedLongLongType:
293                     [invocation setArgument:&value.longLongValue atIndex:i];
294                     break;
295                 case ObjcFloatType:
296                     [invocation setArgument:&value.floatValue atIndex:i];
297                     break;
298                 case ObjcDoubleType:
299                     [invocation setArgument:&value.doubleValue atIndex:i];
300                     break;
301                 default:
302                     // Should never get here.  Argument types are filtered (and
303                     // the assert above should have fired in the impossible case
304                     // of an invalid type anyway).
305                     fprintf(stderr, "%s: invalid type (%d)\n", __PRETTY_FUNCTION__, (int)objcValueType);
306                     ASSERT_NOT_REACHED();
307             }
308         }
309     }
310
311     [invocation invoke];
312
313     // Get the return value type.
314     const char* type = [signature methodReturnType];
315     ObjcValueType objcValueType = objcValueTypeForType(type);
316
317     // Must have a valid return type.  This method signature should have
318     // been filtered already to ensure that it have an acceptable return
319     // type.
320     ASSERT(objcValueType != ObjcInvalidType);
321
322     // Get the return value and convert it to a JavaScript value. Length
323     // of return value will never exceed the size of largest scalar
324     // or a pointer.
325     char buffer[1024];
326     ASSERT([signature methodReturnLength] < 1024);
327
328     if (*type != 'v') {
329         [invocation getReturnValue:buffer];
330         result = convertObjcValueToValue(exec, buffer, objcValueType, m_rootObject.get());
331     }
332 } @catch(NSException* localException) {
333 }
334     moveGlobalExceptionToExecState(exec);
335
336     // Work around problem in some versions of GCC where result gets marked volatile and
337     // it can't handle copying from a volatile to non-volatile.
338     return const_cast<JSValue&>(result);
339 }
340
341 JSC::JSValue ObjcInstance::invokeDefaultMethod(ExecState* exec)
342 {
343     JSValue result = jsUndefined();
344
345     JSLock::DropAllLocks dropAllLocks(exec); // Can't put this inside the @try scope because it unwinds incorrectly.
346     setGlobalException(nil);
347     
348 @try {
349     if (![_instance.get() respondsToSelector:@selector(invokeDefaultMethodWithArguments:)])
350         return result;
351
352     NSMethodSignature* signature = [_instance.get() methodSignatureForSelector:@selector(invokeDefaultMethodWithArguments:)];
353     NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
354     [invocation setSelector:@selector(invokeDefaultMethodWithArguments:)];
355     [invocation setTarget:_instance.get()];
356
357     if (objcValueTypeForType([signature methodReturnType]) != ObjcObjectType) {
358         NSLog(@"Incorrect signature for invokeDefaultMethodWithArguments: -- return type must be object.");
359         return result;
360     }
361
362     NSMutableArray* objcArgs = [NSMutableArray array];
363     unsigned count = exec->argumentCount();
364     for (unsigned i = 0; i < count; i++) {
365         ObjcValue value = convertValueToObjcValue(exec, exec->uncheckedArgument(i), ObjcObjectType);
366         [objcArgs addObject:value.objectValue];
367     }
368     [invocation setArgument:&objcArgs atIndex:2];
369
370     [invocation invoke];
371
372     // Get the return value type, should always be "@" because of
373     // check above.
374     const char* type = [signature methodReturnType];
375     ObjcValueType objcValueType = objcValueTypeForType(type);
376
377     // Get the return value and convert it to a JavaScript value. Length
378     // of return value will never exceed the size of a pointer, so we're
379     // OK with 32 here.
380     char buffer[32];
381     [invocation getReturnValue:buffer];
382     result = convertObjcValueToValue(exec, buffer, objcValueType, m_rootObject.get());
383 } @catch(NSException* localException) {
384 }
385     moveGlobalExceptionToExecState(exec);
386
387     // Work around problem in some versions of GCC where result gets marked volatile and
388     // it can't handle copying from a volatile to non-volatile.
389     return const_cast<JSValue&>(result);
390 }
391
392 bool ObjcInstance::setValueOfUndefinedField(ExecState* exec, PropertyName propertyName, JSValue aValue)
393 {
394     String name(propertyName.publicName());
395     if (name.isNull())
396         return false;
397
398     id targetObject = getObject();
399     if (![targetObject respondsToSelector:@selector(setValue:forUndefinedKey:)])
400         return false;
401
402     JSLock::DropAllLocks dropAllLocks(exec); // Can't put this inside the @try scope because it unwinds incorrectly.
403
404     // This check is not really necessary because NSObject implements
405     // setValue:forUndefinedKey:, and unfortunately the default implementation
406     // throws an exception.
407     if ([targetObject respondsToSelector:@selector(setValue:forUndefinedKey:)]){
408         setGlobalException(nil);
409     
410         ObjcValue objcValue = convertValueToObjcValue(exec, aValue, ObjcObjectType);
411
412         @try {
413             [targetObject setValue:objcValue.objectValue forUndefinedKey:[NSString stringWithCString:name.ascii().data() encoding:NSASCIIStringEncoding]];
414         } @catch(NSException* localException) {
415             // Do nothing.  Class did not override valueForUndefinedKey:.
416         }
417
418         moveGlobalExceptionToExecState(exec);
419     }
420     
421     return true;
422 }
423
424 JSC::JSValue ObjcInstance::getValueOfUndefinedField(ExecState* exec, PropertyName propertyName) const
425 {
426     String name(propertyName.publicName());
427     if (name.isNull())
428         return jsUndefined();
429
430     JSValue result = jsUndefined();
431     
432     id targetObject = getObject();
433
434     JSLock::DropAllLocks dropAllLocks(exec); // Can't put this inside the @try scope because it unwinds incorrectly.
435
436     // This check is not really necessary because NSObject implements
437     // valueForUndefinedKey:, and unfortunately the default implementation
438     // throws an exception.
439     if ([targetObject respondsToSelector:@selector(valueForUndefinedKey:)]){
440         setGlobalException(nil);
441     
442         @try {
443             id objcValue = [targetObject valueForUndefinedKey:[NSString stringWithCString:name.ascii().data() encoding:NSASCIIStringEncoding]];
444             result = convertObjcValueToValue(exec, &objcValue, ObjcObjectType, m_rootObject.get());
445         } @catch(NSException* localException) {
446             // Do nothing.  Class did not override valueForUndefinedKey:.
447         }
448
449         moveGlobalExceptionToExecState(exec);
450     }
451
452     // Work around problem in some versions of GCC where result gets marked volatile and
453     // it can't handle copying from a volatile to non-volatile.
454     return const_cast<JSValue&>(result);
455 }
456
457 JSC::JSValue ObjcInstance::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
458 {
459     if (hint == PreferString)
460         return stringValue(exec);
461     if (hint == PreferNumber)
462         return numberValue(exec);
463     if ([_instance.get() isKindOfClass:[NSString class]])
464         return stringValue(exec);
465     if ([_instance.get() isKindOfClass:[NSNumber class]])
466         return numberValue(exec);
467     return valueOf(exec);
468 }
469
470 JSC::JSValue ObjcInstance::stringValue(ExecState* exec) const
471 {
472     return convertNSStringToString(exec, [getObject() description]);
473 }
474
475 JSC::JSValue ObjcInstance::numberValue(ExecState*) const
476 {
477     // FIXME:  Implement something sensible
478     return jsNumber(0);
479 }
480
481 JSC::JSValue ObjcInstance::booleanValue() const
482 {
483     // FIXME:  Implement something sensible
484     return jsBoolean(false);
485 }
486
487 JSC::JSValue ObjcInstance::valueOf(ExecState* exec) const 
488 {
489     return stringValue(exec);
490 }