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