Replace WTF::move with WTFMove
[WebKit-https.git] / Source / JavaScriptCore / API / ObjCCallbackFunction.mm
1 /*
2  * Copyright (C) 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 #include "config.h"
27 #import "JavaScriptCore.h"
28
29 #if JSC_OBJC_API_ENABLED
30
31 #import "APICallbackFunction.h"
32 #import "APICast.h"
33 #import "Error.h"
34 #import "JSCJSValueInlines.h"
35 #import "JSCell.h"
36 #import "JSCellInlines.h"
37 #import "JSContextInternal.h"
38 #import "JSWrapperMap.h"
39 #import "JSValueInternal.h"
40 #import "ObjCCallbackFunction.h"
41 #import "ObjcRuntimeExtras.h"
42 #import "StructureInlines.h"
43 #import <objc/runtime.h>
44 #import <wtf/RetainPtr.h>
45
46 class CallbackArgument {
47     WTF_MAKE_FAST_ALLOCATED;
48 public:
49     virtual ~CallbackArgument();
50     virtual void set(NSInvocation *, NSInteger, JSContext *, JSValueRef, JSValueRef*) = 0;
51
52     std::unique_ptr<CallbackArgument> m_next;
53 };
54
55 CallbackArgument::~CallbackArgument()
56 {
57 }
58
59 class CallbackArgumentBoolean : public CallbackArgument {
60     virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef*) override
61     {
62         bool value = JSValueToBoolean([context JSGlobalContextRef], argument);
63         [invocation setArgument:&value atIndex:argumentNumber];
64     }
65 };
66
67 template<typename T>
68 class CallbackArgumentInteger : public CallbackArgument {
69     virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
70     {
71         T value = (T)JSC::toInt32(JSValueToNumber([context JSGlobalContextRef], argument, exception));
72         [invocation setArgument:&value atIndex:argumentNumber];
73     }
74 };
75
76 template<typename T>
77 class CallbackArgumentDouble : public CallbackArgument {
78     virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
79     {
80         T value = (T)JSValueToNumber([context JSGlobalContextRef], argument, exception);
81         [invocation setArgument:&value atIndex:argumentNumber];
82     }
83 };
84
85 class CallbackArgumentJSValue : public CallbackArgument {
86     virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef*) override
87     {
88         JSValue *value = [JSValue valueWithJSValueRef:argument inContext:context];
89         [invocation setArgument:&value atIndex:argumentNumber];
90     }
91 };
92
93 class CallbackArgumentId : public CallbackArgument {
94     virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef*) override
95     {
96         id value = valueToObject(context, argument);
97         [invocation setArgument:&value atIndex:argumentNumber];
98     }
99 };
100
101 class CallbackArgumentOfClass : public CallbackArgument {
102 public:
103     CallbackArgumentOfClass(Class cls)
104         : m_class(cls)
105     {
106     }
107
108 private:
109     virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
110     {
111         JSGlobalContextRef contextRef = [context JSGlobalContextRef];
112
113         id object = tryUnwrapObjcObject(contextRef, argument);
114         if (object && [object isKindOfClass:m_class.get()]) {
115             [invocation setArgument:&object atIndex:argumentNumber];
116             return;
117         }
118
119         if (JSValueIsNull(contextRef, argument) || JSValueIsUndefined(contextRef, argument)) {
120             object = nil;
121             [invocation setArgument:&object atIndex:argumentNumber];
122             return;
123         }
124
125         *exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("Argument does not match Objective-C Class")));
126     }
127
128     RetainPtr<Class> m_class;
129 };
130
131 class CallbackArgumentNSNumber : public CallbackArgument {
132     virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
133     {
134         id value = valueToNumber([context JSGlobalContextRef], argument, exception);
135         [invocation setArgument:&value atIndex:argumentNumber];
136     }
137 };
138
139 class CallbackArgumentNSString : public CallbackArgument {
140     virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
141     {
142         id value = valueToString([context JSGlobalContextRef], argument, exception);
143         [invocation setArgument:&value atIndex:argumentNumber];
144     }
145 };
146
147 class CallbackArgumentNSDate : public CallbackArgument {
148     virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
149     {
150         id value = valueToDate([context JSGlobalContextRef], argument, exception);
151         [invocation setArgument:&value atIndex:argumentNumber];
152     }
153 };
154
155 class CallbackArgumentNSArray : public CallbackArgument {
156     virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
157     {
158         id value = valueToArray([context JSGlobalContextRef], argument, exception);
159         [invocation setArgument:&value atIndex:argumentNumber];
160     }
161 };
162
163 class CallbackArgumentNSDictionary : public CallbackArgument {
164     virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
165     {
166         id value = valueToDictionary([context JSGlobalContextRef], argument, exception);
167         [invocation setArgument:&value atIndex:argumentNumber];
168     }
169 };
170
171 class CallbackArgumentStruct : public CallbackArgument {
172 public:
173     CallbackArgumentStruct(NSInvocation *conversionInvocation, const char* encodedType)
174         : m_conversionInvocation(conversionInvocation)
175         , m_buffer(encodedType)
176     {
177     }
178     
179 private:
180     virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef*) override
181     {
182         JSValue *value = [JSValue valueWithJSValueRef:argument inContext:context];
183         [m_conversionInvocation invokeWithTarget:value];
184         [m_conversionInvocation getReturnValue:m_buffer];
185         [invocation setArgument:m_buffer atIndex:argumentNumber];
186     }
187
188     RetainPtr<NSInvocation> m_conversionInvocation;
189     StructBuffer m_buffer;
190 };
191
192 class ArgumentTypeDelegate {
193 public:
194     typedef std::unique_ptr<CallbackArgument> ResultType;
195
196     template<typename T>
197     static ResultType typeInteger()
198     {
199         return std::make_unique<CallbackArgumentInteger<T>>();
200     }
201
202     template<typename T>
203     static ResultType typeDouble()
204     {
205         return std::make_unique<CallbackArgumentDouble<T>>();
206     }
207
208     static ResultType typeBool()
209     {
210         return std::make_unique<CallbackArgumentBoolean>();
211     }
212
213     static ResultType typeVoid()
214     {
215         RELEASE_ASSERT_NOT_REACHED();
216         return nullptr;
217     }
218
219     static ResultType typeId()
220     {
221         return std::make_unique<CallbackArgumentId>();
222     }
223
224     static ResultType typeOfClass(const char* begin, const char* end)
225     {
226         StringRange copy(begin, end);
227         Class cls = objc_getClass(copy);
228         if (!cls)
229             return nullptr;
230
231         if (cls == [JSValue class])
232             return std::make_unique<CallbackArgumentJSValue>();
233         if (cls == [NSString class])
234             return std::make_unique<CallbackArgumentNSString>();
235         if (cls == [NSNumber class])
236             return std::make_unique<CallbackArgumentNSNumber>();
237         if (cls == [NSDate class])
238             return std::make_unique<CallbackArgumentNSDate>();
239         if (cls == [NSArray class])
240             return std::make_unique<CallbackArgumentNSArray>();
241         if (cls == [NSDictionary class])
242             return std::make_unique<CallbackArgumentNSDictionary>();
243
244         return std::make_unique<CallbackArgumentOfClass>(cls);
245     }
246
247     static ResultType typeBlock(const char*, const char*)
248     {
249         return nullptr;
250     }
251
252     static ResultType typeStruct(const char* begin, const char* end)
253     {
254         StringRange copy(begin, end);
255         if (NSInvocation *invocation = valueToTypeInvocationFor(copy))
256             return std::make_unique<CallbackArgumentStruct>(invocation, copy);
257         return nullptr;
258     }
259 };
260
261 class CallbackResult {
262     WTF_MAKE_FAST_ALLOCATED;
263 public:
264     virtual ~CallbackResult()
265     {
266     }
267
268     virtual JSValueRef get(NSInvocation *, JSContext *, JSValueRef*) = 0;
269 };
270
271 class CallbackResultVoid : public CallbackResult {
272     virtual JSValueRef get(NSInvocation *, JSContext *context, JSValueRef*) override
273     {
274         return JSValueMakeUndefined([context JSGlobalContextRef]);
275     }
276 };
277
278 class CallbackResultId : public CallbackResult {
279     virtual JSValueRef get(NSInvocation *invocation, JSContext *context, JSValueRef*) override
280     {
281         id value;
282         [invocation getReturnValue:&value];
283         return objectToValue(context, value);
284     }
285 };
286
287 template<typename T>
288 class CallbackResultNumeric : public CallbackResult {
289     virtual JSValueRef get(NSInvocation *invocation, JSContext *context, JSValueRef*) override
290     {
291         T value;
292         [invocation getReturnValue:&value];
293         return JSValueMakeNumber([context JSGlobalContextRef], value);
294     }
295 };
296
297 class CallbackResultBoolean : public CallbackResult {
298     virtual JSValueRef get(NSInvocation *invocation, JSContext *context, JSValueRef*) override
299     {
300         bool value;
301         [invocation getReturnValue:&value];
302         return JSValueMakeBoolean([context JSGlobalContextRef], value);
303     }
304 };
305
306 class CallbackResultStruct : public CallbackResult {
307 public:
308     CallbackResultStruct(NSInvocation *conversionInvocation, const char* encodedType)
309         : m_conversionInvocation(conversionInvocation)
310         , m_buffer(encodedType)
311     {
312     }
313     
314 private:
315     virtual JSValueRef get(NSInvocation *invocation, JSContext *context, JSValueRef*) override
316     {
317         [invocation getReturnValue:m_buffer];
318
319         [m_conversionInvocation setArgument:m_buffer atIndex:2];
320         [m_conversionInvocation setArgument:&context atIndex:3];
321         [m_conversionInvocation invokeWithTarget:[JSValue class]];
322
323         JSValue *value;
324         [m_conversionInvocation getReturnValue:&value];
325         return valueInternalValue(value);
326     }
327
328     RetainPtr<NSInvocation> m_conversionInvocation;
329     StructBuffer m_buffer;
330 };
331
332 class ResultTypeDelegate {
333 public:
334     typedef std::unique_ptr<CallbackResult> ResultType;
335
336     template<typename T>
337     static ResultType typeInteger()
338     {
339         return std::make_unique<CallbackResultNumeric<T>>();
340     }
341
342     template<typename T>
343     static ResultType typeDouble()
344     {
345         return std::make_unique<CallbackResultNumeric<T>>();
346     }
347
348     static ResultType typeBool()
349     {
350         return std::make_unique<CallbackResultBoolean>();
351     }
352
353     static ResultType typeVoid()
354     {
355         return std::make_unique<CallbackResultVoid>();
356     }
357
358     static ResultType typeId()
359     {
360         return std::make_unique<CallbackResultId>();
361     }
362
363     static ResultType typeOfClass(const char*, const char*)
364     {
365         return std::make_unique<CallbackResultId>();
366     }
367
368     static ResultType typeBlock(const char*, const char*)
369     {
370         return std::make_unique<CallbackResultId>();
371     }
372
373     static ResultType typeStruct(const char* begin, const char* end)
374     {
375         StringRange copy(begin, end);
376         if (NSInvocation *invocation = typeToValueInvocationFor(copy))
377             return std::make_unique<CallbackResultStruct>(invocation, copy);
378         return nullptr;
379     }
380 };
381
382 enum CallbackType {
383     CallbackInitMethod,
384     CallbackInstanceMethod,
385     CallbackClassMethod,
386     CallbackBlock
387 };
388
389 namespace JSC {
390
391 class ObjCCallbackFunctionImpl {
392 public:
393     ObjCCallbackFunctionImpl(NSInvocation *invocation, CallbackType type, Class instanceClass, std::unique_ptr<CallbackArgument> arguments, std::unique_ptr<CallbackResult> result)
394         : m_type(type)
395         , m_instanceClass(instanceClass)
396         , m_invocation(invocation)
397         , m_arguments(WTFMove(arguments))
398         , m_result(WTFMove(result))
399     {
400         ASSERT((type != CallbackInstanceMethod && type != CallbackInitMethod) || instanceClass);
401     }
402
403     void destroy(Heap& heap)
404     {
405         // We need to explicitly release the target since we didn't call 
406         // -retainArguments on m_invocation (and we don't want to do so).
407         if (m_type == CallbackBlock || m_type == CallbackClassMethod)
408             heap.releaseSoon(adoptNS([m_invocation.get() target]));
409         m_instanceClass = nil;
410     }
411
412     JSValueRef call(JSContext *context, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
413
414     id wrappedBlock()
415     {
416         return m_type == CallbackBlock ? [m_invocation target] : nil;
417     }
418
419     id wrappedConstructor()
420     {
421         switch (m_type) {
422         case CallbackBlock:
423             return [m_invocation target];
424         case CallbackInitMethod:
425             return m_instanceClass.get();
426         default:
427             return nil;
428         }
429     }
430
431     bool isConstructible()
432     {
433         return !!wrappedBlock() || m_type == CallbackInitMethod;
434     }
435
436     String name();
437
438 private:
439     CallbackType m_type;
440     RetainPtr<Class> m_instanceClass;
441     RetainPtr<NSInvocation> m_invocation;
442     std::unique_ptr<CallbackArgument> m_arguments;
443     std::unique_ptr<CallbackResult> m_result;
444 };
445
446 static JSValueRef objCCallbackFunctionCallAsFunction(JSContextRef callerContext, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
447 {
448     // Retake the API lock - we need this for a few reasons:
449     // (1) We don't want to support the C-API's confusing drops-locks-once policy - should only drop locks if we can do so recursively.
450     // (2) We're calling some JSC internals that require us to be on the 'inside' - e.g. createTypeError.
451     // (3) We need to be locked (per context would be fine) against conflicting usage of the ObjCCallbackFunction's NSInvocation.
452     JSC::JSLockHolder locker(toJS(callerContext));
453
454     ObjCCallbackFunction* callback = static_cast<ObjCCallbackFunction*>(toJS(function));
455     ObjCCallbackFunctionImpl* impl = callback->impl();
456     JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(callback->globalObject()->globalExec())];
457
458     CallbackData callbackData;
459     JSValueRef result;
460     @autoreleasepool {
461         [context beginCallbackWithData:&callbackData calleeValue:function thisValue:thisObject argumentCount:argumentCount arguments:arguments];
462         result = impl->call(context, thisObject, argumentCount, arguments, exception);
463         if (context.exception)
464             *exception = valueInternalValue(context.exception);
465         [context endCallbackWithData:&callbackData];
466     }
467     return result;
468 }
469
470 static JSObjectRef objCCallbackFunctionCallAsConstructor(JSContextRef callerContext, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
471 {
472     JSC::JSLockHolder locker(toJS(callerContext));
473
474     ObjCCallbackFunction* callback = static_cast<ObjCCallbackFunction*>(toJS(constructor));
475     ObjCCallbackFunctionImpl* impl = callback->impl();
476     JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(toJS(callerContext)->lexicalGlobalObject()->globalExec())];
477
478     CallbackData callbackData;
479     JSValueRef result;
480     @autoreleasepool {
481         [context beginCallbackWithData:&callbackData calleeValue:constructor thisValue:nullptr argumentCount:argumentCount arguments:arguments];
482         result = impl->call(context, nullptr, argumentCount, arguments, exception);
483         if (context.exception)
484             *exception = valueInternalValue(context.exception);
485         [context endCallbackWithData:&callbackData];
486     }
487
488     JSGlobalContextRef contextRef = [context JSGlobalContextRef];
489     if (*exception)
490         return nullptr;
491
492     if (!JSValueIsObject(contextRef, result)) {
493         *exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("Objective-C blocks called as constructors must return an object.")));
494         return nullptr;
495     }
496     return (JSObjectRef)result;
497 }
498
499 const JSC::ClassInfo ObjCCallbackFunction::s_info = { "CallbackFunction", &Base::s_info, 0, CREATE_METHOD_TABLE(ObjCCallbackFunction) };
500
501 ObjCCallbackFunction::ObjCCallbackFunction(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSObjectCallAsFunctionCallback functionCallback, JSObjectCallAsConstructorCallback constructCallback, std::unique_ptr<ObjCCallbackFunctionImpl> impl)
502     : Base(vm, globalObject->objcCallbackFunctionStructure())
503     , m_functionCallback(functionCallback)
504     , m_constructCallback(constructCallback)
505     , m_impl(WTFMove(impl))
506 {
507 }
508
509 ObjCCallbackFunction* ObjCCallbackFunction::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, const String& name, std::unique_ptr<ObjCCallbackFunctionImpl> impl)
510 {
511     ObjCCallbackFunction* function = new (NotNull, allocateCell<ObjCCallbackFunction>(vm.heap)) ObjCCallbackFunction(vm, globalObject, objCCallbackFunctionCallAsFunction, objCCallbackFunctionCallAsConstructor, WTFMove(impl));
512     function->finishCreation(vm, name);
513     return function;
514 }
515
516 void ObjCCallbackFunction::destroy(JSCell* cell)
517 {
518     ObjCCallbackFunction& function = *jsCast<ObjCCallbackFunction*>(cell);
519     function.impl()->destroy(*Heap::heap(cell));
520     function.~ObjCCallbackFunction();
521 }
522
523
524 CallType ObjCCallbackFunction::getCallData(JSCell*, CallData& callData)
525 {
526     callData.native.function = APICallbackFunction::call<ObjCCallbackFunction>;
527     return CallTypeHost;
528 }
529
530 ConstructType ObjCCallbackFunction::getConstructData(JSCell* cell, ConstructData& constructData)
531 {
532     ObjCCallbackFunction* callback = jsCast<ObjCCallbackFunction*>(cell);
533     if (!callback->impl()->isConstructible())
534         return Base::getConstructData(cell, constructData);
535     constructData.native.function = APICallbackFunction::construct<ObjCCallbackFunction>;
536     return ConstructTypeHost;
537 }
538
539 String ObjCCallbackFunctionImpl::name()
540 {
541     if (m_type == CallbackInitMethod)
542         return class_getName(m_instanceClass.get());
543     // FIXME: Maybe we could support having the selector as the name of the non-init 
544     // functions to make it a bit more user-friendly from the JS side?
545     return "";
546 }
547
548 JSValueRef ObjCCallbackFunctionImpl::call(JSContext *context, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
549 {
550     JSGlobalContextRef contextRef = [context JSGlobalContextRef];
551
552     id target;
553     size_t firstArgument;
554     switch (m_type) {
555     case CallbackInitMethod: {
556         RELEASE_ASSERT(!thisObject);
557         target = [m_instanceClass alloc];
558         if (!target || ![target isKindOfClass:m_instanceClass.get()]) {
559             *exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("self type check failed for Objective-C instance method")));
560             return JSValueMakeUndefined(contextRef);
561         }
562         [m_invocation setTarget:target];
563         firstArgument = 2;
564         break;
565     }
566     case CallbackInstanceMethod: {
567         target = tryUnwrapObjcObject(contextRef, thisObject);
568         if (!target || ![target isKindOfClass:m_instanceClass.get()]) {
569             *exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("self type check failed for Objective-C instance method")));
570             return JSValueMakeUndefined(contextRef);
571         }
572         [m_invocation setTarget:target];
573         firstArgument = 2;
574         break;
575     }
576     case CallbackClassMethod:
577         firstArgument = 2;
578         break;
579     case CallbackBlock:
580         firstArgument = 1;
581     }
582
583     size_t argumentNumber = 0;
584     for (CallbackArgument* argument = m_arguments.get(); argument; argument = argument->m_next.get()) {
585         JSValueRef value = argumentNumber < argumentCount ? arguments[argumentNumber] : JSValueMakeUndefined(contextRef);
586         argument->set(m_invocation.get(), argumentNumber + firstArgument, context, value, exception);
587         if (*exception)
588             return JSValueMakeUndefined(contextRef);
589         ++argumentNumber;
590     }
591
592     [m_invocation invoke];
593
594     JSValueRef result = m_result->get(m_invocation.get(), context, exception);
595
596     // Balance our call to -alloc with a call to -autorelease. We have to do this after calling -init
597     // because init family methods are allowed to release the allocated object and return something 
598     // else in its place.
599     if (m_type == CallbackInitMethod) {
600         id objcResult = tryUnwrapObjcObject(contextRef, result);
601         if (objcResult)
602             [objcResult autorelease];
603     }
604
605     return result;
606 }
607
608 } // namespace JSC
609
610 static bool blockSignatureContainsClass()
611 {
612     static bool containsClass = ^{
613         id block = ^(NSString *string){ return string; };
614         return _Block_has_signature(block) && strstr(_Block_signature(block), "NSString");
615     }();
616     return containsClass;
617 }
618
619 static inline bool skipNumber(const char*& position)
620 {
621     if (!isASCIIDigit(*position))
622         return false;
623     while (isASCIIDigit(*++position)) { }
624     return true;
625 }
626
627 static JSObjectRef objCCallbackFunctionForInvocation(JSContext *context, NSInvocation *invocation, CallbackType type, Class instanceClass, const char* signatureWithObjcClasses)
628 {
629     if (!signatureWithObjcClasses)
630         return nullptr;
631
632     const char* position = signatureWithObjcClasses;
633
634     auto result = parseObjCType<ResultTypeDelegate>(position);
635     if (!result || !skipNumber(position))
636         return nullptr;
637
638     switch (type) {
639     case CallbackInitMethod:
640     case CallbackInstanceMethod:
641     case CallbackClassMethod:
642         // Methods are passed two implicit arguments - (id)self, and the selector.
643         if ('@' != *position++ || !skipNumber(position) || ':' != *position++ || !skipNumber(position))
644             return nullptr;
645         break;
646     case CallbackBlock:
647         // Blocks are passed one implicit argument - the block, of type "@?".
648         if (('@' != *position++) || ('?' != *position++) || !skipNumber(position))
649             return nullptr;
650         // Only allow arguments of type 'id' if the block signature contains the NS type information.
651         if ((!blockSignatureContainsClass() && strchr(position, '@')))
652             return nullptr;
653         break;
654     }
655
656     std::unique_ptr<CallbackArgument> arguments;
657     auto* nextArgument = &arguments;
658     unsigned argumentCount = 0;
659     while (*position) {
660         auto argument = parseObjCType<ArgumentTypeDelegate>(position);
661         if (!argument || !skipNumber(position))
662             return nullptr;
663
664         *nextArgument = WTFMove(argument);
665         nextArgument = &(*nextArgument)->m_next;
666         ++argumentCount;
667     }
668
669     JSC::ExecState* exec = toJS([context JSGlobalContextRef]);
670     JSC::JSLockHolder locker(exec);
671     auto impl = std::make_unique<JSC::ObjCCallbackFunctionImpl>(invocation, type, instanceClass, WTFMove(arguments), WTFMove(result));
672     const String& name = impl->name();
673     return toRef(JSC::ObjCCallbackFunction::create(exec->vm(), exec->lexicalGlobalObject(), name, WTFMove(impl)));
674 }
675
676 JSObjectRef objCCallbackFunctionForInit(JSContext *context, Class cls, Protocol *protocol, SEL sel, const char* types)
677 {
678     NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:types]];
679     [invocation setSelector:sel];
680     return objCCallbackFunctionForInvocation(context, invocation, CallbackInitMethod, cls, _protocol_getMethodTypeEncoding(protocol, sel, YES, YES));
681 }
682
683 JSObjectRef objCCallbackFunctionForMethod(JSContext *context, Class cls, Protocol *protocol, BOOL isInstanceMethod, SEL sel, const char* types)
684 {
685     NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:types]];
686     [invocation setSelector:sel];
687     // We need to retain the target Class because m_invocation doesn't retain it by default (and we don't want it to).
688     // FIXME: What releases it?
689     if (!isInstanceMethod)
690         [invocation setTarget:[cls retain]];
691     return objCCallbackFunctionForInvocation(context, invocation, isInstanceMethod ? CallbackInstanceMethod : CallbackClassMethod, isInstanceMethod ? cls : nil, _protocol_getMethodTypeEncoding(protocol, sel, YES, isInstanceMethod));
692 }
693
694 JSObjectRef objCCallbackFunctionForBlock(JSContext *context, id target)
695 {
696     if (!_Block_has_signature(target))
697         return nullptr;
698     const char* signature = _Block_signature(target);
699     NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:signature]];
700
701     // We don't want to use -retainArguments because that leaks memory. Arguments 
702     // would be retained indefinitely between invocations of the callback.
703     // Additionally, we copy the target because we want the block to stick around
704     // until the ObjCCallbackFunctionImpl is destroyed.
705     [invocation setTarget:[target copy]];
706
707     return objCCallbackFunctionForInvocation(context, invocation, CallbackBlock, nil, signature);
708 }
709
710 id tryUnwrapConstructor(JSObjectRef object)
711 {
712     if (!toJS(object)->inherits(JSC::ObjCCallbackFunction::info()))
713         return nil;
714     JSC::ObjCCallbackFunctionImpl* impl = static_cast<JSC::ObjCCallbackFunction*>(toJS(object))->impl();
715     if (!impl->isConstructible())
716         return nil;
717     return impl->wrappedConstructor();
718 }
719
720 #endif