blob: bba9294d306aaaa2cbd1a0d4daeaeeeb8c08e20d [file] [log] [blame]
barraclough@apple.comfc381882013-01-02 03:51:15 +00001/*
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
mhahnenberg@apple.comf0712f92013-02-21 20:00:33 +000029#if JSC_OBJC_API_ENABLED
barraclough@apple.comfc381882013-01-02 03:51:15 +000030
oliver@apple.com5109edb2013-07-25 04:03:12 +000031#import "APICallbackFunction.h"
barraclough@apple.comfc381882013-01-02 03:51:15 +000032#import "APICast.h"
barraclough@apple.comfc381882013-01-02 03:51:15 +000033#import "Error.h"
commit-queue@webkit.org906a4ec2014-09-09 00:21:24 +000034#import "JSCJSValueInlines.h"
mhahnenberg@apple.comf0712f92013-02-21 20:00:33 +000035#import "JSCell.h"
commit-queue@webkit.org906a4ec2014-09-09 00:21:24 +000036#import "JSCellInlines.h"
barraclough@apple.comfc381882013-01-02 03:51:15 +000037#import "JSContextInternal.h"
38#import "JSWrapperMap.h"
39#import "JSValueInternal.h"
40#import "ObjCCallbackFunction.h"
41#import "ObjcRuntimeExtras.h"
barraclough@apple.coma56aeb22013-01-02 23:34:48 +000042#import <objc/runtime.h>
43#import <wtf/RetainPtr.h>
barraclough@apple.comfc381882013-01-02 03:51:15 +000044
45class CallbackArgument {
46public:
47 virtual ~CallbackArgument();
barraclough@apple.come2c07422013-01-03 02:03:12 +000048 virtual void set(NSInvocation *, NSInteger, JSContext *, JSValueRef, JSValueRef*) = 0;
barraclough@apple.comfc381882013-01-02 03:51:15 +000049
darin@apple.comd5fb2b42015-04-20 06:05:26 +000050 std::unique_ptr<CallbackArgument> m_next;
barraclough@apple.comfc381882013-01-02 03:51:15 +000051};
52
53CallbackArgument::~CallbackArgument()
54{
55}
56
57class CallbackArgumentBoolean : public CallbackArgument {
barraclough@apple.come2c07422013-01-03 02:03:12 +000058 virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef*) override
barraclough@apple.comfc381882013-01-02 03:51:15 +000059 {
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +000060 bool value = JSValueToBoolean([context JSGlobalContextRef], argument);
barraclough@apple.comfc381882013-01-02 03:51:15 +000061 [invocation setArgument:&value atIndex:argumentNumber];
62 }
63};
64
65template<typename T>
66class CallbackArgumentInteger : public CallbackArgument {
barraclough@apple.come2c07422013-01-03 02:03:12 +000067 virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
barraclough@apple.comfc381882013-01-02 03:51:15 +000068 {
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +000069 T value = (T)JSC::toInt32(JSValueToNumber([context JSGlobalContextRef], argument, exception));
barraclough@apple.comfc381882013-01-02 03:51:15 +000070 [invocation setArgument:&value atIndex:argumentNumber];
71 }
72};
73
74template<typename T>
75class CallbackArgumentDouble : public CallbackArgument {
barraclough@apple.come2c07422013-01-03 02:03:12 +000076 virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
barraclough@apple.comfc381882013-01-02 03:51:15 +000077 {
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +000078 T value = (T)JSValueToNumber([context JSGlobalContextRef], argument, exception);
barraclough@apple.comfc381882013-01-02 03:51:15 +000079 [invocation setArgument:&value atIndex:argumentNumber];
80 }
81};
82
83class CallbackArgumentJSValue : public CallbackArgument {
barraclough@apple.come2c07422013-01-03 02:03:12 +000084 virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef*) override
barraclough@apple.comfc381882013-01-02 03:51:15 +000085 {
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +000086 JSValue *value = [JSValue valueWithJSValueRef:argument inContext:context];
barraclough@apple.comfc381882013-01-02 03:51:15 +000087 [invocation setArgument:&value atIndex:argumentNumber];
88 }
89};
90
91class CallbackArgumentId : public CallbackArgument {
barraclough@apple.come2c07422013-01-03 02:03:12 +000092 virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef*) override
barraclough@apple.comfc381882013-01-02 03:51:15 +000093 {
94 id value = valueToObject(context, argument);
95 [invocation setArgument:&value atIndex:argumentNumber];
96 }
97};
98
99class CallbackArgumentOfClass : public CallbackArgument {
100public:
101 CallbackArgumentOfClass(Class cls)
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000102 : m_class(cls)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000103 {
barraclough@apple.comfc381882013-01-02 03:51:15 +0000104 }
105
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000106private:
barraclough@apple.come2c07422013-01-03 02:03:12 +0000107 virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
barraclough@apple.comfc381882013-01-02 03:51:15 +0000108 {
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +0000109 JSGlobalContextRef contextRef = [context JSGlobalContextRef];
barraclough@apple.comfc381882013-01-02 03:51:15 +0000110
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000111 id object = tryUnwrapObjcObject(contextRef, argument);
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000112 if (object && [object isKindOfClass:m_class.get()]) {
barraclough@apple.comfc381882013-01-02 03:51:15 +0000113 [invocation setArgument:&object atIndex:argumentNumber];
114 return;
115 }
116
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000117 if (JSValueIsNull(contextRef, argument) || JSValueIsUndefined(contextRef, argument)) {
barraclough@apple.comfc381882013-01-02 03:51:15 +0000118 object = nil;
119 [invocation setArgument:&object atIndex:argumentNumber];
120 return;
121 }
122
mhahnenberg@apple.com635733b2014-02-14 22:44:52 +0000123 *exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("Argument does not match Objective-C Class")));
barraclough@apple.comfc381882013-01-02 03:51:15 +0000124 }
125
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000126 RetainPtr<Class> m_class;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000127};
128
129class CallbackArgumentNSNumber : public CallbackArgument {
barraclough@apple.come2c07422013-01-03 02:03:12 +0000130 virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
barraclough@apple.comfc381882013-01-02 03:51:15 +0000131 {
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +0000132 id value = valueToNumber([context JSGlobalContextRef], argument, exception);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000133 [invocation setArgument:&value atIndex:argumentNumber];
134 }
135};
136
137class CallbackArgumentNSString : public CallbackArgument {
barraclough@apple.come2c07422013-01-03 02:03:12 +0000138 virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
barraclough@apple.comfc381882013-01-02 03:51:15 +0000139 {
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +0000140 id value = valueToString([context JSGlobalContextRef], argument, exception);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000141 [invocation setArgument:&value atIndex:argumentNumber];
142 }
143};
144
145class CallbackArgumentNSDate : public CallbackArgument {
barraclough@apple.come2c07422013-01-03 02:03:12 +0000146 virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
barraclough@apple.comfc381882013-01-02 03:51:15 +0000147 {
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +0000148 id value = valueToDate([context JSGlobalContextRef], argument, exception);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000149 [invocation setArgument:&value atIndex:argumentNumber];
150 }
151};
152
153class CallbackArgumentNSArray : public CallbackArgument {
barraclough@apple.come2c07422013-01-03 02:03:12 +0000154 virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
barraclough@apple.comfc381882013-01-02 03:51:15 +0000155 {
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +0000156 id value = valueToArray([context JSGlobalContextRef], argument, exception);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000157 [invocation setArgument:&value atIndex:argumentNumber];
158 }
159};
160
161class CallbackArgumentNSDictionary : public CallbackArgument {
barraclough@apple.come2c07422013-01-03 02:03:12 +0000162 virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
barraclough@apple.comfc381882013-01-02 03:51:15 +0000163 {
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +0000164 id value = valueToDictionary([context JSGlobalContextRef], argument, exception);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000165 [invocation setArgument:&value atIndex:argumentNumber];
166 }
167};
168
169class CallbackArgumentStruct : public CallbackArgument {
170public:
barraclough@apple.come2c07422013-01-03 02:03:12 +0000171 CallbackArgumentStruct(NSInvocation *conversionInvocation, const char* encodedType)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000172 : m_conversionInvocation(conversionInvocation)
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000173 , m_buffer(encodedType)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000174 {
barraclough@apple.comfc381882013-01-02 03:51:15 +0000175 }
176
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000177private:
barraclough@apple.come2c07422013-01-03 02:03:12 +0000178 virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef*) override
barraclough@apple.comfc381882013-01-02 03:51:15 +0000179 {
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +0000180 JSValue *value = [JSValue valueWithJSValueRef:argument inContext:context];
barraclough@apple.comfc381882013-01-02 03:51:15 +0000181 [m_conversionInvocation invokeWithTarget:value];
182 [m_conversionInvocation getReturnValue:m_buffer];
183 [invocation setArgument:m_buffer atIndex:argumentNumber];
184 }
185
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000186 RetainPtr<NSInvocation> m_conversionInvocation;
187 StructBuffer m_buffer;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000188};
189
barraclough@apple.comfc381882013-01-02 03:51:15 +0000190class ArgumentTypeDelegate {
191public:
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000192 typedef std::unique_ptr<CallbackArgument> ResultType;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000193
194 template<typename T>
195 static ResultType typeInteger()
196 {
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000197 return std::make_unique<CallbackArgumentInteger<T>>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000198 }
199
200 template<typename T>
201 static ResultType typeDouble()
202 {
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000203 return std::make_unique<CallbackArgumentDouble<T>>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000204 }
205
206 static ResultType typeBool()
207 {
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000208 return std::make_unique<CallbackArgumentBoolean>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000209 }
210
211 static ResultType typeVoid()
212 {
oliver@apple.com5598c182013-01-23 22:25:07 +0000213 RELEASE_ASSERT_NOT_REACHED();
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000214 return nullptr;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000215 }
216
217 static ResultType typeId()
218 {
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000219 return std::make_unique<CallbackArgumentId>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000220 }
221
222 static ResultType typeOfClass(const char* begin, const char* end)
223 {
224 StringRange copy(begin, end);
225 Class cls = objc_getClass(copy);
226 if (!cls)
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000227 return nullptr;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000228
229 if (cls == [JSValue class])
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000230 return std::make_unique<CallbackArgumentJSValue>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000231 if (cls == [NSString class])
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000232 return std::make_unique<CallbackArgumentNSString>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000233 if (cls == [NSNumber class])
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000234 return std::make_unique<CallbackArgumentNSNumber>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000235 if (cls == [NSDate class])
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000236 return std::make_unique<CallbackArgumentNSDate>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000237 if (cls == [NSArray class])
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000238 return std::make_unique<CallbackArgumentNSArray>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000239 if (cls == [NSDictionary class])
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000240 return std::make_unique<CallbackArgumentNSDictionary>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000241
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000242 return std::make_unique<CallbackArgumentOfClass>(cls);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000243 }
244
mhahnenberg@apple.com789bdff2013-03-01 21:14:24 +0000245 static ResultType typeBlock(const char*, const char*)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000246 {
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000247 return nullptr;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000248 }
249
250 static ResultType typeStruct(const char* begin, const char* end)
251 {
252 StringRange copy(begin, end);
barraclough@apple.come2c07422013-01-03 02:03:12 +0000253 if (NSInvocation *invocation = valueToTypeInvocationFor(copy))
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000254 return std::make_unique<CallbackArgumentStruct>(invocation, copy);
255 return nullptr;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000256 }
257};
258
259class CallbackResult {
260public:
261 virtual ~CallbackResult()
262 {
263 }
264
barraclough@apple.come2c07422013-01-03 02:03:12 +0000265 virtual JSValueRef get(NSInvocation *, JSContext *, JSValueRef*) = 0;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000266};
267
268class CallbackResultVoid : public CallbackResult {
barraclough@apple.come2c07422013-01-03 02:03:12 +0000269 virtual JSValueRef get(NSInvocation *, JSContext *context, JSValueRef*) override
barraclough@apple.comfc381882013-01-02 03:51:15 +0000270 {
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +0000271 return JSValueMakeUndefined([context JSGlobalContextRef]);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000272 }
273};
274
275class CallbackResultId : public CallbackResult {
barraclough@apple.come2c07422013-01-03 02:03:12 +0000276 virtual JSValueRef get(NSInvocation *invocation, JSContext *context, JSValueRef*) override
barraclough@apple.comfc381882013-01-02 03:51:15 +0000277 {
278 id value;
279 [invocation getReturnValue:&value];
280 return objectToValue(context, value);
281 }
282};
283
284template<typename T>
285class CallbackResultNumeric : public CallbackResult {
barraclough@apple.come2c07422013-01-03 02:03:12 +0000286 virtual JSValueRef get(NSInvocation *invocation, JSContext *context, JSValueRef*) override
barraclough@apple.comfc381882013-01-02 03:51:15 +0000287 {
288 T value;
289 [invocation getReturnValue:&value];
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +0000290 return JSValueMakeNumber([context JSGlobalContextRef], value);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000291 }
292};
293
294class CallbackResultBoolean : public CallbackResult {
barraclough@apple.come2c07422013-01-03 02:03:12 +0000295 virtual JSValueRef get(NSInvocation *invocation, JSContext *context, JSValueRef*) override
barraclough@apple.comfc381882013-01-02 03:51:15 +0000296 {
297 bool value;
298 [invocation getReturnValue:&value];
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +0000299 return JSValueMakeBoolean([context JSGlobalContextRef], value);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000300 }
301};
302
303class CallbackResultStruct : public CallbackResult {
304public:
barraclough@apple.come2c07422013-01-03 02:03:12 +0000305 CallbackResultStruct(NSInvocation *conversionInvocation, const char* encodedType)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000306 : m_conversionInvocation(conversionInvocation)
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000307 , m_buffer(encodedType)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000308 {
barraclough@apple.comfc381882013-01-02 03:51:15 +0000309 }
310
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000311private:
barraclough@apple.come2c07422013-01-03 02:03:12 +0000312 virtual JSValueRef get(NSInvocation *invocation, JSContext *context, JSValueRef*) override
barraclough@apple.comfc381882013-01-02 03:51:15 +0000313 {
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000314 [invocation getReturnValue:m_buffer];
barraclough@apple.comfc381882013-01-02 03:51:15 +0000315
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000316 [m_conversionInvocation setArgument:m_buffer atIndex:2];
barraclough@apple.comfc381882013-01-02 03:51:15 +0000317 [m_conversionInvocation setArgument:&context atIndex:3];
318 [m_conversionInvocation invokeWithTarget:[JSValue class]];
319
barraclough@apple.come2c07422013-01-03 02:03:12 +0000320 JSValue *value;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000321 [m_conversionInvocation getReturnValue:&value];
322 return valueInternalValue(value);
323 }
324
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000325 RetainPtr<NSInvocation> m_conversionInvocation;
326 StructBuffer m_buffer;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000327};
328
329class ResultTypeDelegate {
330public:
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000331 typedef std::unique_ptr<CallbackResult> ResultType;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000332
333 template<typename T>
334 static ResultType typeInteger()
335 {
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000336 return std::make_unique<CallbackResultNumeric<T>>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000337 }
338
339 template<typename T>
340 static ResultType typeDouble()
341 {
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000342 return std::make_unique<CallbackResultNumeric<T>>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000343 }
344
345 static ResultType typeBool()
346 {
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000347 return std::make_unique<CallbackResultBoolean>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000348 }
349
350 static ResultType typeVoid()
351 {
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000352 return std::make_unique<CallbackResultVoid>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000353 }
354
355 static ResultType typeId()
356 {
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000357 return std::make_unique<CallbackResultId>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000358 }
359
360 static ResultType typeOfClass(const char*, const char*)
361 {
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000362 return std::make_unique<CallbackResultId>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000363 }
364
365 static ResultType typeBlock(const char*, const char*)
366 {
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000367 return std::make_unique<CallbackResultId>();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000368 }
369
370 static ResultType typeStruct(const char* begin, const char* end)
371 {
372 StringRange copy(begin, end);
barraclough@apple.come2c07422013-01-03 02:03:12 +0000373 if (NSInvocation *invocation = typeToValueInvocationFor(copy))
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000374 return std::make_unique<CallbackResultStruct>(invocation, copy);
375 return nullptr;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000376 }
377};
378
379enum CallbackType {
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000380 CallbackInitMethod,
barraclough@apple.comfc381882013-01-02 03:51:15 +0000381 CallbackInstanceMethod,
382 CallbackClassMethod,
383 CallbackBlock
384};
385
mhahnenberg@apple.com9c4b2102013-03-14 21:14:01 +0000386namespace JSC {
387
388class ObjCCallbackFunctionImpl {
barraclough@apple.comfc381882013-01-02 03:51:15 +0000389public:
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000390 ObjCCallbackFunctionImpl(NSInvocation *invocation, CallbackType type, Class instanceClass, std::unique_ptr<CallbackArgument> arguments, std::unique_ptr<CallbackResult> result)
mhahnenberg@apple.come4b8bb72013-10-15 21:08:07 +0000391 : m_type(type)
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000392 , m_instanceClass(instanceClass)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000393 , m_invocation(invocation)
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000394 , m_arguments(WTF::move(arguments))
395 , m_result(WTF::move(result))
barraclough@apple.comfc381882013-01-02 03:51:15 +0000396 {
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000397 ASSERT((type != CallbackInstanceMethod && type != CallbackInitMethod) || instanceClass);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000398 }
399
mhahnenberg@apple.comac6f1fd2013-11-15 19:53:30 +0000400 void destroy(Heap& heap)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000401 {
mhahnenberg@apple.comac6f1fd2013-11-15 19:53:30 +0000402 // We need to explicitly release the target since we didn't call
mhahnenberg@apple.comfc78fbc2013-11-05 22:51:52 +0000403 // -retainArguments on m_invocation (and we don't want to do so).
404 if (m_type == CallbackBlock || m_type == CallbackClassMethod)
mhahnenberg@apple.comac6f1fd2013-11-15 19:53:30 +0000405 heap.releaseSoon(adoptNS([m_invocation.get() target]));
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000406 m_instanceClass = nil;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000407 }
408
409 JSValueRef call(JSContext *context, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
410
barraclough@apple.comfc381882013-01-02 03:51:15 +0000411 id wrappedBlock()
412 {
413 return m_type == CallbackBlock ? [m_invocation target] : nil;
414 }
415
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000416 id wrappedConstructor()
417 {
418 switch (m_type) {
419 case CallbackBlock:
420 return [m_invocation target];
421 case CallbackInitMethod:
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000422 return m_instanceClass.get();
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000423 default:
424 return nil;
425 }
426 }
427
428 bool isConstructible()
429 {
430 return !!wrappedBlock() || m_type == CallbackInitMethod;
431 }
432
433 String name();
434
barraclough@apple.comfc381882013-01-02 03:51:15 +0000435private:
barraclough@apple.comfc381882013-01-02 03:51:15 +0000436 CallbackType m_type;
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000437 RetainPtr<Class> m_instanceClass;
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000438 RetainPtr<NSInvocation> m_invocation;
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000439 std::unique_ptr<CallbackArgument> m_arguments;
440 std::unique_ptr<CallbackResult> m_result;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000441};
442
barraclough@apple.comfc381882013-01-02 03:51:15 +0000443static JSValueRef objCCallbackFunctionCallAsFunction(JSContextRef callerContext, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
444{
445 // Retake the API lock - we need this for a few reasons:
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000446 // (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.
447 // (2) We're calling some JSC internals that require us to be on the 'inside' - e.g. createTypeError.
448 // (3) We need to be locked (per context would be fine) against conflicting usage of the ObjCCallbackFunction's NSInvocation.
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000449 JSC::JSLockHolder locker(toJS(callerContext));
barraclough@apple.comfc381882013-01-02 03:51:15 +0000450
mhahnenberg@apple.com9c4b2102013-03-14 21:14:01 +0000451 ObjCCallbackFunction* callback = static_cast<ObjCCallbackFunction*>(toJS(function));
452 ObjCCallbackFunctionImpl* impl = callback->impl();
mhahnenberg@apple.come4b8bb72013-10-15 21:08:07 +0000453 JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(callback->globalObject()->globalExec())];
barraclough@apple.comfc381882013-01-02 03:51:15 +0000454
455 CallbackData callbackData;
456 JSValueRef result;
457 @autoreleasepool {
mhahnenberg@apple.com4f18e952014-02-07 01:56:45 +0000458 [context beginCallbackWithData:&callbackData calleeValue:function thisValue:thisObject argumentCount:argumentCount arguments:arguments];
mhahnenberg@apple.com9c4b2102013-03-14 21:14:01 +0000459 result = impl->call(context, thisObject, argumentCount, arguments, exception);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000460 if (context.exception)
461 *exception = valueInternalValue(context.exception);
462 [context endCallbackWithData:&callbackData];
463 }
464 return result;
465}
466
mhahnenberg@apple.com2ac93f32013-10-10 18:20:13 +0000467static JSObjectRef objCCallbackFunctionCallAsConstructor(JSContextRef callerContext, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
468{
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000469 JSC::JSLockHolder locker(toJS(callerContext));
mhahnenberg@apple.com2ac93f32013-10-10 18:20:13 +0000470
471 ObjCCallbackFunction* callback = static_cast<ObjCCallbackFunction*>(toJS(constructor));
472 ObjCCallbackFunctionImpl* impl = callback->impl();
473 JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(toJS(callerContext)->lexicalGlobalObject()->globalExec())];
474
475 CallbackData callbackData;
476 JSValueRef result;
477 @autoreleasepool {
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000478 [context beginCallbackWithData:&callbackData calleeValue:constructor thisValue:nullptr argumentCount:argumentCount arguments:arguments];
479 result = impl->call(context, nullptr, argumentCount, arguments, exception);
mhahnenberg@apple.com2ac93f32013-10-10 18:20:13 +0000480 if (context.exception)
481 *exception = valueInternalValue(context.exception);
482 [context endCallbackWithData:&callbackData];
483 }
484
485 JSGlobalContextRef contextRef = [context JSGlobalContextRef];
486 if (*exception)
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000487 return nullptr;
mhahnenberg@apple.com2ac93f32013-10-10 18:20:13 +0000488
489 if (!JSValueIsObject(contextRef, result)) {
mhahnenberg@apple.com635733b2014-02-14 22:44:52 +0000490 *exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("Objective-C blocks called as constructors must return an object.")));
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000491 return nullptr;
mhahnenberg@apple.com2ac93f32013-10-10 18:20:13 +0000492 }
493 return (JSObjectRef)result;
494}
495
akling@apple.com2de49b72014-07-30 22:26:22 +0000496const JSC::ClassInfo ObjCCallbackFunction::s_info = { "CallbackFunction", &Base::s_info, 0, CREATE_METHOD_TABLE(ObjCCallbackFunction) };
mhahnenberg@apple.com9c4b2102013-03-14 21:14:01 +0000497
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000498ObjCCallbackFunction::ObjCCallbackFunction(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSObjectCallAsFunctionCallback functionCallback, JSObjectCallAsConstructorCallback constructCallback, std::unique_ptr<ObjCCallbackFunctionImpl> impl)
akling@apple.com59875522013-09-30 03:45:30 +0000499 : Base(vm, globalObject->objcCallbackFunctionStructure())
mhahnenberg@apple.com2ac93f32013-10-10 18:20:13 +0000500 , m_functionCallback(functionCallback)
501 , m_constructCallback(constructCallback)
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000502 , m_impl(WTF::move(impl))
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000503{
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000504}
505
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000506ObjCCallbackFunction* ObjCCallbackFunction::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, const String& name, std::unique_ptr<ObjCCallbackFunctionImpl> impl)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000507{
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000508 ObjCCallbackFunction* function = new (NotNull, allocateCell<ObjCCallbackFunction>(vm.heap)) ObjCCallbackFunction(vm, globalObject, objCCallbackFunctionCallAsFunction, objCCallbackFunctionCallAsConstructor, WTF::move(impl));
akling@apple.com59875522013-09-30 03:45:30 +0000509 function->finishCreation(vm, name);
mhahnenberg@apple.com9c4b2102013-03-14 21:14:01 +0000510 return function;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000511}
512
mhahnenberg@apple.com9c4b2102013-03-14 21:14:01 +0000513void ObjCCallbackFunction::destroy(JSCell* cell)
514{
mhahnenberg@apple.comac6f1fd2013-11-15 19:53:30 +0000515 ObjCCallbackFunction& function = *jsCast<ObjCCallbackFunction*>(cell);
516 function.impl()->destroy(*Heap::heap(cell));
517 function.~ObjCCallbackFunction();
mhahnenberg@apple.com9c4b2102013-03-14 21:14:01 +0000518}
519
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000520
oliver@apple.com5109edb2013-07-25 04:03:12 +0000521CallType ObjCCallbackFunction::getCallData(JSCell*, CallData& callData)
522{
523 callData.native.function = APICallbackFunction::call<ObjCCallbackFunction>;
524 return CallTypeHost;
525}
526
mhahnenberg@apple.com2ac93f32013-10-10 18:20:13 +0000527ConstructType ObjCCallbackFunction::getConstructData(JSCell* cell, ConstructData& constructData)
528{
529 ObjCCallbackFunction* callback = jsCast<ObjCCallbackFunction*>(cell);
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000530 if (!callback->impl()->isConstructible())
mhahnenberg@apple.com2ac93f32013-10-10 18:20:13 +0000531 return Base::getConstructData(cell, constructData);
532 constructData.native.function = APICallbackFunction::construct<ObjCCallbackFunction>;
533 return ConstructTypeHost;
534}
535
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000536String ObjCCallbackFunctionImpl::name()
537{
538 if (m_type == CallbackInitMethod)
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000539 return class_getName(m_instanceClass.get());
mhahnenberg@apple.comfc78fbc2013-11-05 22:51:52 +0000540 // FIXME: Maybe we could support having the selector as the name of the non-init
541 // functions to make it a bit more user-friendly from the JS side?
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000542 return "";
543}
544
mhahnenberg@apple.com9c4b2102013-03-14 21:14:01 +0000545JSValueRef ObjCCallbackFunctionImpl::call(JSContext *context, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000546{
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +0000547 JSGlobalContextRef contextRef = [context JSGlobalContextRef];
barraclough@apple.comfc381882013-01-02 03:51:15 +0000548
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000549 id target;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000550 size_t firstArgument;
551 switch (m_type) {
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000552 case CallbackInitMethod: {
553 RELEASE_ASSERT(!thisObject);
554 target = [m_instanceClass alloc];
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000555 if (!target || ![target isKindOfClass:m_instanceClass.get()]) {
mhahnenberg@apple.com635733b2014-02-14 22:44:52 +0000556 *exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("self type check failed for Objective-C instance method")));
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000557 return JSValueMakeUndefined(contextRef);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000558 }
559 [m_invocation setTarget:target];
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000560 firstArgument = 2;
561 break;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000562 }
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000563 case CallbackInstanceMethod: {
564 target = tryUnwrapObjcObject(contextRef, thisObject);
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000565 if (!target || ![target isKindOfClass:m_instanceClass.get()]) {
mhahnenberg@apple.com635733b2014-02-14 22:44:52 +0000566 *exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("self type check failed for Objective-C instance method")));
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000567 return JSValueMakeUndefined(contextRef);
568 }
569 [m_invocation setTarget:target];
570 firstArgument = 2;
571 break;
572 }
barraclough@apple.comfc381882013-01-02 03:51:15 +0000573 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()) {
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000582 JSValueRef value = argumentNumber < argumentCount ? arguments[argumentNumber] : JSValueMakeUndefined(contextRef);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000583 argument->set(m_invocation.get(), argumentNumber + firstArgument, context, value, exception);
584 if (*exception)
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000585 return JSValueMakeUndefined(contextRef);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000586 ++argumentNumber;
587 }
588
589 [m_invocation invoke];
590
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000591 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;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000603}
604
mhahnenberg@apple.com9c4b2102013-03-14 21:14:01 +0000605} // namespace JSC
606
barraclough@apple.comfc381882013-01-02 03:51:15 +0000607static bool blockSignatureContainsClass()
608{
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000609 static bool containsClass = ^{
barraclough@apple.comfc381882013-01-02 03:51:15 +0000610 id block = ^(NSString *string){ return string; };
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000611 return _Block_has_signature(block) && strstr(_Block_signature(block), "NSString");
mhahnenberg@apple.combf1fd772013-01-11 23:09:37 +0000612 }();
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000613 return containsClass;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000614}
615
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000616static inline bool skipNumber(const char*& position)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000617{
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000618 if (!isASCIIDigit(*position))
barraclough@apple.comfc381882013-01-02 03:51:15 +0000619 return false;
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000620 while (isASCIIDigit(*++position)) { }
barraclough@apple.comfc381882013-01-02 03:51:15 +0000621 return true;
622}
623
barraclough@apple.come2c07422013-01-03 02:03:12 +0000624static JSObjectRef objCCallbackFunctionForInvocation(JSContext *context, NSInvocation *invocation, CallbackType type, Class instanceClass, const char* signatureWithObjcClasses)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000625{
mhahnenberg@apple.com3cdb3ab2014-02-20 19:40:04 +0000626 if (!signatureWithObjcClasses)
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000627 return nullptr;
mhahnenberg@apple.com3cdb3ab2014-02-20 19:40:04 +0000628
barraclough@apple.comfc381882013-01-02 03:51:15 +0000629 const char* position = signatureWithObjcClasses;
630
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000631 auto result = parseObjCType<ResultTypeDelegate>(position);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000632 if (!result || !skipNumber(position))
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000633 return nullptr;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000634
635 switch (type) {
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000636 case CallbackInitMethod:
barraclough@apple.comfc381882013-01-02 03:51:15 +0000637 case CallbackInstanceMethod:
638 case CallbackClassMethod:
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000639 // Methods are passed two implicit arguments - (id)self, and the selector.
640 if ('@' != *position++ || !skipNumber(position) || ':' != *position++ || !skipNumber(position))
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000641 return nullptr;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000642 break;
643 case CallbackBlock:
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000644 // Blocks are passed one implicit argument - the block, of type "@?".
645 if (('@' != *position++) || ('?' != *position++) || !skipNumber(position))
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000646 return nullptr;
barraclough@apple.coma56aeb22013-01-02 23:34:48 +0000647 // Only allow arguments of type 'id' if the block signature contains the NS type information.
648 if ((!blockSignatureContainsClass() && strchr(position, '@')))
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000649 return nullptr;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000650 break;
651 }
652
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000653 std::unique_ptr<CallbackArgument> arguments;
654 auto* nextArgument = &arguments;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000655 unsigned argumentCount = 0;
656 while (*position) {
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000657 auto argument = parseObjCType<ArgumentTypeDelegate>(position);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000658 if (!argument || !skipNumber(position))
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000659 return nullptr;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000660
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000661 *nextArgument = WTF::move(argument);
barraclough@apple.comfc381882013-01-02 03:51:15 +0000662 nextArgument = &(*nextArgument)->m_next;
663 ++argumentCount;
664 }
665
ggaren@apple.com58bf4ea2013-04-30 21:55:43 +0000666 JSC::ExecState* exec = toJS([context JSGlobalContextRef]);
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000667 JSC::JSLockHolder locker(exec);
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000668 auto impl = std::make_unique<JSC::ObjCCallbackFunctionImpl>(invocation, type, instanceClass, WTF::move(arguments), WTF::move(result));
669 const String& name = impl->name();
670 return toRef(JSC::ObjCCallbackFunction::create(exec->vm(), exec->lexicalGlobalObject(), name, WTF::move(impl)));
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000671}
672
673JSObjectRef objCCallbackFunctionForInit(JSContext *context, Class cls, Protocol *protocol, SEL sel, const char* types)
674{
675 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:types]];
676 [invocation setSelector:sel];
677 return objCCallbackFunctionForInvocation(context, invocation, CallbackInitMethod, cls, _protocol_getMethodTypeEncoding(protocol, sel, YES, YES));
barraclough@apple.comfc381882013-01-02 03:51:15 +0000678}
679
barraclough@apple.come2c07422013-01-03 02:03:12 +0000680JSObjectRef objCCallbackFunctionForMethod(JSContext *context, Class cls, Protocol *protocol, BOOL isInstanceMethod, SEL sel, const char* types)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000681{
barraclough@apple.come2c07422013-01-03 02:03:12 +0000682 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:types]];
barraclough@apple.comfc381882013-01-02 03:51:15 +0000683 [invocation setSelector:sel];
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000684 // We need to retain the target Class because m_invocation doesn't retain it by default (and we don't want it to).
685 // FIXME: What releases it?
barraclough@apple.comfc381882013-01-02 03:51:15 +0000686 if (!isInstanceMethod)
mhahnenberg@apple.comfc78fbc2013-11-05 22:51:52 +0000687 [invocation setTarget:[cls retain]];
barraclough@apple.comfc381882013-01-02 03:51:15 +0000688 return objCCallbackFunctionForInvocation(context, invocation, isInstanceMethod ? CallbackInstanceMethod : CallbackClassMethod, isInstanceMethod ? cls : nil, _protocol_getMethodTypeEncoding(protocol, sel, YES, isInstanceMethod));
689}
690
barraclough@apple.come2c07422013-01-03 02:03:12 +0000691JSObjectRef objCCallbackFunctionForBlock(JSContext *context, id target)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000692{
693 if (!_Block_has_signature(target))
darin@apple.comd5fb2b42015-04-20 06:05:26 +0000694 return nullptr;
barraclough@apple.comfc381882013-01-02 03:51:15 +0000695 const char* signature = _Block_signature(target);
barraclough@apple.come2c07422013-01-03 02:03:12 +0000696 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:signature]];
mhahnenberg@apple.comfc78fbc2013-11-05 22:51:52 +0000697
698 // We don't want to use -retainArguments because that leaks memory. Arguments
699 // would be retained indefinitely between invocations of the callback.
700 // Additionally, we copy the target because we want the block to stick around
701 // until the ObjCCallbackFunctionImpl is destroyed.
702 [invocation setTarget:[target copy]];
703
barraclough@apple.comfc381882013-01-02 03:51:15 +0000704 return objCCallbackFunctionForInvocation(context, invocation, CallbackBlock, nil, signature);
705}
706
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000707id tryUnwrapConstructor(JSObjectRef object)
barraclough@apple.comfc381882013-01-02 03:51:15 +0000708{
fpizlo@apple.comf00d7092013-08-14 05:21:10 +0000709 if (!toJS(object)->inherits(JSC::ObjCCallbackFunction::info()))
barraclough@apple.comfc381882013-01-02 03:51:15 +0000710 return nil;
mhahnenberg@apple.com8d51e002013-10-30 17:58:12 +0000711 JSC::ObjCCallbackFunctionImpl* impl = static_cast<JSC::ObjCCallbackFunction*>(toJS(object))->impl();
712 if (!impl->isConstructible())
713 return nil;
714 return impl->wrappedConstructor();
barraclough@apple.comfc381882013-01-02 03:51:15 +0000715}
716
717#endif