Skip to content

Commit a1c6be1

Browse files
Update support for 64-bit devices.
1 parent a668015 commit a1c6be1

File tree

11 files changed

+423
-316
lines changed

11 files changed

+423
-316
lines changed

Classes/JSBMessageForwarding.h

Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
//
2+
// JSBMessageForwarding.h
3+
// JavaScriptBridge
4+
//
5+
// Created by kishikawa katsumi on 2014/01/04.
6+
// Copyright (c) 2014 kishikawa katsumi. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
#import "JSBScriptingSupport.h"
11+
12+
@import ObjectiveC;
13+
@import JavaScriptCore;
14+
15+
static NSString *mangledNameFromClass(Class cls)
16+
{
17+
return [NSString stringWithFormat:@"__JSB_%@", NSStringFromClass(cls)];
18+
}
19+
20+
static NSString *propertyNameFromSelector(SEL selector)
21+
{
22+
NSArray *split = [NSStringFromSelector(selector) componentsSeparatedByString:@":"];
23+
NSMutableString *propertyName = [[NSMutableString alloc] init];
24+
for (NSInteger i = 0; i < split.count; i++) {
25+
NSString *string = split[i];
26+
if (i > 0) {
27+
if (string.length > 0) {
28+
NSString *firstCharacter = [string substringWithRange:NSMakeRange(0, 1)];
29+
[propertyName appendString:[string stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:firstCharacter.uppercaseString]];
30+
}
31+
} else {
32+
[propertyName appendString:string];
33+
}
34+
}
35+
36+
return propertyName;
37+
}
38+
39+
#pragma mark -
40+
41+
static void invokeSuper(NSInvocation *inv)
42+
{
43+
SEL sel = NSSelectorFromString(@"invokeSuper");
44+
NSMethodSignature *signature = [inv methodSignatureForSelector:sel];
45+
46+
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
47+
invocation.selector = sel;
48+
invocation.target = inv;
49+
50+
[invocation invoke];
51+
}
52+
53+
static NSArray *extractArguments(NSInvocation *invocation)
54+
{
55+
NSMethodSignature *methodSignature = invocation.methodSignature;
56+
NSUInteger numberOfArguments = methodSignature.numberOfArguments;
57+
NSMutableArray *arguments = [[NSMutableArray alloc] initWithCapacity:numberOfArguments];
58+
59+
for (NSUInteger i = 2; i < numberOfArguments; i++) {
60+
const char *type = [methodSignature getArgumentTypeAtIndex:i];
61+
if (strcmp(type, @encode(char)) == 0) {
62+
char argument;
63+
[invocation getArgument:&argument atIndex:i];
64+
[arguments addObject:@(argument)];
65+
} else if (strcmp(type, @encode(bool)) == 0) {
66+
bool argument;
67+
[invocation getArgument:&argument atIndex:i];
68+
[arguments addObject:@(argument)];
69+
} else if (strcmp(type, @encode(short)) == 0) {
70+
short argument;
71+
[invocation getArgument:&argument atIndex:i];
72+
[arguments addObject:@(argument)];
73+
} else if (strcmp(type, @encode(int)) == 0) {
74+
int argument;
75+
[invocation getArgument:&argument atIndex:i];
76+
[arguments addObject:@(argument)];
77+
} else if (strcmp(type, @encode(long)) == 0) {
78+
long argument;
79+
[invocation getArgument:&argument atIndex:i];
80+
[arguments addObject:@(argument)];
81+
} else if (strcmp(type, @encode(long long)) == 0) {
82+
long long argument;
83+
[invocation getArgument:&argument atIndex:i];
84+
[arguments addObject:@(argument)];
85+
} else if (strcmp(type, @encode(unsigned char)) == 0) {
86+
unsigned char argument;
87+
[invocation getArgument:&argument atIndex:i];
88+
[arguments addObject:@(argument)];
89+
} else if (strcmp(type, @encode(unsigned short)) == 0) {
90+
unsigned short argument;
91+
[invocation getArgument:&argument atIndex:i];
92+
[arguments addObject:@(argument)];
93+
} else if (strcmp(type, @encode(unsigned int)) == 0) {
94+
unsigned int argument;
95+
[invocation getArgument:&argument atIndex:i];
96+
[arguments addObject:@(argument)];
97+
} else if (strcmp(type, @encode(unsigned long)) == 0) {
98+
unsigned long argument;
99+
[invocation getArgument:&argument atIndex:i];
100+
[arguments addObject:@(argument)];
101+
} else if (strcmp(type, @encode(unsigned long long)) == 0) {
102+
unsigned long long argument;
103+
[invocation getArgument:&argument atIndex:i];
104+
[arguments addObject:@(argument)];
105+
} else if (strcmp(type, @encode(float)) == 0) {
106+
float argument;
107+
[invocation getArgument:&argument atIndex:i];
108+
[arguments addObject:@(argument)];
109+
} else if (strcmp(type, @encode(double)) == 0) {
110+
double argument;
111+
[invocation getArgument:&argument atIndex:i];
112+
[arguments addObject:@(argument)];
113+
} else if (strcmp(type, @encode(char *)) == 0) {
114+
char *argument;
115+
[invocation getArgument:&argument atIndex:i];
116+
[arguments addObject:@(argument)];
117+
} else if (strcmp(type, @encode(BOOL)) == 0) {
118+
BOOL argument;
119+
[invocation getArgument:&argument atIndex:i];
120+
[arguments addObject:@(argument)];
121+
} else if (strcmp(type, @encode(void *)) == 0) {
122+
void *argument;
123+
[invocation getArgument:&argument atIndex:i];
124+
[arguments addObject:(__bridge id)argument];
125+
} else if (strcmp(type, @encode(id)) == 0) {
126+
id __unsafe_unretained argument = nil;
127+
[invocation getArgument:&argument atIndex:i];
128+
[arguments addObject:argument];
129+
} else if (strcmp(type, @encode(SEL)) == 0) {
130+
const char *argument = nil;
131+
[invocation getArgument:&argument atIndex:i];
132+
[arguments addObject:@(argument)];
133+
} else if (strcmp(type, @encode(Class)) == 0) {
134+
Class __unsafe_unretained argument = nil;
135+
[invocation getArgument:&argument atIndex:i];
136+
[arguments addObject:argument];
137+
}
138+
}
139+
140+
return arguments.copy;
141+
}
142+
143+
static void setReturnValue(JSValue *value, NSInvocation *invocation)
144+
{
145+
NSMethodSignature *methodSignature = invocation.methodSignature;
146+
const char *type = methodSignature.methodReturnType;
147+
148+
if (strcmp(type, @encode(void)) == 0) {
149+
return;
150+
}
151+
152+
if (strcmp(type, @encode(char)) == 0 ||
153+
strcmp(type, @encode(short)) == 0 ||
154+
strcmp(type, @encode(int)) == 0 ||
155+
strcmp(type, @encode(unsigned char)) == 0 ||
156+
strcmp(type, @encode(unsigned short)) == 0 ||
157+
strcmp(type, @encode(unsigned int)) == 0) {
158+
int32_t returnValue = value.toInt32;
159+
[invocation setReturnValue:&returnValue];
160+
} else if (strcmp(type, @encode(long)) == 0 ||
161+
strcmp(type, @encode(unsigned long)) == 0 ||
162+
strcmp(type, @encode(long long)) == 0 ||
163+
strcmp(type, @encode(unsigned long long)) == 0) {
164+
int64_t returnValue = value.toInt32;
165+
[invocation setReturnValue:&returnValue];
166+
} else if (strcmp(type, @encode(bool)) == 0 ||
167+
strcmp(type, @encode(BOOL)) == 0) {
168+
BOOL returnValue = value.toBool;
169+
[invocation setReturnValue:&returnValue];
170+
} else if (strcmp(type, @encode(float)) == 0) {
171+
float returnValue = value.toDouble;
172+
[invocation setReturnValue:&returnValue];
173+
} else if (strcmp(type, @encode(double)) == 0) {
174+
double returnValue = value.toDouble;
175+
[invocation setReturnValue:&returnValue];
176+
} else {
177+
id __unsafe_unretained returnValue = value.toObject;
178+
[invocation setReturnValue:&returnValue];
179+
}
180+
}
181+
182+
#pragma mark -
183+
184+
static CGFloat tableViewHeightForRowAtIndexPath(id self, SEL _cmd, UITableView *tableView, NSIndexPath *indexPath)
185+
{
186+
JSContext *context = [JSBScriptingSupport globalContext];
187+
188+
NSString *propertyName = propertyNameFromSelector(_cmd);
189+
JSValue *function = context[mangledNameFromClass([self class])][@"instanceMembers"][propertyName];
190+
191+
if (!function.isUndefined) {
192+
JSValue *returnValue = [function callWithArguments:@[tableView, indexPath]];
193+
return returnValue.toDouble;
194+
}
195+
196+
return 0.0f;
197+
}
198+
199+
static CGFloat tableViewHeightForHeaderInSection(id self, SEL _cmd, UITableView *tableView, NSInteger section)
200+
{
201+
JSContext *context = [JSBScriptingSupport globalContext];
202+
203+
NSString *propertyName = propertyNameFromSelector(_cmd);
204+
JSValue *function = context[mangledNameFromClass([self class])][@"instanceMembers"][propertyName];
205+
206+
if (!function.isUndefined) {
207+
JSValue *returnValue = [function callWithArguments:@[tableView, @(section)]];
208+
return returnValue.toDouble;
209+
}
210+
211+
return 0.0f;
212+
}
213+
214+
static CGFloat tableViewHeightForFooterInSection(id self, SEL _cmd, UITableView *tableView, NSInteger section)
215+
{
216+
JSContext *context = [JSBScriptingSupport globalContext];
217+
218+
NSString *propertyName = propertyNameFromSelector(_cmd);
219+
JSValue *function = context[mangledNameFromClass([self class])][@"instanceMembers"][propertyName];
220+
221+
if (!function.isUndefined) {
222+
JSValue *returnValue = [function callWithArguments:@[tableView, @(section)]];
223+
return returnValue.toDouble;
224+
}
225+
226+
return 0.0f;
227+
}
228+
229+
#pragma mark -
230+
231+
static void setupForwardingImplementations(Class targetClass, Class cls, JSValue *functions)
232+
{
233+
unsigned int count = 0;
234+
Method *methods = class_copyMethodList(cls, &count);
235+
for (unsigned int i = 0; i < count; i++) {
236+
Method m = methods[i];
237+
struct objc_method_description *description = method_getDescription(m);
238+
239+
NSString *propertyName = propertyNameFromSelector(description->name);
240+
JSValue *function = functions[propertyName];
241+
if (!function.isUndefined) {
242+
if (strcmp(@encode(NSInteger), "q") == 0) { // for 64bit devices
243+
if (description->name == @selector(tableView:heightForRowAtIndexPath:)) {
244+
class_addMethod(targetClass, description->name, (IMP)tableViewHeightForRowAtIndexPath, description->types);
245+
continue;
246+
} else if (description->name == @selector(tableView:heightForHeaderInSection:)) {
247+
class_addMethod(targetClass, description->name, (IMP)tableViewHeightForHeaderInSection, description->types);
248+
continue;
249+
} else if (description->name == @selector(tableView:heightForFooterInSection:)) {
250+
class_addMethod(targetClass, description->name, (IMP)tableViewHeightForFooterInSection, description->types);
251+
continue;
252+
} else if (description->name == @selector(tableView:estimatedHeightForRowAtIndexPath:)) {
253+
class_addMethod(targetClass, description->name, (IMP)tableViewHeightForRowAtIndexPath, description->types);
254+
continue;
255+
} else if (description->name == @selector(tableView:estimatedHeightForHeaderInSection:)) {
256+
class_addMethod(targetClass, description->name, (IMP)tableViewHeightForHeaderInSection, description->types);
257+
continue;
258+
} else if (description->name == @selector(tableView:estimatedHeightForFooterInSection:)) {
259+
class_addMethod(targetClass, description->name, (IMP)tableViewHeightForFooterInSection, description->types);
260+
continue;
261+
}
262+
}
263+
264+
class_addMethod(targetClass, description->name, _objc_msgForward, description->types);
265+
}
266+
}
267+
if (methods) {
268+
free(methods);
269+
}
270+
271+
Class superClass = class_getSuperclass(cls);
272+
if (superClass) {
273+
setupForwardingImplementations(targetClass, superClass, functions);
274+
}
275+
}
276+
277+
#pragma mark -
278+
279+
static void forwardInvocation(id self, SEL _cmd, NSInvocation *invocation)
280+
{
281+
JSContext *context = [JSBScriptingSupport globalContext];
282+
283+
if ([[self superclass] instancesRespondToSelector:invocation.selector]) {
284+
invokeSuper(invocation);
285+
}
286+
287+
context[@"self"] = self;
288+
289+
NSString *propertyName = propertyNameFromSelector(invocation.selector);
290+
JSValue *function = context[mangledNameFromClass([self class])][@"instanceMembers"][propertyName];
291+
292+
if (!function.isUndefined) {
293+
NSArray *arguments = extractArguments(invocation);
294+
JSValue *returnValue = [function callWithArguments:arguments];
295+
296+
setReturnValue(returnValue, invocation);
297+
}
298+
299+
context[@"self"] = nil;
300+
}
301+
302+
static NSMethodSignature *methodSignatureForSelector(id self, SEL _cmd, SEL selector)
303+
{
304+
NSMethodSignature *methodSignature = nil;
305+
306+
Class cls = [self class];
307+
methodSignature = [cls instanceMethodSignatureForSelector:selector];
308+
if (methodSignature) {
309+
return methodSignature;
310+
}
311+
312+
NSUInteger numberOfArguments = [[NSStringFromSelector(selector) componentsSeparatedByString:@":"] count] - 1;
313+
return [NSMethodSignature signatureWithObjCTypes:[[@"@@:" stringByPaddingToLength:numberOfArguments + 3 withString:@"@" startingAtIndex:0] UTF8String]];
314+
}
315+
316+
static BOOL respondsToSelector(id self, SEL _cmd, SEL selector)
317+
{
318+
JSContext *context = [JSBScriptingSupport globalContext];
319+
320+
NSString *propertyName = propertyNameFromSelector(selector);
321+
JSValue *value = context[mangledNameFromClass([self class])][@"instanceMembers"][propertyName];
322+
323+
return !value.isUndefined;
324+
}

Classes/JSBScriptingSupport.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//
88

99
#import <Foundation/Foundation.h>
10-
#import "JSContext+Helper.h"
10+
#import "JSContext+JavaScriptBridge.h"
1111

1212
@import JavaScriptCore;
1313

0 commit comments

Comments
 (0)