在《Objective-C高级编程iOS与OS X多线程和内存管理》这本书里经常有如下的Demo:
@autoreleasepool {
id __autoreleasing obj = [[NSObject alloc] init];
}
编译器模拟代码:
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_autorelease(obj);
objc_autoreleasePoolPop(pool);
那么问题来了:该模拟代码是如何得到了?
查看Stack Overflow发现有一个类似的问题:
https://stackoverflow.com/questions/33950466/how-to-translate-objective-c-code-to-c-with-arc-enabling?answertab=oldest#tab-top
但是现在是无法好使了。
尝试了如下的两个命令:
clang -x objective-c -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk -rewrite-objc -fobjc-arc -mmacosx-version-min=10.14.5 -fobjc-runtime=macosx-10.14.5 -O0 second.m
clang -x objective-c -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.2.sdk -rewrite-objc -fobjc-arc -fblocks -mmacosx-version-min=10.14.5 -fobjc-runtime=macosx-10.14.5 -O0
依然不好用。
然后在这篇文章发现如下的命令:
clang -S -fobjc-arc -emit-llvm first.m -o first2.ll
上述的代码就会转换为如下:
%3 = alloca i32, align 4
%4 = alloca i8**, align 8
%5 = alloca i8*, align 8
store i32 %0, i32* %3, align 4
store i8** %1, i8*** %4, align 8
%6 = call i8* @objc_autoreleasePoolPush() #3
%7 = load %struct._class_t*, %struct._class_t** @"OBJC_CLASSLIST_REFERENCES_$_.6", align 8
%8 = load i8*, i8** @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !9
%9 = bitcast %struct._class_t* %7 to i8*
%10 = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %9, i8* %8)
%11 = bitcast i8* %10 to %1*
%12 = load i8*, i8** @OBJC_SELECTOR_REFERENCES_.2, align 8, !invariant.load !9
%13 = bitcast %1* %11 to i8*
%14 = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %13, i8* %12)
%15 = bitcast i8* %14 to %1*
%16 = bitcast %1* %15 to i8*
%17 = call i8* @objc_autorelease(i8* %16) #3
store i8* %17, i8** %5, align 8
call void @objc_autoreleasePoolPop(i8* %6)
里面的代码跟结果代码一直,应该就是这个命令然后简化一下得到模拟代码了。
还有一个优化后的命令:
clang -O3 -S -fobjc-arc -emit-llvm first.m -o first.ll
得到的代码如下:
%3 = tail call i8* @objc_autoreleasePoolPush() #4
%4 = load i8*, i8** bitcast (%struct._class_t** @"OBJC_CLASSLIST_REFERENCES_$_.6" to i8**), align 8
%5 = load i8*, i8** @OBJC_SELECTOR_REFERENCES_, align 8, !invariant.load !9
%6 = tail call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %4, i8* %5), !clang.arc.no_objc_arc_exceptions !9
%7 = load i8*, i8** @OBJC_SELECTOR_REFERENCES_.2, align 8, !invariant.load !9
%8 = tail call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %6, i8* %7), !clang.arc.no_objc_arc_exceptions !9
call void @objc_release(i8* %8) #4, !clang.imprecise_release !9
tail call void @objc_autoreleasePoolPop(i8* %3) #4, !clang.arc.no_objc_arc_exceptions !9
翻译成模拟代码如下:
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_release(obj);
objc_autoreleasePoolPop(pool);
把objc_autorelease(obj);
优化为objc_release(obj);
这里完全是正确的!
网友评论