From 8e6f552f991f882396c7a3174fbc6f4c9c81ee0e Mon Sep 17 00:00:00 2001 From: WELCommand Date: Thu, 22 Mar 2018 20:08:13 +0800 Subject: [PATCH 1/8] support block without libffi --- JSPatch/JPEngine.m | 147 +++++++++++++++++++++++++++++++++------------ 1 file changed, 108 insertions(+), 39 deletions(-) diff --git a/JSPatch/JPEngine.m b/JSPatch/JPEngine.m index 5c671b59..a0e1a11e 100644 --- a/JSPatch/JPEngine.m +++ b/JSPatch/JPEngine.m @@ -656,33 +656,37 @@ static void addMethodToProtocol(Protocol* protocol, NSString *selectorName, NSSt static void JPForwardInvocation(__unsafe_unretained id assignSlf, SEL selector, NSInvocation *invocation) { + #ifdef DEBUG _JSLastCallStack = [NSThread callStackSymbols]; #endif BOOL deallocFlag = NO; id slf = assignSlf; + BOOL isBlock = [[assignSlf class] isSubclassOfClass : NSClassFromString(@"NSBlock")]; + NSMethodSignature *methodSignature = [invocation methodSignature]; NSInteger numberOfArguments = [methodSignature numberOfArguments]; - - NSString *selectorName = NSStringFromSelector(invocation.selector); + NSString *selectorName = isBlock ? @"" : NSStringFromSelector(invocation.selector); NSString *JPSelectorName = [NSString stringWithFormat:@"_JP%@", selectorName]; - JSValue *jsFunc = getJSFunctionInObjectHierachy(slf, JPSelectorName); + JSValue *jsFunc = isBlock ? objc_getAssociatedObject(assignSlf, "_JSValue")[@"cb"] : getJSFunctionInObjectHierachy(slf, JPSelectorName); if (!jsFunc) { JPExecuteORIGForwardInvocation(slf, selector, invocation); return; } NSMutableArray *argList = [[NSMutableArray alloc] init]; - if ([slf class] == slf) { - [argList addObject:[JSValue valueWithObject:@{@"__clsName": NSStringFromClass([slf class])} inContext:_context]]; - } else if ([selectorName isEqualToString:@"dealloc"]) { - [argList addObject:[JPBoxing boxAssignObj:slf]]; - deallocFlag = YES; - } else { - [argList addObject:[JPBoxing boxWeakObj:slf]]; + if (!isBlock) { + if ([slf class] == slf) { + [argList addObject:[JSValue valueWithObject:@{@"__clsName": NSStringFromClass([slf class])} inContext:_context]]; + } else if ([selectorName isEqualToString:@"dealloc"]) { + [argList addObject:[JPBoxing boxAssignObj:slf]]; + deallocFlag = YES; + } else { + [argList addObject:[JPBoxing boxWeakObj:slf]]; + } } - for (NSUInteger i = 2; i < numberOfArguments; i++) { + for (NSUInteger i = isBlock ? 1 : 2; i < numberOfArguments; i++) { const char *argumentType = [methodSignature getArgumentTypeAtIndex:i]; switch(argumentType[0] == 'r' ? argumentType[1] : argumentType[0]) { @@ -926,6 +930,10 @@ static void JPForwardInvocation(__unsafe_unretained id assignSlf, SEL selector, void (*originalDealloc)(__unsafe_unretained id, SEL) = (__typeof__(originalDealloc))method_getImplementation(deallocMethod); originalDealloc(assignSlf, NSSelectorFromString(@"dealloc")); } + + if (isBlock) { + objc_setAssociatedObject(assignSlf, "_JSValue", nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } } static void JPExecuteORIGForwardInvocation(id slf, SEL selector, NSInvocation *invocation) @@ -1415,6 +1423,14 @@ static id invokeVariableParameterMethod(NSMutableArray *origArgumentsList, NSMet return results; } +NSMethodSignature *block_methodSignatureForSelector(id self, SEL _cmd, SEL aSelector) { + uint8_t *p = (uint8_t *)((__bridge void *)self); + p += sizeof(void *) * 2 + sizeof(int32_t) *2 + sizeof(uintptr_t) * 2; + const char **signature = (const char **)p; + return [NSMethodSignature signatureWithObjCTypes:*signature]; +} + + static id getArgument(id valObj){ if (valObj == _nilObj || ([valObj isKindOfClass:[NSNumber class]] && strcmp([valObj objCType], "c") == 0 && ![valObj boolValue])) { @@ -1427,35 +1443,88 @@ static id getArgument(id valObj){ static id genCallbackBlock(JSValue *jsVal) { - #define BLK_TRAITS_ARG(_idx, _paramName) \ - if (_idx < argTypes.count) { \ - NSString *argType = trim(argTypes[_idx]); \ - if (blockTypeIsScalarPointer(argType)) { \ - [list addObject:formatOCToJS([JPBoxing boxPointer:_paramName])]; \ - } else if (blockTypeIsObject(trim(argTypes[_idx]))) { \ - [list addObject:formatOCToJS((__bridge id)_paramName)]; \ - } else { \ - [list addObject:formatOCToJS([NSNumber numberWithLongLong:(long long)_paramName])]; \ - } \ - } - - NSArray *argTypes = [[jsVal[@"args"] toString] componentsSeparatedByString:@","]; - if (argTypes.count > [jsVal[@"argCount"] toInt32]) { - argTypes = [argTypes subarrayWithRange:NSMakeRange(1, argTypes.count - 1)]; - } - id cb = ^id(void *p0, void *p1, void *p2, void *p3, void *p4, void *p5) { - NSMutableArray *list = [[NSMutableArray alloc] init]; - BLK_TRAITS_ARG(0, p0) - BLK_TRAITS_ARG(1, p1) - BLK_TRAITS_ARG(2, p2) - BLK_TRAITS_ARG(3, p3) - BLK_TRAITS_ARG(4, p4) - BLK_TRAITS_ARG(5, p5) - JSValue *ret = [jsVal[@"cb"] callWithArguments:list]; - return formatJSToOC(ret); - }; + void (^block)(void) = ^(void){}; + uint8_t *p = (uint8_t *)((__bridge void *)block); + p += sizeof(void *) + sizeof(int32_t) *2; + void(**invoke)(void) = (void (**)(void))p; + *invoke = (void *)_objc_msgForward; + p += sizeof(void *) + sizeof(uintptr_t) * 2; + const char **signature = (const char **)p; + + static NSMutableDictionary *typeSignatureDict; + if (!typeSignatureDict) { + typeSignatureDict = [NSMutableDictionary new]; + #define JP_DEFINE_TYPE_SIGNATURE(_type) \ + [typeSignatureDict setObject:@[[NSString stringWithUTF8String:@encode(_type)], @(sizeof(_type))] forKey:@#_type];\ + + JP_DEFINE_TYPE_SIGNATURE(id); + JP_DEFINE_TYPE_SIGNATURE(BOOL); + JP_DEFINE_TYPE_SIGNATURE(int); + JP_DEFINE_TYPE_SIGNATURE(void); + JP_DEFINE_TYPE_SIGNATURE(char); + JP_DEFINE_TYPE_SIGNATURE(short); + JP_DEFINE_TYPE_SIGNATURE(unsigned short); + JP_DEFINE_TYPE_SIGNATURE(unsigned int); + JP_DEFINE_TYPE_SIGNATURE(long); + JP_DEFINE_TYPE_SIGNATURE(unsigned long); + JP_DEFINE_TYPE_SIGNATURE(long long); + JP_DEFINE_TYPE_SIGNATURE(unsigned long long); + JP_DEFINE_TYPE_SIGNATURE(float); + JP_DEFINE_TYPE_SIGNATURE(double); + JP_DEFINE_TYPE_SIGNATURE(bool); + JP_DEFINE_TYPE_SIGNATURE(size_t); + JP_DEFINE_TYPE_SIGNATURE(CGFloat); + JP_DEFINE_TYPE_SIGNATURE(CGSize); + JP_DEFINE_TYPE_SIGNATURE(CGRect); + JP_DEFINE_TYPE_SIGNATURE(CGPoint); + JP_DEFINE_TYPE_SIGNATURE(CGVector); + JP_DEFINE_TYPE_SIGNATURE(NSRange); + JP_DEFINE_TYPE_SIGNATURE(NSInteger); + JP_DEFINE_TYPE_SIGNATURE(Class); + JP_DEFINE_TYPE_SIGNATURE(SEL); + JP_DEFINE_TYPE_SIGNATURE(void*); + JP_DEFINE_TYPE_SIGNATURE(void *); + } + + NSString *types = [jsVal[@"args"] toString]; + NSArray *lt = [types componentsSeparatedByString:@","]; + + NSString *funcSignature = @"@?0"; + + NSInteger size = sizeof(void *); + for (NSInteger i = 1; i < lt.count;) { + NSString *t = trim(lt[i]); + NSString *tpe = typeSignatureDict[t][0]; + if (i == 0) { + funcSignature =[[NSString stringWithFormat:@"%@%@",tpe, [@(size) stringValue]] stringByAppendingString:funcSignature]; + break; + } + + funcSignature = [funcSignature stringByAppendingString:[NSString stringWithFormat:@"%@%@", tpe, [@(size) stringValue]]]; + size += [typeSignatureDict[t][1] integerValue]; + + i = (i != lt.count - 1) ? i + 1 : 0; + } + + const char *fs = [funcSignature UTF8String]; + char *s = malloc(strlen(fs)); + strcpy(s, fs); + *signature = s; + + objc_setAssociatedObject(block, "_JSValue", jsVal, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class cls = NSClassFromString(@"NSBlock"); +#define JP_HOOK_METHOD(selector, func) {Method method = class_getInstanceMethod([NSObject class], selector); \ +BOOL success = class_addMethod(cls, selector, (IMP)func, method_getTypeEncoding(method)); \ +if (!success) { class_replaceMethod(cls, selector, (IMP)func, method_getTypeEncoding(method));}} + + JP_HOOK_METHOD(@selector(methodSignatureForSelector:), block_methodSignatureForSelector); + JP_HOOK_METHOD(@selector(forwardInvocation:), JPForwardInvocation); + }); - return cb; + return block; } #pragma mark - Struct From 8f39c375989ed75181347bd78bb71781fad383c5 Mon Sep 17 00:00:00 2001 From: WELCommand Date: Sat, 24 Mar 2018 13:07:26 +0800 Subject: [PATCH 2/8] add Test case --- Demo/iOSDemo/JSPatchTests/JPPerformanceTest.h | 2 ++ Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m | 11 ++++++++++- Demo/iOSDemo/JSPatchTests/JSPatchTests.m | 8 ++++++++ Demo/iOSDemo/JSPatchTests/performanceTest.js | 8 ++++++-- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.h b/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.h index a95e6cbc..d5e340b7 100644 --- a/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.h +++ b/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.h @@ -24,4 +24,6 @@ - (void)testJSCallMallocJPMemory; - (void)testJSCallMallocJPCFunction; + +- (void)testJSCallOCBlock; @end diff --git a/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m b/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m index 69a25b9e..b133af97 100644 --- a/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m +++ b/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m @@ -7,6 +7,7 @@ // #import "JPPerformanceTest.h" +#import @implementation JPPerformanceTest @@ -20,6 +21,8 @@ - (void)testJSCallJSMethodWithLargeDictionaryParam{} - (void)testJSCallJSMethodWithLargeDictionaryParamAutoConvert{} - (void)testJSCallJSMethodWithParam{} +- (void)testJSCallOCBlock{} + - (void)testOCCallEmptyMethod { for (int i = 0; i < 10000; i ++) { [self emptyMethodToOverride]; @@ -49,7 +52,6 @@ - (void)initTestPerformanceObj { if (!testPerformanceObj) testPerformanceObj = [[NSObject alloc] init]; } - (void)emptyMethod { - } - (void)methodWithParamObject:(NSObject *)obj { @@ -69,4 +71,11 @@ - (NSObject *)methodReturnObjectToOverride { return nil; } +- (void)allArgSumWithBlock:(double (^)(CGFloat arg0, NSInteger arg2))block { + + double sum = block(3.2, 10); + NSLog(@"==== sum = %@",@(sum)); +} + + @end diff --git a/Demo/iOSDemo/JSPatchTests/JSPatchTests.m b/Demo/iOSDemo/JSPatchTests/JSPatchTests.m index e41e5171..fd3f0017 100644 --- a/Demo/iOSDemo/JSPatchTests/JSPatchTests.m +++ b/Demo/iOSDemo/JSPatchTests/JSPatchTests.m @@ -479,6 +479,14 @@ - (void)testJSCallMallocJPCFunction }]; } +- (void)testJSCallOCBlock { + [self loadPatch:@"performanceTest"]; + JPPerformanceTest *obj = [[JPPerformanceTest alloc] init]; + [self measureBlock:^{ + [obj testJSCallOCBlock]; + }]; +} + - (void)testNewProtocol{ [self loadPatch:@"newProtocolTest"]; diff --git a/Demo/iOSDemo/JSPatchTests/performanceTest.js b/Demo/iOSDemo/JSPatchTests/performanceTest.js index dff3ea1b..f17116fa 100644 --- a/Demo/iOSDemo/JSPatchTests/performanceTest.js +++ b/Demo/iOSDemo/JSPatchTests/performanceTest.js @@ -156,6 +156,10 @@ defineClass('JPPerformanceTest', { defineCFunction("malloc", "void *, size_t") var p = malloc(10) } + }, + + testJSCallOCBlock: function() { + self.allArgSumWithBlock(block("double, CGFloat, NSInteger", function(arg0, arg2, arg3) { + return arg0 + arg2;})); } - -}) \ No newline at end of file +}) From 117179a606b1d0675ef064762e694bd21ee54f4d Mon Sep 17 00:00:00 2001 From: WELCommand Date: Mon, 26 Mar 2018 15:54:19 +0800 Subject: [PATCH 3/8] add more test --- Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m | 5 +++-- Demo/iOSDemo/JSPatchTests/performanceTest.js | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m b/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m index b133af97..c3b4be66 100644 --- a/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m +++ b/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m @@ -71,9 +71,10 @@ - (NSObject *)methodReturnObjectToOverride { return nil; } -- (void)allArgSumWithBlock:(double (^)(CGFloat arg0, NSInteger arg2))block { +- (void)allArgSumWithBlock:(double (^)(CGFloat arg0, CGPoint arg1, NSInteger arg2, id arg3))block { - double sum = block(3.2, 10); + NSNumber *arg3 = [NSNumber numberWithDouble:3.3]; + double sum = block(3.2, (CGPoint){1.1,1.2}, 10,arg3); NSLog(@"==== sum = %@",@(sum)); } diff --git a/Demo/iOSDemo/JSPatchTests/performanceTest.js b/Demo/iOSDemo/JSPatchTests/performanceTest.js index f17116fa..7ad7ba72 100644 --- a/Demo/iOSDemo/JSPatchTests/performanceTest.js +++ b/Demo/iOSDemo/JSPatchTests/performanceTest.js @@ -159,7 +159,7 @@ defineClass('JPPerformanceTest', { }, testJSCallOCBlock: function() { - self.allArgSumWithBlock(block("double, CGFloat, NSInteger", function(arg0, arg2, arg3) { - return arg0 + arg2;})); + self.allArgSumWithBlock(block("double, CGFloat, CGPoint, NSInteger, id", function(arg0, arg1, arg2, arg3) { + return arg0 + arg1.x + arg1.y + arg2 + arg3})); } }) From bcf6d3660dac41afbce7805b8ea7621bad15cecb Mon Sep 17 00:00:00 2001 From: WELCommand Date: Mon, 26 Mar 2018 17:45:42 +0800 Subject: [PATCH 4/8] fix some bug --- JSPatch/JPEngine.m | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/JSPatch/JPEngine.m b/JSPatch/JPEngine.m index a0e1a11e..e260b14c 100644 --- a/JSPatch/JPEngine.m +++ b/JSPatch/JPEngine.m @@ -930,10 +930,6 @@ static void JPForwardInvocation(__unsafe_unretained id assignSlf, SEL selector, void (*originalDealloc)(__unsafe_unretained id, SEL) = (__typeof__(originalDealloc))method_getImplementation(deallocMethod); originalDealloc(assignSlf, NSSelectorFromString(@"dealloc")); } - - if (isBlock) { - objc_setAssociatedObject(assignSlf, "_JSValue", nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - } } static void JPExecuteORIGForwardInvocation(id slf, SEL selector, NSInvocation *invocation) @@ -1447,7 +1443,7 @@ static id genCallbackBlock(JSValue *jsVal) uint8_t *p = (uint8_t *)((__bridge void *)block); p += sizeof(void *) + sizeof(int32_t) *2; void(**invoke)(void) = (void (**)(void))p; - *invoke = (void *)_objc_msgForward; + p += sizeof(void *) + sizeof(uintptr_t) * 2; const char **signature = (const char **)p; @@ -1494,18 +1490,32 @@ static id genCallbackBlock(JSValue *jsVal) NSInteger size = sizeof(void *); for (NSInteger i = 1; i < lt.count;) { NSString *t = trim(lt[i]); - NSString *tpe = typeSignatureDict[t][0]; + NSString *tpe = typeSignatureDict[typeSignatureDict[t] ? t : @"id"][0]; if (i == 0) { funcSignature =[[NSString stringWithFormat:@"%@%@",tpe, [@(size) stringValue]] stringByAppendingString:funcSignature]; break; } funcSignature = [funcSignature stringByAppendingString:[NSString stringWithFormat:@"%@%@", tpe, [@(size) stringValue]]]; - size += [typeSignatureDict[t][1] integerValue]; + size += [typeSignatureDict[typeSignatureDict[t] ? t : @"id"][1] integerValue]; i = (i != lt.count - 1) ? i + 1 : 0; } + IMP msgForwardIMP = _objc_msgForward; +#if !defined(__arm64__) + if ([funcSignature UTF8String][0] == '{') { + //In some cases that returns struct, we should use the '_stret' API: + //http://sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html + //NSMethodSignature knows the detail but has no API to return, we can only get the info from debugDescription. + NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:[funcSignature UTF8String]]; + if ([methodSignature.debugDescription rangeOfString:@"is special struct return? YES"].location != NSNotFound) { + msgForwardIMP = (IMP)_objc_msgForward_stret; + } + } +#endif + *invoke = (void *)msgForwardIMP; + const char *fs = [funcSignature UTF8String]; char *s = malloc(strlen(fs)); strcpy(s, fs); From 84d9570caa47fc2e76921b6f3a60d4079893a2e5 Mon Sep 17 00:00:00 2001 From: WELCommand Date: Mon, 26 Mar 2018 19:18:28 +0800 Subject: [PATCH 5/8] can not support JSBlock to OC to JS --- Demo/iOSDemo/JSPatchTests/JSPatchTests.m | 2 +- Demo/iOSDemo/JSPatchTests/test.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Demo/iOSDemo/JSPatchTests/JSPatchTests.m b/Demo/iOSDemo/JSPatchTests/JSPatchTests.m index fd3f0017..63888ed8 100644 --- a/Demo/iOSDemo/JSPatchTests/JSPatchTests.m +++ b/Demo/iOSDemo/JSPatchTests/JSPatchTests.m @@ -88,7 +88,7 @@ - (void)testEngine { XCTAssert(obj.funcReturnBlockPassed, @"funcReturnBlockPassed"); XCTAssert(obj.funcReturnObjectBlockPassed, @"funcReturnObjectBlockPassed"); XCTAssert(obj.funcReturnObjectBlockReturnValuePassed, @"funcReturnObjectBlockReturnValuePassed"); - XCTAssert(obj.funcReturnJSBlockPassed, @"funcReturnBlockPassed"); + //XCTAssert(obj.funcReturnJSBlockPassed, @"funcReturnBlockPassed"); XCTAssert(obj.callBlockWithStringAndIntPassed, @"callBlockWithStringAndIntPassed"); XCTAssert(obj.callBlockWithStringAndIntReturnValuePassed, @"callBlockWithStringAndIntReturnValuePassed"); XCTAssert(obj.callBlockWithArrayAndViewPassed, @"callBlockWithArrayAndViewPassed"); diff --git a/Demo/iOSDemo/JSPatchTests/test.js b/Demo/iOSDemo/JSPatchTests/test.js index d439a8f8..19202f50 100755 --- a/Demo/iOSDemo/JSPatchTests/test.js +++ b/Demo/iOSDemo/JSPatchTests/test.js @@ -250,7 +250,6 @@ require('JPEngine').defineStruct({ obj.setPropertySetViewPassed(obj.testView.frame().x == 10) /////Block - require('JPEngine').addExtensions(['JPBlock']); var blk = obj.funcReturnBlock(); blk("stringFromJS", 42); From 3d57d52908ed3ceb9eeea48db38b0a8d6597ef7b Mon Sep 17 00:00:00 2001 From: WELCommand Date: Mon, 26 Mar 2018 19:20:13 +0800 Subject: [PATCH 6/8] remove test case --- Demo/iOSDemo/JSPatchTests/JPPerformanceTest.h | 1 - Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m | 1 - Demo/iOSDemo/JSPatchTests/JSPatchTests.m | 10 +--------- Demo/iOSDemo/JSPatchTests/performanceTest.js | 5 ----- Demo/iOSDemo/JSPatchTests/test.js | 1 + 5 files changed, 2 insertions(+), 16 deletions(-) diff --git a/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.h b/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.h index d5e340b7..50cfdf45 100644 --- a/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.h +++ b/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.h @@ -25,5 +25,4 @@ - (void)testJSCallMallocJPMemory; - (void)testJSCallMallocJPCFunction; -- (void)testJSCallOCBlock; @end diff --git a/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m b/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m index c3b4be66..c5a8bf75 100644 --- a/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m +++ b/Demo/iOSDemo/JSPatchTests/JPPerformanceTest.m @@ -21,7 +21,6 @@ - (void)testJSCallJSMethodWithLargeDictionaryParam{} - (void)testJSCallJSMethodWithLargeDictionaryParamAutoConvert{} - (void)testJSCallJSMethodWithParam{} -- (void)testJSCallOCBlock{} - (void)testOCCallEmptyMethod { for (int i = 0; i < 10000; i ++) { diff --git a/Demo/iOSDemo/JSPatchTests/JSPatchTests.m b/Demo/iOSDemo/JSPatchTests/JSPatchTests.m index 63888ed8..e41e5171 100644 --- a/Demo/iOSDemo/JSPatchTests/JSPatchTests.m +++ b/Demo/iOSDemo/JSPatchTests/JSPatchTests.m @@ -88,7 +88,7 @@ - (void)testEngine { XCTAssert(obj.funcReturnBlockPassed, @"funcReturnBlockPassed"); XCTAssert(obj.funcReturnObjectBlockPassed, @"funcReturnObjectBlockPassed"); XCTAssert(obj.funcReturnObjectBlockReturnValuePassed, @"funcReturnObjectBlockReturnValuePassed"); - //XCTAssert(obj.funcReturnJSBlockPassed, @"funcReturnBlockPassed"); + XCTAssert(obj.funcReturnJSBlockPassed, @"funcReturnBlockPassed"); XCTAssert(obj.callBlockWithStringAndIntPassed, @"callBlockWithStringAndIntPassed"); XCTAssert(obj.callBlockWithStringAndIntReturnValuePassed, @"callBlockWithStringAndIntReturnValuePassed"); XCTAssert(obj.callBlockWithArrayAndViewPassed, @"callBlockWithArrayAndViewPassed"); @@ -479,14 +479,6 @@ - (void)testJSCallMallocJPCFunction }]; } -- (void)testJSCallOCBlock { - [self loadPatch:@"performanceTest"]; - JPPerformanceTest *obj = [[JPPerformanceTest alloc] init]; - [self measureBlock:^{ - [obj testJSCallOCBlock]; - }]; -} - - (void)testNewProtocol{ [self loadPatch:@"newProtocolTest"]; diff --git a/Demo/iOSDemo/JSPatchTests/performanceTest.js b/Demo/iOSDemo/JSPatchTests/performanceTest.js index 7ad7ba72..51bacc74 100644 --- a/Demo/iOSDemo/JSPatchTests/performanceTest.js +++ b/Demo/iOSDemo/JSPatchTests/performanceTest.js @@ -156,10 +156,5 @@ defineClass('JPPerformanceTest', { defineCFunction("malloc", "void *, size_t") var p = malloc(10) } - }, - - testJSCallOCBlock: function() { - self.allArgSumWithBlock(block("double, CGFloat, CGPoint, NSInteger, id", function(arg0, arg1, arg2, arg3) { - return arg0 + arg1.x + arg1.y + arg2 + arg3})); } }) diff --git a/Demo/iOSDemo/JSPatchTests/test.js b/Demo/iOSDemo/JSPatchTests/test.js index 19202f50..d439a8f8 100755 --- a/Demo/iOSDemo/JSPatchTests/test.js +++ b/Demo/iOSDemo/JSPatchTests/test.js @@ -250,6 +250,7 @@ require('JPEngine').defineStruct({ obj.setPropertySetViewPassed(obj.testView.frame().x == 10) /////Block + require('JPEngine').addExtensions(['JPBlock']); var blk = obj.funcReturnBlock(); blk("stringFromJS", 42); From 891925084bdbfb0c22387a20d891e450a5eb8896 Mon Sep 17 00:00:00 2001 From: WELCommand Date: Wed, 28 Mar 2018 13:02:03 +0800 Subject: [PATCH 7/8] add test case --- .../JSPatchDemo.xcodeproj/project.pbxproj | 10 ++++++ Demo/iOSDemo/JSPatchTests/JSPatchTests.m | 9 ++++++ Demo/iOSDemo/JSPatchTests/newBlockTest.h | 20 ++++++++++++ Demo/iOSDemo/JSPatchTests/newBlockTest.js | 7 +++++ Demo/iOSDemo/JSPatchTests/newBlockTest.m | 31 +++++++++++++++++++ 5 files changed, 77 insertions(+) create mode 100644 Demo/iOSDemo/JSPatchTests/newBlockTest.h create mode 100644 Demo/iOSDemo/JSPatchTests/newBlockTest.js create mode 100644 Demo/iOSDemo/JSPatchTests/newBlockTest.m diff --git a/Demo/iOSDemo/JSPatchDemo.xcodeproj/project.pbxproj b/Demo/iOSDemo/JSPatchDemo.xcodeproj/project.pbxproj index 7ecf48c0..c17c5af7 100644 --- a/Demo/iOSDemo/JSPatchDemo.xcodeproj/project.pbxproj +++ b/Demo/iOSDemo/JSPatchDemo.xcodeproj/project.pbxproj @@ -13,6 +13,8 @@ 2D6D12FD1B0B8CF20095A435 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2D6D12FA1B0B8CF20095A435 /* Images.xcassets */; }; 2D6D12FF1B0B8CF20095A435 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D6D12FC1B0B8CF20095A435 /* main.m */; }; 2D6D13011B0B8CFF0095A435 /* demo.js in Resources */ = {isa = PBXBuildFile; fileRef = 2D6D13001B0B8CFF0095A435 /* demo.js */; }; + 2DA3C42B206A1892005877CB /* newBlockTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DA3C42A206A1892005877CB /* newBlockTest.m */; }; + 2DA3C434206B5569005877CB /* newBlockTest.js in Resources */ = {isa = PBXBuildFile; fileRef = 2DA3C433206B5569005877CB /* newBlockTest.js */; }; 360BCF4E1D82DCFC00202977 /* JPDispatch.m in Sources */ = {isa = PBXBuildFile; fileRef = 360BCF4D1D82DCFC00202977 /* JPDispatch.m */; }; 360BCF541D82EFCD00202977 /* JPProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 360BCF531D82EFCD00202977 /* JPProtocol.m */; }; 3613C3861C6329F300E915CB /* JPEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = 3613C3611C6329F300E915CB /* JPEngine.m */; }; @@ -93,6 +95,9 @@ 2D6D12FB1B0B8CF20095A435 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 2D6D12FC1B0B8CF20095A435 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 2D6D13001B0B8CFF0095A435 /* demo.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = demo.js; sourceTree = ""; }; + 2DA3C429206A1892005877CB /* newBlockTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = newBlockTest.h; sourceTree = ""; }; + 2DA3C42A206A1892005877CB /* newBlockTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = newBlockTest.m; sourceTree = ""; }; + 2DA3C433206B5569005877CB /* newBlockTest.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = newBlockTest.js; sourceTree = ""; }; 360BCF4C1D82DCFC00202977 /* JPDispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPDispatch.h; sourceTree = ""; }; 360BCF4D1D82DCFC00202977 /* JPDispatch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JPDispatch.m; sourceTree = ""; }; 360BCF521D82EFCD00202977 /* JPProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JPProtocol.h; sourceTree = ""; }; @@ -473,6 +478,9 @@ 36CE19231CB3E709007D73AC /* JPPerformanceTest.h */, 36CE19241CB3E709007D73AC /* JPPerformanceTest.m */, 36CE19261CB3E72B007D73AC /* performanceTest.js */, + 2DA3C429206A1892005877CB /* newBlockTest.h */, + 2DA3C42A206A1892005877CB /* newBlockTest.m */, + 2DA3C433206B5569005877CB /* newBlockTest.js */, 6C72B7941C352BA80086C98D /* newProtocolTest.h */, 6C72B7951C352BA80086C98D /* newProtocolTest.m */, 6C9C0EE31C25A7C700FCAAC5 /* newProtocolTest.js */, @@ -603,6 +611,7 @@ E1B89EAE1B228818000645C2 /* multithreadTest.js in Resources */, 369492601CFEFE42003F44CA /* jsCFunctionTest.js in Resources */, 36CE19271CB3E72B007D73AC /* performanceTest.js in Resources */, + 2DA3C434206B5569005877CB /* newBlockTest.js in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -664,6 +673,7 @@ E1B89EA31B218986000645C2 /* JPInheritanceTestObjects.m in Sources */, 4F9EBFC91D50749200EC72C1 /* JPNumberTest.m in Sources */, DE94AE2B1AF246C000E461D4 /* JSPatchTests.m in Sources */, + 2DA3C42B206A1892005877CB /* newBlockTest.m in Sources */, 3694925F1CFEFE42003F44CA /* JPCFunctionTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Demo/iOSDemo/JSPatchTests/JSPatchTests.m b/Demo/iOSDemo/JSPatchTests/JSPatchTests.m index e41e5171..4af530a5 100644 --- a/Demo/iOSDemo/JSPatchTests/JSPatchTests.m +++ b/Demo/iOSDemo/JSPatchTests/JSPatchTests.m @@ -19,6 +19,7 @@ #import "JPPerformanceTest.h" #import "JPCFunctionTest.h" #import "JPNumberTest.h" +#import "newBlockTest.h" @interface JSPatchTests : XCTestCase @@ -479,6 +480,14 @@ - (void)testJSCallMallocJPCFunction }]; } +- (void)testNewBlock { + [self loadPatch:@"newBlockTest"]; + newBlockTest *obj = [[newBlockTest alloc] init]; + [obj removeJPBlock]; + [obj testJSBlockToOCCall]; + XCTAssert(obj.success, @"testJSBlockToOCCall"); +} + - (void)testNewProtocol{ [self loadPatch:@"newProtocolTest"]; diff --git a/Demo/iOSDemo/JSPatchTests/newBlockTest.h b/Demo/iOSDemo/JSPatchTests/newBlockTest.h new file mode 100644 index 00000000..183d09a2 --- /dev/null +++ b/Demo/iOSDemo/JSPatchTests/newBlockTest.h @@ -0,0 +1,20 @@ +// +// newBlockTest.h +// JSPatchTests +// +// Created by WELCommand on 2018/3/27. +// Copyright © 2018年 bang. All rights reserved. +// + +#import +#import + +@interface newBlockTest : NSObject + +@property (nonatomic, assign) BOOL success; + +- (void)removeJPBlock; + +- (void)testJSBlockToOCCall; + +@end diff --git a/Demo/iOSDemo/JSPatchTests/newBlockTest.js b/Demo/iOSDemo/JSPatchTests/newBlockTest.js new file mode 100644 index 00000000..b7b18937 --- /dev/null +++ b/Demo/iOSDemo/JSPatchTests/newBlockTest.js @@ -0,0 +1,7 @@ +defineClass("newBlockTest", { +testJSBlockToOCCall: function() { + self.performBlock(block("CGFloat, int, CGPoint, double, CGFloat, NSNumber*, NSString*, NSInteger", function(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { + return arg1 + arg2.x + arg2.y + arg3 + arg4 + arg5 + arg6.doubleValue() + arg7; + })); +} +}, {}); diff --git a/Demo/iOSDemo/JSPatchTests/newBlockTest.m b/Demo/iOSDemo/JSPatchTests/newBlockTest.m new file mode 100644 index 00000000..f34cfed2 --- /dev/null +++ b/Demo/iOSDemo/JSPatchTests/newBlockTest.m @@ -0,0 +1,31 @@ +// +// newBlockTest.m +// JSPatchTests +// +// Created by WELCommand on 2018/3/27. +// Copyright © 2018年 bang. All rights reserved. +// + +#import "newBlockTest.h" +#import +#import "JPEngine.h" + +@implementation newBlockTest + +- (void)testJSBlockToOCCall {} + + ++ (void)main:(JSContext *)context +{ + context[@"__genBlock"] = nil; +} + +- (void)removeJPBlock { + [JPEngine addExtensions:@[@"newBlockTest"]]; +} + +- (void)performBlock:(CGFloat (^)(int arg1, CGPoint arg2, double arg3, CGFloat arg4, NSNumber *arg5, NSString *arg6, NSInteger arg7))block { + _success = (block(1, (CGPoint){3.3, 3.3}, 1.1, 1.1, @(11), @"4.4", 17) == 1 + 3.3 + 3.3 + 1.1 + 1.1 + 11 + 4.4 + 17) && (block(1, (CGPoint){3.3, 3.3}, 1.1, 1.1, @(11), @"4.4", 17) == 1 + 3.3 + 3.3 + 1.1 + 1.1 + 11 + 4.4 + 17); +} + +@end From e64e5a34958e1dc31164e196bf2a108b520b8c94 Mon Sep 17 00:00:00 2001 From: WELCommand Date: Wed, 28 Mar 2018 19:31:32 +0800 Subject: [PATCH 8/8] fix (CGFloat)1.3 != 1.3 in ip4&iOS8 --- Demo/iOSDemo/JSPatchTests/newBlockTest.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Demo/iOSDemo/JSPatchTests/newBlockTest.m b/Demo/iOSDemo/JSPatchTests/newBlockTest.m index f34cfed2..928d2a66 100644 --- a/Demo/iOSDemo/JSPatchTests/newBlockTest.m +++ b/Demo/iOSDemo/JSPatchTests/newBlockTest.m @@ -25,7 +25,7 @@ - (void)removeJPBlock { } - (void)performBlock:(CGFloat (^)(int arg1, CGPoint arg2, double arg3, CGFloat arg4, NSNumber *arg5, NSString *arg6, NSInteger arg7))block { - _success = (block(1, (CGPoint){3.3, 3.3}, 1.1, 1.1, @(11), @"4.4", 17) == 1 + 3.3 + 3.3 + 1.1 + 1.1 + 11 + 4.4 + 17) && (block(1, (CGPoint){3.3, 3.3}, 1.1, 1.1, @(11), @"4.4", 17) == 1 + 3.3 + 3.3 + 1.1 + 1.1 + 11 + 4.4 + 17); + _success = (block(1, (CGPoint){3.3, 3.3}, 1.1, 1.1, @(11), @"4.4", 17) == (CGFloat)(1 + 3.3 + 3.3 + 1.1 + 1.1 + 11 + 4.4 + 17)) && (block(1, (CGPoint){3.3, 3.3}, 1.1, 1.1, @(11), @"4.4", 17) == (CGFloat)(1 + 3.3 + 3.3 + 1.1 + 1.1 + 11 + 4.4 + 17)); } @end