-
Notifications
You must be signed in to change notification settings - Fork 0
/
JSBContext.m
590 lines (530 loc) · 22.6 KB
/
JSBContext.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
//
// JSBContext.m
// JavaScriptBridging
//
// Created by Adam Strzelecki on 21.09.2013.
// Copyright (c) 2013-2014 nanoANT Adam Strzelecki. All rights reserved.
//
#import "JSBContext.h"
#import <objc/runtime.h>
#import <JavaScriptCore/JavaScriptCore.h>
NSString *const JSBErrorDomain = @"JSBErrorDomain";
NSString *const JSBExceptionKey = @"JSBExceptionKey";
// set to 1 if you want use Foundation dictionaries when converting to JSValue
#define JSB_USE_DICTIONARY 0
#define JSB_USE_MUTABLE_DICTIONARY 0
@interface JSBContext () {
@public
JSObjectRef _arrayConstructor;
#if JSB_USE_DICTIONARY
JSClassRef _dictionaryClass;
#endif // JSB_USE_DICTIONARY
NSMapTable *_methodMap;
NSMapTable *_propertyMap;
}
@property(nonatomic, assign) JSGlobalContextRef context;
@property(nonatomic, assign) JSObjectRef global;
@property(nonatomic, assign) JSObjectRef arrayConstructor;
#if JSB_USE_DICTIONARY
@property(nonatomic, assign) JSClassRef dictionaryClass;
#endif // JSB_USE_DICTIONARY
@property(nonatomic, strong) NSMapTable *methodMap;
@property(nonatomic, strong) NSMapTable *propertyMap;
@end
#define CAST_CASES \
CASE('@', __autoreleasing, id, JSBValueToObject, JSBObjectToJSValue); \
CASE('d', , double, JSValueToNumber, JSValueMakeNumber, NULL); \
CASE('f', , float, JSValueToNumber, JSValueMakeNumber, NULL); \
CASE('i', , int, JSValueToNumber, JSValueMakeNumber, NULL); \
CASE('I', , unsigned int, JSValueToNumber, JSValueMakeNumber, NULL); \
CASE('l', , long, JSValueToNumber, JSValueMakeNumber, NULL); \
CASE('L', , unsigned long, JSValueToNumber, JSValueMakeNumber, NULL); \
CASE('q', , long long, JSValueToNumber, JSValueMakeNumber, NULL); \
CASE('Q', , unsigned long long, JSValueToNumber, JSValueMakeNumber, NULL); \
CASE('B', , bool, JSValueToBoolean, JSValueMakeBoolean);
static JSValueRef JSBObjectToJSValue(JSContextRef context, id object);
static id JSBValueToObject(JSContextRef context, JSValueRef value);
static inline NSError *JSBExceptionToNSError(JSContextRef context,
JSValueRef exception);
// these functions are there in iOS but they are absent in headers
void NSMapInsert(NSMapTable *table, const void *key, const void *value);
void NSMapInsertKnownAbsent(NSMapTable *table, const void *key,
const void *value);
void *NSMapGet(NSMapTable *table, const void *key);
void NSMapRemove(NSMapTable *table, const void *key);
static void JSBObjectFinalize(JSObjectRef object)
{
CFBridgingRelease(JSObjectGetPrivate(object));
}
static JSValueRef JSBObjectConvertToTypeCallback(JSContextRef context,
JSObjectRef objectRef,
JSType type,
JSValueRef *exception)
{
// returns just object description
if (type == kJSTypeString) {
id object = (__bridge id)JSObjectGetPrivate(objectRef);
JSStringRef stringRef =
JSStringCreateWithCFString((__bridge CFStringRef)[object description]);
JSValueRef valueRef = JSValueMakeString(context, stringRef);
JSStringRelease(stringRef);
return valueRef;
}
return JSValueMakeUndefined(context);
}
static JSValueRef JSBMethodCall(JSContextRef context, JSObjectRef methodRef,
JSObjectRef thisObject, size_t argumentCount,
const JSValueRef arguments[],
JSValueRef *exception)
{
NSMapTable *methodMap = ((__bridge JSBContext *)JSObjectGetPrivate(
JSContextGetGlobalObject(context)))->_methodMap;
id object = (__bridge id)JSObjectGetPrivate(thisObject);
SEL selector = NSMapGet(methodMap, methodRef);
if (object && selector) {
NSMethodSignature *methodSignature =
[[object class] instanceMethodSignatureForSelector:selector];
NSInvocation *invocation =
[NSInvocation invocationWithMethodSignature:methodSignature];
invocation.target = object;
invocation.selector = selector;
argumentCount = MIN(argumentCount, [methodSignature numberOfArguments] - 2);
#define CASE(C, TF, T, F, U, ...) \
case C: { \
TF T value = (T)F(context, arguments[i], ##__VA_ARGS__); \
[invocation setArgument:&value atIndex:i + 2]; \
} break;
for (unsigned i = 0; i < argumentCount; ++i) {
switch ([methodSignature getArgumentTypeAtIndex:i + 2][0]) {
CAST_CASES
}
}
#undef CASE
[invocation retainArguments];
[invocation invoke];
#define CASE(C, TF, T, U, F, ...) \
case C: { \
TF T value; \
[invocation getReturnValue:&value]; \
return F(context, value); \
}
switch ([methodSignature methodReturnType][0]) {
CAST_CASES
default:
return JSValueMakeUndefined(context);
}
}
#undef CASE
return JSValueMakeUndefined(context);
}
#if JSB_USE_DICTIONARY
static JSValueRef JSBDictionaryGetProperty(JSContextRef context,
JSObjectRef objectRef,
JSStringRef propertyNameRef,
JSValueRef *exception)
{
NSDictionary *dictionary =
(__bridge NSDictionary *)JSObjectGetPrivate(objectRef);
NSString *propertyName = (__bridge_transfer NSString *)JSStringCopyCFString(
kCFAllocatorDefault, propertyNameRef);
id value = dictionary[propertyName];
return JSBObjectToJSValue(context, value);
}
#if JSB_USE_MUTABLE_DICTIONARY
static bool JSBDictionarySetProperty(JSContextRef context,
JSObjectRef objectRef,
JSStringRef propertyNameRef,
JSValueRef valueRef, JSValueRef *exception)
{
NSMutableDictionary *dictionary =
(__bridge NSMutableDictionary *)JSObjectGetPrivate(objectRef);
NSString *propertyName = (__bridge_transfer NSString *)JSStringCopyCFString(
kCFAllocatorDefault, propertyNameRef);
id value = JSBValueToObject(context, valueRef);
dictionary[propertyName] = value;
return YES;
}
#endif // JSB_USE_MUTABLE_DICTIONARY
static void
JSBDictionaryGetPropertyNames(JSContextRef context, JSObjectRef objectRef,
JSPropertyNameAccumulatorRef propertyNames)
{
NSDictionary *dictionary =
(__bridge NSDictionary *)JSObjectGetPrivate(objectRef);
for (NSString *key in dictionary) {
JSStringRef propertyNameRef =
JSStringCreateWithCFString((__bridge CFStringRef)key);
JSPropertyNameAccumulatorAddName(propertyNames, propertyNameRef);
JSStringRelease(propertyNameRef);
}
}
#endif // JSB_USE_DICTIONARY
static JSValueRef JSBObjectToJSValue(JSContextRef context, id object)
{
if ([object isKindOfClass:[NSString class]]) {
JSStringRef stringRef =
JSStringCreateWithCFString((__bridge CFStringRef)object);
JSValueRef valueRef = JSValueMakeString(context, stringRef);
JSStringRelease(stringRef);
return valueRef;
} else if ([object isKindOfClass:[NSArray class]]) {
size_t count = [object count];
JSValueRef elements[count];
for (size_t i = 0; i < count; ++i) {
elements[i] = JSBObjectToJSValue(context, ((NSArray *)object)[i]);
}
return JSObjectMakeArray(context, count, elements, NULL);
} else if ([object isKindOfClass:[NSDictionary class]]) {
#if JSB_USE_DICTIONARY
JSClassRef dictionaryClass =
((__bridge JSBContext *)JSObjectGetPrivate(
JSContextGetGlobalObject(context)))->_dictionaryClass;
return JSObjectMake(context, dictionaryClass, (__bridge_retained void *)
#if JSB_USE_MUTABLE_DICTIONARY
[object mutableCopy]
#else
object
#endif // JSB_USE_MUTABLE_DICTIONARY
);
#else
JSObjectRef objectRef = JSObjectMake(context, NULL, NULL);
NSDictionary *dictionary = (NSDictionary *)object;
for (NSString *key in dictionary) {
JSStringRef nameRef =
JSStringCreateWithCFString((__bridge CFStringRef)key);
id value = dictionary[key];
JSObjectSetProperty(context, objectRef, nameRef,
JSBObjectToJSValue(context, value),
kJSPropertyAttributeNone, NULL);
JSStringRelease(nameRef);
}
return objectRef;
#endif // JSB_USE_DICTIONARY
} else if ([object isKindOfClass:[NSNumber class]]) {
return JSValueMakeNumber(context, [object doubleValue]);
} else if ([object isKindOfClass:[NSNull class]]) {
return JSValueMakeNull(context);
}
return JSValueMakeUndefined(context);
}
static NSString *JSBValueToString(JSContextRef context, JSValueRef value)
{
JSStringRef stringRef = JSValueToStringCopy(context, value, NULL);
NSString *string = (__bridge_transfer NSString *)JSStringCopyCFString(
kCFAllocatorDefault, stringRef);
JSStringRelease(stringRef);
return string;
}
static id JSBValueToObject(JSContextRef context, JSValueRef value)
{
if (!value) return nil;
JSObjectRef arrayConstructor =
((__bridge JSBContext *)JSObjectGetPrivate(
JSContextGetGlobalObject(context)))->_arrayConstructor;
switch (JSValueGetType(context, value)) {
// JS object
case kJSTypeObject: {
JSObjectRef objectRef = JSValueToObject(context, value, NULL);
// JS array -> NSArray
if (JSValueIsInstanceOfConstructor(context, value, arrayConstructor,
NULL)) {
NSMutableArray *array = [NSMutableArray array];
for (size_t i = 0;; ++i) {
JSValueRef propertyRef =
JSObjectGetPropertyAtIndex(context, objectRef, i, NULL);
if (JSValueIsUndefined(context, propertyRef)) break;
[array addObject:JSBValueToObject(context, propertyRef)];
}
return [array copy];
} else { // otherwise NSDictionary
JSPropertyNameArrayRef propertyNameArrayRef =
JSObjectCopyPropertyNames(context, objectRef);
size_t propertyCount = JSPropertyNameArrayGetCount(propertyNameArrayRef);
NSMutableDictionary *dictionary =
[NSMutableDictionary dictionaryWithCapacity:propertyCount];
for (size_t i = 0; i < propertyCount; ++i) {
JSStringRef propertyNameRef =
JSPropertyNameArrayGetNameAtIndex(propertyNameArrayRef, i);
JSValueRef propertyRef =
JSObjectGetProperty(context, objectRef, propertyNameRef, NULL);
NSString *propertyName =
(__bridge_transfer NSString *)JSStringCopyCFString(
kCFAllocatorDefault, propertyNameRef);
dictionary[propertyName] = JSBValueToObject(context, propertyRef);
}
JSPropertyNameArrayRelease(propertyNameArrayRef);
return [dictionary copy];
}
}
case kJSTypeString:
return JSBValueToString(context, value);
case kJSTypeNumber:
return @(JSValueToNumber(context, value, NULL));
case kJSTypeBoolean:
return @(JSValueToBoolean(context, value));
case kJSTypeNull:
return [NSNull null];
case kJSTypeUndefined:
default:
return nil;
}
}
#if JSB_USE_GLOBAL_PROPERTIES
JSValueRef JSBGlobalGetProperty(JSContextRef context, JSObjectRef objectRef,
JSStringRef propertyNameRef,
JSValueRef *exception)
{
NSMapTable *propertyMap =
((__bridge JSBContext *)JSObjectGetPrivate(objectRef))->_propertyMap;
NSString *propertyName = (__bridge_transfer NSString *)JSStringCopyCFString(
kCFAllocatorDefault, propertyNameRef);
return NSMapGet(propertyMap, (__bridge void *)propertyName);
}
bool JSBGlobalSetProperty(JSContextRef context, JSObjectRef objectRef,
JSStringRef propertyNameRef, JSValueRef valueRef,
JSValueRef *exception)
{
NSMapTable *propertyMap =
((__bridge JSBContext *)JSObjectGetPrivate(objectRef))->_propertyMap;
NSString *propertyName = (__bridge_transfer NSString *)JSStringCopyCFString(
kCFAllocatorDefault, propertyNameRef);
NSMapInsert(propertyMap, (__bridge void *)propertyName, valueRef);
return true;
}
#endif
@implementation JSBContext
- (id)init
{
if (!(self = [super init])) return nil;
_methodMap =
[NSMapTable mapTableWithKeyOptions:NSPointerFunctionsOpaquePersonality |
NSPointerFunctionsOpaqueMemory
valueOptions:NSPointerFunctionsOpaquePersonality |
NSPointerFunctionsOpaqueMemory];
_propertyMap =
[NSMapTable mapTableWithKeyOptions:NSPointerFunctionsObjectPersonality |
NSPointerFunctionsCopyIn
valueOptions:NSPointerFunctionsOpaquePersonality |
NSPointerFunctionsOpaqueMemory];
#if JSB_USE_DICTIONARY
JSClassDefinition dictionaryDefinition = kJSClassDefinitionEmpty;
dictionaryDefinition.attributes = kJSClassAttributeNone;
dictionaryDefinition.getProperty = JSBDictionaryGetProperty;
dictionaryDefinition.getPropertyNames = JSBDictionaryGetPropertyNames;
#if JSB_USE_MUTABLE_DICTIONARY
dictionaryDefinition.setProperty = JSBDictionarySetProperty;
#endif // JSB_USE_MUTABLE_DICTIONARY
dictionaryDefinition.convertToType = JSBObjectConvertToTypeCallback;
_dictionaryClass = JSClassCreate(&dictionaryDefinition);
#endif // JSB_USE_DICTIONARY
JSClassDefinition globalDefinition = kJSClassDefinitionEmpty;
globalDefinition.attributes = kJSClassAttributeNone;
#if JSB_USE_GLOBAL_PROPERTIES
globalDefinition.getProperty = JSBGlobalGetProperty;
globalDefinition.setProperty = JSBGlobalSetProperty;
#endif
globalDefinition.convertToType = JSBObjectConvertToTypeCallback;
JSClassRef globalClass = JSClassCreate(&globalDefinition);
_context = JSGlobalContextCreate(globalClass);
JSClassRelease(globalClass);
_global = JSContextGetGlobalObject(_context);
JSObjectSetPrivate(_global, (__bridge void *)self);
JSStringRef arrayStringRef = JSStringCreateWithUTF8CString("Array");
_arrayConstructor = JSValueToObject(
_context, JSObjectGetProperty(_context, _global, arrayStringRef, NULL),
NULL);
JSStringRelease(arrayStringRef);
return self;
}
static inline NSError *JSBExceptionToNSError(JSContextRef context,
JSValueRef exception)
{
if (!exception) return nil;
return [NSError
errorWithDomain:JSBErrorDomain
code:0
userInfo:@{
JSBExceptionKey : JSBValueToObject(context, exception),
NSLocalizedDescriptionKey : JSBValueToString(context, exception)
}];
}
- (void)install:(id)object withName:(NSString *)name
{
// count js_ methods
unsigned int methodCount;
Method *methods = class_copyMethodList([object class], &methodCount);
unsigned int jsMethodCount = 0;
for (unsigned int i = 0; i < methodCount; ++i) {
NSString *methodName = NSStringFromSelector(method_getName(methods[i]));
if ([methodName hasPrefix:@"js_"]) {
++jsMethodCount;
}
}
if (!jsMethodCount) return;
JSStaticFunction staticFunctions[jsMethodCount + 1];
NSMapTable *selectorMap =
[NSMapTable mapTableWithKeyOptions:NSPointerFunctionsCStringPersonality |
NSPointerFunctionsMallocMemory |
NSPointerFunctionsCopyIn
valueOptions:NSPointerFunctionsOpaquePersonality |
NSPointerFunctionsOpaqueMemory];
// create & map methods
jsMethodCount = 0;
for (unsigned int i = 0; i < methodCount; ++i) {
SEL selector = method_getName(methods[i]);
NSString *methodName = NSStringFromSelector(selector);
if ([methodName hasPrefix:@"js_"]) {
methodName = [methodName substringFromIndex:3];
NSRange colonRange = [methodName rangeOfString:@":"];
if (colonRange.location != NSNotFound) {
methodName = [methodName substringToIndex:colonRange.location];
}
const char *methodNameUTF8 = [methodName UTF8String];
NSMapInsertKnownAbsent(selectorMap, methodNameUTF8, selector);
staticFunctions[jsMethodCount].attributes = kJSPropertyAttributeReadOnly;
staticFunctions[jsMethodCount].name = strdup(methodNameUTF8);
staticFunctions[jsMethodCount].callAsFunction = JSBMethodCall;
++jsMethodCount;
}
}
staticFunctions[jsMethodCount].attributes = 0;
staticFunctions[jsMethodCount].name = NULL;
staticFunctions[jsMethodCount].callAsFunction = NULL;
// create class if it does not exist yet
JSClassDefinition objectDefinition = kJSClassDefinitionEmpty;
objectDefinition.attributes = kJSClassAttributeNone;
objectDefinition.finalize = JSBObjectFinalize;
objectDefinition.staticFunctions = staticFunctions;
objectDefinition.convertToType = JSBObjectConvertToTypeCallback;
JSClassRef objectClass = JSClassCreate(&objectDefinition);
// instantiate object
JSObjectRef objectRef =
JSObjectMake(_context, objectClass, (__bridge_retained void *)object);
JSClassRelease(objectClass);
for (unsigned int i = 0; i < jsMethodCount; ++i) {
free((void *)staticFunctions[i].name);
}
JSObjectRef prototypeRef = JSValueToObject(
_context, JSObjectGetPrototype(_context, objectRef), NULL);
JSPropertyNameArrayRef propertyNameArrayRef =
JSObjectCopyPropertyNames(_context, prototypeRef);
size_t propertyCount = JSPropertyNameArrayGetCount(propertyNameArrayRef);
// assign selectors to methods
for (size_t i = 0; i < propertyCount; ++i) {
JSStringRef propertyNameRef =
JSPropertyNameArrayGetNameAtIndex(propertyNameArrayRef, i);
JSValueRef propertyRef =
JSObjectGetProperty(_context, objectRef, propertyNameRef, NULL);
NSString *propertyName = (__bridge_transfer NSString *)JSStringCopyCFString(
kCFAllocatorDefault, propertyNameRef);
SEL selector = NSMapGet(selectorMap, [propertyName UTF8String]);
if (selector && JSValueIsObject(_context, propertyRef)) {
JSObjectRef methodRef = JSValueToObject(_context, propertyRef, NULL);
if (JSObjectIsFunction(_context, methodRef)) {
NSMapInsertKnownAbsent(_methodMap, methodRef, selector);
}
}
}
JSPropertyNameArrayRelease(propertyNameArrayRef);
// now assign object to global scope
JSStringRef nameRef = JSStringCreateWithCFString((__bridge CFStringRef)name);
JSObjectSetProperty(
_context, _global, nameRef, objectRef,
kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, NULL);
JSStringRelease(nameRef);
}
- (id)evaluate:(NSString *)script error:(NSError **)error
{
JSStringRef scriptString =
JSStringCreateWithCFString((__bridge CFStringRef)script);
JSValueRef exception = NULL;
JSValueRef ret =
JSEvaluateScript(_context, scriptString, NULL, NULL, 0, &exception);
JSStringRelease(scriptString);
id object = JSBValueToObject(_context, ret);
JSGarbageCollect(_context);
if (error) *error = JSBExceptionToNSError(_context, exception);
return object;
}
- (id)call:(NSString *)name
arguments:(NSArray *)arguments
error:(NSError **)error
{
JSStringRef nameRef = JSStringCreateWithCFString((__bridge CFStringRef)name);
JSValueRef methodValue =
JSObjectGetProperty(_context, _global, nameRef, NULL);
JSStringRelease(nameRef);
JSObjectRef methodObject = JSValueToObject(_context, methodValue, NULL);
JSValueRef argumentArray[arguments.count];
for (NSUInteger i = 0; i < arguments.count; ++i) {
argumentArray[i] = JSBObjectToJSValue(_context, arguments[i]);
}
JSValueRef exception = NULL;
JSValueRef ret =
JSObjectCallAsFunction(_context, methodObject, _global, arguments.count,
argumentArray, &exception);
id object = JSBValueToObject(_context, ret);
JSGarbageCollect(_context);
if (error) *error = JSBExceptionToNSError(_context, exception);
return object;
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
NSString *methodName = NSStringFromSelector(invocation.selector);
NSRange colonRange = [methodName rangeOfString:@":"];
if (colonRange.location != NSNotFound) {
methodName = [methodName substringToIndex:colonRange.location];
}
JSStringRef methodNameRef =
JSStringCreateWithCFString((__bridge CFStringRef)methodName);
JSValueRef valueRef =
JSObjectGetProperty(_context, _global, methodNameRef, NULL);
JSStringRelease(methodNameRef);
JSObjectRef objectRef;
NSMethodSignature *methodSignature = invocation.methodSignature;
if (JSValueIsObject(_context, valueRef) &&
(objectRef = JSValueToObject(_context, valueRef, NULL)) &&
JSObjectIsFunction(_context, objectRef)) {
NSUInteger argumentCount = methodSignature.numberOfArguments;
JSValueRef arguments[argumentCount];
#define CASE(C, TF, T, U, F, ...) \
case C: { \
T value; \
[invocation getArgument:&value atIndex:i + 2]; \
arguments[i] = F(_context, value); \
} break;
for (NSUInteger i = 0; i < argumentCount - 2; ++i) {
switch ([methodSignature getArgumentTypeAtIndex:i + 2][0]) {
CAST_CASES
default:
arguments[i] = JSValueMakeUndefined(_context);
}
}
#undef CASE
valueRef = JSObjectCallAsFunction(_context, objectRef, _global,
argumentCount, arguments, NULL);
}
#define CASE(C, TF, T, F, U, ...) \
case C: { \
TF T value = (T)F(_context, valueRef, ##__VA_ARGS__); \
[invocation setReturnValue:&value]; \
} break;
switch ([methodSignature methodReturnType][0]) {
CAST_CASES
default: {
NSUInteger returnLength = [methodSignature methodReturnLength];
char zero[returnLength];
memset(zero, 0, returnLength);
[invocation setReturnValue:&zero];
}
}
#undef CASE
}
- (void)dealloc
{
JSGlobalContextRelease(_context);
#if JSB_USE_DICTIONARY
JSClassRelease(_dictionaryClass);
#endif // JSB_USE_DICTIONARY
}
@end