[
  {
    "path": ".gitignore",
    "content": "# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n## Build generated\nbuild/\nDerivedData/\n\n## Various settings\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata/\n\n## Other\n*.moved-aside\n*.xccheckout\n*.xcscmblueprint\n\n## Obj-C/Swift specific\n*.hmap\n*.ipa\n*.dSYM.zip\n*.dSYM\n\n# CocoaPods\n#\n# We recommend against adding the Pods directory to your .gitignore. However\n# you should judge for yourself, the pros and cons are mentioned at:\n# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control\n#\n# Pods/\n\n# Carthage\n#\n# Add this line if you want to avoid checking in source code from Carthage dependencies.\n# Carthage/Checkouts\n\nCarthage/Build\n\n# fastlane\n#\n# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the\n# screenshots whenever they are needed.\n# For more information about the recommended setup visit:\n# https://docs.fastlane.tools/best-practices/source-control/#source-control\n\nfastlane/report.xml\nfastlane/Preview.html\nfastlane/screenshots\nfastlane/test_output\n\n# Code Injection\n#\n# After new code Injection tools there's a generated folder /iOSInjectionProject\n# https://github.com/johnno1962/injectionforxcode\n\niOSInjectionProject/\n"
  },
  {
    "path": "BlockFile.md",
    "content": "# Block\n\n> 面试驱动技术合集（初中级iOS开发），关注仓库，及时获取更新 [Interview-series](https://github.com/miniLV/Interview-series)\n\n![](https://user-gold-cdn.xitu.io/2019/3/10/16967d7dc4bb1e67?w=1360&h=896&f=jpeg&s=158902)\n\nBlock 在 iOS 算比较常见常用且常考的了，现在面试中，要么没面试题，有面试题的，基本都会考到 block 的点。\n\n先来个面试题热热身，题目: **手撕代码 - 用Block实现两个数的求和**\n\n*(这题如果会的，block基础知识可以跳过了，直接到* Block原理探究）\n\n\n\n####  简单介绍block入门级用法\n\nBlock结构比较复杂，一般用 typedef 定义，直接调用的感觉比较简单、清晰易懂\n\n```\n//typedef block的时候有提示\ntypedef void(^MNBlock)(int);\n\n@interface ViewController ()\n\n@property (nonatomic, copy) MNBlock block;\n\n@end\n\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    \n    //直接用self.block调用\n    self.block = ^(int a) {\n        //dosomething...\n    };\n}\n```\n\n- **参数解释:**\n\n`typedef <#returnType#>(^<#name#>)(<#arguments#>);`\n\n\n![](https://user-gold-cdn.xitu.io/2019/3/6/16952561d5d28953?w=838&h=281&f=png&s=378402)\n\n\n**题目: 手撕代码 - 用Block实现两个数的求和**\n\n*日常开发中，block声明一般写的比较多，实现一般是靠Xcode自动补全提示出现的，手撕代码的情况下，等号右侧的block实现要怎么写？*\n\n声明:\n```\ntypedef int(^MNBlock)(int a, int b);\n\n@interface ViewController ()\n\n@property (nonatomic, copy) MNBlock sum;\n```\n\nVip补全功能:\n\n![](https://user-gold-cdn.xitu.io/2019/3/6/1695258327b5d40d?w=338&h=41&f=png&s=4862)\n\n纸上按Enter没用啊兄弟！看来还是需要了解一下Block右边的东西~\n\n先在 Xcode上按下 Enter，了解下再撕\n![](https://user-gold-cdn.xitu.io/2019/3/6/16952597e5c08f81?w=1251&h=80&f=png&s=13055)\n\n```\n^int(int a, int b) {\n    //Control reaches end of non-void block    \n    因为返回值是int类型，所以这里需要返回\n}\n```\n\n![](https://user-gold-cdn.xitu.io/2019/3/6/169526002706cf63?w=926&h=516&f=png&s=681574)\n\n\n```\nint(^Sum)(int, int) = ^(int a, int b){\n    return a + b;\n};\nint result = Sum(5, 10);\n```\n\n\n![](https://user-gold-cdn.xitu.io/2019/3/6/16952676c9db9951?w=1030&h=285&f=png&s=504069)\n\n\n\n#### Block的坑出现！新手可能会写错的地方\n\n1.声明出错 - `void ^(testBlock)`\n\n![](https://user-gold-cdn.xitu.io/2019/3/6/169526924a0616d0?w=713&h=91&f=png&s=14053)\n\n\n修正版：\n\n```\nvoid (^testBlock)() = ^{\n    \n};\n```\nblock的声明，^ 和 blockName 都是在小括号里面！！\n\n\n2.block各种实现的参数问题\n\n声明`typedef int(^MNBlock)(int, int);`\n\n\n![](https://user-gold-cdn.xitu.io/2019/3/6/169526c0aac25322?w=773&h=180&f=png&s=39960)\n\n```\n    self.sum = ^int(int a, int b) {\n        return a + b;\n    };\n```\n\n这里要注意，block声明里面只有参数类型，没有实际参数的话，Xcode提示也只有参数，这里涉及到形参和实参的问题\n\n声明是形参，可以不写参数，但是使用的时候，必须有实际参数，才可以进行使用，所以这里需要实参，可以在 `^int(int , int)` 中手动添加实参`^int(int a, int b)`，就可以让a 和 b 参与运算\n\n小tips：实际开发中，建议声明的时候，如果需要带参数，最好形参也声明下，这样使用Xcode提示的时候，会把参数带进去，方便得多~(踩过坑的自然懂！)\n\n\n\n\n3. 省略void导致看不懂block结构的 *(正常是两个void导致局面混乱)*\n\n```\n//声明\ntypedef void(^MNBlock)(void);\n\n//实现\nself.sum = ^{\n    //dosomething...\n};\n\n```\n\n这种情况下，能知道怎么省略的，声明里两个void，能知道怎么对应的吗？\n\n这个其实比较简单，block不管声明 or 实现，最后一个小括号，里面都是参数，而参数是可以省略的！\n\n而为了把声明的两个void区分开，返回值 or 参数区分开，其实就ok了\n\n参数非void的例子\n```\n//声明非void的参数\ntypedef void(^MNBlock)(int a);\n\n//实现就必须带参数，不可省略！\nself.sum = ^(int a) {\n    \n}\n```\n\n参数void的例子 ==> 参数可以省略\n```\ntypedef int(^MNBlock)(void);\n\nself.sum = ^{\n    //声明的返回值类型是int，所以一定要return；\n    return 5;\n};\n```\n\n其实-返回值是void的，也可以不省略\n```\ntypedef void(^MNBlock)(void);\n\n//实现的返回值不省略\nself.sum = ^void () {\n    \n};\n\n```\n\n参数是void的省略:\n```\ntypedef int(^MNBlock)();\n\n//实现里面，没有参数，就可以不写()\nself.sum = ^int{\n    return 5;\n}\n```\n\n**注意！！ 声明里面的返回值void是不可以省略的！！**\n\n![](https://user-gold-cdn.xitu.io/2019/3/7/16956f058259665d?w=403&h=88&f=png&s=13283)\n\n\n4. 小箭头^混乱的问题,到底放小括号内还是小括号外\n\n声明是 `int(^MNBlock)(int a , int b)`\n\n实现是 `^int(int a, int b)`\n\n注意，这里箭头之后的，不管是多写() 还是少写，都会出错\n\n![](https://user-gold-cdn.xitu.io/2019/3/6/1695278e3061b90d?w=1020&h=103&f=png&s=23020)\n\n![](https://user-gold-cdn.xitu.io/2019/3/6/16952795f17d3bb9?w=1038&h=191&f=png&s=32246)\n\n> 所以这里还不能死记，比如不管声明还是实现,死记 (^ xxx) 是没问题的 or 死记 ^…… xxx 不加括号是没问题的,在这里都行不通，只能靠脑记了\n\n这时候，就需要用到巧记了！\n\n*^ 和小括号组合的，一共有三种情况*\n\n- 一种是声明的，`void(^MNBlock)`\n- 一种是实现的，`^int(int a,)`\n- 还一种 `^(int a)`\n\n兄弟，看到这你还不乱吗！！\n\n\n![](https://user-gold-cdn.xitu.io/2019/3/7/16956e251f2c8ce3?w=222&h=227&f=jpeg&s=6734)\n\n怎么记看这里，\n- 手写分为两个部分，block等号左边 or 等号右边的，左边为声明，右边为实现区分开\n- 声明记住：^后面跟blockName，他们需要包起来！ (^blockName),只有声明会用到blockName，先记住一点，如果有blockName，要和^一起，用小括号包起来\n- 实现又分为两种：\n    - `^int`:^后面跟的是返回值类型\n      - ^ 直接跟类型，不用加\"( )\" ==> `^int`\n    - `^(int a)`:^后面直接跟参数 *(返回值是void)*。\n        - 参数都是要用\"( )\"包起来的，如果^后面跟参数，就得用\"( )\" ==> `^(int a)`,\n        - 实现里，肯定有实际参数，这时候，参数类型和实参，就得用( )包起来\n\n### ^与小括号纠缠的总结\n\n- ^ 后面仅跟类型，不需要小括号，==> `^int`\n- ^ 后面跟参数，参数需要小括号 ==> `^(int a)`\n- ^ 后面跟block名称，^和blockName需要小括号 ==> `void (^MNBlock)`\n\n<br>\n\n\n\n## Block原理探究 \n\n```objective-c\nvoid (^MNBlock)(void) = ^(void){\n    NSLog(@\"this is a Block~ rua~\");\n};\nMNBlock();\n```\n\n\n\n 使用 `xcrun  -sdk  iphoneos  clang  -arch  arm64  -rewrite-objc main.m` 转成 C++ 代码, 查看底层结构\n\n\n\n```objective-c\n//对应上面的 MNBlock声明\nvoid (*MNBlock)(void) = (&__main_block_impl_0(__main_block_func_0,\n                                                      &__main_block_desc_0_DATA));\n        \n//对应上面的 MNblock() 调用\nMNBlock->FuncPtr(MNBlock);\n```\n\n\n\n```objective-c\n//block声明调用的 - __main_block_impl_0\nstruct __main_block_impl_0 {\n  //结构体内的参数\n  struct __block_impl impl;\n  struct __main_block_desc_0* Desc;\n  \n  //c++中的构造函数，类似于 OC 的 init 方法，返回一个结构体对象\n  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {\n    impl.isa = &_NSConcreteStackBlock;\n    impl.Flags = flags;\n    impl.FuncPtr = fp;\n    Desc = desc;\n  }\n};\n\nstruct __block_impl {\n  void *isa;\n  int Flags;\n  int Reserved;\n  void *FuncPtr;\n};\n\nstatic struct __main_block_desc_0 {\n  size_t reserved;\n  size_t Block_size;\n}\n```\n\n\n\n这里的block封装的函数调用解释`MNBlock->FuncPtr(MNBlock);`\n\nMNBlock 其实内部结构是 `__main_block_impl_0`，\n\n```\nstruct __main_block_impl_0 {\n\n  //函数调用地址在这个结构体内\n  struct __block_impl impl;\n\n  struct __main_block_desc_0* Desc;\n  }\n  \n  struct __block_impl {\n  void *isa;\n  int Flags;\n  int Reserved;\n  //函数调用地址在这里\n  void *FuncPtr;\n};\n```\n\n内部只有两个参数，一个`impl`，一个`Desc`，而函数的调用地址 - `FuncPtr`是再`impl`中的，为什么这里能直接这样写呢？\n\n> 因为，__main_block_impl_0 结构的地址和他的第一个成员一样，第一个成员的地址是__block_impl，所以__main_block_impl_0 和 __block_impl 的地址其实是同一个，通过格式强制转换，将 main_block_impl_0 转成 block_impl 就可以直接拿到他内部的 FuncPtr 函数地址，然后进行调用！\n\n\n\n![image-20190307213258239](https://user-gold-cdn.xitu.io/2019/3/8/1695da89a57989cf?w=1489&h=1080&f=jpeg&s=303137)\n\n\n\n- 可见- block本质上是OC对象，内部有一个isa指针\n\n- block是封装了函数调用已经函数调用的oc对象\n\n  \n\n### Block面试题抛砖引玉~\n\n**开胃菜先来一下，以下结果输出什么**\n\n```\nint a = 10;\nvoid (^MNBlock)(void) = ^{\n    NSLog(@\"a = %d\",a);\n};\na += 20;\n\nMNBlock();\n```\n\n\n\n调用 `MNBlock();` 之前，a 已经 + 20了，输出30？ 太天真了兄弟，这里涉及到capture的概念，即变量捕获\n\n\n\n### Block捕获变量(capture)\n\n捕获：Block内部会新增一个成员，来存储传进来的变量\n\n\n\n![image-20190307214010613](https://user-gold-cdn.xitu.io/2019/3/8/1695da89a686ef14?w=1988&h=586&f=jpeg&s=141880)\n\nblock 内部直接捕获了穿进去的这个变量a(10)\n\n![image-20190307214351958](/Users/liangyuhang/Library/Application Support/typora-user-images/image-20190307214351958.png)\n\n\n\n创建block的时候，已经将变量a=10 捕获到 block内部，之后再怎么修改，不会影响block 内部的  a\n\n\n\n**auto 和 static的区别**:以下会输出什么~ \n\n```\nstatic int b = 10;\nvoid (^MNBlock)(void) = ^{\n    NSLog(@\"a = %d, b = %d\",a,b);\n};\na = 20;\nb = 20;\n\nMNBlock();\n```\n\n输出\n\n```\n2019-03-07 21:49:49 Block-Demo a = 10, b = 20\n```\n\n\n\nwhy?\n\n查看原因:\n\n```\nauto int a = 10;\nstatic int b = 10;\nvoid (*MNBlock)(void) = (&__main_block_impl_0(__main_block_func_0,\n                                              &__main_block_desc_0_DATA,\n                                              a,\n                                              &b));\n```\n\n\n\n发现：两种变量，都有捕获到block内部。\n\na 是auto变量，走的是值传递，\n\nb 是 static 变量，走的是地址传递，所以会影响(指针指向同一块内存，修改的等于是同个对象)\n\n\n\n**总结**\n\n- 只有局部变量才需要捕获，\n- 全局变量不需要捕获，因为在哪都可以访问\n- 需不需要捕获，其实主要是看作用域问题\n- auto局部变量 ==>值传递->因为会销毁\n- static局部练练==>不会销毁==>所以地址传递\n\n\n\n**看图就行~**\n\n![image-20190307220857223](https://user-gold-cdn.xitu.io/2019/3/8/1695da89a7997ead?w=1566&h=1012&f=jpeg&s=247371)\n\n\n\n**进阶考题 - self 会被捕获到 block 内部吗**\n\n```\nvoid (^MNBlock)(void) = ^{\n    NSLog(@\"p = %p\",self);\n};\n```\n\n\n\n模拟看官作答：不会，因为整个类里，都能调用self，应该是全局的，全局变量不会捕获到block中\n\n\n\n哈哈哈哈！中计了！其实 self 是参数(局部变量)\n\n\n\n```\nstruct __MNDemo__test_block_impl_0 {\n  struct __block_impl impl;\n  struct __MNDemo__test_block_desc_0* Desc;\n  MNDemo *self; ==> 捕捉到了兄弟\n  }\n```\n\n\n\n> 解释原因：\n>\n> - 每个OC函数，其实默认有两个参数，一个self，一个_cmd，只是他们倆兄弟默认是隐藏的\n> - 而由于他们是参数，所以是局部变量，局部变量就要被 block 捕获\n> - `- (void)test(self, SEL _cmd){XXX}` 默认的OC方法里面其实有这两个隐藏的参数！所以上题的答案，self是会被block捕获的！**（能听懂掌声！）**\n\n\n\n**进进阶考题 - 成员变量_name 会被捕获到 block 内部吗**\n\n\n\n```\nvoid (^MNBlock)(void) = ^{\n    NSLog(@\"==%@\",_name);\n};\n```\n\n模拟看官作答：呵呵，老子都中了这么多次技了，这题学会了！！ 因为_name是成员变量，全局的，也没有self，所以不需要捕获整个类就都可以随便访问它！\n\n\n\n哎，兄弟，还是太年轻了！！\n\n```\nvoid (^MNBlock)(void) = ^{\n    NSLog(@\"==%@\",self->_name);\n};\n```\n\n看图说话，不多bb, *（能听懂掌声！）*\n\n\n\n## Block的类型\n\n- `__NSGlobalBlock__`\n\n- `__NSStackBlock__`\n\n- `__NSMallocBlock__`\n\n\n\nMRC环境下\n\n```\nvoid (^global)() = ^{\n    NSLog(@\"globalValue = %d\",globalValue);\n};\n\nvoid (^autoBlock)() = ^{\n    NSLog(@\"this is a Block~ rua~ = %d\",a);\n};\n\nvoid (^copyAuto)() = [autoBlock copy];\n\n--------------------------------------------\nprint class\n2019-03-08 17:40:43 Block-Demo\n\n global class = __NSGlobalBlock__ \n autoBlock class = __NSStackBlock__ \n copyAuto = __NSMallocBlock__\n```\n\n\n\n总结:\n\n![image-20190308174640436](/Users/liangyuhang/Library/Application Support/typora-user-images/image-20190308174640436.png)\n\n\n![](https://user-gold-cdn.xitu.io/2019/3/8/1695daddd8d9af3c?w=1482&h=920&f=png&s=1979727)\n\n\n\n栈上的内存系统会自动回收\n\n- 栈空间的block 不会对 对象进行强引用\n- 堆空间的block 可能会对对象产生强引用：\n  - 如果是weak指针，不会强引用\n  - 如果是strong指针，会强引用\n\n堆上的内存是由程序员控制，所以一般将block 拷贝到堆上，让程序员控制他与内部变量的生命周期\n\n\n\n题目：以下输出的顺序是什么(ARC环境下)\n\n```\n@implementation MNPerson\n\n- (void)dealloc{\n    NSLog(@\"MNPerson - dealloc\");\n}\n\n@end\n\n--------------------------------------\n\nMNPerson *person = [[MNPerson alloc]init];\n\n__weak MNPerson *weakPerson = person;\n\ndispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\n    \n    NSLog(@\"1-----%@\",person);\n    \n    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\n        NSLog(@\"2------%@\",weakPerson);\n    });\n    \n});\n\nNSLog(@\"touchesBegan\");\n```\n\n\n\n输出结果\n\n```\n2019-03-08 22:38:59.038452+0800 touchesBegan\n2019-03-08 22:39:00.056746+0800 1-----<MNPerson: 0x604000207840>\n2019-03-08 22:39:00.057891+0800 MNPerson - dealloc\n2019-03-08 22:39:02.058011+0800 2-----(null)\n```\n\n解释：\n\n1. gcd的block会自动对auto变量进行copy操作\n\n2. block内部对 auto 变量的强弱引用，取决于指针类型\n\n3. 1 中的auto变量是 person，没声明默认对象是 strong 类型，所以 gcd1 会对 person进行 1s的强引用\n\n4. gcd2 中的变量是 weakPerson，看到是__wesk指针，所以block内部不会对其产生强引用\n\n5. 随后，gcd1 对 person进行1s的强引用之后，gcd1 的block销毁，person对象销毁，打印MNPerson dealloc\n\n6. 最终，2s过后打印 2——weakPerson，因为person对象在gcd1 block结束之后，释放掉了，所以此时person是空，因为是weak指针，对象是null不会crash，最终打印null\n\n\n\n#### 对象类型的auto变量\n\n- 当 block 内部访问了对象类型的auto变量时\t\n  - 如果block在展示，不会对 auto 变量产生强引用\n  - 如果 block 被 拷贝到堆上\n    - 会调用 block 内部的 copy 函数\n    - copy 函数内部会调用 _Block_object_assign 函数\n    - _Block_object_assign 函数会根据auto变量的修饰符 *( strong、 weak、unsafe_unretained )* 做出对应的操作，看对内部auto变量进行强引用还是弱引用(类似于 retain)\n  - 如果 block 从 堆上移除\n    - 会调用 block 内部的 dispose 函数\n    - dispose函数内部会调用_Block_object_dispose 函数\n    - _Block_object_dispose 类似于 release，会对auto变量进行自动释放(当引用计数器=0的时候 )\n\n![image-20190308173027757](/Users/liangyuhang/Library/Application%20Support/typora-user-images/image-20190308173027757.png)\n\n\n\n#### block中的copy\n\n- 在ARC环境下，编译器会根据情况，自动将栈上的block拷贝到堆上，比如以下几种情况\n  - block 作为函数返回值的时候\n  - 将block复制给__strong指针的时候\n  - block作为Cocoa API中方法名含有usingBlock的方法参数事\n    - 比如：`[array enumerateObjectsUsingBlock:XXX]`\n\n\n\n### __block 修饰符的使用\n\n\n\n题目：以下代码的是否编译通过，可以的话输出结果是什么\n\n```\nint a = 10;\nvoid (^block)() = ^{\n    a = 20;\n    NSLog(@\"a = %d\",a);\n};\n```\n\n\n\n结果如下：\n\n![image-20190308225448279](https://user-gold-cdn.xitu.io/2019/3/8/1695dee6803c470f?w=1770&h=280&f=jpeg&s=75077)\n\n*思考：无法编译，为啥呢？编译的时候，block应该是会把auto变量捕获进去的，那block结构中应该有a才对啊*\n\n\n\n```\n//main函数\nint main(int argc, const char * argv[]) {\n    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; \n\n        int a = 10;\n        void (*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));\n\n    }\n    return 0;\n}\n\n//block执行地址\n  static void __main_block_func_0(struct __main_block_impl_0 *__cself) {\n  int a = __cself->a; // bound by copy\n  NSLog((NSString *)&__NSConstantStringImpl__var_folders_kh_0rp73c0s2mvfp5gjf25j5y6h0000gn_T_main_1a12fa_mi_0,a);}\n```\n\n\n\nblock执行的时候，内部是 `__main_block_func_0` 函数，而a的声明，是在`main`函数，两个函数相互独立，对于他们来说，a都是一个局部变量，而且两个函数中都对a初始化，两个函数的中a不是同一个，那怎么可以在 执行函数中，修改main函数中的局部变量呢，所以编译报错！\n\n\n\n如何改？\n\n\n\n- **方案一：使用static**\n\n```\nstatic int a = 10;\nvoid (^block)() = ^{\n    a = 20;\n    NSLog(@\"a = %d\",a);\n};\n```\n\n\n\n因为static修饰的auto变量，最终在block中进行的不是值传递，而是地址传递，措意执行函数中的a 和 main 函数中的a，是同一个地址 ==> 等于同一个a，所以可以修改，输出20\n\n\n\n但是使用static，就会变成静态变量，永远在内存中\n\n\n\n- **方案二： 使用__blcok**\n\n```\n__block auto int a = 10;\nvoid (^block)() = ^{\n    a = 20;\n    NSLog(@\"a = %d\",a);\n};\n```\n\n\n\n```\nstruct __main_block_impl_0 {\n  struct __block_impl impl;\n  struct __main_block_desc_0* Desc;\n  __Block_byref_a_0 *a; // by ref ==> auto的话，是int a，__block，变成对象了\n}\n```\n\n\n\n```\nstruct __Block_byref_a_0 {\n  void *__isa;\n__Block_byref_a_0 *__forwarding;==> 指向自己的结构体\n int __flags;\n int __size;\n int a; ==> 10在这里\n};\n```\n\na = 20;最终转成 `(a->__forwarding->a) = 20;`\n\n> 解释下：__forwarding  是指向结构体本身的指针，等价于a本身，其实就是通过a的结构体指针，拿到里面的成员a，再对他赋值\n>\n> 指针传递，所以可以修改 auto 变量，通过block，间接引用 auto 变量\n\n\n\n![image-20190309205908169](https://user-gold-cdn.xitu.io/2019/3/9/16962f6575523772?w=1526&h=978&f=jpeg&s=287383)\n\n\n\n#### __block的内存管理\n\n- 当 block 在栈上的时候，不会对内部的__block 变量产生强硬有\n- 当 block 从栈上被 copy 到堆上的时候\n  - 会调用block内部的copy函数\n  - copy函数内部会调用_Block_object_assign 函数\n  - _Block_object_assign 函数会对 __block 变量进行一次 retain操作，产生强引用\n\n\n\n抄图分析 :\n\n![image-20190309210956453](https://user-gold-cdn.xitu.io/2019/3/9/16962f6581a28a56?w=832&h=400&f=jpeg&s=27226)\n\n![image-20190309211009229](https://user-gold-cdn.xitu.io/2019/3/9/16962f657a06fcdf?w=954&h=394&f=jpeg&s=28143)\n\n\n\n- 当block从堆中移除时\n  - 会调用 block 内部的 dispose 函数\n  - dispose内部会调用_Block_object_dispose函数\n  - _Block_object_dispose函数会对`__block`变量进行一次release操作，如果retainCount为0，自动释放该__block变量\n\n\n\n![image-20190309211246277](https://user-gold-cdn.xitu.io/2019/3/9/16962f6579f78ec5?w=754&h=388&f=jpeg&s=20257)\n\n![image-20190309211257030](https://user-gold-cdn.xitu.io/2019/3/9/16962f657a5060f1?w=1018&h=438&f=jpeg&s=41360)\n\n**总结：**\n\n- block在栈上的时候，不会对内部的变量产生强引用\n- 当block从栈上 copy 到堆上的时候，内部都会调用 __Block_object_assign\n  - 如果是`__block`修饰的变量，会__block修饰的对象产生强引用\n  - 如果是普通auto变量，看修饰的指针类型是strong 还是 weak(unsafe_unretained)\n    - strong修饰的，block就会对内部的auto变量产生强引用\n    - weak修饰的，block就不会对内部的auto变量产生强引用\n  - 特别注意！上述条件仅在ARC环境下生效，如果是MRC环境下，block不会对内部auto变量产生强引用！**(MRC下不会进行retain操作)**\n- 当block从堆上移除的时候，内部会调用`__Block_object_dispose `函数，相当于对`block`内部所持有的对象进行移除release操作，如果retainCount为0，自动释放该__block变量\n\n\n\n#### __block中的 _ forwarding 指针\n\n内存拷贝的时候，如果block从栈被copy到堆上，肯定也希望内部的变量一起存储到堆上(让变量的生命周期可控，才不会被回收)\n\n\n\n加入变量a在栈上，在栈上的指针，指向堆上的 block，堆上的block的 forwarding指向他自己，就可以保证，修改&获取的变量，都是堆上的变量\n\n![image-20190309213120820](https://user-gold-cdn.xitu.io/2019/3/9/16962f657a64e5e6?w=1404&h=1046&f=jpeg&s=83580)\n\n最终，__block指向的变量，是指向堆上的\n\n\n\n#### __block 修饰的类型\n\n\n\n```\n@implementation MNObject\n\n- (void)dealloc{\n    NSLog(@\"MNObject - dealloc\");\n}\n\n@end\n\n\n--------------------------------------------\n\ntypedef void (^MNBlock)();\n\nMNBlock block;\n{\n    MNObject *obj = [[MNObject alloc]init];\n    __block __weak MNObject *weakObj = obj;\n    \n    block = ^{\n        NSLog(@\"----------%p\",weakObj);\n    };\n}\nblock();\n\n```\n\n\n\n问，上述代码的输出顺序是？\n\n```\n2019-03-09 21:57:56.673296+0800 Block-Demo[72692:8183596] MNObject - dealloc\n2019-03-09 21:57:56.673520+0800 Block-Demo[72692:8183596] ----------0x0\n```\n\n\n\n解释：ARC下\n\n![image-20190309220353476](https://user-gold-cdn.xitu.io/2019/3/9/16962f65b2fe9473?w=1444&h=922&f=jpeg&s=274783)\n\n\n\n上述代码，block 持有的是 weakObj，weak指针，所以block内部的__block结构体，对他内部持有的person不强引用！所以出了 小括号后，person没有被强引用，生命gg，先dealloc，输出`dealloc`，之后进行block调用，打印 ---------\n\n\n\n**特别注意，上述逻辑进在ARC下，如果在MRC下，中间结构体对象，不会对person 进行retain操作! 即便 person 是强指针修饰，也不会对内部的person对象进行强引用！**\n\n\n\nMRC环境下\n\n```\nMNBlock block;\n{\n    MNObject *obj = [[MNObject alloc]init];\n    block = [^{\n        NSLog(@\"----------%p\",obj);\n    }copy];\n    \n    [obj release];\n}\nblock();\n\n[block release];\n\n--------------------\n输出:\n2019-03-09 21:59:56.673296+0800 Block-Demo[72692:8183596] MNObject - dealloc\n2019-03-09 21:59:56.673520+0800 Block-Demo[72692:8183596] ----------0x0\n```\n\n\n\n上述代码，obj 是 __strong 修饰，但是并没有被 block 强引用！可见MRC环境下，__修饰的对象，生成的中间block对象不会对 auto变量产生强引用。\n\n\n\n### Block的循环应用问题\n\n传送门：[ 实际开发中-Block导致循环引用的问题(ARC环境下)](https://www.jianshu.com/p/fc2f4d207d25)\n\n\n\n**考题：MRC 下，block的循环引用如何解决呢？**\n\n\n\n- **方案1：unsafe_unretained**\n\nMRC下，没有__weak，所以只能用_unsafe_unretained指针，原理和 weak 一样(ARC环境下不推荐使用，可能导致野指针，推荐使用weak)\n\n```\n__unsafe_unretained MNObject *weakSelf = self;\nself.block = [^{\n    NSLog(@\"----------%p\",weakSelf);\n}copy];\n```\n\n\n\n- **方案2： __block**\n\n```\n__block self;\nself.block = [^{\n    NSLog(@\"----------%p\",self);\n}copy];\n```\n\n\n\nwhy? 上面关于 __block的总结 \n\n> 特别注意！上述条件仅在ARC环境下生效，如果是MRC环境下，block不会对内部auto变量产生强引用！(MRC下不会进行retain操作)\n\n\n\n![image-20190309224535679](https://user-gold-cdn.xitu.io/2019/3/9/16962f914228a686?w=1374&h=940&f=jpeg&s=262830)\n\n\n\n- **方案3: 手动在block函数内将对象制空，并且必须手动保证block调用**\n\n```\nMNObject *obj = [[MNObject alloc]init];\n__unsafe_unretained MNObject *weakObj = obj;\nobj.block = [^{\n    NSLog(@\"----------%p\",obj);\n    obj = nil;\n}copy];\n\nobj.block();\n```\n\n![image-20190309225056495](https://user-gold-cdn.xitu.io/2019/3/9/16962f65bf4c0f7f?w=1550&h=584&f=jpeg&s=175229)\n\n\n\n但是这个一定要注意，block必须调用，因为对象指针的清空操作，是写在block函数中的，如果没调用block，循环引用问题还是会存在，所以不推荐使用。\n\n\n\n实际开发中，循环引用的检测工具推荐，facebook开源的 [FBRetainCycleDetector](https://github.com/facebook/FBRetainCycleDetector)，用过的都说好~\n\n\n\n---\n\n老实说，block其实非常难，能考得特别深，本文也只是简单探究&总结下中级iOS常见的block考题，以及对Block底层的初步探究，如果是像我所在的三线城市，去面试那种非一线公司的话，如果能掌握本文，可能block相关的题目能答个八九不离十吧！*(可能题目会变换组合，但是万变不离其宗)*\n\n\n\nblock的文章其实很多，但是如果要真的深入理解，还是得动手，这里推荐初中级iOSer可以跟着本文的思路，一步一步跟着探究试试，本文只是起个抛砖引玉的作用\n\n<br>\n\n---\n\n<br>\n\n\n\n友情演出:[小马哥MJ](https://github.com/CoderMJLee)\n\n\n*参考资料*\n\n[实际开发中-Block导致循环引用的问题(ARC环境下)](https://www.jianshu.com/p/fc2f4d207d25)\n\n[招聘一个靠谱的 iOS](https://blog.sunnyxx.com/2015/07/04/ios-interview/)\n\n[ChenYilong/iOSInterviewQuestions](https://github.com/ChenYilong/iOSInterviewQuestions/blob/master/01%E3%80%8A%E6%8B%9B%E8%81%98%E4%B8%80%E4%B8%AA%E9%9D%A0%E8%B0%B1%E7%9A%84iOS%E3%80%8B%E9%9D%A2%E8%AF%95%E9%A2%98%E5%8F%82%E8%80%83%E7%AD%94%E6%A1%88/%E3%80%8A%E6%8B%9B%E8%81%98%E4%B8%80%E4%B8%AA%E9%9D%A0%E8%B0%B1%E7%9A%84iOS%E3%80%8B%E9%9D%A2%E8%AF%95%E9%A2%98%E5%8F%82%E8%80%83%E7%AD%94%E6%A1%88%EF%BC%88%E4%B8%8B%EF%BC%89.md#45-addobserverforkeypathoptionscontext%E5%90%84%E4%B8%AA%E5%8F%82%E6%95%B0%E7%9A%84%E4%BD%9C%E7%94%A8%E5%88%86%E5%88%AB%E6%98%AF%E4%BB%80%E4%B9%88observer%E4%B8%AD%E9%9C%80%E8%A6%81%E5%AE%9E%E7%8E%B0%E5%93%AA%E4%B8%AA%E6%96%B9%E6%B3%95%E6%89%8D%E8%83%BD%E8%8E%B7%E5%BE%97kvo%E5%9B%9E%E8%B0%83)"
  },
  {
    "path": "InterView-obj-isa-class/InterView-obj-isa-class/NSObject+MNTest.h",
    "content": "//\n//  NSObject+MNTest.h\n//  InterView-obj-isa-class\n//\n//  Created by 梁宇航 on 2019/1/20.\n//  Copyright © 2019年 梁宇航. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface NSObject (MNTest)\n\n+ (void)checkSuperclass;\n\n@end\n"
  },
  {
    "path": "InterView-obj-isa-class/InterView-obj-isa-class/NSObject+MNTest.m",
    "content": "//\n//  NSObject+MNTest.m\n//  InterView-obj-isa-class\n//\n//  Created by 梁宇航 on 2019/1/20.\n//  Copyright © 2019年 梁宇航. All rights reserved.\n//\n\n#import \"NSObject+MNTest.h\"\n\n@implementation NSObject (MNTest)\n\n//+ (void)checkSuperclass{\n//    NSLog(@\"+NSObject checkSuperclass - %p\",self);\n//}\n\n- (void)checkSuperclass{\n    NSLog(@\"-NSObject checkSuperclass - %p\",self);\n}\n\n@end\n"
  },
  {
    "path": "InterView-obj-isa-class/InterView-obj-isa-class/main.m",
    "content": "//\n//  main.m\n//  InterView-obj-isa-class\n//\n//  Created by 梁宇航 on 2019/1/20.\n//  Copyright © 2019年 梁宇航. All rights reserved.\n//\n\n#import <objc/runtime.h>\n#import <malloc/malloc.h>\n#import \"NSObject+MNTest.h\"\n\n@interface MNSuperclass : NSObject\n\n- (void)superclassInstanceMethod;\n+ (void)superClassMethod;\n\n@end\n\n@implementation MNSuperclass\n\n- (void)superclassInstanceMethod{\n    NSLog(@\"superclass-InstanceMethod - %p\",self);\n}\n\n+ (void)superClassMethod{\n    NSLog(@\"+ superClass-classMethod- %p\",self);\n}\n\n@end\n\n@interface MNSubclass : MNSuperclass\n\n- (void)subclassInstanceMethod;\n- (void)compareSelfWithSuperclass;\n@end\n\n@implementation MNSubclass\n\n- (void)subclassInstanceMethod{\n    NSLog(@\"subclassInstanceMethod- %p\",self);\n    \n}\n\n- (void)compareSelfWithSuperclass{\n    NSLog(@\"self class = %@\",[self class]);\n    NSLog(@\"super class = %@\",[super class]);\n}\n\n@end\n\nint main(int argc, char * argv[]) {\n    @autoreleasepool\n    {\n        MNSubclass *subclass = [[MNSubclass alloc]init];\n        [subclass superclassInstanceMethod];\n        NSLog(@\"subclass = %p, MNSubclass = %p\",subclass,[MNSubclass class]);\n        \n        [MNSubclass superClassMethod];\n        \n        //检验 - root-meta-class的superclass 是否指向 root-class\n        [MNSubclass checkSuperclass];\n        NSLog(@\"MNSubclass = %p\",[MNSubclass class]);\n        \n        //回答 - [self class] && [super class] 的答案\n        [subclass compareSelfWithSuperclass];\n        \n    }\n    \n    return 0;\n}\n\n\n"
  },
  {
    "path": "InterView-obj-isa-class/InterView-obj-isa-class.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 50;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tA793EB6421F4CECA003661CD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = A793EB6321F4CECA003661CD /* main.m */; };\n\t\tA793EB6C21F4CEDF003661CD /* NSObject+MNTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A793EB6A21F4CEDF003661CD /* NSObject+MNTest.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\tA793EB5E21F4CECA003661CD /* CopyFiles */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = /usr/share/man/man1/;\n\t\t\tdstSubfolderSpec = 0;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 1;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\tA793EB6021F4CECA003661CD /* InterView-obj-isa-class */ = {isa = PBXFileReference; explicitFileType = \"compiled.mach-o.executable\"; includeInIndex = 0; path = \"InterView-obj-isa-class\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tA793EB6321F4CECA003661CD /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\tA793EB6A21F4CEDF003661CD /* NSObject+MNTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"NSObject+MNTest.m\"; sourceTree = \"<group>\"; };\n\t\tA793EB6B21F4CEDF003661CD /* NSObject+MNTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"NSObject+MNTest.h\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tA793EB5D21F4CECA003661CD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tA793EB5721F4CECA003661CD = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA793EB6221F4CECA003661CD /* InterView-obj-isa-class */,\n\t\t\t\tA793EB6121F4CECA003661CD /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA793EB6121F4CECA003661CD /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA793EB6021F4CECA003661CD /* InterView-obj-isa-class */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tA793EB6221F4CECA003661CD /* InterView-obj-isa-class */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tA793EB6B21F4CEDF003661CD /* NSObject+MNTest.h */,\n\t\t\t\tA793EB6A21F4CEDF003661CD /* NSObject+MNTest.m */,\n\t\t\t\tA793EB6321F4CECA003661CD /* main.m */,\n\t\t\t);\n\t\t\tpath = \"InterView-obj-isa-class\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tA793EB5F21F4CECA003661CD /* InterView-obj-isa-class */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = A793EB6721F4CECA003661CD /* Build configuration list for PBXNativeTarget \"InterView-obj-isa-class\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tA793EB5C21F4CECA003661CD /* Sources */,\n\t\t\t\tA793EB5D21F4CECA003661CD /* Frameworks */,\n\t\t\t\tA793EB5E21F4CECA003661CD /* CopyFiles */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"InterView-obj-isa-class\";\n\t\t\tproductName = \"InterView-obj-isa-class\";\n\t\t\tproductReference = A793EB6021F4CECA003661CD /* InterView-obj-isa-class */;\n\t\t\tproductType = \"com.apple.product-type.tool\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tA793EB5821F4CECA003661CD /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 0930;\n\t\t\t\tORGANIZATIONNAME = \"梁宇航\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tA793EB5F21F4CECA003661CD = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.3;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = A793EB5B21F4CECA003661CD /* Build configuration list for PBXProject \"InterView-obj-isa-class\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t);\n\t\t\tmainGroup = A793EB5721F4CECA003661CD;\n\t\t\tproductRefGroup = A793EB6121F4CECA003661CD /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tA793EB5F21F4CECA003661CD /* InterView-obj-isa-class */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tA793EB5C21F4CECA003661CD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tA793EB6C21F4CEDF003661CD /* NSObject+MNTest.m in Sources */,\n\t\t\t\tA793EB6421F4CECA003661CD /* main.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\tA793EB6521F4CECA003661CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.13;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tA793EB6621F4CECA003661CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.13;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tA793EB6821F4CECA003661CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tA793EB6921F4CECA003661CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tA793EB5B21F4CECA003661CD /* Build configuration list for PBXProject \"InterView-obj-isa-class\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tA793EB6521F4CECA003661CD /* Debug */,\n\t\t\t\tA793EB6621F4CECA003661CD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tA793EB6721F4CECA003661CD /* Build configuration list for PBXNativeTarget \"InterView-obj-isa-class\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tA793EB6821F4CECA003661CD /* Debug */,\n\t\t\t\tA793EB6921F4CECA003661CD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = A793EB5821F4CECA003661CD /* Project object */;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/InterView-obj-isa-class.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:InterView-obj-isa-class.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "InterView-obj-isa-class/InterView-obj-isa-class.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/.clang-format",
    "content": "# Format of this file is YAML\n# Minimum clang-format version required: clang-format version 3.6.0\n# Detailed description of options available at http://clang.llvm.org/docs/ClangFormatStyleOptions.html\n\nAlignEscapedNewlinesLeft: true\n# Bad:\n# void foo() {\n#        someFunction();\n#  someOtherFunction();\n# }\n# Good:\n# void foo() {\n#    someFunction();\n#    someOtherFunction();\n# }\n\nAlignTrailingComments: true\n# align all comments to right based of //\n# == Avoid using // based comments altogether ==\n\nAlignAfterOpenBracket: false\n# don't align after a bracket, uses indentation rules to indent\n\nAllowAllParametersOfDeclarationOnNextLine: false\n# allow funtion definition as\n# someFunction(foo,\n#             bar,\n#             baz);\n\nAlignConsecutiveAssignments:  false\n# does not align consecutive assignments with '=' operator\n\nAllowShortBlocksOnASingleLine: true\n# single statement block can be merged on one line \n# e.g if (a) { return; }\n\nAllowShortCaseLabelsOnASingleLine: false\n# Single statement case statements should be on their own lines\n\nAllowShortFunctionsOnASingleLine: None\n# Bad:\n# int foo() { return 123; }\n\nAllowShortIfStatementsOnASingleLine: false\n# Bad: \n# if (someOtherVar) return; \n# Good:\n# if (someOtherVar) \n#     return;\n\nAllowShortLoopsOnASingleLine: false\n# Bad:\n# while(i>0) i--;\n# Good:\n# while(i>0) {\n#         i--;\n#     }\n\nAlwaysBreakAfterDefinitionReturnType: true\n# Ensures return type is one its own line\n# e.g. unsigned int\n# function(char param) { }\n\nAlwaysBreakBeforeMultilineStrings: true\n# multine strings should begin on new line\n\nBinPackArguments: true\nBinPackParameters: false\n# functions arguments should all be on one line or have a single line for each param\n\nBreakBeforeBinaryOperators: None\n# break for new line after binary operator in case of length is over ColumnLimit\n# e.g.\n# int foo = bar +\n#           baz;\n\nBreakBeforeBraces: Linux\n# Always attach braces to surrounding context except -\n# break before braces on function, namespace and class definitions\n\nColumnLimit: 132\n# every body has wide screen now. 132 seems to be reasonable limit now.\n\nContinuationIndentWidth: 8\n# indent continued lines by two tabs\n\nIndentCaseLabels: false\n# case labels have same indentation as switch statement.\n\nIndentWidth: 4\n# 4 spaces for indentation\nTabWidth: 4\n# tabwidth is 4 spaces\n\nUseTab: Always\n# always indent lines with tabs\n\nIndentWrappedFunctionNames: false\nKeepEmptyLinesAtTheStartOfBlocks: false\n# remove excess empty lines at start of blocks.\n\nPointerAlignment: Right\n# \"void *foo\" (vs. \"void* foo\" or \"void * foo\")\n\nSpaceAfterCStyleCast: false\n# No space after (cast). E.g\n# int blah = (int)((void *)foo + bar)\n\nSpaceBeforeAssignmentOperators: true\n# Assignment = should be seperated by spaces on both sides.\n\nSpaceBeforeParens: ControlStatements\n# for control statements a space is required before '{'\n# Bad: for(){ statement; }\n# Good: for() { statement; }\n\nSpaceInEmptyParentheses: false\n# No spaces required for empty ()\n\nSpacesInCStyleCastParentheses: false\n# No spaces required for (unsigned int) type cast\n\nSpacesInParentheses: false\n\nSpacesInSquareBrackets: false\n# No spaces in [count] style invocations of []\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/.gitattributes",
    "content": ""
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/.gitignore",
    "content": "# /libmalloc.xcodeproj/\n/libmalloc.xcodeproj/*.xcworkspace\n/libmalloc.xcodeproj/xcuserdata\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/include/malloc/_malloc.h",
    "content": "/*\n * Copyright (c) 2018 Apple Computer, Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _MALLOC_UNDERSCORE_MALLOC_H_\n#define _MALLOC_UNDERSCORE_MALLOC_H_\n\n/*\n * This header is included from <stdlib.h>, so the contents of this file have\n * broad source compatibility and POSIX conformance implications.\n * Be cautious about what is included and declared here.\n */\n\n#include <Availability.h>\n#include <sys/cdefs.h>\n#include <_types.h>\n#include <sys/_types/_size_t.h>\n\n__BEGIN_DECLS\n\nvoid\t*malloc(size_t __size) __result_use_check __alloc_size(1);\nvoid\t*calloc(size_t __count, size_t __size) __result_use_check __alloc_size(1,2);\nvoid\t free(void *);\nvoid\t*realloc(void *__ptr, size_t __size) __result_use_check __alloc_size(2);\n#if !defined(_ANSI_SOURCE) && (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))\nvoid\t*valloc(size_t) __alloc_size(1);\n#endif // !defined(_ANSI_SOURCE) && (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))\nint \t posix_memalign(void **__memptr, size_t __alignment, size_t __size) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0);\n\n__END_DECLS\n\n#endif /* _MALLOC_UNDERSCORE_MALLOC_H_ */\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/include/malloc/malloc.h",
    "content": "/*\n * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _MALLOC_MALLOC_H_\n#define _MALLOC_MALLOC_H_\n\n#include <stddef.h>\n#include <mach/mach_types.h>\n#include <sys/cdefs.h>\n#include <Availability.h>\n\n#if __has_feature(ptrauth_calls)\n#include <ptrauth.h>\n\n// Zone function pointer, type-diversified but not address-diversified (because\n// the zone can be copied). Process-independent because the zone structure may\n// be in the shared library cache.\n#define MALLOC_ZONE_FN_PTR(fn) __ptrauth(ptrauth_key_process_independent_code, \\\n\t\tFALSE, ptrauth_string_discriminator(\"malloc_zone_fn.\" #fn)) fn\n\n// Introspection function pointer, address- and type-diversified.\n// Process-independent because the malloc_introspection_t structure that contains\n// these pointers may be in the shared library cache.\n#define MALLOC_INTROSPECT_FN_PTR(fn) __ptrauth(ptrauth_key_process_independent_code, \\\n\t\tTRUE, ptrauth_string_discriminator(\"malloc_introspect_fn.\" #fn)) fn\n\n// Pointer to the introspection pointer table, type-diversified but not\n// address-diversified (because the zone can be copied).\n// Process-independent because the table pointer may be in the shared library cache.\n#define MALLOC_INTROSPECT_TBL_PTR(ptr) __ptrauth(ptrauth_key_process_independent_data,\\\n\t\tFALSE, ptrauth_string_discriminator(\"malloc_introspect_tbl\")) ptr\n\n#endif\t// __has_feature(ptrauth_calls)\n\n#ifndef MALLOC_ZONE_FN_PTR\n#define MALLOC_ZONE_FN_PTR(fn) fn\n#define MALLOC_INTROSPECT_FN_PTR(fn) fn\n#define MALLOC_INTROSPECT_TBL_PTR(ptr) ptr\n#endif // MALLOC_ZONE_FN_PTR\n\n__BEGIN_DECLS\n/*********\tType definitions\t************/\n\ntypedef struct _malloc_zone_t {\n    /* Only zone implementors should depend on the layout of this structure;\n    Regular callers should use the access functions below */\n    void\t*reserved1;\t/* RESERVED FOR CFAllocator DO NOT USE */\n    void\t*reserved2;\t/* RESERVED FOR CFAllocator DO NOT USE */\n    size_t \t(* MALLOC_ZONE_FN_PTR(size))(struct _malloc_zone_t *zone, const void *ptr); /* returns the size of a block or 0 if not in this zone; must be fast, especially for negative answers */\n    void \t*(* MALLOC_ZONE_FN_PTR(malloc))(struct _malloc_zone_t *zone, size_t size);\n    void \t*(* MALLOC_ZONE_FN_PTR(calloc))(struct _malloc_zone_t *zone, size_t num_items, size_t size); /* same as malloc, but block returned is set to zero */\n    void \t*(* MALLOC_ZONE_FN_PTR(valloc))(struct _malloc_zone_t *zone, size_t size); /* same as malloc, but block returned is set to zero and is guaranteed to be page aligned */\n    void \t(* MALLOC_ZONE_FN_PTR(free))(struct _malloc_zone_t *zone, void *ptr);\n    void \t*(* MALLOC_ZONE_FN_PTR(realloc))(struct _malloc_zone_t *zone, void *ptr, size_t size);\n    void \t(* MALLOC_ZONE_FN_PTR(destroy))(struct _malloc_zone_t *zone); /* zone is destroyed and all memory reclaimed */\n    const char\t*zone_name;\n\n    /* Optional batch callbacks; these may be NULL */\n    unsigned\t(* MALLOC_ZONE_FN_PTR(batch_malloc))(struct _malloc_zone_t *zone, size_t size, void **results, unsigned num_requested); /* given a size, returns pointers capable of holding that size; returns the number of pointers allocated (maybe 0 or less than num_requested) */\n    void\t(* MALLOC_ZONE_FN_PTR(batch_free))(struct _malloc_zone_t *zone, void **to_be_freed, unsigned num_to_be_freed); /* frees all the pointers in to_be_freed; note that to_be_freed may be overwritten during the process */\n\n    struct malloc_introspection_t\t* MALLOC_INTROSPECT_TBL_PTR(introspect);\n    unsigned\tversion;\n    \t\n    /* aligned memory allocation. The callback may be NULL. Present in version >= 5. */\n    void *(* MALLOC_ZONE_FN_PTR(memalign))(struct _malloc_zone_t *zone, size_t alignment, size_t size);\n    \n    /* free a pointer known to be in zone and known to have the given size. The callback may be NULL. Present in version >= 6.*/\n    void (* MALLOC_ZONE_FN_PTR(free_definite_size))(struct _malloc_zone_t *zone, void *ptr, size_t size);\n\n    /* Empty out caches in the face of memory pressure. The callback may be NULL. Present in version >= 8. */\n    size_t \t(* MALLOC_ZONE_FN_PTR(pressure_relief))(struct _malloc_zone_t *zone, size_t goal);\n\n\t/*\n\t * Checks whether an address might belong to the zone. May be NULL. Present in version >= 10.\n\t * False positives are allowed (e.g. the pointer was freed, or it's in zone space that has\n\t * not yet been allocated. False negatives are not allowed.\n\t */\n    boolean_t (* MALLOC_ZONE_FN_PTR(claimed_address))(struct _malloc_zone_t *zone, void *ptr);\n} malloc_zone_t;\n\n/*********\tCreation and destruction\t************/\n\nextern malloc_zone_t *malloc_default_zone(void);\n    /* The initial zone */\n\nextern malloc_zone_t *malloc_create_zone(vm_size_t start_size, unsigned flags);\n    /* Creates a new zone with default behavior and registers it */\n\nextern void malloc_destroy_zone(malloc_zone_t *zone);\n    /* Destroys zone and everything it allocated */\n\n/*********\tBlock creation and manipulation\t************/\n\nextern void *malloc_zone_malloc(malloc_zone_t *zone, size_t size) __alloc_size(2);\n    /* Allocates a new pointer of size size; zone must be non-NULL */\n\nextern void *malloc_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size) __alloc_size(2,3);\n    /* Allocates a new pointer of size num_items * size; block is cleared; zone must be non-NULL */\n\nextern void *malloc_zone_valloc(malloc_zone_t *zone, size_t size) __alloc_size(2);\n    /* Allocates a new pointer of size size; zone must be non-NULL; Pointer is guaranteed to be page-aligned and block is cleared */\n\nextern void malloc_zone_free(malloc_zone_t *zone, void *ptr);\n    /* Frees pointer in zone; zone must be non-NULL */\n\nextern void *malloc_zone_realloc(malloc_zone_t *zone, void *ptr, size_t size) __alloc_size(3);\n    /* Enlarges block if necessary; zone must be non-NULL */\n\nextern malloc_zone_t *malloc_zone_from_ptr(const void *ptr);\n    /* Returns the zone for a pointer, or NULL if not in any zone.\n    The ptr must have been returned from a malloc or realloc call. */\n\nextern size_t malloc_size(const void *ptr);\n    /* Returns size of given ptr */\n\nextern size_t malloc_good_size(size_t size);\n    /* Returns number of bytes greater than or equal to size that can be allocated without padding */\n\nextern void *malloc_zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size) __alloc_size(3) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0);\n    /* \n     * Allocates a new pointer of size size whose address is an exact multiple of alignment.\n     * alignment must be a power of two and at least as large as sizeof(void *).\n     * zone must be non-NULL.\n     */\n\n/*********\tBatch methods\t************/\n\nextern unsigned malloc_zone_batch_malloc(malloc_zone_t *zone, size_t size, void **results, unsigned num_requested);\n    /* Allocates num blocks of the same size; Returns the number truly allocated (may be 0) */\n\nextern void malloc_zone_batch_free(malloc_zone_t *zone, void **to_be_freed, unsigned num);\n    /* frees all the pointers in to_be_freed; note that to_be_freed may be overwritten during the process; This function will always free even if the zone has no batch callback */\n\n/*********\tFunctions for libcache\t************/\n\nextern malloc_zone_t *malloc_default_purgeable_zone(void) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0);\n    /* Returns a pointer to the default purgeable_zone. */\n\nextern void malloc_make_purgeable(void *ptr) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0);\n    /* Make an allocation from the purgeable zone purgeable if possible.  */\n\nextern int malloc_make_nonpurgeable(void *ptr) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0);\n    /* Makes an allocation from the purgeable zone nonpurgeable.\n     * Returns zero if the contents were not purged since the last\n     * call to malloc_make_purgeable, else returns non-zero. */\n\n/*********\tFunctions for zone implementors\t************/\n\nextern void malloc_zone_register(malloc_zone_t *zone);\n    /* Registers a custom malloc zone; Should typically be called after a \n     * malloc_zone_t has been filled in with custom methods by a client.  See\n     * malloc_create_zone for creating additional malloc zones with the\n     * default allocation and free behavior. */\n\nextern void malloc_zone_unregister(malloc_zone_t *zone);\n    /* De-registers a zone\n    Should typically be called before calling the zone destruction routine */\n\nextern void malloc_set_zone_name(malloc_zone_t *zone, const char *name);\n    /* Sets the name of a zone */\n\nextern const char *malloc_get_zone_name(malloc_zone_t *zone);\n    /* Returns the name of a zone */\n\nsize_t malloc_zone_pressure_relief(malloc_zone_t *zone, size_t goal) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);\n    /* malloc_zone_pressure_relief() advises the malloc subsystem that the process is under memory pressure and \n     * that the subsystem should make its best effort towards releasing (i.e. munmap()-ing) \"goal\" bytes from \"zone\". \n     * If \"goal\" is passed as zero, the malloc subsystem will attempt to achieve maximal pressure relief in \"zone\". \n     * If \"zone\" is passed as NULL, all zones are examined for pressure relief opportunities. \n     * malloc_zone_pressure_relief() returns the number of bytes released. \n     */\n\ntypedef struct {\n    vm_address_t\taddress;\n    vm_size_t\t\tsize;\n} vm_range_t;\n\ntypedef struct malloc_statistics_t {\n    unsigned\tblocks_in_use;\n    size_t\tsize_in_use;\n    size_t\tmax_size_in_use;\t/* high water mark of touched memory */\n    size_t\tsize_allocated;\t\t/* reserved in memory */\n} malloc_statistics_t;\n\ntypedef kern_return_t memory_reader_t(task_t remote_task, vm_address_t remote_address, vm_size_t size, void **local_memory);\n    /* given a task, \"reads\" the memory at the given address and size\nlocal_memory: set to a contiguous chunk of memory; validity of local_memory is assumed to be limited (until next call) */\n\n#define MALLOC_PTR_IN_USE_RANGE_TYPE\t1\t/* for allocated pointers */\n#define MALLOC_PTR_REGION_RANGE_TYPE\t2\t/* for region containing pointers */\n#define MALLOC_ADMIN_REGION_RANGE_TYPE\t4\t/* for region used internally */\n#define MALLOC_ZONE_SPECIFIC_FLAGS\t0xff00\t/* bits reserved for zone-specific purposes */\n\ntypedef void vm_range_recorder_t(task_t, void *, unsigned type, vm_range_t *, unsigned);\n    /* given a task and context, \"records\" the specified addresses */\n\ntypedef struct malloc_introspection_t {\n\tkern_return_t (* MALLOC_INTROSPECT_FN_PTR(enumerator))(task_t task, void *, unsigned type_mask, vm_address_t zone_address, memory_reader_t reader, vm_range_recorder_t recorder); /* enumerates all the malloc pointers in use */\n\tsize_t\t(* MALLOC_INTROSPECT_FN_PTR(good_size))(malloc_zone_t *zone, size_t size);\n\tboolean_t \t(* MALLOC_INTROSPECT_FN_PTR(check))(malloc_zone_t *zone); /* Consistency checker */\n\tvoid \t(* MALLOC_INTROSPECT_FN_PTR(print))(malloc_zone_t *zone, boolean_t verbose); /* Prints zone  */\n\tvoid\t(* MALLOC_INTROSPECT_FN_PTR(log))(malloc_zone_t *zone, void *address); /* Enables logging of activity */\n\tvoid\t(* MALLOC_INTROSPECT_FN_PTR(force_lock))(malloc_zone_t *zone); /* Forces locking zone */\n\tvoid\t(* MALLOC_INTROSPECT_FN_PTR(force_unlock))(malloc_zone_t *zone); /* Forces unlocking zone */\n\tvoid\t(* MALLOC_INTROSPECT_FN_PTR(statistics))(malloc_zone_t *zone, malloc_statistics_t *stats); /* Fills statistics */\n\tboolean_t   (* MALLOC_INTROSPECT_FN_PTR(zone_locked))(malloc_zone_t *zone); /* Are any zone locks held */\n\n    /* Discharge checking. Present in version >= 7. */\n\tboolean_t\t(* MALLOC_INTROSPECT_FN_PTR(enable_discharge_checking))(malloc_zone_t *zone);\n\tvoid\t(* MALLOC_INTROSPECT_FN_PTR(disable_discharge_checking))(malloc_zone_t *zone);\n\tvoid\t(* MALLOC_INTROSPECT_FN_PTR(discharge))(malloc_zone_t *zone, void *memory);\n#ifdef __BLOCKS__\n\tvoid     (* MALLOC_INTROSPECT_FN_PTR(enumerate_discharged_pointers))(malloc_zone_t *zone, void (^report_discharged)(void *memory, void *info));\n\t#else\n    void\t*enumerate_unavailable_without_blocks;   \n#endif /* __BLOCKS__ */\n\tvoid\t(* MALLOC_INTROSPECT_FN_PTR(reinit_lock))(malloc_zone_t *zone); /* Reinitialize zone locks, called only from atfork_child handler. Present in version >= 9. */\n} malloc_introspection_t;\n\nextern void malloc_printf(const char *format, ...);\n    /* Convenience for logging errors and warnings;\n    No allocation is performed during execution of this function;\n    Only understands usual %p %d %s formats, and %y that expresses a number of bytes (5b,10KB,1MB...)\n    */\n\n/*********\tFunctions for performance tools\t************/\n\nextern kern_return_t malloc_get_all_zones(task_t task, memory_reader_t reader, vm_address_t **addresses, unsigned *count);\n    /* Fills addresses and count with the addresses of the zones in task;\n    Note that the validity of the addresses returned correspond to the validity of the memory returned by reader */\n\n/*********\tDebug helpers\t************/\n\nextern void malloc_zone_print_ptr_info(void *ptr);\n    /* print to stdout if this pointer is in the malloc heap, free status, and size */\n\nextern boolean_t malloc_zone_check(malloc_zone_t *zone);\n    /* Checks zone is well formed; if !zone, checks all zones */\n\nextern void malloc_zone_print(malloc_zone_t *zone, boolean_t verbose);\n    /* Prints summary on zone; if !zone, prints all zones */\n\nextern void malloc_zone_statistics(malloc_zone_t *zone, malloc_statistics_t *stats);\n    /* Fills statistics for zone; if !zone, sums up all zones */\n\nextern void malloc_zone_log(malloc_zone_t *zone, void *address);\n    /* Controls logging of all activity; if !zone, for all zones;\n    If address==0 nothing is logged;\n    If address==-1 all activity is logged;\n    Else only the activity regarding address is logged */\n\nstruct mstats {\n    size_t\tbytes_total;\n    size_t\tchunks_used;\n    size_t\tbytes_used;\n    size_t\tchunks_free;\n    size_t\tbytes_free;\n};\n\nextern struct mstats mstats(void);\n\nextern boolean_t malloc_zone_enable_discharge_checking(malloc_zone_t *zone) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);\n/* Increment the discharge checking enabled counter for a zone. Returns true if the zone supports checking, false if it does not. */\n\nextern void malloc_zone_disable_discharge_checking(malloc_zone_t *zone) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);\n/* Decrement the discharge checking enabled counter for a zone. */\n\nextern void malloc_zone_discharge(malloc_zone_t *zone, void *memory) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);\n/* Register memory that the programmer expects to be freed soon. \n   zone may be NULL in which case the zone is determined using malloc_zone_from_ptr(). \n   If discharge checking is off for the zone this function is a no-op. */\n \n#ifdef __BLOCKS__\nextern void malloc_zone_enumerate_discharged_pointers(malloc_zone_t *zone, void (^report_discharged)(void *memory, void *info)) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);\n/* Calls report_discharged for each block that was registered using malloc_zone_discharge() but has not yet been freed. \n   info is used to provide zone defined information about the memory block. \n   If zone is NULL then the enumeration covers all zones. */\n#else\nextern void malloc_zone_enumerate_discharged_pointers(malloc_zone_t *zone, void *) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);\n#endif /* __BLOCKS__ */\n\n__END_DECLS\n\n#endif /* _MALLOC_MALLOC_H_ */\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/libmalloc.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXAggregateTarget section */\n\t\t3FE9201116A9111000D1238A /* libmalloc */ = {\n\t\t\tisa = PBXAggregateTarget;\n\t\t\tbuildConfigurationList = 3FE9201216A9111000D1238A /* Build configuration list for PBXAggregateTarget \"libmalloc\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t3FC1927C16DD946500315C26 /* Install Man Pages */,\n\t\t\t\t3FE9201D16A9143E00D1238A /* Sanitise Headers (rdar://problem/10241868) */,\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tC0CE45501C52CCBD00C24048 /* PBXTargetDependency */,\n\t\t\t\t3FE9201816A9111600D1238A /* PBXTargetDependency */,\n\t\t\t\t3FE9201616A9111400D1238A /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = libmalloc;\n\t\t\tproductName = libmalloc;\n\t\t};\n\t\t45039161198FFF73004EE2A3 /* libmalloc_test */ = {\n\t\t\tisa = PBXAggregateTarget;\n\t\t\tbuildConfigurationList = 45039162198FFF73004EE2A3 /* Build configuration list for PBXAggregateTarget \"libmalloc_test\" */;\n\t\t\tbuildPhases = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t45039168198FFFA6004EE2A3 /* PBXTargetDependency */,\n\t\t\t\t925383D91BD03D0000F745DB /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = libmalloc_test;\n\t\t\tproductName = libmalloc_test;\n\t\t};\n\t\tB60A57932009307E006215CB /* executables */ = {\n\t\t\tisa = PBXAggregateTarget;\n\t\t\tbuildConfigurationList = B60A57962009307E006215CB /* Build configuration list for PBXAggregateTarget \"executables\" */;\n\t\t\tbuildPhases = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tB60A579820093093006215CB /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = executables;\n\t\t\tproductName = executables;\n\t\t};\n/* End PBXAggregateTarget section */\n\n/* Begin PBXBuildFile section */\n\t\t084F5E841D50204F006CD296 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 084F5E831D50204F006CD296 /* Foundation.framework */; };\n\t\t084F5E851D502102006CD296 /* radix_tree_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 08C28B3A1D501ACC000AE997 /* radix_tree_debug.c */; };\n\t\t088C4D771D1AF049005C6B36 /* radix_tree.c in Sources */ = {isa = PBXBuildFile; fileRef = 088C4D741D1AEFB5005C6B36 /* radix_tree.c */; };\n\t\t088C4D841D1AF16F005C6B36 /* radix_tree.c in Sources */ = {isa = PBXBuildFile; fileRef = 088C4D741D1AEFB5005C6B36 /* radix_tree.c */; };\n\t\t08FEED021D501F6B00BE8A69 /* radix_tree_main.m in Sources */ = {isa = PBXBuildFile; fileRef = 08C28B421D501D2C000AE997 /* radix_tree_main.m */; };\n\t\t0D468DCF1C7BEF51006FACF5 /* magazine_lite.c in Sources */ = {isa = PBXBuildFile; fileRef = 0D468DCC1C7BEE56006FACF5 /* magazine_lite.c */; };\n\t\t0D468DD01C7BEF71006FACF5 /* stack_logging_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D468DCD1C7BEE65006FACF5 /* stack_logging_internal.h */; };\n\t\t2B67B5682040B3AF0003E78F /* _malloc.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B67B5672040B3A50003E78F /* _malloc.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t3D157E7420354E02001630BF /* perfdata.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D157E7320354E02001630BF /* perfdata.framework */; };\n\t\t3FE91FED16A90B9200D1238A /* bitarray.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD116A90A8D00D1238A /* bitarray.c */; };\n\t\t3FE91FF016A90B9200D1238A /* magazine_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD616A90A8D00D1238A /* magazine_malloc.c */; };\n\t\t3FE91FF116A90B9200D1238A /* magmallocProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD716A90A8D00D1238A /* magmallocProvider.d */; };\n\t\t3FE91FF216A90B9200D1238A /* malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD816A90A8D00D1238A /* malloc.c */; };\n\t\t3FE91FF416A90B9200D1238A /* nano_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FDA16A90A8D00D1238A /* nano_malloc.c */; };\n\t\t3FE91FF616A90B9200D1238A /* stack_logging_disk.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FDC16A90A8D00D1238A /* stack_logging_disk.c */; };\n\t\t3FE91FFA16A90BEF00D1238A /* malloc.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FE91FF916A90BEF00D1238A /* malloc.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t3FE91FFF16A9109E00D1238A /* bitarray.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD116A90A8D00D1238A /* bitarray.c */; };\n\t\t3FE9200116A9109E00D1238A /* magazine_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD616A90A8D00D1238A /* magazine_malloc.c */; };\n\t\t3FE9200216A9109E00D1238A /* magmallocProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD716A90A8D00D1238A /* magmallocProvider.d */; };\n\t\t3FE9200316A9109E00D1238A /* malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD816A90A8D00D1238A /* malloc.c */; };\n\t\t3FE9200416A9109E00D1238A /* nano_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FDA16A90A8D00D1238A /* nano_malloc.c */; };\n\t\t3FE9200616A9109E00D1238A /* stack_logging_disk.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FDC16A90A8D00D1238A /* stack_logging_disk.c */; };\n\t\t925383DA1BD03D5100F745DB /* stress_test.c in Sources */ = {isa = PBXBuildFile; fileRef = 925383D11BD03B4A00F745DB /* stress_test.c */; };\n\t\tB61341DE20114B660038D163 /* ktrace.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B61341DD20114B070038D163 /* ktrace.framework */; };\n\t\tB629CF28202BA149007719B9 /* nanov2_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = B68B7FA41FCDD9A500BAD1AA /* nanov2_malloc.c */; };\n\t\tB629CF2D202BB337007719B9 /* radix_tree.c in Sources */ = {isa = PBXBuildFile; fileRef = 088C4D741D1AEFB5005C6B36 /* radix_tree.c */; };\n\t\tB629CF2E202BB337007719B9 /* bitarray.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD116A90A8D00D1238A /* bitarray.c */; };\n\t\tB629CF2F202BB337007719B9 /* purgeable_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C957429E1BF681B00027269A /* purgeable_malloc.c */; };\n\t\tB629CF30202BB337007719B9 /* magazine_large.c in Sources */ = {isa = PBXBuildFile; fileRef = C957429B1BF672F80027269A /* magazine_large.c */; };\n\t\tB629CF31202BB337007719B9 /* magazine_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD616A90A8D00D1238A /* magazine_malloc.c */; };\n\t\tB629CF32202BB337007719B9 /* empty.s in Sources */ = {isa = PBXBuildFile; fileRef = C9ABCA041CB6FC6800ECB399 /* empty.s */; };\n\t\tB629CF33202BB337007719B9 /* magazine_small.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742981BF670D00027269A /* magazine_small.c */; };\n\t\tB629CF34202BB337007719B9 /* legacy_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742AA1BF685CB0027269A /* legacy_malloc.c */; };\n\t\tB629CF35202BB337007719B9 /* magmallocProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD716A90A8D00D1238A /* magmallocProvider.d */; };\n\t\tB629CF36202BB337007719B9 /* malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD816A90A8D00D1238A /* malloc.c */; };\n\t\tB629CF37202BB337007719B9 /* frozen_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742A41BF6842F0027269A /* frozen_malloc.c */; };\n\t\tB629CF38202BB337007719B9 /* nanov2_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = B68B7FA41FCDD9A500BAD1AA /* nanov2_malloc.c */; };\n\t\tB629CF39202BB337007719B9 /* nano_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FDA16A90A8D00D1238A /* nano_malloc.c */; };\n\t\tB629CF3A202BB337007719B9 /* stack_logging_disk.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FDC16A90A8D00D1238A /* stack_logging_disk.c */; };\n\t\tB629CF3B202BB337007719B9 /* magazine_tiny.c in Sources */ = {isa = PBXBuildFile; fileRef = C957428F1BF419DF0027269A /* magazine_tiny.c */; };\n\t\tB629CF3C202BB337007719B9 /* nano_malloc_common.c in Sources */ = {isa = PBXBuildFile; fileRef = B68B7F9D1FCDCBC600BAD1AA /* nano_malloc_common.c */; };\n\t\tB65FBE2C2087AA2F00E21F59 /* malloc_printf.c in Sources */ = {isa = PBXBuildFile; fileRef = B65FBE2B2087AA2F00E21F59 /* malloc_printf.c */; };\n\t\tB66C71D92034BFAE0047E265 /* malloc_common.h in Headers */ = {isa = PBXBuildFile; fileRef = B66C71D72034BFAE0047E265 /* malloc_common.h */; };\n\t\tB66C71DA2034BFAE0047E265 /* malloc_common.c in Sources */ = {isa = PBXBuildFile; fileRef = B66C71D82034BFAE0047E265 /* malloc_common.c */; };\n\t\tB66C71DB2034BFD30047E265 /* malloc_common.c in Sources */ = {isa = PBXBuildFile; fileRef = B66C71D82034BFAE0047E265 /* malloc_common.c */; };\n\t\tB66C71DC2034BFD40047E265 /* malloc_common.c in Sources */ = {isa = PBXBuildFile; fileRef = B66C71D82034BFAE0047E265 /* malloc_common.c */; };\n\t\tB68B7F9E1FCDCBC600BAD1AA /* nano_malloc_common.h in Headers */ = {isa = PBXBuildFile; fileRef = B68B7F9C1FCDCBC600BAD1AA /* nano_malloc_common.h */; };\n\t\tB68B7F9F1FCDCBC600BAD1AA /* nano_malloc_common.c in Sources */ = {isa = PBXBuildFile; fileRef = B68B7F9D1FCDCBC600BAD1AA /* nano_malloc_common.c */; };\n\t\tB68B7FA01FCDCBE700BAD1AA /* nano_malloc_common.c in Sources */ = {isa = PBXBuildFile; fileRef = B68B7F9D1FCDCBC600BAD1AA /* nano_malloc_common.c */; };\n\t\tB68B7FA11FCDCBE800BAD1AA /* nano_malloc_common.c in Sources */ = {isa = PBXBuildFile; fileRef = B68B7F9D1FCDCBC600BAD1AA /* nano_malloc_common.c */; };\n\t\tB68B7FA31FCDD67100BAD1AA /* nanov2_malloc.h in Headers */ = {isa = PBXBuildFile; fileRef = B68B7FA21FCDD60F00BAD1AA /* nanov2_malloc.h */; };\n\t\tB68B7FA51FCDD9A500BAD1AA /* nanov2_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = B68B7FA41FCDD9A500BAD1AA /* nanov2_malloc.c */; };\n\t\tB68B7FA61FCDD9B200BAD1AA /* nanov2_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = B68B7FA41FCDD9A500BAD1AA /* nanov2_malloc.c */; };\n\t\tB68B7FA71FCDD9B200BAD1AA /* nanov2_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = B68B7FA41FCDD9A500BAD1AA /* nanov2_malloc.c */; };\n\t\tB6910F67202B630D00FF2EB0 /* radix_tree.c in Sources */ = {isa = PBXBuildFile; fileRef = 088C4D741D1AEFB5005C6B36 /* radix_tree.c */; };\n\t\tB6910F68202B630D00FF2EB0 /* bitarray.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD116A90A8D00D1238A /* bitarray.c */; };\n\t\tB6910F69202B630D00FF2EB0 /* purgeable_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C957429E1BF681B00027269A /* purgeable_malloc.c */; };\n\t\tB6910F6A202B630D00FF2EB0 /* magazine_large.c in Sources */ = {isa = PBXBuildFile; fileRef = C957429B1BF672F80027269A /* magazine_large.c */; };\n\t\tB6910F6B202B630D00FF2EB0 /* magazine_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD616A90A8D00D1238A /* magazine_malloc.c */; };\n\t\tB6910F6C202B630D00FF2EB0 /* empty.s in Sources */ = {isa = PBXBuildFile; fileRef = C9ABCA041CB6FC6800ECB399 /* empty.s */; };\n\t\tB6910F6D202B630D00FF2EB0 /* magazine_small.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742981BF670D00027269A /* magazine_small.c */; };\n\t\tB6910F6E202B630D00FF2EB0 /* legacy_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742AA1BF685CB0027269A /* legacy_malloc.c */; };\n\t\tB6910F6F202B630D00FF2EB0 /* magmallocProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD716A90A8D00D1238A /* magmallocProvider.d */; };\n\t\tB6910F70202B630D00FF2EB0 /* malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD816A90A8D00D1238A /* malloc.c */; };\n\t\tB6910F71202B630D00FF2EB0 /* frozen_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742A41BF6842F0027269A /* frozen_malloc.c */; };\n\t\tB6910F73202B630D00FF2EB0 /* nano_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FDA16A90A8D00D1238A /* nano_malloc.c */; };\n\t\tB6910F74202B630D00FF2EB0 /* stack_logging_disk.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FDC16A90A8D00D1238A /* stack_logging_disk.c */; };\n\t\tB6910F75202B630D00FF2EB0 /* magazine_tiny.c in Sources */ = {isa = PBXBuildFile; fileRef = C957428F1BF419DF0027269A /* magazine_tiny.c */; };\n\t\tB6910F76202B630D00FF2EB0 /* nano_malloc_common.c in Sources */ = {isa = PBXBuildFile; fileRef = B68B7F9D1FCDCBC600BAD1AA /* nano_malloc_common.c */; };\n\t\tB6CA644E1FCE2C1900DEBA12 /* nanov2_zone.h in Headers */ = {isa = PBXBuildFile; fileRef = B6CA644D1FCE2C0A00DEBA12 /* nanov2_zone.h */; };\n\t\tB6CA644F1FCE2C1A00DEBA12 /* nanov2_zone.h in Headers */ = {isa = PBXBuildFile; fileRef = B6CA644D1FCE2C0A00DEBA12 /* nanov2_zone.h */; };\n\t\tB6CA64501FCE2C1B00DEBA12 /* nanov2_zone.h in Headers */ = {isa = PBXBuildFile; fileRef = B6CA644D1FCE2C0A00DEBA12 /* nanov2_zone.h */; };\n\t\tB6CA64521FCF1AD200DEBA12 /* nano_zone_common.h in Headers */ = {isa = PBXBuildFile; fileRef = B6CA64511FCF1AAD00DEBA12 /* nano_zone_common.h */; };\n\t\tB6CA64531FCF1AD400DEBA12 /* nano_zone_common.h in Headers */ = {isa = PBXBuildFile; fileRef = B6CA64511FCF1AAD00DEBA12 /* nano_zone_common.h */; };\n\t\tB6CA64541FCF1AD400DEBA12 /* nano_zone_common.h in Headers */ = {isa = PBXBuildFile; fileRef = B6CA64511FCF1AAD00DEBA12 /* nano_zone_common.h */; };\n\t\tB6D2ED572007D91A007AF994 /* malloc_replay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6D2ED552007D91A007AF994 /* malloc_replay.cpp */; };\n\t\tB6D5C7F1202E26F80035E376 /* resolver.c in Sources */ = {isa = PBXBuildFile; fileRef = B6D5C7ED202E26CA0035E376 /* resolver.c */; };\n\t\tB6D5C7F2202E26F80035E376 /* resolver.c in Sources */ = {isa = PBXBuildFile; fileRef = B6D5C7ED202E26CA0035E376 /* resolver.c */; };\n\t\tB6D5C7F3202E26F90035E376 /* resolver.c in Sources */ = {isa = PBXBuildFile; fileRef = B6D5C7ED202E26CA0035E376 /* resolver.c */; };\n\t\tB6D5C7F4202E26F90035E376 /* resolver.c in Sources */ = {isa = PBXBuildFile; fileRef = B6D5C7ED202E26CA0035E376 /* resolver.c */; };\n\t\tB6D5C7F5202E26FA0035E376 /* resolver.c in Sources */ = {isa = PBXBuildFile; fileRef = B6D5C7ED202E26CA0035E376 /* resolver.c */; };\n\t\tC0352EC71C3F3C4400DB5126 /* malloc_private.h in Headers */ = {isa = PBXBuildFile; fileRef = C0352EC61C3F3C3600DB5126 /* malloc_private.h */; settings = {ATTRIBUTES = (Private, ); }; };\n\t\tC0CE45311C52C90500C24048 /* bitarray.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD116A90A8D00D1238A /* bitarray.c */; };\n\t\tC0CE45321C52C90500C24048 /* purgeable_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C957429E1BF681B00027269A /* purgeable_malloc.c */; };\n\t\tC0CE45331C52C90500C24048 /* magazine_large.c in Sources */ = {isa = PBXBuildFile; fileRef = C957429B1BF672F80027269A /* magazine_large.c */; };\n\t\tC0CE45341C52C90500C24048 /* magazine_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD616A90A8D00D1238A /* magazine_malloc.c */; };\n\t\tC0CE45351C52C90500C24048 /* magazine_small.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742981BF670D00027269A /* magazine_small.c */; };\n\t\tC0CE45361C52C90500C24048 /* legacy_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742AA1BF685CB0027269A /* legacy_malloc.c */; };\n\t\tC0CE45371C52C90500C24048 /* magmallocProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD716A90A8D00D1238A /* magmallocProvider.d */; };\n\t\tC0CE45381C52C90500C24048 /* malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FD816A90A8D00D1238A /* malloc.c */; };\n\t\tC0CE45391C52C90500C24048 /* frozen_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742A41BF6842F0027269A /* frozen_malloc.c */; };\n\t\tC0CE453A1C52C90500C24048 /* nano_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FDA16A90A8D00D1238A /* nano_malloc.c */; };\n\t\tC0CE453C1C52C90500C24048 /* stack_logging_disk.c in Sources */ = {isa = PBXBuildFile; fileRef = 3FE91FDC16A90A8D00D1238A /* stack_logging_disk.c */; };\n\t\tC0CE453D1C52C90500C24048 /* magazine_tiny.c in Sources */ = {isa = PBXBuildFile; fileRef = C957428F1BF419DF0027269A /* magazine_tiny.c */; };\n\t\tC0CE45401C52C90500C24048 /* magazine_inline.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742921BF41C970027269A /* magazine_inline.h */; };\n\t\tC0CE45411C52C90500C24048 /* nano_zone.h in Headers */ = {isa = PBXBuildFile; fileRef = C957427E1BF33D130027269A /* nano_zone.h */; };\n\t\tC0CE45421C52C90500C24048 /* thresholds.h in Headers */ = {isa = PBXBuildFile; fileRef = C957428C1BF411330027269A /* thresholds.h */; };\n\t\tC0CE45431C52C90500C24048 /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = C957427B1BF2C8DE0027269A /* debug.h */; };\n\t\tC0CE45441C52C90500C24048 /* frozen_malloc.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742A51BF6842F0027269A /* frozen_malloc.h */; };\n\t\tC0CE45451C52C90500C24048 /* magazine_zone.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742861BF3F9550027269A /* magazine_zone.h */; };\n\t\tC0CE45461C52C90500C24048 /* magazine_malloc.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742951BF41E480027269A /* magazine_malloc.h */; };\n\t\tC0CE45471C52C90500C24048 /* purgeable_malloc.h in Headers */ = {isa = PBXBuildFile; fileRef = C957429F1BF681B00027269A /* purgeable_malloc.h */; };\n\t\tC0CE45481C52C90500C24048 /* base.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742891BF3FD290027269A /* base.h */; };\n\t\tC0CE454E1C52C9E600C24048 /* libmalloc.a in CopyFiles */ = {isa = PBXBuildFile; fileRef = C0CE454C1C52C90500C24048 /* libmalloc.a */; };\n\t\tC932D2681D6B8D840063B19E /* vm.c in Sources */ = {isa = PBXBuildFile; fileRef = C932D2661D6B8D840063B19E /* vm.c */; };\n\t\tC932D2691D6B8D840063B19E /* vm.h in Headers */ = {isa = PBXBuildFile; fileRef = C932D2671D6B8D840063B19E /* vm.h */; };\n\t\tC938BBD31C74F7A400522BBD /* trace.h in Headers */ = {isa = PBXBuildFile; fileRef = C938BBD21C74F7A400522BBD /* trace.h */; };\n\t\tC9571C3A1C18AA1D00A67EE3 /* stack_logging.h in Headers */ = {isa = PBXBuildFile; fileRef = C9571C391C18AA1D00A67EE3 /* stack_logging.h */; settings = {ATTRIBUTES = (Private, ); }; };\n\t\tC95742721BF2C2880027269A /* bitarray.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FE91FD216A90A8D00D1238A /* bitarray.h */; };\n\t\tC95742731BF2C2880027269A /* internal.h in Headers */ = {isa = PBXBuildFile; fileRef = C957426D1BF2C0C80027269A /* internal.h */; };\n\t\tC95742741BF2C2880027269A /* locking.h in Headers */ = {isa = PBXBuildFile; fileRef = C957426E1BF2C1480027269A /* locking.h */; };\n\t\tC95742751BF2C2880027269A /* printf.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FE91FD916A90A8D00D1238A /* printf.h */; };\n\t\tC95742761BF2C2880027269A /* platform.h in Headers */ = {isa = PBXBuildFile; fileRef = C9F77BBA1BF2B84800812E13 /* platform.h */; };\n\t\tC95742771BF2C2880027269A /* legacy_malloc.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FE91FFB16A90E6C00D1238A /* legacy_malloc.h */; };\n\t\tC957427A1BF2C67E0027269A /* nano_malloc.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742791BF2C5F40027269A /* nano_malloc.h */; };\n\t\tC957427C1BF2C8DE0027269A /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = C957427B1BF2C8DE0027269A /* debug.h */; };\n\t\tC957427D1BF2C8DE0027269A /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = C957427B1BF2C8DE0027269A /* debug.h */; };\n\t\tC957427F1BF33D130027269A /* nano_zone.h in Headers */ = {isa = PBXBuildFile; fileRef = C957427E1BF33D130027269A /* nano_zone.h */; };\n\t\tC95742801BF33D130027269A /* nano_zone.h in Headers */ = {isa = PBXBuildFile; fileRef = C957427E1BF33D130027269A /* nano_zone.h */; };\n\t\tC95742871BF3F9550027269A /* magazine_zone.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742861BF3F9550027269A /* magazine_zone.h */; };\n\t\tC95742881BF3F9550027269A /* magazine_zone.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742861BF3F9550027269A /* magazine_zone.h */; };\n\t\tC957428A1BF3FD290027269A /* base.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742891BF3FD290027269A /* base.h */; };\n\t\tC957428B1BF3FD290027269A /* base.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742891BF3FD290027269A /* base.h */; };\n\t\tC957428D1BF411330027269A /* thresholds.h in Headers */ = {isa = PBXBuildFile; fileRef = C957428C1BF411330027269A /* thresholds.h */; };\n\t\tC957428E1BF411330027269A /* thresholds.h in Headers */ = {isa = PBXBuildFile; fileRef = C957428C1BF411330027269A /* thresholds.h */; };\n\t\tC95742901BF419DF0027269A /* magazine_tiny.c in Sources */ = {isa = PBXBuildFile; fileRef = C957428F1BF419DF0027269A /* magazine_tiny.c */; };\n\t\tC95742911BF419DF0027269A /* magazine_tiny.c in Sources */ = {isa = PBXBuildFile; fileRef = C957428F1BF419DF0027269A /* magazine_tiny.c */; };\n\t\tC95742931BF41C970027269A /* magazine_inline.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742921BF41C970027269A /* magazine_inline.h */; };\n\t\tC95742941BF41C970027269A /* magazine_inline.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742921BF41C970027269A /* magazine_inline.h */; };\n\t\tC95742961BF41E480027269A /* magazine_malloc.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742951BF41E480027269A /* magazine_malloc.h */; };\n\t\tC95742971BF41E480027269A /* magazine_malloc.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742951BF41E480027269A /* magazine_malloc.h */; };\n\t\tC95742991BF670D00027269A /* magazine_small.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742981BF670D00027269A /* magazine_small.c */; };\n\t\tC957429A1BF670D00027269A /* magazine_small.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742981BF670D00027269A /* magazine_small.c */; };\n\t\tC957429C1BF672F80027269A /* magazine_large.c in Sources */ = {isa = PBXBuildFile; fileRef = C957429B1BF672F80027269A /* magazine_large.c */; };\n\t\tC957429D1BF672F80027269A /* magazine_large.c in Sources */ = {isa = PBXBuildFile; fileRef = C957429B1BF672F80027269A /* magazine_large.c */; };\n\t\tC95742A01BF681B00027269A /* purgeable_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C957429E1BF681B00027269A /* purgeable_malloc.c */; };\n\t\tC95742A11BF681B00027269A /* purgeable_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C957429E1BF681B00027269A /* purgeable_malloc.c */; };\n\t\tC95742A21BF681B00027269A /* purgeable_malloc.h in Headers */ = {isa = PBXBuildFile; fileRef = C957429F1BF681B00027269A /* purgeable_malloc.h */; };\n\t\tC95742A31BF681B00027269A /* purgeable_malloc.h in Headers */ = {isa = PBXBuildFile; fileRef = C957429F1BF681B00027269A /* purgeable_malloc.h */; };\n\t\tC95742A61BF6842F0027269A /* frozen_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742A41BF6842F0027269A /* frozen_malloc.c */; };\n\t\tC95742A71BF6842F0027269A /* frozen_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742A41BF6842F0027269A /* frozen_malloc.c */; };\n\t\tC95742A81BF6842F0027269A /* frozen_malloc.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742A51BF6842F0027269A /* frozen_malloc.h */; };\n\t\tC95742A91BF6842F0027269A /* frozen_malloc.h in Headers */ = {isa = PBXBuildFile; fileRef = C95742A51BF6842F0027269A /* frozen_malloc.h */; };\n\t\tC95742AB1BF685CB0027269A /* legacy_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742AA1BF685CB0027269A /* legacy_malloc.c */; };\n\t\tC95742AC1BF685CB0027269A /* legacy_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = C95742AA1BF685CB0027269A /* legacy_malloc.c */; };\n\t\tC99E320B1D6F7366005655A8 /* magazine_rack.c in Sources */ = {isa = PBXBuildFile; fileRef = C99E32091D6F7366005655A8 /* magazine_rack.c */; };\n\t\tC99E320C1D6F7366005655A8 /* magazine_rack.h in Headers */ = {isa = PBXBuildFile; fileRef = C99E320A1D6F7366005655A8 /* magazine_rack.h */; };\n\t\tC9ABCA051CB6FC6800ECB399 /* empty.s in Sources */ = {isa = PBXBuildFile; fileRef = C9ABCA041CB6FC6800ECB399 /* empty.s */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t3FE9201516A9111400D1238A /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 3FFC1BE516A908F800027192 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 3FE91FFD16A9109E00D1238A;\n\t\t\tremoteInfo = libmalloc_eOS;\n\t\t};\n\t\t3FE9201716A9111600D1238A /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 3FFC1BE516A908F800027192 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 3FE91FE716A90AEC00D1238A;\n\t\t\tremoteInfo = libsystem_malloc;\n\t\t};\n\t\t45039167198FFFA6004EE2A3 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 3FFC1BE516A908F800027192 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 456E51C8197DF0D600A7E488;\n\t\t\tremoteInfo = libmalloc_stress_test;\n\t\t};\n\t\t925383D81BD03D0000F745DB /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 3FFC1BE516A908F800027192 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 925383D41BD03C0500F745DB;\n\t\t\tremoteInfo = darwintests;\n\t\t};\n\t\tB60A579720093093006215CB /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 3FFC1BE516A908F800027192 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = B6D2ED492007D76F007AF994;\n\t\t\tremoteInfo = libmalloc_replay;\n\t\t};\n\t\tB629CF43202BB389007719B9 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 3FFC1BE516A908F800027192 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = B629CF2B202BB337007719B9;\n\t\t\tremoteInfo = libmalloc_alt;\n\t\t};\n\t\tB676F4AB202B66EF00933F6D /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 3FFC1BE516A908F800027192 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = B6910F65202B630D00FF2EB0;\n\t\t\tremoteInfo = libmalloc_mp;\n\t\t};\n\t\tC0CE454F1C52CCBD00C24048 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 3FFC1BE516A908F800027192 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = C0CE452F1C52C90500C24048;\n\t\t\tremoteInfo = libmalloc_static;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t456E51C7197DF0D600A7E488 /* CopyFiles */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = /usr/share/man/man1/;\n\t\t\tdstSubfolderSpec = 0;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 1;\n\t\t};\n\t\tC0CE454D1C52C9D900C24048 /* CopyFiles */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 8;\n\t\t\tdstPath = /usr/local/lib/loaderd;\n\t\t\tdstSubfolderSpec = 0;\n\t\t\tfiles = (\n\t\t\t\tC0CE454E1C52C9E600C24048 /* libmalloc.a in CopyFiles */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 1;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t084F5E831D50204F006CD296 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };\n\t\t088C4D731D1AEFB5005C6B36 /* radix_tree_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = radix_tree_internal.h; sourceTree = \"<group>\"; };\n\t\t088C4D741D1AEFB5005C6B36 /* radix_tree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = radix_tree.c; sourceTree = \"<group>\"; };\n\t\t088C4D751D1AEFB5005C6B36 /* radix_tree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = radix_tree.h; sourceTree = \"<group>\"; };\n\t\t088C4D761D1AEFC5005C6B36 /* radix_tree_test.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = radix_tree_test.m; sourceTree = \"<group>\"; };\n\t\t08C28B3A1D501ACC000AE997 /* radix_tree_debug.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = radix_tree_debug.c; sourceTree = \"<group>\"; };\n\t\t08C28B401D501D2C000AE997 /* radix-tree */ = {isa = PBXFileReference; explicitFileType = \"compiled.mach-o.executable\"; includeInIndex = 0; path = \"radix-tree\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t08C28B421D501D2C000AE997 /* radix_tree_main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = radix_tree_main.m; sourceTree = \"<group>\"; };\n\t\t0D468DCC1C7BEE56006FACF5 /* magazine_lite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = magazine_lite.c; sourceTree = \"<group>\"; };\n\t\t0D468DCD1C7BEE65006FACF5 /* stack_logging_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stack_logging_internal.h; sourceTree = \"<group>\"; };\n\t\t0D468DCE1C7BEE74006FACF5 /* stack_logging_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = stack_logging_test.c; sourceTree = \"<group>\"; };\n\t\t2B67B5672040B3A50003E78F /* _malloc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _malloc.h; sourceTree = \"<group>\"; };\n\t\t3D157E7320354E02001630BF /* perfdata.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = perfdata.framework; path = ../MacOSX10.14.Internal.sdk/System/Library/PrivateFrameworks/perfdata.framework; sourceTree = SDKROOT; };\n\t\t3FC452FF18E4ABFE003D6A38 /* manpages.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = manpages.sh; sourceTree = \"<group>\"; };\n\t\t3FE91FC916A90A8D00D1238A /* malloc.3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = malloc.3; sourceTree = \"<group>\"; };\n\t\t3FE91FCA16A90A8D00D1238A /* malloc_size.3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = malloc_size.3; sourceTree = \"<group>\"; };\n\t\t3FE91FCB16A90A8D00D1238A /* malloc_zone_malloc.3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = malloc_zone_malloc.3; sourceTree = \"<group>\"; };\n\t\t3FE91FD116A90A8D00D1238A /* bitarray.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = bitarray.c; sourceTree = \"<group>\"; };\n\t\t3FE91FD216A90A8D00D1238A /* bitarray.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bitarray.h; sourceTree = \"<group>\"; };\n\t\t3FE91FD616A90A8D00D1238A /* magazine_malloc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = magazine_malloc.c; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.c; };\n\t\t3FE91FD716A90A8D00D1238A /* magmallocProvider.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = magmallocProvider.d; sourceTree = \"<group>\"; };\n\t\t3FE91FD816A90A8D00D1238A /* malloc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = malloc.c; sourceTree = \"<group>\"; };\n\t\t3FE91FD916A90A8D00D1238A /* printf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = printf.h; sourceTree = \"<group>\"; };\n\t\t3FE91FDA16A90A8D00D1238A /* nano_malloc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nano_malloc.c; sourceTree = \"<group>\"; };\n\t\t3FE91FDC16A90A8D00D1238A /* stack_logging_disk.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = stack_logging_disk.c; sourceTree = \"<group>\"; usesTabs = 1; };\n\t\t3FE91FE016A90A8D00D1238A /* libmalloc.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = libmalloc.xcconfig; sourceTree = \"<group>\"; };\n\t\t3FE91FE116A90A8D00D1238A /* libmalloc_eos.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = libmalloc_eos.xcconfig; sourceTree = \"<group>\"; };\n\t\t3FE91FE316A90A8D00D1238A /* sanitise_headers.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = sanitise_headers.sh; sourceTree = \"<group>\"; };\n\t\t3FE91FE816A90AEC00D1238A /* libsystem_malloc.dylib */ = {isa = PBXFileReference; explicitFileType = \"compiled.mach-o.dylib\"; includeInIndex = 0; path = libsystem_malloc.dylib; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t3FE91FF916A90BEF00D1238A /* malloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = malloc.h; sourceTree = \"<group>\"; };\n\t\t3FE91FFB16A90E6C00D1238A /* legacy_malloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = legacy_malloc.h; sourceTree = \"<group>\"; };\n\t\t3FE9201016A9109E00D1238A /* libmalloc_eOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libmalloc_eOS.a; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t456E51C9197DF0D600A7E488 /* libmalloc_stress_test */ = {isa = PBXFileReference; explicitFileType = \"compiled.mach-o.executable\"; includeInIndex = 0; path = libmalloc_stress_test; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t8CB962B01F7E9F610046942E /* asan.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = asan.c; sourceTree = \"<group>\"; };\n\t\t8CB962B11F7E9FD00046942E /* tsan.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tsan.c; sourceTree = \"<group>\"; };\n\t\t925383D01BD03B4A00F745DB /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = \"<group>\"; };\n\t\t925383D11BD03B4A00F745DB /* stress_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = stress_test.c; sourceTree = \"<group>\"; };\n\t\t925383D31BD03B8F00F745DB /* manpages.lst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = manpages.lst; sourceTree = \"<group>\"; };\n\t\tB61341DD20114B070038D163 /* ktrace.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ktrace.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.Internal.sdk/System/Library/PrivateFrameworks/ktrace.framework; sourceTree = DEVELOPER_DIR; };\n\t\tB629CF29202BA3C2007719B9 /* libmalloc_resolver.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = libmalloc_resolver.xcconfig; sourceTree = \"<group>\"; };\n\t\tB629CF42202BB337007719B9 /* libmalloc_alt.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libmalloc_alt.a; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tB629CF46202BBDEC007719B9 /* resolver_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resolver_internal.h; sourceTree = \"<group>\"; };\n\t\tB629CF48202BBE3B007719B9 /* resolver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = resolver.h; sourceTree = \"<group>\"; };\n\t\tB64E100A205311DC004C4BA6 /* malloc_size_test.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = malloc_size_test.c; sourceTree = \"<group>\"; };\n\t\tB6536A62204754B6005FBE22 /* perf_contended_malloc_free.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = perf_contended_malloc_free.c; sourceTree = \"<group>\"; };\n\t\tB6536A6320475BA4005FBE22 /* basic_malloc_free_perf.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = basic_malloc_free_perf.c; sourceTree = \"<group>\"; };\n\t\tB65FBE2B2087AA2F00E21F59 /* malloc_printf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = malloc_printf.c; sourceTree = \"<group>\"; };\n\t\tB66AA658202A70B00019D607 /* libmalloc_resolved.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = libmalloc_resolved.xcconfig; sourceTree = \"<group>\"; };\n\t\tB66C71D72034BFAE0047E265 /* malloc_common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = malloc_common.h; sourceTree = \"<group>\"; };\n\t\tB66C71D82034BFAE0047E265 /* malloc_common.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = malloc_common.c; sourceTree = \"<group>\"; };\n\t\tB670DABD2072D0BB00139A1D /* perf_realloc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = perf_realloc.c; sourceTree = \"<group>\"; };\n\t\tB671CFFD207578CC00EEAF20 /* libmalloc.dirty */ = {isa = PBXFileReference; lastKnownFileType = text; path = libmalloc.dirty; sourceTree = \"<group>\"; };\n\t\tB675F74520213D0A00B5038B /* nano_tests.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nano_tests.c; sourceTree = \"<group>\"; };\n\t\tB68B7F9C1FCDCBC600BAD1AA /* nano_malloc_common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nano_malloc_common.h; sourceTree = \"<group>\"; };\n\t\tB68B7F9D1FCDCBC600BAD1AA /* nano_malloc_common.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nano_malloc_common.c; sourceTree = \"<group>\"; };\n\t\tB68B7FA21FCDD60F00BAD1AA /* nanov2_malloc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nanov2_malloc.h; sourceTree = \"<group>\"; };\n\t\tB68B7FA41FCDD9A500BAD1AA /* nanov2_malloc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nanov2_malloc.c; sourceTree = \"<group>\"; };\n\t\tB6910F89202B630D00FF2EB0 /* libmalloc_mp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libmalloc_mp.a; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tB69B2B941FB3D00500FD5A8F /* magazine_malloc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = magazine_malloc.c; sourceTree = \"<group>\"; };\n\t\tB6A414EA1FBDF01C0038DC53 /* malloc_claimed_address_tests.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = malloc_claimed_address_tests.c; sourceTree = \"<group>\"; };\n\t\tB6A494971F9918DD0016A799 /* calloc_test.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = calloc_test.c; sourceTree = \"<group>\"; };\n\t\tB6A9C48C1F991716007D0853 /* malloc_free_test.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = malloc_free_test.c; sourceTree = \"<group>\"; };\n\t\tB6C1C9C720D9B70F002CCC0B /* nano_trace_replay.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nano_trace_replay.c; sourceTree = \"<group>\"; };\n\t\tB6CA644D1FCE2C0A00DEBA12 /* nanov2_zone.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nanov2_zone.h; sourceTree = \"<group>\"; };\n\t\tB6CA64511FCF1AAD00DEBA12 /* nano_zone_common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nano_zone_common.h; sourceTree = \"<group>\"; };\n\t\tB6D2ED512007D76F007AF994 /* libmalloc_replay */ = {isa = PBXFileReference; explicitFileType = \"compiled.mach-o.executable\"; includeInIndex = 0; path = libmalloc_replay; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tB6D2ED552007D91A007AF994 /* malloc_replay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = malloc_replay.cpp; sourceTree = \"<group>\"; };\n\t\tB6D2ED562007D91A007AF994 /* malloc_replay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = malloc_replay.h; sourceTree = \"<group>\"; };\n\t\tB6D5C7ED202E26CA0035E376 /* resolver.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = resolver.c; sourceTree = \"<group>\"; };\n\t\tC0352EC61C3F3C3600DB5126 /* malloc_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = malloc_private.h; sourceTree = \"<group>\"; };\n\t\tC0CE450E1C52B9E300C24048 /* libmalloc_static.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = libmalloc_static.xcconfig; sourceTree = \"<group>\"; };\n\t\tC0CE454C1C52C90500C24048 /* libmalloc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libmalloc.a; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tC92853A01C767F08001FEAF3 /* install-codes.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = \"install-codes.sh\"; sourceTree = \"<group>\"; };\n\t\tC931B58F1C81248100D0D230 /* madvise.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = madvise.c; sourceTree = \"<group>\"; };\n\t\tC932D2631D6B6ED40063B19E /* magazine_tiny_test.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = magazine_tiny_test.c; sourceTree = \"<group>\"; };\n\t\tC932D2641D6B73270063B19E /* dtrace.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dtrace.h; sourceTree = \"<group>\"; };\n\t\tC932D2661D6B8D840063B19E /* vm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vm.c; sourceTree = \"<group>\"; };\n\t\tC932D2671D6B8D840063B19E /* vm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vm.h; sourceTree = \"<group>\"; };\n\t\tC938BBD21C74F7A400522BBD /* trace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = trace.h; sourceTree = \"<group>\"; };\n\t\tC93F76D71D6B9F8C0088931B /* magazine_testing.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = magazine_testing.h; sourceTree = \"<group>\"; };\n\t\tC9571C391C18AA1D00A67EE3 /* stack_logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stack_logging.h; sourceTree = \"<group>\"; };\n\t\tC9571C3C1C18AD5F00A67EE3 /* balloon.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = balloon.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C3D1C18AD5F00A67EE3 /* balloon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = balloon.h; sourceTree = \"<group>\"; };\n\t\tC9571C3E1C18AD5F00A67EE3 /* Benchmark.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Benchmark.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C3F1C18AD5F00A67EE3 /* Benchmark.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Benchmark.h; sourceTree = \"<group>\"; };\n\t\tC9571C401C18AD5F00A67EE3 /* big.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = big.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C411C18AD5F00A67EE3 /* big.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = big.h; sourceTree = \"<group>\"; };\n\t\tC9571C421C18AD5F00A67EE3 /* churn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = churn.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C431C18AD5F00A67EE3 /* churn.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = churn.h; sourceTree = \"<group>\"; };\n\t\tC9571C441C18AD5F00A67EE3 /* CommandLine.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CommandLine.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C451C18AD5F00A67EE3 /* CommandLine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommandLine.h; sourceTree = \"<group>\"; };\n\t\tC9571C461C18AD5F00A67EE3 /* CPUCount.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CPUCount.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C471C18AD5F00A67EE3 /* CPUCount.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CPUCount.h; sourceTree = \"<group>\"; };\n\t\tC9571C4C1C18AD5F00A67EE3 /* fragment.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = fragment.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C4D1C18AD5F00A67EE3 /* fragment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fragment.h; sourceTree = \"<group>\"; };\n\t\tC9571C4E1C18AD5F00A67EE3 /* Interpreter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Interpreter.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C4F1C18AD5F00A67EE3 /* Interpreter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Interpreter.h; sourceTree = \"<group>\"; };\n\t\tC9571C501C18AD5F00A67EE3 /* list.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = list.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C511C18AD5F00A67EE3 /* list.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = list.h; sourceTree = \"<group>\"; };\n\t\tC9571C521C18AD5F00A67EE3 /* mbmalloc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = mbmalloc.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C531C18AD5F00A67EE3 /* mbmalloc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mbmalloc.h; sourceTree = \"<group>\"; };\n\t\tC9571C541C18AD5F00A67EE3 /* medium.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = medium.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C551C18AD5F00A67EE3 /* medium.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = medium.h; sourceTree = \"<group>\"; };\n\t\tC9571C561C18AD5F00A67EE3 /* memalign.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = memalign.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C571C18AD5F00A67EE3 /* memalign.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = memalign.h; sourceTree = \"<group>\"; };\n\t\tC9571C581C18AD5F00A67EE3 /* message.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = message.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C591C18AD5F00A67EE3 /* message.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = message.h; sourceTree = \"<group>\"; };\n\t\tC9571C5A1C18AD5F00A67EE3 /* realloc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = realloc.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C5B1C18AD5F00A67EE3 /* realloc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = realloc.h; sourceTree = \"<group>\"; };\n\t\tC9571C5E1C18AD5F00A67EE3 /* stress_aligned.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = stress_aligned.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C5F1C18AD5F00A67EE3 /* stress_aligned.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = stress_aligned.h; sourceTree = \"<group>\"; };\n\t\tC9571C601C18AD5F00A67EE3 /* stress.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = stress.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C611C18AD5F00A67EE3 /* stress.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = stress.h; sourceTree = \"<group>\"; };\n\t\tC9571C641C18AD5F00A67EE3 /* tree.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = tree.cpp; sourceTree = \"<group>\"; };\n\t\tC9571C651C18AD5F00A67EE3 /* tree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = tree.h; sourceTree = \"<group>\"; };\n\t\tC9571C661C18AD6A00A67EE3 /* MallocBench.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MallocBench.cpp; sourceTree = \"<group>\"; };\n\t\tC957426D1BF2C0C80027269A /* internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = \"<group>\"; };\n\t\tC957426E1BF2C1480027269A /* locking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = locking.h; sourceTree = \"<group>\"; };\n\t\tC95742791BF2C5F40027269A /* nano_malloc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nano_malloc.h; sourceTree = \"<group>\"; };\n\t\tC957427B1BF2C8DE0027269A /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = \"<group>\"; };\n\t\tC957427E1BF33D130027269A /* nano_zone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nano_zone.h; sourceTree = \"<group>\"; };\n\t\tC95742861BF3F9550027269A /* magazine_zone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = magazine_zone.h; sourceTree = \"<group>\"; };\n\t\tC95742891BF3FD290027269A /* base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = base.h; sourceTree = \"<group>\"; };\n\t\tC957428C1BF411330027269A /* thresholds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = thresholds.h; sourceTree = \"<group>\"; };\n\t\tC957428F1BF419DF0027269A /* magazine_tiny.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = magazine_tiny.c; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.c; };\n\t\tC95742921BF41C970027269A /* magazine_inline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = magazine_inline.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\tC95742951BF41E480027269A /* magazine_malloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = magazine_malloc.h; sourceTree = \"<group>\"; };\n\t\tC95742981BF670D00027269A /* magazine_small.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = magazine_small.c; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.c; };\n\t\tC957429B1BF672F80027269A /* magazine_large.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = magazine_large.c; sourceTree = \"<group>\"; };\n\t\tC957429E1BF681B00027269A /* purgeable_malloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = purgeable_malloc.c; sourceTree = \"<group>\"; };\n\t\tC957429F1BF681B00027269A /* purgeable_malloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = purgeable_malloc.h; sourceTree = \"<group>\"; };\n\t\tC95742A41BF6842F0027269A /* frozen_malloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = frozen_malloc.c; sourceTree = \"<group>\"; };\n\t\tC95742A51BF6842F0027269A /* frozen_malloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = frozen_malloc.h; sourceTree = \"<group>\"; };\n\t\tC95742AA1BF685CB0027269A /* legacy_malloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = legacy_malloc.c; sourceTree = \"<group>\"; };\n\t\tC99E32091D6F7366005655A8 /* magazine_rack.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = magazine_rack.c; sourceTree = \"<group>\"; };\n\t\tC99E320A1D6F7366005655A8 /* magazine_rack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = magazine_rack.h; sourceTree = \"<group>\"; };\n\t\tC9ABCA041CB6FC6800ECB399 /* empty.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = empty.s; sourceTree = \"<group>\"; };\n\t\tC9F77BBA1BF2B84800812E13 /* platform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = platform.h; sourceTree = \"<group>\"; };\n\t\tC9F8C2681D70B521008C4044 /* magazine_small_test.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = magazine_small_test.c; sourceTree = \"<group>\"; };\n\t\tC9F8C2691D74C93A008C4044 /* magazine_rack.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = magazine_rack.c; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t08C28B3D1D501D2C000AE997 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t084F5E841D50204F006CD296 /* Foundation.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t3FE91FE516A90AEC00D1238A /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t3FE9200716A9109E00D1238A /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t456E51C6197DF0D600A7E488 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tB629CF3D202BB337007719B9 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tB6910F77202B630D00FF2EB0 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tB6D2ED4C2007D76F007AF994 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t3D157E7420354E02001630BF /* perfdata.framework in Frameworks */,\n\t\t\t\tB61341DE20114B660038D163 /* ktrace.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC0CE453E1C52C90500C24048 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t084F5E821D50204F006CD296 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3D157E7320354E02001630BF /* perfdata.framework */,\n\t\t\t\tB61341DD20114B070038D163 /* ktrace.framework */,\n\t\t\t\t084F5E831D50204F006CD296 /* Foundation.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t08C28B411D501D2C000AE997 /* tools */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t08C28B421D501D2C000AE997 /* radix_tree_main.m */,\n\t\t\t\tB6D2ED552007D91A007AF994 /* malloc_replay.cpp */,\n\t\t\t\tB6D2ED562007D91A007AF994 /* malloc_replay.h */,\n\t\t\t);\n\t\t\tpath = tools;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3FE91FC816A90A8D00D1238A /* man */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t925383D31BD03B8F00F745DB /* manpages.lst */,\n\t\t\t\t3FE91FC916A90A8D00D1238A /* malloc.3 */,\n\t\t\t\t3FE91FCA16A90A8D00D1238A /* malloc_size.3 */,\n\t\t\t\t3FE91FCB16A90A8D00D1238A /* malloc_zone_malloc.3 */,\n\t\t\t);\n\t\t\tpath = man;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3FE91FCC16A90A8D00D1238A /* src */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t08C28B3A1D501ACC000AE997 /* radix_tree_debug.c */,\n\t\t\t\t088C4D731D1AEFB5005C6B36 /* radix_tree_internal.h */,\n\t\t\t\t088C4D741D1AEFB5005C6B36 /* radix_tree.c */,\n\t\t\t\t088C4D751D1AEFB5005C6B36 /* radix_tree.h */,\n\t\t\t\tC95742891BF3FD290027269A /* base.h */,\n\t\t\t\t3FE91FD116A90A8D00D1238A /* bitarray.c */,\n\t\t\t\t3FE91FD216A90A8D00D1238A /* bitarray.h */,\n\t\t\t\tC957427B1BF2C8DE0027269A /* debug.h */,\n\t\t\t\tC932D2641D6B73270063B19E /* dtrace.h */,\n\t\t\t\tC9ABCA041CB6FC6800ECB399 /* empty.s */,\n\t\t\t\tC95742A41BF6842F0027269A /* frozen_malloc.c */,\n\t\t\t\tC95742A51BF6842F0027269A /* frozen_malloc.h */,\n\t\t\t\tC957426D1BF2C0C80027269A /* internal.h */,\n\t\t\t\tC95742AA1BF685CB0027269A /* legacy_malloc.c */,\n\t\t\t\t3FE91FFB16A90E6C00D1238A /* legacy_malloc.h */,\n\t\t\t\tC957426E1BF2C1480027269A /* locking.h */,\n\t\t\t\tC95742921BF41C970027269A /* magazine_inline.h */,\n\t\t\t\tC957429B1BF672F80027269A /* magazine_large.c */,\n\t\t\t\t0D468DCC1C7BEE56006FACF5 /* magazine_lite.c */,\n\t\t\t\t3FE91FD616A90A8D00D1238A /* magazine_malloc.c */,\n\t\t\t\tC95742951BF41E480027269A /* magazine_malloc.h */,\n\t\t\t\tB65FBE2B2087AA2F00E21F59 /* malloc_printf.c */,\n\t\t\t\tC99E32091D6F7366005655A8 /* magazine_rack.c */,\n\t\t\t\tC99E320A1D6F7366005655A8 /* magazine_rack.h */,\n\t\t\t\tC95742981BF670D00027269A /* magazine_small.c */,\n\t\t\t\tC957428F1BF419DF0027269A /* magazine_tiny.c */,\n\t\t\t\tC95742861BF3F9550027269A /* magazine_zone.h */,\n\t\t\t\t3FE91FD716A90A8D00D1238A /* magmallocProvider.d */,\n\t\t\t\t3FE91FD816A90A8D00D1238A /* malloc.c */,\n\t\t\t\tB66C71D82034BFAE0047E265 /* malloc_common.c */,\n\t\t\t\tB66C71D72034BFAE0047E265 /* malloc_common.h */,\n\t\t\t\tB68B7F9D1FCDCBC600BAD1AA /* nano_malloc_common.c */,\n\t\t\t\tB68B7F9C1FCDCBC600BAD1AA /* nano_malloc_common.h */,\n\t\t\t\t3FE91FDA16A90A8D00D1238A /* nano_malloc.c */,\n\t\t\t\tC95742791BF2C5F40027269A /* nano_malloc.h */,\n\t\t\t\tC957427E1BF33D130027269A /* nano_zone.h */,\n\t\t\t\tB6CA64511FCF1AAD00DEBA12 /* nano_zone_common.h */,\n\t\t\t\tB68B7FA41FCDD9A500BAD1AA /* nanov2_malloc.c */,\n\t\t\t\tB68B7FA21FCDD60F00BAD1AA /* nanov2_malloc.h */,\n\t\t\t\tB6CA644D1FCE2C0A00DEBA12 /* nanov2_zone.h */,\n\t\t\t\tC9F77BBA1BF2B84800812E13 /* platform.h */,\n\t\t\t\t3FE91FD916A90A8D00D1238A /* printf.h */,\n\t\t\t\tC957429E1BF681B00027269A /* purgeable_malloc.c */,\n\t\t\t\tC957429F1BF681B00027269A /* purgeable_malloc.h */,\n\t\t\t\t3FE91FDC16A90A8D00D1238A /* stack_logging_disk.c */,\n\t\t\t\t0D468DCD1C7BEE65006FACF5 /* stack_logging_internal.h */,\n\t\t\t\tC957428C1BF411330027269A /* thresholds.h */,\n\t\t\t\tC938BBD21C74F7A400522BBD /* trace.h */,\n\t\t\t\tC932D2661D6B8D840063B19E /* vm.c */,\n\t\t\t\tC932D2671D6B8D840063B19E /* vm.h */,\n\t\t\t);\n\t\t\tpath = src;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3FE91FDF16A90A8D00D1238A /* xcodeconfig */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3FE91FE016A90A8D00D1238A /* libmalloc.xcconfig */,\n\t\t\t\t3FE91FE116A90A8D00D1238A /* libmalloc_eos.xcconfig */,\n\t\t\t\tC0CE450E1C52B9E300C24048 /* libmalloc_static.xcconfig */,\n\t\t\t\tB66AA658202A70B00019D607 /* libmalloc_resolved.xcconfig */,\n\t\t\t\tB629CF29202BA3C2007719B9 /* libmalloc_resolver.xcconfig */,\n\t\t\t\tB671CFFD207578CC00EEAF20 /* libmalloc.dirty */,\n\t\t\t);\n\t\t\tpath = xcodeconfig;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3FE91FE216A90A8D00D1238A /* xcodescripts */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3FC452FF18E4ABFE003D6A38 /* manpages.sh */,\n\t\t\t\t3FE91FE316A90A8D00D1238A /* sanitise_headers.sh */,\n\t\t\t\tC92853A01C767F08001FEAF3 /* install-codes.sh */,\n\t\t\t);\n\t\t\tpath = xcodescripts;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3FE91FE916A90AEC00D1238A /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3FE91FE816A90AEC00D1238A /* libsystem_malloc.dylib */,\n\t\t\t\t3FE9201016A9109E00D1238A /* libmalloc_eOS.a */,\n\t\t\t\t456E51C9197DF0D600A7E488 /* libmalloc_stress_test */,\n\t\t\t\tC0CE454C1C52C90500C24048 /* libmalloc.a */,\n\t\t\t\t08C28B401D501D2C000AE997 /* radix-tree */,\n\t\t\t\tB6D2ED512007D76F007AF994 /* libmalloc_replay */,\n\t\t\t\tB6910F89202B630D00FF2EB0 /* libmalloc_mp.a */,\n\t\t\t\tB629CF42202BB337007719B9 /* libmalloc_alt.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3FE91FF716A90BEF00D1238A /* include */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3FE91FF816A90BEF00D1238A /* malloc */,\n\t\t\t);\n\t\t\tpath = include;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3FE91FF816A90BEF00D1238A /* malloc */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2B67B5672040B3A50003E78F /* _malloc.h */,\n\t\t\t\t3FE91FF916A90BEF00D1238A /* malloc.h */,\n\t\t\t);\n\t\t\tpath = malloc;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3FFC1BE416A908F800027192 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3FE91FF716A90BEF00D1238A /* include */,\n\t\t\t\t3FE91FC816A90A8D00D1238A /* man */,\n\t\t\t\tC9571C381C18AA0A00A67EE3 /* private */,\n\t\t\t\t3FE91FCC16A90A8D00D1238A /* src */,\n\t\t\t\tB629CF45202BBDCC007719B9 /* resolver */,\n\t\t\t\t925383BD1BD03B4A00F745DB /* tests */,\n\t\t\t\t3FE91FDF16A90A8D00D1238A /* xcodeconfig */,\n\t\t\t\t3FE91FE216A90A8D00D1238A /* xcodescripts */,\n\t\t\t\t08C28B411D501D2C000AE997 /* tools */,\n\t\t\t\t3FE91FE916A90AEC00D1238A /* Products */,\n\t\t\t\t084F5E821D50204F006CD296 /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t\ttabWidth = 4;\n\t\t\tusesTabs = 1;\n\t\t};\n\t\t925383BD1BD03B4A00F745DB /* tests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8CB962B01F7E9F610046942E /* asan.c */,\n\t\t\t\t8CB962B11F7E9FD00046942E /* tsan.c */,\n\t\t\t\tC931B58F1C81248100D0D230 /* madvise.c */,\n\t\t\t\tC9F8C2691D74C93A008C4044 /* magazine_rack.c */,\n\t\t\t\tB6A494971F9918DD0016A799 /* calloc_test.c */,\n\t\t\t\tB6A9C48C1F991716007D0853 /* malloc_free_test.c */,\n\t\t\t\tB6A414EA1FBDF01C0038DC53 /* malloc_claimed_address_tests.c */,\n\t\t\t\tC9F8C2681D70B521008C4044 /* magazine_small_test.c */,\n\t\t\t\tB64E100A205311DC004C4BA6 /* malloc_size_test.c */,\n\t\t\t\tC93F76D71D6B9F8C0088931B /* magazine_testing.h */,\n\t\t\t\tC932D2631D6B6ED40063B19E /* magazine_tiny_test.c */,\n\t\t\t\tB69B2B941FB3D00500FD5A8F /* magazine_malloc.c */,\n\t\t\t\t925383D01BD03B4A00F745DB /* Makefile */,\n\t\t\t\tC9571C3B1C18AD4F00A67EE3 /* MallocBench */,\n\t\t\t\tC9571C661C18AD6A00A67EE3 /* MallocBench.cpp */,\n\t\t\t\tB6536A6320475BA4005FBE22 /* basic_malloc_free_perf.c */,\n\t\t\t\tB675F74520213D0A00B5038B /* nano_tests.c */,\n\t\t\t\tB6C1C9C720D9B70F002CCC0B /* nano_trace_replay.c */,\n\t\t\t\tB6536A62204754B6005FBE22 /* perf_contended_malloc_free.c */,\n\t\t\t\tB670DABD2072D0BB00139A1D /* perf_realloc.c */,\n\t\t\t\t088C4D761D1AEFC5005C6B36 /* radix_tree_test.m */,\n\t\t\t\t0D468DCE1C7BEE74006FACF5 /* stack_logging_test.c */,\n\t\t\t\t925383D11BD03B4A00F745DB /* stress_test.c */,\n\t\t\t);\n\t\t\tpath = tests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB629CF45202BBDCC007719B9 /* resolver */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB629CF48202BBE3B007719B9 /* resolver.h */,\n\t\t\t\tB629CF46202BBDEC007719B9 /* resolver_internal.h */,\n\t\t\t\tB6D5C7ED202E26CA0035E376 /* resolver.c */,\n\t\t\t);\n\t\t\tpath = resolver;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC9571C381C18AA0A00A67EE3 /* private */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC9571C391C18AA1D00A67EE3 /* stack_logging.h */,\n\t\t\t\tC0352EC61C3F3C3600DB5126 /* malloc_private.h */,\n\t\t\t);\n\t\t\tpath = private;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC9571C3B1C18AD4F00A67EE3 /* MallocBench */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tC9571C3C1C18AD5F00A67EE3 /* balloon.cpp */,\n\t\t\t\tC9571C3D1C18AD5F00A67EE3 /* balloon.h */,\n\t\t\t\tC9571C3E1C18AD5F00A67EE3 /* Benchmark.cpp */,\n\t\t\t\tC9571C3F1C18AD5F00A67EE3 /* Benchmark.h */,\n\t\t\t\tC9571C401C18AD5F00A67EE3 /* big.cpp */,\n\t\t\t\tC9571C411C18AD5F00A67EE3 /* big.h */,\n\t\t\t\tC9571C421C18AD5F00A67EE3 /* churn.cpp */,\n\t\t\t\tC9571C431C18AD5F00A67EE3 /* churn.h */,\n\t\t\t\tC9571C441C18AD5F00A67EE3 /* CommandLine.cpp */,\n\t\t\t\tC9571C451C18AD5F00A67EE3 /* CommandLine.h */,\n\t\t\t\tC9571C461C18AD5F00A67EE3 /* CPUCount.cpp */,\n\t\t\t\tC9571C471C18AD5F00A67EE3 /* CPUCount.h */,\n\t\t\t\tC9571C4C1C18AD5F00A67EE3 /* fragment.cpp */,\n\t\t\t\tC9571C4D1C18AD5F00A67EE3 /* fragment.h */,\n\t\t\t\tC9571C4E1C18AD5F00A67EE3 /* Interpreter.cpp */,\n\t\t\t\tC9571C4F1C18AD5F00A67EE3 /* Interpreter.h */,\n\t\t\t\tC9571C501C18AD5F00A67EE3 /* list.cpp */,\n\t\t\t\tC9571C511C18AD5F00A67EE3 /* list.h */,\n\t\t\t\tC9571C521C18AD5F00A67EE3 /* mbmalloc.cpp */,\n\t\t\t\tC9571C531C18AD5F00A67EE3 /* mbmalloc.h */,\n\t\t\t\tC9571C541C18AD5F00A67EE3 /* medium.cpp */,\n\t\t\t\tC9571C551C18AD5F00A67EE3 /* medium.h */,\n\t\t\t\tC9571C561C18AD5F00A67EE3 /* memalign.cpp */,\n\t\t\t\tC9571C571C18AD5F00A67EE3 /* memalign.h */,\n\t\t\t\tC9571C581C18AD5F00A67EE3 /* message.cpp */,\n\t\t\t\tC9571C591C18AD5F00A67EE3 /* message.h */,\n\t\t\t\tC9571C5A1C18AD5F00A67EE3 /* realloc.cpp */,\n\t\t\t\tC9571C5B1C18AD5F00A67EE3 /* realloc.h */,\n\t\t\t\tC9571C5E1C18AD5F00A67EE3 /* stress_aligned.cpp */,\n\t\t\t\tC9571C5F1C18AD5F00A67EE3 /* stress_aligned.h */,\n\t\t\t\tC9571C601C18AD5F00A67EE3 /* stress.cpp */,\n\t\t\t\tC9571C611C18AD5F00A67EE3 /* stress.h */,\n\t\t\t\tC9571C641C18AD5F00A67EE3 /* tree.cpp */,\n\t\t\t\tC9571C651C18AD5F00A67EE3 /* tree.h */,\n\t\t\t);\n\t\t\tpath = MallocBench;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXHeadersBuildPhase section */\n\t\t3FE91FE616A90AEC00D1238A /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC957428A1BF3FD290027269A /* base.h in Headers */,\n\t\t\t\tC0352EC71C3F3C4400DB5126 /* malloc_private.h in Headers */,\n\t\t\t\t0D468DD01C7BEF71006FACF5 /* stack_logging_internal.h in Headers */,\n\t\t\t\tC95742731BF2C2880027269A /* internal.h in Headers */,\n\t\t\t\tB6CA644E1FCE2C1900DEBA12 /* nanov2_zone.h in Headers */,\n\t\t\t\tC99E320C1D6F7366005655A8 /* magazine_rack.h in Headers */,\n\t\t\t\tC95742721BF2C2880027269A /* bitarray.h in Headers */,\n\t\t\t\tC932D2691D6B8D840063B19E /* vm.h in Headers */,\n\t\t\t\tB6CA64521FCF1AD200DEBA12 /* nano_zone_common.h in Headers */,\n\t\t\t\tC938BBD31C74F7A400522BBD /* trace.h in Headers */,\n\t\t\t\tC95742A81BF6842F0027269A /* frozen_malloc.h in Headers */,\n\t\t\t\tC957428D1BF411330027269A /* thresholds.h in Headers */,\n\t\t\t\tC95742741BF2C2880027269A /* locking.h in Headers */,\n\t\t\t\tC95742931BF41C970027269A /* magazine_inline.h in Headers */,\n\t\t\t\tB68B7FA31FCDD67100BAD1AA /* nanov2_malloc.h in Headers */,\n\t\t\t\tC95742761BF2C2880027269A /* platform.h in Headers */,\n\t\t\t\tC957427A1BF2C67E0027269A /* nano_malloc.h in Headers */,\n\t\t\t\tB66C71D92034BFAE0047E265 /* malloc_common.h in Headers */,\n\t\t\t\tC957427C1BF2C8DE0027269A /* debug.h in Headers */,\n\t\t\t\t2B67B5682040B3AF0003E78F /* _malloc.h in Headers */,\n\t\t\t\tC95742961BF41E480027269A /* magazine_malloc.h in Headers */,\n\t\t\t\tC9571C3A1C18AA1D00A67EE3 /* stack_logging.h in Headers */,\n\t\t\t\t3FE91FFA16A90BEF00D1238A /* malloc.h in Headers */,\n\t\t\t\tC95742871BF3F9550027269A /* magazine_zone.h in Headers */,\n\t\t\t\tC95742771BF2C2880027269A /* legacy_malloc.h in Headers */,\n\t\t\t\tC95742A21BF681B00027269A /* purgeable_malloc.h in Headers */,\n\t\t\t\tB68B7F9E1FCDCBC600BAD1AA /* nano_malloc_common.h in Headers */,\n\t\t\t\tC957427F1BF33D130027269A /* nano_zone.h in Headers */,\n\t\t\t\tC95742751BF2C2880027269A /* printf.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t3FE9200816A9109E00D1238A /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC95742941BF41C970027269A /* magazine_inline.h in Headers */,\n\t\t\t\tC95742801BF33D130027269A /* nano_zone.h in Headers */,\n\t\t\t\tB6CA644F1FCE2C1A00DEBA12 /* nanov2_zone.h in Headers */,\n\t\t\t\tC957428E1BF411330027269A /* thresholds.h in Headers */,\n\t\t\t\tC957427D1BF2C8DE0027269A /* debug.h in Headers */,\n\t\t\t\tC95742A91BF6842F0027269A /* frozen_malloc.h in Headers */,\n\t\t\t\tC95742881BF3F9550027269A /* magazine_zone.h in Headers */,\n\t\t\t\tC95742971BF41E480027269A /* magazine_malloc.h in Headers */,\n\t\t\t\tC95742A31BF681B00027269A /* purgeable_malloc.h in Headers */,\n\t\t\t\tC957428B1BF3FD290027269A /* base.h in Headers */,\n\t\t\t\tB6CA64531FCF1AD400DEBA12 /* nano_zone_common.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC0CE453F1C52C90500C24048 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC0CE45401C52C90500C24048 /* magazine_inline.h in Headers */,\n\t\t\t\tC0CE45411C52C90500C24048 /* nano_zone.h in Headers */,\n\t\t\t\tB6CA64501FCE2C1B00DEBA12 /* nanov2_zone.h in Headers */,\n\t\t\t\tC0CE45421C52C90500C24048 /* thresholds.h in Headers */,\n\t\t\t\tC0CE45431C52C90500C24048 /* debug.h in Headers */,\n\t\t\t\tC0CE45441C52C90500C24048 /* frozen_malloc.h in Headers */,\n\t\t\t\tC0CE45451C52C90500C24048 /* magazine_zone.h in Headers */,\n\t\t\t\tC0CE45461C52C90500C24048 /* magazine_malloc.h in Headers */,\n\t\t\t\tC0CE45471C52C90500C24048 /* purgeable_malloc.h in Headers */,\n\t\t\t\tC0CE45481C52C90500C24048 /* base.h in Headers */,\n\t\t\t\tB6CA64541FCF1AD400DEBA12 /* nano_zone_common.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXHeadersBuildPhase section */\n\n/* Begin PBXLegacyTarget section */\n\t\t925383D41BD03C0500F745DB /* darwintests */ = {\n\t\t\tisa = PBXLegacyTarget;\n\t\t\tbuildArgumentsString = \"$(ACTION)\";\n\t\t\tbuildConfigurationList = 925383D51BD03C0500F745DB /* Build configuration list for PBXLegacyTarget \"darwintests\" */;\n\t\t\tbuildPhases = (\n\t\t\t);\n\t\t\tbuildToolPath = /usr/bin/make;\n\t\t\tbuildWorkingDirectory = tests;\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = darwintests;\n\t\t\tpassBuildSettingsInEnvironment = 1;\n\t\t\tproductName = darwintests;\n\t\t};\n/* End PBXLegacyTarget section */\n\n/* Begin PBXNativeTarget section */\n\t\t08C28B3F1D501D2C000AE997 /* radix-tree */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 08C28B441D501D2C000AE997 /* Build configuration list for PBXNativeTarget \"radix-tree\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t08C28B3C1D501D2C000AE997 /* Sources */,\n\t\t\t\t08C28B3D1D501D2C000AE997 /* Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"radix-tree\";\n\t\t\tproductName = \"radix-tree\";\n\t\t\tproductReference = 08C28B401D501D2C000AE997 /* radix-tree */;\n\t\t\tproductType = \"com.apple.product-type.tool\";\n\t\t};\n\t\t3FE91FE716A90AEC00D1238A /* libsystem_malloc */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 3FE91FEA16A90AEC00D1238A /* Build configuration list for PBXNativeTarget \"libsystem_malloc\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t3FE91FE416A90AEC00D1238A /* Sources */,\n\t\t\t\t3FE91FE516A90AEC00D1238A /* Frameworks */,\n\t\t\t\t3FE91FE616A90AEC00D1238A /* Headers */,\n\t\t\t\tC92853A11C767F78001FEAF3 /* Install Codes File */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tB676F4AC202B66EF00933F6D /* PBXTargetDependency */,\n\t\t\t\tB629CF44202BB389007719B9 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = libsystem_malloc;\n\t\t\tproductName = libmalloc;\n\t\t\tproductReference = 3FE91FE816A90AEC00D1238A /* libsystem_malloc.dylib */;\n\t\t\tproductType = \"com.apple.product-type.library.dynamic\";\n\t\t};\n\t\t3FE91FFD16A9109E00D1238A /* libmalloc_eOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 3FE9200D16A9109E00D1238A /* Build configuration list for PBXNativeTarget \"libmalloc_eOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t3FE91FFE16A9109E00D1238A /* Sources */,\n\t\t\t\t3FE9200716A9109E00D1238A /* Frameworks */,\n\t\t\t\t3FE9200816A9109E00D1238A /* Headers */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = libmalloc_eOS;\n\t\t\tproductName = libmalloc;\n\t\t\tproductReference = 3FE9201016A9109E00D1238A /* libmalloc_eOS.a */;\n\t\t\tproductType = \"com.apple.product-type.library.static\";\n\t\t};\n\t\t456E51C8197DF0D600A7E488 /* libmalloc_stress_test */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 456E51CF197DF0D600A7E488 /* Build configuration list for PBXNativeTarget \"libmalloc_stress_test\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t456E51C5197DF0D600A7E488 /* Sources */,\n\t\t\t\t456E51C6197DF0D600A7E488 /* Frameworks */,\n\t\t\t\t456E51C7197DF0D600A7E488 /* CopyFiles */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = libmalloc_stress_test;\n\t\t\tproductName = libmalloc_stress_test;\n\t\t\tproductReference = 456E51C9197DF0D600A7E488 /* libmalloc_stress_test */;\n\t\t\tproductType = \"com.apple.product-type.tool\";\n\t\t};\n\t\tB629CF2B202BB337007719B9 /* libmalloc_alt */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = B629CF3F202BB337007719B9 /* Build configuration list for PBXNativeTarget \"libmalloc_alt\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tB629CF2C202BB337007719B9 /* Sources */,\n\t\t\t\tB629CF3D202BB337007719B9 /* Frameworks */,\n\t\t\t\tB629CF3E202BB337007719B9 /* Symlink normal variant */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = libmalloc_alt;\n\t\t\tproductName = libmalloc;\n\t\t\tproductReference = B629CF42202BB337007719B9 /* libmalloc_alt.a */;\n\t\t\tproductType = \"com.apple.product-type.library.static\";\n\t\t};\n\t\tB6910F65202B630D00FF2EB0 /* libmalloc_mp */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = B6910F86202B630D00FF2EB0 /* Build configuration list for PBXNativeTarget \"libmalloc_mp\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tB6910F66202B630D00FF2EB0 /* Sources */,\n\t\t\t\tB6910F77202B630D00FF2EB0 /* Frameworks */,\n\t\t\t\tB629CF2A202BB226007719B9 /* Symlink normal variant */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = libmalloc_mp;\n\t\t\tproductName = libmalloc;\n\t\t\tproductReference = B6910F89202B630D00FF2EB0 /* libmalloc_mp.a */;\n\t\t\tproductType = \"com.apple.product-type.library.static\";\n\t\t};\n\t\tB6D2ED492007D76F007AF994 /* libmalloc_replay */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = B6D2ED4E2007D76F007AF994 /* Build configuration list for PBXNativeTarget \"libmalloc_replay\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tB6D2ED4A2007D76F007AF994 /* Sources */,\n\t\t\t\tB6D2ED4C2007D76F007AF994 /* Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = libmalloc_replay;\n\t\t\tproductName = libmalloc_stress_test;\n\t\t\tproductReference = B6D2ED512007D76F007AF994 /* libmalloc_replay */;\n\t\t\tproductType = \"com.apple.product-type.tool\";\n\t\t};\n\t\tC0CE452F1C52C90500C24048 /* libmalloc_static */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = C0CE45491C52C90500C24048 /* Build configuration list for PBXNativeTarget \"libmalloc_static\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tC0CE45301C52C90500C24048 /* Sources */,\n\t\t\t\tC0CE453E1C52C90500C24048 /* Frameworks */,\n\t\t\t\tC0CE453F1C52C90500C24048 /* Headers */,\n\t\t\t\tC0CE454D1C52C9D900C24048 /* CopyFiles */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = libmalloc_static;\n\t\t\tproductName = libmalloc;\n\t\t\tproductReference = C0CE454C1C52C90500C24048 /* libmalloc.a */;\n\t\t\tproductType = \"com.apple.product-type.library.static\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t3FFC1BE516A908F800027192 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0700;\n\t\t\t\tLastUpgradeCheck = 0900;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t08C28B3F1D501D2C000AE997 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\t45039161198FFF73004EE2A3 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.0;\n\t\t\t\t\t};\n\t\t\t\t\t456E51C8197DF0D600A7E488 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.0;\n\t\t\t\t\t};\n\t\t\t\t\t925383D41BD03C0500F745DB = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.1;\n\t\t\t\t\t};\n\t\t\t\t\tB60A57932009307E006215CB = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.3;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 3FFC1BE816A908F800027192 /* Build configuration list for PBXProject \"libmalloc\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t);\n\t\t\tmainGroup = 3FFC1BE416A908F800027192;\n\t\t\tproductRefGroup = 3FE91FE916A90AEC00D1238A /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t3FE9201116A9111000D1238A /* libmalloc */,\n\t\t\t\t45039161198FFF73004EE2A3 /* libmalloc_test */,\n\t\t\t\t3FE91FE716A90AEC00D1238A /* libsystem_malloc */,\n\t\t\t\tB6910F65202B630D00FF2EB0 /* libmalloc_mp */,\n\t\t\t\tB629CF2B202BB337007719B9 /* libmalloc_alt */,\n\t\t\t\t3FE91FFD16A9109E00D1238A /* libmalloc_eOS */,\n\t\t\t\tC0CE452F1C52C90500C24048 /* libmalloc_static */,\n\t\t\t\tB6D2ED492007D76F007AF994 /* libmalloc_replay */,\n\t\t\t\t456E51C8197DF0D600A7E488 /* libmalloc_stress_test */,\n\t\t\t\t08C28B3F1D501D2C000AE997 /* radix-tree */,\n\t\t\t\t925383D41BD03C0500F745DB /* darwintests */,\n\t\t\t\tB60A57932009307E006215CB /* executables */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t3FC1927C16DD946500315C26 /* Install Man Pages */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 8;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"$(SRCROOT)/xcodescripts/manpages.sh\",\n\t\t\t);\n\t\t\tname = \"Install Man Pages\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 1;\n\t\t\tshellPath = \"/bin/bash -e\";\n\t\t\tshellScript = \". \\\"${SCRIPT_INPUT_FILE_0}\\\"\";\n\t\t};\n\t\t3FE9201D16A9143E00D1238A /* Sanitise Headers (rdar://problem/10241868) */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 8;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"$(SRCROOT)/xcodescripts/sanitise_headers.sh\",\n\t\t\t);\n\t\t\tname = \"Sanitise Headers (rdar://problem/10241868)\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 1;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \". \\\"${SCRIPT_INPUT_FILE_0}\\\"\";\n\t\t};\n\t\tB629CF2A202BB226007719B9 /* Symlink normal variant */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Symlink normal variant\";\n\t\t\toutputPaths = (\n\t\t\t\t\"$(CONFIGURATION_BUILD_DIR)/$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)_normal$(EXECUTABLE_SUFFIX)\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = \"/bin/bash -e -x\";\n\t\t\tshellScript = \"ln -fs \\\"${EXECUTABLE_PREFIX}${PRODUCT_NAME}${EXECUTABLE_SUFFIX}\\\" \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tB629CF3E202BB337007719B9 /* Symlink normal variant */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Symlink normal variant\";\n\t\t\toutputPaths = (\n\t\t\t\t\"$(CONFIGURATION_BUILD_DIR)/$(EXECUTABLE_PREFIX)$(PRODUCT_NAME)_normal$(EXECUTABLE_SUFFIX)\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = \"/bin/bash -e -x\";\n\t\t\tshellScript = \"ln -fs \\\"${EXECUTABLE_PREFIX}${PRODUCT_NAME}${EXECUTABLE_SUFFIX}\\\" \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tC92853A11C767F78001FEAF3 /* Install Codes File */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"$(SRCROOT)/src/trace.h\",\n\t\t\t);\n\t\t\tname = \"Install Codes File\";\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DSTROOT)/usr/local/share/misc/libmalloc.codes\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/bash;\n\t\t\tshellScript = \". \\\"$PROJECT_DIR\\\"/xcodescripts/install-codes.sh\";\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t08C28B3C1D501D2C000AE997 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t084F5E851D502102006CD296 /* radix_tree_debug.c in Sources */,\n\t\t\t\t08FEED021D501F6B00BE8A69 /* radix_tree_main.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t3FE91FE416A90AEC00D1238A /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t088C4D771D1AF049005C6B36 /* radix_tree.c in Sources */,\n\t\t\t\t3FE91FED16A90B9200D1238A /* bitarray.c in Sources */,\n\t\t\t\tB66C71DA2034BFAE0047E265 /* malloc_common.c in Sources */,\n\t\t\t\tC95742A01BF681B00027269A /* purgeable_malloc.c in Sources */,\n\t\t\t\tC957429C1BF672F80027269A /* magazine_large.c in Sources */,\n\t\t\t\t3FE91FF016A90B9200D1238A /* magazine_malloc.c in Sources */,\n\t\t\t\tC95742991BF670D00027269A /* magazine_small.c in Sources */,\n\t\t\t\tC99E320B1D6F7366005655A8 /* magazine_rack.c in Sources */,\n\t\t\t\tC95742AB1BF685CB0027269A /* legacy_malloc.c in Sources */,\n\t\t\t\tC932D2681D6B8D840063B19E /* vm.c in Sources */,\n\t\t\t\t3FE91FF116A90B9200D1238A /* magmallocProvider.d in Sources */,\n\t\t\t\t0D468DCF1C7BEF51006FACF5 /* magazine_lite.c in Sources */,\n\t\t\t\tB68B7FA51FCDD9A500BAD1AA /* nanov2_malloc.c in Sources */,\n\t\t\t\tB6D5C7F1202E26F80035E376 /* resolver.c in Sources */,\n\t\t\t\tB68B7F9F1FCDCBC600BAD1AA /* nano_malloc_common.c in Sources */,\n\t\t\t\t3FE91FF216A90B9200D1238A /* malloc.c in Sources */,\n\t\t\t\tC95742A61BF6842F0027269A /* frozen_malloc.c in Sources */,\n\t\t\t\t3FE91FF416A90B9200D1238A /* nano_malloc.c in Sources */,\n\t\t\t\t3FE91FF616A90B9200D1238A /* stack_logging_disk.c in Sources */,\n\t\t\t\tC95742901BF419DF0027269A /* magazine_tiny.c in Sources */,\n\t\t\t\tB65FBE2C2087AA2F00E21F59 /* malloc_printf.c in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t3FE91FFE16A9109E00D1238A /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tB66C71DB2034BFD30047E265 /* malloc_common.c in Sources */,\n\t\t\t\t3FE91FFF16A9109E00D1238A /* bitarray.c in Sources */,\n\t\t\t\tC95742A11BF681B00027269A /* purgeable_malloc.c in Sources */,\n\t\t\t\tC957429D1BF672F80027269A /* magazine_large.c in Sources */,\n\t\t\t\t3FE9200116A9109E00D1238A /* magazine_malloc.c in Sources */,\n\t\t\t\tC957429A1BF670D00027269A /* magazine_small.c in Sources */,\n\t\t\t\tC95742AC1BF685CB0027269A /* legacy_malloc.c in Sources */,\n\t\t\t\tB68B7FA01FCDCBE700BAD1AA /* nano_malloc_common.c in Sources */,\n\t\t\t\tB68B7FA61FCDD9B200BAD1AA /* nanov2_malloc.c in Sources */,\n\t\t\t\t3FE9200216A9109E00D1238A /* magmallocProvider.d in Sources */,\n\t\t\t\t3FE9200316A9109E00D1238A /* malloc.c in Sources */,\n\t\t\t\tC95742A71BF6842F0027269A /* frozen_malloc.c in Sources */,\n\t\t\t\t3FE9200416A9109E00D1238A /* nano_malloc.c in Sources */,\n\t\t\t\t3FE9200616A9109E00D1238A /* stack_logging_disk.c in Sources */,\n\t\t\t\tC95742911BF419DF0027269A /* magazine_tiny.c in Sources */,\n\t\t\t\tB6D5C7F4202E26F90035E376 /* resolver.c in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t456E51C5197DF0D600A7E488 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t925383DA1BD03D5100F745DB /* stress_test.c in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tB629CF2C202BB337007719B9 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tB629CF2D202BB337007719B9 /* radix_tree.c in Sources */,\n\t\t\t\tB629CF2E202BB337007719B9 /* bitarray.c in Sources */,\n\t\t\t\tB629CF2F202BB337007719B9 /* purgeable_malloc.c in Sources */,\n\t\t\t\tB6D5C7F3202E26F90035E376 /* resolver.c in Sources */,\n\t\t\t\tB629CF30202BB337007719B9 /* magazine_large.c in Sources */,\n\t\t\t\tB629CF31202BB337007719B9 /* magazine_malloc.c in Sources */,\n\t\t\t\tB629CF32202BB337007719B9 /* empty.s in Sources */,\n\t\t\t\tB629CF33202BB337007719B9 /* magazine_small.c in Sources */,\n\t\t\t\tB629CF34202BB337007719B9 /* legacy_malloc.c in Sources */,\n\t\t\t\tB629CF35202BB337007719B9 /* magmallocProvider.d in Sources */,\n\t\t\t\tB629CF36202BB337007719B9 /* malloc.c in Sources */,\n\t\t\t\tB629CF37202BB337007719B9 /* frozen_malloc.c in Sources */,\n\t\t\t\tB629CF38202BB337007719B9 /* nanov2_malloc.c in Sources */,\n\t\t\t\tB629CF39202BB337007719B9 /* nano_malloc.c in Sources */,\n\t\t\t\tB629CF3A202BB337007719B9 /* stack_logging_disk.c in Sources */,\n\t\t\t\tB629CF3B202BB337007719B9 /* magazine_tiny.c in Sources */,\n\t\t\t\tB629CF3C202BB337007719B9 /* nano_malloc_common.c in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tB6910F66202B630D00FF2EB0 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tB6910F67202B630D00FF2EB0 /* radix_tree.c in Sources */,\n\t\t\t\tB6910F68202B630D00FF2EB0 /* bitarray.c in Sources */,\n\t\t\t\tB6910F69202B630D00FF2EB0 /* purgeable_malloc.c in Sources */,\n\t\t\t\tB6D5C7F2202E26F80035E376 /* resolver.c in Sources */,\n\t\t\t\tB6910F6A202B630D00FF2EB0 /* magazine_large.c in Sources */,\n\t\t\t\tB6910F6B202B630D00FF2EB0 /* magazine_malloc.c in Sources */,\n\t\t\t\tB6910F6C202B630D00FF2EB0 /* empty.s in Sources */,\n\t\t\t\tB6910F6D202B630D00FF2EB0 /* magazine_small.c in Sources */,\n\t\t\t\tB6910F6E202B630D00FF2EB0 /* legacy_malloc.c in Sources */,\n\t\t\t\tB6910F6F202B630D00FF2EB0 /* magmallocProvider.d in Sources */,\n\t\t\t\tB6910F70202B630D00FF2EB0 /* malloc.c in Sources */,\n\t\t\t\tB6910F71202B630D00FF2EB0 /* frozen_malloc.c in Sources */,\n\t\t\t\tB629CF28202BA149007719B9 /* nanov2_malloc.c in Sources */,\n\t\t\t\tB6910F73202B630D00FF2EB0 /* nano_malloc.c in Sources */,\n\t\t\t\tB6910F74202B630D00FF2EB0 /* stack_logging_disk.c in Sources */,\n\t\t\t\tB6910F75202B630D00FF2EB0 /* magazine_tiny.c in Sources */,\n\t\t\t\tB6910F76202B630D00FF2EB0 /* nano_malloc_common.c in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tB6D2ED4A2007D76F007AF994 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tB6D2ED572007D91A007AF994 /* malloc_replay.cpp in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC0CE45301C52C90500C24048 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t088C4D841D1AF16F005C6B36 /* radix_tree.c in Sources */,\n\t\t\t\tC0CE45311C52C90500C24048 /* bitarray.c in Sources */,\n\t\t\t\tC0CE45321C52C90500C24048 /* purgeable_malloc.c in Sources */,\n\t\t\t\tB6D5C7F5202E26FA0035E376 /* resolver.c in Sources */,\n\t\t\t\tC0CE45331C52C90500C24048 /* magazine_large.c in Sources */,\n\t\t\t\tC0CE45341C52C90500C24048 /* magazine_malloc.c in Sources */,\n\t\t\t\tC9ABCA051CB6FC6800ECB399 /* empty.s in Sources */,\n\t\t\t\tC0CE45351C52C90500C24048 /* magazine_small.c in Sources */,\n\t\t\t\tC0CE45361C52C90500C24048 /* legacy_malloc.c in Sources */,\n\t\t\t\tC0CE45371C52C90500C24048 /* magmallocProvider.d in Sources */,\n\t\t\t\tC0CE45381C52C90500C24048 /* malloc.c in Sources */,\n\t\t\t\tC0CE45391C52C90500C24048 /* frozen_malloc.c in Sources */,\n\t\t\t\tB68B7FA71FCDD9B200BAD1AA /* nanov2_malloc.c in Sources */,\n\t\t\t\tB66C71DC2034BFD40047E265 /* malloc_common.c in Sources */,\n\t\t\t\tC0CE453A1C52C90500C24048 /* nano_malloc.c in Sources */,\n\t\t\t\tC0CE453C1C52C90500C24048 /* stack_logging_disk.c in Sources */,\n\t\t\t\tC0CE453D1C52C90500C24048 /* magazine_tiny.c in Sources */,\n\t\t\t\tB68B7FA11FCDCBE800BAD1AA /* nano_malloc_common.c in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t3FE9201616A9111400D1238A /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 3FE91FFD16A9109E00D1238A /* libmalloc_eOS */;\n\t\t\ttargetProxy = 3FE9201516A9111400D1238A /* PBXContainerItemProxy */;\n\t\t};\n\t\t3FE9201816A9111600D1238A /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 3FE91FE716A90AEC00D1238A /* libsystem_malloc */;\n\t\t\ttargetProxy = 3FE9201716A9111600D1238A /* PBXContainerItemProxy */;\n\t\t};\n\t\t45039168198FFFA6004EE2A3 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 456E51C8197DF0D600A7E488 /* libmalloc_stress_test */;\n\t\t\ttargetProxy = 45039167198FFFA6004EE2A3 /* PBXContainerItemProxy */;\n\t\t};\n\t\t925383D91BD03D0000F745DB /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 925383D41BD03C0500F745DB /* darwintests */;\n\t\t\ttargetProxy = 925383D81BD03D0000F745DB /* PBXContainerItemProxy */;\n\t\t};\n\t\tB60A579820093093006215CB /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = B6D2ED492007D76F007AF994 /* libmalloc_replay */;\n\t\t\ttargetProxy = B60A579720093093006215CB /* PBXContainerItemProxy */;\n\t\t};\n\t\tB629CF44202BB389007719B9 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = B629CF2B202BB337007719B9 /* libmalloc_alt */;\n\t\t\ttargetProxy = B629CF43202BB389007719B9 /* PBXContainerItemProxy */;\n\t\t};\n\t\tB676F4AC202B66EF00933F6D /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = B6910F65202B630D00FF2EB0 /* libmalloc_mp */;\n\t\t\ttargetProxy = B676F4AB202B66EF00933F6D /* PBXContainerItemProxy */;\n\t\t};\n\t\tC0CE45501C52CCBD00C24048 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = C0CE452F1C52C90500C24048 /* libmalloc_static */;\n\t\t\ttargetProxy = C0CE454F1C52CCBD00C24048 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin XCBuildConfiguration section */\n\t\t08C28B451D501D2C000AE997 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t08C28B461D501D2C000AE997 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t3FE91FEB16A90AEC00D1238A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = B629CF29202BA3C2007719B9 /* libmalloc_resolver.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t3FE91FEC16A90AEC00D1238A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = B629CF29202BA3C2007719B9 /* libmalloc_resolver.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t3FE9200E16A9109E00D1238A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 3FE91FE116A90A8D00D1238A /* libmalloc_eos.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t3FE9200F16A9109E00D1238A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 3FE91FE116A90A8D00D1238A /* libmalloc_eos.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t3FE9201316A9111000D1238A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t3FE9201416A9111000D1238A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t3FFC1BE916A908F800027192 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t3FFC1BEA16A908F800027192 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t45039163198FFF73004EE2A3 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t45039164198FFF73004EE2A3 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t456E51CD197DF0D600A7E488 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx.internal;\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos appletvos watchos\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t456E51CE197DF0D600A7E488 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx.internal;\n\t\t\t\t\"SKIP_INSTALL[sdk=iphonesimulator*]\" = YES;\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos appletvos watchos\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t925383D61BD03C0500F745DB /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx.internal;\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos appletvos watchos\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t925383D71BD03C0500F745DB /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx.internal;\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos appletvos watchos\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tB60A57942009307E006215CB /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB60A57952009307E006215CB /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tB629CF40202BB337007719B9 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = B66AA658202A70B00019D607 /* libmalloc_resolved.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tPRODUCT_NAME = \"$(PRODUCT_NAME)\";\n\t\t\t\tRESOLVED_VARIANT = alt;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB629CF41202BB337007719B9 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = B66AA658202A70B00019D607 /* libmalloc_resolved.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tPRODUCT_NAME = \"$(PRODUCT_NAME)\";\n\t\t\t\tRESOLVED_VARIANT = alt;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tB6910F87202B630D00FF2EB0 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = B66AA658202A70B00019D607 /* libmalloc_resolved.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tPRODUCT_NAME = \"$(PRODUCT_NAME)\";\n\t\t\t\tRESOLVED_VARIANT = mp;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB6910F88202B630D00FF2EB0 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = B66AA658202A70B00019D607 /* libmalloc_resolved.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tPRODUCT_NAME = \"$(PRODUCT_NAME)\";\n\t\t\t\tRESOLVED_VARIANT = mp;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tB6D2ED4F2007D76F007AF994 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++0x\";\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(SDKROOT)/System/Library/PrivateFrameworks\",\n\t\t\t\t\t\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\",\n\t\t\t\t);\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(SRCROOT)/src\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx.internal;\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator\";\n\t\t\t\tVALID_ARCHS = \"armv6 armv7 arm64 arm64_32 armv7k x86_64 x86_64h\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB6D2ED502007D76F007AF994 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++0x\";\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(SDKROOT)/System/Library/PrivateFrameworks\",\n\t\t\t\t\t\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(SRCROOT)/src\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx.internal;\n\t\t\t\t\"SKIP_INSTALL[sdk=iphonesimulator*]\" = YES;\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator\";\n\t\t\t\tVALID_ARCHS = \"armv6 armv7 arm64 arm64_32 armv7k x86_64 x86_64h\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tC0CE454A1C52C90500C24048 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = C0CE450E1C52B9E300C24048 /* libmalloc_static.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tPRODUCT_NAME = \"$(PRODUCT_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tC0CE454B1C52C90500C24048 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = C0CE450E1C52B9E300C24048 /* libmalloc_static.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tPRODUCT_NAME = \"$(PRODUCT_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t08C28B441D501D2C000AE997 /* Build configuration list for PBXNativeTarget \"radix-tree\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t08C28B451D501D2C000AE997 /* Debug */,\n\t\t\t\t08C28B461D501D2C000AE997 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t3FE91FEA16A90AEC00D1238A /* Build configuration list for PBXNativeTarget \"libsystem_malloc\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t3FE91FEB16A90AEC00D1238A /* Debug */,\n\t\t\t\t3FE91FEC16A90AEC00D1238A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t3FE9200D16A9109E00D1238A /* Build configuration list for PBXNativeTarget \"libmalloc_eOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t3FE9200E16A9109E00D1238A /* Debug */,\n\t\t\t\t3FE9200F16A9109E00D1238A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t3FE9201216A9111000D1238A /* Build configuration list for PBXAggregateTarget \"libmalloc\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t3FE9201316A9111000D1238A /* Debug */,\n\t\t\t\t3FE9201416A9111000D1238A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t3FFC1BE816A908F800027192 /* Build configuration list for PBXProject \"libmalloc\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t3FFC1BE916A908F800027192 /* Debug */,\n\t\t\t\t3FFC1BEA16A908F800027192 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t45039162198FFF73004EE2A3 /* Build configuration list for PBXAggregateTarget \"libmalloc_test\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t45039163198FFF73004EE2A3 /* Debug */,\n\t\t\t\t45039164198FFF73004EE2A3 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t456E51CF197DF0D600A7E488 /* Build configuration list for PBXNativeTarget \"libmalloc_stress_test\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t456E51CD197DF0D600A7E488 /* Debug */,\n\t\t\t\t456E51CE197DF0D600A7E488 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t925383D51BD03C0500F745DB /* Build configuration list for PBXLegacyTarget \"darwintests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t925383D61BD03C0500F745DB /* Debug */,\n\t\t\t\t925383D71BD03C0500F745DB /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tB60A57962009307E006215CB /* Build configuration list for PBXAggregateTarget \"executables\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB60A57942009307E006215CB /* Debug */,\n\t\t\t\tB60A57952009307E006215CB /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tB629CF3F202BB337007719B9 /* Build configuration list for PBXNativeTarget \"libmalloc_alt\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB629CF40202BB337007719B9 /* Debug */,\n\t\t\t\tB629CF41202BB337007719B9 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tB6910F86202B630D00FF2EB0 /* Build configuration list for PBXNativeTarget \"libmalloc_mp\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB6910F87202B630D00FF2EB0 /* Debug */,\n\t\t\t\tB6910F88202B630D00FF2EB0 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tB6D2ED4E2007D76F007AF994 /* Build configuration list for PBXNativeTarget \"libmalloc_replay\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB6D2ED4F2007D76F007AF994 /* Debug */,\n\t\t\t\tB6D2ED502007D76F007AF994 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tC0CE45491C52C90500C24048 /* Build configuration list for PBXNativeTarget \"libmalloc_static\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tC0CE454A1C52C90500C24048 /* Debug */,\n\t\t\t\tC0CE454B1C52C90500C24048 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 3FFC1BE516A908F800027192 /* Project object */;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/man/malloc.3",
    "content": ".\\\" Copyright (c) 2006 Apple Computer, Inc.  All rights reserved.\n.\\\"\n.\\\" @APPLE_LICENSE_HEADER_START@\n.\\\"\n.\\\" The contents of this file constitute Original Code as defined in and\n.\\\" are subject to the Apple Public Source License Version 1.1 (the\n.\\\" \"License\").  You may not use this file except in compliance with the\n.\\\" License.  Please obtain a copy of the License at\n.\\\" http://www.apple.com/publicsource and read it before using this file.\n.\\\"\n.\\\" This Original Code and all software distributed under the License are\n.\\\" distributed on an \"AS IS\" basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n.\\\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n.\\\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n.\\\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the\n.\\\" License for the specific language governing rights and limitations\n.\\\" under the License.\n.\\\"\n.\\\" @APPLE_LICENSE_HEADER_END@\n.\\\"\n.Dd Aug 13, 2008\n.Dt MALLOC 3\n.Os\n.Sh NAME\n.Nm calloc ,\n.Nm free ,\n.Nm malloc ,\n.Nm realloc ,\n.Nm reallocf ,\n.Nm valloc\n.Nd memory allocation\n.Sh SYNOPSIS\n.In stdlib.h\n.Ft void *\n.Fo calloc\n.Fa \"size_t count\"\n.Fa \"size_t size\"\n.Fc\n.Ft void\n.Fo free\n.Fa \"void *ptr\"\n.Fc\n.Ft void *\n.Fo malloc\n.Fa \"size_t size\"\n.Fc\n.Ft void *\n.Fo realloc\n.Fa \"void *ptr\"\n.Fa \"size_t size\"\n.Fc\n.Ft void *\n.Fo reallocf\n.Fa \"void *ptr\"\n.Fa \"size_t size\"\n.Fc\n.Ft void *\n.Fo valloc\n.Fa \"size_t size\"\n.Fc\n.Sh DESCRIPTION\nThe\n.Fn malloc ,\n.Fn calloc ,\n.Fn valloc ,\n.Fn realloc ,\nand\n.Fn reallocf\nfunctions allocate memory.\nThe allocated memory is aligned such that it can be used for any data type,\nincluding AltiVec- and SSE-related types.\nThe\n.Fn free\nfunction frees allocations that were created via the preceding allocation\nfunctions.\n.Pp\nThe\n.Fn malloc\nfunction allocates\n.Fa size\nbytes of memory and returns a pointer to the allocated memory.\n.Pp\nThe\n.Fn calloc\nfunction contiguously allocates enough space for\n.Fa count\nobjects that are\n.Fa size\nbytes of memory each and returns a pointer to the allocated memory.\nThe allocated memory is filled with bytes of value zero.\n.Pp\nThe\n.Fn valloc\nfunction allocates\n.Fa size\nbytes of memory and returns a pointer to the allocated memory.\nThe allocated memory is aligned on a page boundary.\n.Pp\nThe\n.Fn realloc\nfunction tries to change the size of the allocation pointed to by\n.Fa ptr\nto\n.Fa size ,\nand returns\n.Fa ptr .\nIf there is not enough room to enlarge the memory allocation pointed to by\n.Fa ptr ,\n.Fn realloc\ncreates a new allocation, copies as much of the old data pointed to by\n.Fa ptr\nas will fit to the new allocation, frees the old allocation, and returns a\npointer to the allocated memory.\nIf\n.Fa ptr\nis \n.Dv NULL ,\n.Fn realloc\nis identical to a call to \n.Fn malloc\nfor \n.Fa size\nbytes.\nIf\n.Fa size\nis zero and \n.Fa ptr\nis not \n.Dv NULL ,\na new, minimum sized object is allocated and the original object is freed.\nWhen extending a region allocated with calloc(3), realloc(3) does not guarantee \nthat the additional memory is also zero-filled.\n.Pp\nThe\n.Fn reallocf\nfunction is identical to the\n.Fn realloc\nfunction, except that it\nwill free the passed pointer when the requested memory cannot be allocated.\nThis is a\n.Fx\nspecific API designed to ease the problems with traditional coding styles\nfor realloc causing memory leaks in libraries.\n.Pp\nThe\n.Fn free\nfunction deallocates the memory allocation pointed to by\n.Fa ptr .  If\n.Fa ptr \nis a NULL pointer, no operation is performed.\n.Sh RETURN VALUES\nIf successful,\n.Fn calloc ,\n.Fn malloc ,\n.Fn realloc ,\n.Fn reallocf ,\nand\n.Fn valloc\nfunctions return a pointer to allocated memory.\nIf there is an error, they return a\n.Dv NULL\npointer and set\n.Va errno\nto\n.Er ENOMEM .\n.Pp\nFor\n.Fn realloc ,\nthe input pointer is still valid if reallocation failed.\nFor\n.Fn reallocf ,\nthe input pointer will have been freed if reallocation failed.\n.Pp\nThe\n.Fn free\nfunction does not return a value.\n.Sh DEBUGGING ALLOCATION ERRORS\nA number of facilities are provided to aid in debugging allocation errors in\napplications.\nThese facilities are primarily controlled via environment variables.\nThe recognized environment variables and their meanings are documented below.\n.Sh ENVIRONMENT\nThe following environment variables change the behavior of the\nallocation-related functions.\n.Bl -tag -width \".Ev MallocStackLoggingNoCompact\"\n.It Ev MallocDebugReport\nIf set, specifies where messages are written. Set to \"stderr\" to write messages\nto the standard error stream, \"none\" to discard all messages and \"crash\" to\nwrite messages to standard error only for a condition that is about to cause a\ncrash. When not set, message are written to the standard error stream if it\nappears to be a terminal (that is, if isatty(STDERR_FILENO) returns a non-zero\nvalue) and are otherwise discarded.\n.It Ev MallocGuardEdges\nIf set, add a guard page before and after each large block.\n.It Ev MallocDoNotProtectPrelude\nIf set, do not add a guard page before large blocks,\neven if the\n.Ev MallocGuardEdges\nenvironment variable is set.\n.It Ev MallocDoNotProtectPostlude\nIf set, do not add a guard page after large blocks,\neven if the\n.Ev MallocGuardEdges\nenvironment variable is set.\n.It Ev MallocStackLogging\nThe default behavior if this is set is to record all allocation and deallocation events to an on-disk log, along with stacks, so that tools like\n.Xr leaks 1\nand\n.Xr malloc_history 1\ncan be used.\n.Pp\nSet to \"vm\" to record only allocation of virtual memory regions allocated by system calls and mach traps, such as by\n.Xr mmap 1\n.\n.Pp\nSet to \"malloc\" to record only allocations via\n.Xr malloc 3\nand related interfaces, not virtual memory regions.\n.Pp\nSet to \"lite\" to record current allocations only, not history.   These are recorded by in-memory data structures, instead of an on-disk log.\n.It Ev MallocStackLoggingNoCompact\nIf set, record all stacks in a manner that is compatible with the\n.Nm malloc_history\nprogram.\n.It Ev MallocStackLoggingDirectory\nIf set, records stack logs to the directory specified instead of saving them to the default location (/tmp).\n.It Ev MallocScribble\nIf set, fill memory that has been allocated with 0xaa bytes.\nThis increases the likelihood that a program making assumptions about the contents of\nfreshly allocated memory will fail.\nAlso if set, fill memory that has been deallocated with 0x55 bytes.\nThis increases the likelihood that a program will fail due to accessing memory\nthat is no longer allocated. Note that due to the way in which freed memory is\nmanaged internally, the 0x55 pattern may not appear in some parts of a\ndeallocated memory block.\n.It Ev MallocCheckHeapStart <s>\nIf set, specifies the number of allocations\n.Fa <s>\nto wait before begining periodic heap checks every\n.Fa <n>\nas specified by \n.Ev MallocCheckHeapEach .\nIf\n.Ev MallocCheckHeapStart\nis set but \n.Ev MallocCheckHeapEach\nis not specified, the default check repetition is 1000.\n.It Ev MallocCheckHeapEach <n>\nIf set, run a consistency check on the heap every\n.Fa <n>\noperations.\n.Ev MallocCheckHeapEach\nis only meaningful if\n.Ev MallocCheckHeapStart\nis also set.\n.It Ev MallocCheckHeapSleep <t>\nSets the number of seconds to sleep (waiting for a debugger to attach) when\n.Ev MallocCheckHeapStart\nis set and a heap corruption is detected.\nThe default is 100 seconds.\nSetting this to zero means not to sleep at all.\nSetting this to a negative number means to sleep (for the positive number of\nseconds) only the very first time a heap corruption is detected.\n.It Ev MallocCheckHeapAbort <b>\nWhen\n.Ev MallocCheckHeapStart\nis set and this is set to a non-zero value, causes\n.Xr abort 3\nto be called if a heap corruption is detected, instead of any sleeping.\n.It Ev MallocErrorAbort\nIf set, causes\n.Xr abort 3\nto be called if an error was encountered in\n.Xr malloc 3\nor \n.Xr free 3\n, such as a calling\n.Xr free 3\non a pointer previously freed.\n.It Ev MallocCorruptionAbort\nSimilar to\n.Ev MallocErrorAbort \nbut will not abort in out of memory conditions, making it more useful to catch\nonly those errors which will cause memory corruption.\nMallocCorruptionAbort is always set on 64-bit processes.\n.It Ev MallocHelp\nIf set, print a list of environment variables that are paid heed to by the\nallocation-related functions, along with short descriptions.\nThe list should correspond to this documentation.\n.El\n.Sh DIAGNOSTIC MESSAGES\n.Sh SEE ALSO\n.Xr leaks 1 ,\n.Xr malloc_history 1 ,\n.Xr abort 3 ,\n.Xr malloc_size 3 ,\n.Xr malloc_zone_malloc 3 ,\n.Xr posix_memalign 3 ,\n.Xr libgmalloc 3\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/man/malloc_size.3",
    "content": ".\\\" Copyright (c) 2006 Apple Computer, Inc.  All rights reserved.\n.\\\"\n.\\\" @APPLE_LICENSE_HEADER_START@\n.\\\"\n.\\\" The contents of this file constitute Original Code as defined in and\n.\\\" are subject to the Apple Public Source License Version 1.1 (the\n.\\\" \"License\").  You may not use this file except in compliance with the\n.\\\" License.  Please obtain a copy of the License at\n.\\\" http://www.apple.com/publicsource and read it before using this file.\n.\\\"\n.\\\" This Original Code and all software distributed under the License are\n.\\\" distributed on an \"AS IS\" basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n.\\\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n.\\\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n.\\\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the\n.\\\" License for the specific language governing rights and limitations\n.\\\" under the License.\n.\\\"\n.\\\" @APPLE_LICENSE_HEADER_END@\n.\\\"\n.Dd May 23, 2006\n.Dt MALLOC_SIZE 3\n.Os\n.Sh NAME\n.Nm malloc_good_size ,\n.Nm malloc_size\n.Nd memory allocation information\n.Sh SYNOPSIS\n.In malloc/malloc.h\n.Ft size_t\n.Fo malloc_good_size\n.Fa \"size_t size\"\n.Fc\n.Ft size_t\n.Fo malloc_size\n.Fa \"const void *ptr\"\n.Fc\n.Sh DESCRIPTION\nThe\n.Fn malloc_size\nfunction returns the size of the memory block\nthat backs the allocation pointed to by\n.Fa ptr .\nThe memory block size is always at least as large\nas the allocation it backs, and may be larger.\n.Pp\nThe\n.Fn malloc_good_size\nfunction rounds\n.Fa size\nup to a value that the allocator implementation can allocate\nwithout adding any padding;\nit then returns that rounded-up value.\n.Sh SEE ALSO\n.Xr malloc 3\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/man/malloc_zone_malloc.3",
    "content": ".\\\" Copyright (c) 2008 Apple, Inc.  All rights reserved.\n.\\\"\n.\\\" @APPLE_LICENSE_HEADER_START@\n.\\\"\n.\\\" The contents of this file constitute Original Code as defined in and\n.\\\" are subject to the Apple Public Source License Version 1.1 (the\n.\\\" \"License\").  You may not use this file except in compliance with the\n.\\\" License.  Please obtain a copy of the License at\n.\\\" http://www.apple.com/publicsource and read it before using this file.\n.\\\"\n.\\\" This Original Code and all software distributed under the License are\n.\\\" distributed on an \"AS IS\" basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n.\\\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n.\\\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n.\\\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the\n.\\\" License for the specific language governing rights and limitations\n.\\\" under the License.\n.\\\"\n.\\\" @APPLE_LICENSE_HEADER_END@\n.\\\"\n.Dd Aug 13, 2008\n.Dt MALLOC_ZONE_MALLOC 3\n.Os\n.Sh NAME\n.Nm malloc_create_zone ,\n.Nm malloc_destroy_zone ,\n.Nm malloc_default_zone ,\n.Nm malloc_zone_from_ptr ,\n.Nm malloc_zone_malloc ,\n.Nm malloc_zone_calloc ,\n.Nm malloc_zone_valloc ,\n.Nm malloc_zone_realloc ,\n.Nm malloc_zone_memalign ,\n.Nm malloc_zone_free\n.Nd zone-based memory allocation\n.Sh SYNOPSIS\n.In malloc/malloc.h\n.Ft malloc_zone_t *\n.Fo malloc_create_zone\n.Fa \"vm_size_t start_size\"\n.Fa \"unsigned flags\"\n.Fc\n.Ft void\n.Fo malloc_destroy_zone\n.Fa \"malloc_zone_t *zone\"\n.Fc\n.Ft malloc_zone_t *\n.Fo malloc_default_zone\n.Fa void\n.Fc\n.Ft malloc_zone_t *\n.Fo malloc_zone_from_ptr\n.Fa \"const void *ptr\"\n.Fc\n.Ft void *\n.Fo malloc_zone_malloc\n.Fa \"malloc_zone_t *zone\"\n.Fa \"size_t size\"\n.Fc\n.Ft void *\n.Fo malloc_zone_calloc\n.Fa \"malloc_zone_t *zone\"\n.Fa \"size_t num_items\"\n.Fa \"size_t size\"\n.Fc\n.Ft void *\n.Fo malloc_zone_valloc\n.Fa \"malloc_zone_t *zone\"\n.Fa \"size_t size\"\n.Fc\n.Ft void *\n.Fo malloc_zone_realloc\n.Fa \"malloc_zone_t *zone\"\n.Fa \"void *ptr\"\n.Fa \"size_t size\"\n.Fc\n.Ft void *\n.Fo malloc_zone_memalign\n.Fa \"malloc_zone_t *zone\"\n.Fa \"size_t alignment\"\n.Fa \"size_t size\"\n.Fc\n.Ft void\n.Fo malloc_zone_free\n.Fa \"malloc_zone_t *zone\"\n.Fa \"void *ptr\"\n.Fc\n.Sh DESCRIPTION\nThe\n.Fn malloc_create_zone\nfunction creates a malloc zone, advising an initial allocation of\n.Fa start_size\nbytes, and specifying \n.Fa flags\nThe returned malloc zone can be used to provide custom allocation and \ndeallocation behavior, and to retrieve additional information about the\nallocations in that zone.\nAt present there are no client settable flag values recognized by malloc_create_zone(),\nthe flags argument should always be passed as zero.\n.Pp\nThe\n.Fn malloc_destroy_zone\nfunction deallocates all memory associated with objects in \n.Fa zone\nas well as \n.Fa zone\nitself.\n.Pp\nThe\n.Fn malloc_default_zone\nfunction returns the default system malloc zone, used by\n.Xr malloc 3 ,\nand\n.Xr free 3 .\n.Pp\nThe\n.Fn malloc_zone_from_ptr\nfunction returns a pointer to the malloc zone which contains\n.Fa ptr\nor NULL, if the pointer does not point to an allocated object in any current\nmalloc zone.\n.Pp\nThe\n.Fn malloc_zone_malloc ,\n.Fn malloc_zone_calloc ,\n.Fn malloc_zone_valloc ,\n.Fn malloc_zone_realloc ,\n.Fn malloc_zone_memalign ,\nand\n.Fn malloc_zone_free\nperform the same task on\n.Fa zone\nas their non-prefixed variants, \n.Xr malloc 3 ,\n.Xr calloc 3 ,\n.Xr valloc 3 ,\n.Xr realloc 3 ,\n.Xr posix_memalign 3 ,\nand \n.Xr free 3 perform on the default system malloc zone.\n.Sh RETURN VALUES\nThe \n.Fn malloc_create_zone ,\n.Fn malloc_default_zone ,\nand\n.Fn malloc_zone_from_ptr\nfunctions return a pointer to a malloc_zone_t structure, or NULL if there was\nan error.\n.Pp\nThe \n.Fn malloc_zone_malloc ,\n.Fn malloc_zone_calloc ,\n.Fn malloc_zone_valloc ,\n.Fn malloc_zone_realloc ,\nand\n.Fn malloc_zone_memalign\nfunctions return a pointer to allocated memory.  If there is an error, they \nreturn a NULL pointer.  They are not required to set \n.Va errno .\n.Sh SEE ALSO\n.Xr malloc 3 ,\n.Xr posix_memalign 3\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/man/manpages.lst",
    "content": "# manpage tables\n# <source> <dest> [<link> <link> ...]\n\n# man3\nmalloc.3 malloc.3 calloc.3 free.3 realloc.3 reallocf.3 valloc.3\nmalloc_size.3 malloc_size.3 malloc_good_size.3\nmalloc_zone_malloc.3 malloc_zone_malloc.3 malloc_create_zone.3 malloc_destroy_zone.3 malloc_default_zone.3 malloc_zone_from_ptr.3 malloc_zone_calloc.3 malloc_zone_valloc.3 malloc_zone_realloc.3 malloc_zone_memalign.3 malloc_zone_free.3\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/private/malloc_private.h",
    "content": "/*\n * Copyright (c) 1999-2016 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _MALLOC_PRIVATE_H_\n#define _MALLOC_PRIVATE_H_\n\n/* Here be dragons (SPIs) */\n\n#include <mach/boolean.h>\n#include <sys/cdefs.h>\n#include <Availability.h>\n#include <os/availability.h>\n#include <malloc/malloc.h>\n\n/*********\tCallbacks\t************/\n\nAPI_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0))\nvoid malloc_enter_process_memory_limit_warn_mode(void);\n\t/* A callback invoked once the process receives a warning for approaching\n\t * memory limit. */\n\n__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0)\n__TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0)\nvoid malloc_memory_event_handler(unsigned long);\n\t/* A function invoked when malloc needs to handle any flavor of\n\t * memory pressure notification or process memory limit notification. */\n\nAPI_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0))\nvoid * reallocarray(void * in_ptr, size_t nmemb, size_t size) __DARWIN_EXTSN(reallocarray) __result_use_check;\n\nAPI_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0))\nvoid * reallocarrayf(void * in_ptr, size_t nmemb, size_t size) __DARWIN_EXTSN(reallocarrayf) __result_use_check;\n\n/*\n * Checks whether an address might belong to any registered zone. False positives\n * are allowed (e.g. the memory was freed, or it's in a part of the address\n * space used by malloc that has not yet been allocated.) False negatives are\n * not allowed.\n */\nAPI_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0))\nboolean_t malloc_claimed_address(void *ptr) __result_use_check;\n\n/*\n * Checks whether an address might belong to a given zone. False positives are\n * allowed (e.g. the memory was freed, or it's in a part of the address space\n * used by malloc that has not yet been allocated.) False negatives are not\n * allowed.\n */\nAPI_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0))\nboolean_t malloc_zone_claimed_address(malloc_zone_t *zone, void *ptr) __result_use_check;\n\n/**\n * Returns whether the nano allocator is engaged. The return value is 0 if Nano\n * is not engaged and the allocator version otherwise.\n */\nAPI_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0))\nint malloc_engaged_nano(void) __result_use_check;\n\n#endif /* _MALLOC_PRIVATE_H_ */\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/private/stack_logging.h",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#import <stdbool.h>\n#import <malloc/malloc.h>\n#import <mach/vm_statistics.h>\n#import <sys/cdefs.h>\n#import <os/availability.h>\n\n#define STACK_LOGGING_MAX_STACK_SIZE 512\n\n#define stack_logging_type_free\t\t0\n#define stack_logging_type_generic\t1\t/* anything that is not allocation/deallocation */\n#define stack_logging_type_alloc\t2\t/* malloc, realloc, etc... */\n#define stack_logging_type_dealloc\t4\t/* free, realloc, etc... */\n#define stack_logging_type_vm_allocate  16      /* vm_allocate or mmap */\n#define stack_logging_type_vm_deallocate  32\t/* vm_deallocate or munmap */\n#define stack_logging_type_mapped_file_or_shared_mem\t128\n\n// The valid flags include those from VM_FLAGS_ALIAS_MASK, which give the user_tag of allocated VM regions.\n#define stack_logging_valid_type_flags ( \\\n\tstack_logging_type_generic | \\\n\tstack_logging_type_alloc | \\\n\tstack_logging_type_dealloc | \\\n\tstack_logging_type_vm_allocate | \\\n\tstack_logging_type_vm_deallocate | \\\n\tstack_logging_type_mapped_file_or_shared_mem | \\\n\tVM_FLAGS_ALIAS_MASK);\n\n// Following flags are absorbed by stack_logging_log_stack()\n#define\tstack_logging_flag_zone\t\t8\t/* NSZoneMalloc, etc... */\n#define stack_logging_flag_cleared\t64\t/* for NewEmptyHandle */\n\n#define STACK_LOGGING_VM_USER_TAG(flags) (((flags) & VM_FLAGS_ALIAS_MASK) >> 24)\n\n\n/* Macro used to disguise addresses so that leak finding can work */\n#define STACK_LOGGING_DISGUISE(address)\t((address) ^ 0x00005555) /* nicely idempotent */\n\ntypedef enum {\n\tstack_logging_mode_none = 0,\n\tstack_logging_mode_all,\n\tstack_logging_mode_malloc,\n\tstack_logging_mode_vm,\n\tstack_logging_mode_lite,\n\tstack_logging_mode_vmlite\n} stack_logging_mode_type;\n\nextern boolean_t turn_on_stack_logging(stack_logging_mode_type mode);\nextern void turn_off_stack_logging();\n\n/* constants for enabling/disabling malloc stack logging via the memorystatus_vm_pressure_send sysctl */\n#define\tMEMORYSTATUS_ENABLE_MSL_MALLOC\t\t0x10000000\n#define MEMORYSTATUS_ENABLE_MSL_VM\t\t\t0x20000000\n#define MEMORYSTATUS_ENABLE_MSL_LITE\t\t0x40000000\n#define MEMORYSTATUS_DISABLE_MSL\t\t\t0x80000000\n#define MEMORYSTATUS_ENABLE_MSL_LITE_FULL\t(MEMORYSTATUS_ENABLE_MSL_LITE | MEMORYSTATUS_ENABLE_MSL_VM | MEMORYSTATUS_ENABLE_MSL_MALLOC)\n#define MEMORYSTATUS_ENABLE_MSL_LITE_VM\t\t(MEMORYSTATUS_ENABLE_MSL_LITE | MEMORYSTATUS_ENABLE_MSL_VM)\n\nextern void __disk_stack_logging_log_stack(uint32_t type_flags, uintptr_t zone_ptr, uintptr_t size, uintptr_t ptr_arg, uintptr_t return_val, uint32_t num_hot_to_skip);\n\t/* Fits as the malloc_logger; logs malloc/free/realloc events and can log custom events if called directly */\n\n\n/* 64-bit-aware stack log access.  As new SPI, these routines are prefixed with double-underscore to avoid conflict with Libsystem clients. */\n\ntypedef struct mach_stack_logging_record {\n\tuint32_t\t\ttype_flags;\n\tuint64_t\t\tstack_identifier;\n\tuint64_t\t\targument;\n\tmach_vm_address_t\taddress;\n} mach_stack_logging_record_t;\n\nextern kern_return_t __mach_stack_logging_start_reading(task_t task, vm_address_t shared_memory_address, boolean_t *uses_lite_mode);\nextern kern_return_t __mach_stack_logging_stop_reading(task_t task);\n\n/* Clients *should* call these start/stop functions to properly initialize stack logging data\n * structures and fully clean them up when they're done looking at a process.  If the client does *not*\n * call these then currently it should still work but some data structures will still remain after\n * reading the stack logs (e.g., an extra shared memory segment, an open stack log file, etc).\n * NULL can be passed for uses_lite_mode if the client doesn’t need them.\n *\n * It is recommended that the client suspend the task before actually reading the stacks, and resume the task when done,\n * if the task uses lite mode.\n */\n\nextern kern_return_t __mach_stack_logging_set_file_path(task_t task, char* file_path);\n\nextern kern_return_t __mach_stack_logging_get_frames(task_t task, mach_vm_address_t address, mach_vm_address_t *stack_frames_buffer, uint32_t max_stack_frames, uint32_t *count);\n    /* Gets the last allocation record (malloc, realloc, or free) about address */\n\nextern kern_return_t __mach_stack_logging_enumerate_records(task_t task, mach_vm_address_t address, void enumerator(mach_stack_logging_record_t, void *), void *context);\n    /* Applies enumerator to all records involving address sending context as enumerator's second parameter; if !address, applies enumerator to all records */\n\nextern kern_return_t __mach_stack_logging_frames_for_uniqued_stack(task_t task, uint64_t stack_identifier, mach_vm_address_t *stack_frames_buffer, uint32_t max_stack_frames, uint32_t *count)\n\tAPI_DEPRECATED(\"use __mach_stack_logging_get_frames_for_stackid instead\", macos(10.9, 10.13), ios(7.0, 11.0), watchos(1.0, 4.0), tvos(9.0, 11.0));\n    /* Given a uniqued_stack fills stack_frames_buffer. */\n\nextern kern_return_t __mach_stack_logging_get_frames_for_stackid(task_t task, uint64_t stack_identifier, mach_vm_address_t *stack_frames_buffer, uint32_t max_stack_frames, uint32_t *count,\n                                                                     bool *last_frame_is_threadid)\n\tAPI_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));\n    /* Given a uniqued_stack fills stack_frames_buffer. */\n\nextern uint64_t __mach_stack_logging_stackid_for_vm_region(task_t task, mach_vm_address_t address);\n\t/* given the address of a vm region, lookup it's stackid */\n\n\nstruct backtrace_uniquing_table;\n\nextern kern_return_t\n__mach_stack_logging_uniquing_table_read_stack(struct backtrace_uniquing_table *uniquing_table,\n\t\t\t\t\t\t\t\t\t\t\t   uint64_t stackid,\n\t\t\t\t\t\t\t\t\t\t\t   mach_vm_address_t *out_frames_buffer,\n\t\t\t\t\t\t\t\t\t\t\t   uint32_t *out_frames_count,\n\t\t\t\t\t\t\t\t\t\t\t   uint32_t max_frames);\n\nextern\nstruct backtrace_uniquing_table *\n__mach_stack_logging_copy_uniquing_table(task_t task);\n/* returns a retained pointer to copy of the task's uniquing table */\n\nextern\nvoid\n__mach_stack_logging_uniquing_table_release(struct backtrace_uniquing_table *);\n\nextern\nvoid\n__mach_stack_logging_uniquing_table_retain(struct backtrace_uniquing_table *);\n\nextern\nsize_t\n__mach_stack_logging_uniquing_table_sizeof(struct backtrace_uniquing_table *);\n/* returns the serialized size of a uniquing talbe in bytes */\n\nextern\nvoid *\n__mach_stack_logging_uniquing_table_serialize(struct backtrace_uniquing_table *table, mach_vm_size_t *size);\n/* Writes out a serialized representation of the table.  Free it with mach_vm_deallocate. */\n\nextern\nstruct backtrace_uniquing_table *\n__mach_stack_logging_uniquing_table_copy_from_serialized(void *buffer, size_t size);\n/* creates a malloc uniquing table from a serialized representation */\n\n\nextern void thread_stack_pcs(vm_address_t *buffer, unsigned max, unsigned *num);\n    /* Convenience to fill buffer with the PCs of the frames, starting with the hot frames;\n    num: returned number of frames\n    */\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/resolver/resolver.c",
    "content": "/*\n * Copyright (c) 2018 Apple Inc. All rights reserved.\n *\n * @APPLE_APACHE_LICENSE_HEADER_START@\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * @APPLE_APACHE_LICENSE_HEADER_END@\n */\n\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/resolver/resolver.h",
    "content": "/*\n * Copyright (c) 2018 Apple Inc. All rights reserved.\n *\n * @APPLE_APACHE_LICENSE_HEADER_START@\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * @APPLE_APACHE_LICENSE_HEADER_END@\n */\n\n#ifndef __MALLOC_RESOLVER_H__\n#define __MALLOC_RESOLVER_H__\n\n#include \"resolver_internal.h\"\n\n\n#endif // __MALLOC_RESOLVER_H__\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/resolver/resolver_internal.h",
    "content": "/*\n * Copyright (c) 2018 Apple Inc. All rights reserved.\n *\n * @APPLE_APACHE_LICENSE_HEADER_START@\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * @APPLE_APACHE_LICENSE_HEADER_END@\n */\n\n#ifndef __MALLOC_RESOLVER_INTERNAL_H__\n#define __MALLOC_RESOLVER_INTERNAL_H__\n\n#define OS_RESOLVED_VARIANT_ADDR(s) (void *)(&s)\n\n#endif // __MALLOC_RESOLVER_INTERNAL_H__\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/base.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __BASE_H\n#define __BASE_H\n\n#ifndef __has_extension\n#define __has_extension(x) 0\n#endif\n\n#if __has_extension(c_static_assert)\n#define MALLOC_STATIC_ASSERT(x, y) _Static_assert((x), y)\n#else\n#define MALLOC_STATIC_ASSERT(x, y)\n#endif\n\n#define MALLOC_ASSERT(e) ({ \\\n\tif (__builtin_expect(!(e), 0)) { \\\n\t\t__asm__ __volatile__ (\"\"); \\\n\t\t__builtin_trap(); \\\n\t} \\\n})\n\n#define MALLOC_FATAL_ERROR(cause, message) ({ \\\n\t\t_os_set_crash_log_cause_and_message((cause), \"FATAL ERROR - \" message); \\\n\t\t__asm__ __volatile__ (\"\"); \\\n\t\t__builtin_trap(); \\\n})\n\n#define MALLOC_REPORT_FATAL_ERROR(cause, message) ({ \\\n\t\tmalloc_report(ASL_LEVEL_ERR, \"*** FATAL ERROR - \" message \".\\n\"); \\\n\t\tMALLOC_FATAL_ERROR((cause), message); \\\n})\n\n#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__)\n#   define __APPLE_API_PRIVATE\n#   include <machine/cpu_capabilities.h>\n#   if defined(__i386__) || defined(__x86_64__)\n#      define _COMM_PAGE_VERSION_REQD 9\n#   else\n#      define _COMM_PAGE_VERSION_REQD 3\n#   endif\n#   undef __APPLE_API_PRIVATE\n#else\n#   include <sys/sysctl.h>\n#endif\n\n#if defined(__i386__) || defined(__x86_64__)\n// <rdar://problem/23495834> nano vs. magazine have different definitions\n// for this cache-line size.\n#   define MALLOC_CACHE_LINE 128\n#   define MALLOC_NANO_CACHE_LINE 64\n#elif defined(__arm__) || defined(__arm64__)\n#   define MALLOC_CACHE_LINE 64\n#   define MALLOC_NANO_CACHE_LINE 64\n#else\n#   define MALLOC_CACHE_LINE 32\n#   define MALLOC_NANO_CACHE_LINE 32\n#endif\n\n#define MALLOC_CACHE_ALIGN __attribute__ ((aligned (MALLOC_CACHE_LINE) ))\n#define MALLOC_NANO_CACHE_ALIGN __attribute__ ((aligned (MALLOC_NANO_CACHE_LINE) ))\n#define MALLOC_EXPORT extern __attribute__((visibility(\"default\")))\n#define MALLOC_NOEXPORT __attribute__((visibility(\"hidden\")))\n#define MALLOC_NOINLINE __attribute__((noinline))\n#define MALLOC_INLINE __inline__\n#define MALLOC_ALWAYS_INLINE __attribute__((always_inline))\n#define MALLOC_PACKED __attribute__((packed))\n#define MALLOC_USED __attribute__((used))\n#define MALLOC_UNUSED __attribute__((unused))\n#define CHECK_MAGAZINE_PTR_LOCKED(szone, mag_ptr, fun) {}\n\n#define SCRIBBLE_BYTE 0xaa /* allocated scribble */\n#define SCRABBLE_BYTE 0x55 /* free()'d scribble */\n#define SCRUBBLE_BYTE 0xdd /* madvise(..., MADV_FREE) scriblle */\n\n#define NDEBUG 1\n#define trunc_page_quanta(x) trunc_page((x))\n#define round_page_quanta(x) round_page((x))\n#define vm_page_quanta_size (vm_page_size)\n#define vm_page_quanta_shift (vm_page_shift)\n\n// add a guard page before and after each VM region to help debug\n#define MALLOC_ADD_GUARD_PAGES (1 << 0)\n// do not protect prelude page\n#define MALLOC_DONT_PROTECT_PRELUDE (1 << 1)\n// do not protect postlude page\n#define MALLOC_DONT_PROTECT_POSTLUDE (1 << 2)\n// write 0x55 onto free blocks\n#define MALLOC_DO_SCRIBBLE (1 << 3)\n// call abort() on any malloc error, such as double free or out of memory.\n#define MALLOC_ABORT_ON_ERROR (1 << 4)\n// allocate objects such that they may be used with VM purgability APIs\n#define MALLOC_PURGEABLE (1 << 5)\n// call abort() on malloc errors, but not on out of memory.\n#define MALLOC_ABORT_ON_CORRUPTION (1 << 6)\n// expanded small-zone free list size (256 slots)\n#define MALLOC_EXTENDED_SMALL_SLOTS (1 << 7)\n\n/*\n * msize - a type to refer to the number of quanta of a tiny or small\n * allocation.  A tiny block with an msize of 3 would be 3 << SHIFT_TINY_QUANTUM\n * bytes in size.\n */\ntypedef unsigned short msize_t;\n\ntypedef unsigned int grain_t; // N.B. wide enough to index all free slots\ntypedef struct large_entry_s large_entry_t;\ntypedef struct szone_s szone_t;\ntypedef struct rack_s rack_t;\ntypedef struct magazine_s magazine_t;\ntypedef int mag_index_t;\ntypedef void *region_t;\n\n#endif // __BASE_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/bitarray.c",
    "content": "/*\n * Copyright (c) 1999, 2000, 2003, 2005, 2008, 2012 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n//\n//  bitarray.c\n//  bitarray\n//\n//  Created by Bertrand Serlet on 9/26/10.\n//  Copyright (c) 2010 Apple. All rights reserved.\n//\n\n#include \"internal.h\"\n\n/******************************** Utilities ***************************/\n\n#define STATIC_INLINE static __inline\n\nSTATIC_INLINE unsigned\n__ffsll(uint64_t xx)\n{\n#if defined(__LP64__)\n\treturn __builtin_ffsl(xx);\n#else\n\treturn __builtin_ffsll(xx);\n#endif\n}\n\n#define BIT_SET(old, bit) ((old) | (1ULL << (bit)))\n#define BIT_GET(old, bit) ((old) & (1ULL << (bit)))\n#define BIT_ZAP(old, bit) ((old) & ~(1ULL << (bit)))\n\n// several variants below of bit setting or zapping to generate minimal code\n// All these do 1 memory read and (maybe) 1 memory write\nSTATIC_INLINE bool\nword_get_bit_simple(uint64_t *word, unsigned bit)\n{\n\tuint64_t old = *word;\n\treturn BIT_GET(old, bit) != 0;\n}\n\nSTATIC_INLINE void\nword_set_bit_simple(uint64_t *word, unsigned bit)\n{\n\tuint64_t old = *word;\n\t*word = BIT_SET(old, bit);\n}\n\nSTATIC_INLINE bool\nword_set_bit_changed(uint64_t *word, unsigned bit)\n{\n\t// returns 1 iff word has changed\n\tuint64_t old = *word;\n\tuint64_t new = BIT_SET(old, bit);\n\tif (old == new) {\n\t\treturn 0;\n\t}\n\t*word = new;\n\treturn 1;\n}\n\nSTATIC_INLINE bool\nword_set_bit_changed_go_down(uint64_t *word, unsigned bit, bool *was_non_zero)\n{\n\t// returns 1 iff word changed\n\t// sets was_non_zero (when something changed)\n\tuint64_t old = *word;\n\tuint64_t new = BIT_SET(old, bit);\n\tif (old == new) {\n\t\treturn 0;\n\t}\n\t*word = new;\n\t*was_non_zero = old != 0;\n\treturn 1;\n}\n\nSTATIC_INLINE bool\nword_set_bit_go_down(uint64_t *word, unsigned bit)\n{\n\t// returns 1 iff level below should be set too\n\tuint64_t old = *word;\n\tuint64_t new = BIT_SET(old, bit);\n\tif (old == new) {\n\t\treturn 0;\n\t}\n\t*word = new;\n\treturn !old;\n}\n\nSTATIC_INLINE void\nword_zap_bit_simple(uint64_t *word, unsigned bit)\n{\n\tuint64_t old = *word;\n\t*word = BIT_ZAP(old, bit);\n}\n\nSTATIC_INLINE bool\nword_zap_bit_changed(uint64_t *word, unsigned bit)\n{\n\t// returns 1 iff word changed\n\tuint64_t old = *word;\n\tuint64_t new = BIT_ZAP(old, bit);\n\tif (old == new) {\n\t\treturn 0;\n\t}\n\t*word = new;\n\treturn 1;\n}\n\nSTATIC_INLINE bool\nword_zap_bit_changed_go_down(uint64_t *word, unsigned bit, bool *is_now_zero)\n{\n\t// returns 1 iff word changed\n\t// sets is_now_zero (when something changed)\n\tuint64_t old = *word;\n\tuint64_t new = BIT_ZAP(old, bit);\n\tif (old == new) {\n\t\treturn 0;\n\t}\n\t*word = new;\n\t*is_now_zero = !new;\n\treturn 1;\n}\n\nSTATIC_INLINE bool\nword_zap_bit_go_down(uint64_t *word, unsigned bit)\n{\n\t// returns 1 iff level below might require a bit-zeroing\n\tuint64_t old = *word;\n\tuint64_t new = BIT_ZAP(old, bit);\n\tif (old == new) {\n\t\treturn 0;\n\t}\n\t*word = new;\n\treturn !new;\n}\n\n/******************************** Helpers ***************************/\n\n#define NB 9 // number of bits we process at once\n// must be at least 6 (64-bit) and 9 seems the best on x86\n#define MASKNB ((1 << NB) - 1)  // to just keep these bits\n#define NUM_64b (1 << (NB - 6)) // number of 64-bit words we process at once\n\n// number of uint64_t of summaries\n#define LEVEL0 (NUM_64b)\n#define LEVEL1 (LEVEL0 + (1 << NB) * NUM_64b)\n#define LEVEL2 (LEVEL1 + (1 << (NB + NB)) * NUM_64b)\n#define LEVEL3 (LEVEL2 + (1 << (NB + NB + NB)) * NUM_64b)\n\n#define MAX_LEVEL 5\n\nstatic const unsigned levels_num_words[] = {\n\t\tLEVEL0, LEVEL1, LEVEL2, LEVEL3}; // this encodes the number of words reserved for the bitmap summaries at various levels\n\nSTATIC_INLINE bool\nGET_SIMPLE(uint64_t *word, unsigned bit)\n{\n\treturn word_get_bit_simple(word + (bit >> 6), bit & 63);\n}\n\nSTATIC_INLINE void\nSET_SIMPLE(uint64_t *word, unsigned bit)\n{\n\tword_set_bit_simple(word + (bit >> 6), bit & 63);\n}\n\nSTATIC_INLINE bool\nSET_CHANGED(uint64_t *word, unsigned bit)\n{\n\t// returns 1 iff word changed\n\treturn word_set_bit_changed(word + (bit >> 6), bit & 63);\n}\n\nSTATIC_INLINE bool\nSET_CHANGED_GO_DOWN(uint64_t *word, unsigned bit, bool *was_non_zero)\n{\n\t// returns 1 iff word changed\n\t// sets was_non_zero (when something changed)\n\treturn word_set_bit_changed_go_down(word + (bit >> 6), bit & 63, was_non_zero);\n}\n\nSTATIC_INLINE bool\nSET_GO_DOWN(uint64_t *word, unsigned bit)\n{\n\t// returns 1 iff level below should be set too\n\treturn word_set_bit_go_down(word + (bit >> 6), bit & 63);\n}\n\nSTATIC_INLINE void\nZAP_SIMPLE(uint64_t *word, unsigned bit)\n{\n\treturn word_zap_bit_simple(word + (bit >> 6), bit & 63);\n}\n\nSTATIC_INLINE bool\nZAP_CHANGED(uint64_t *word, unsigned bit)\n{\n\t// returns 1 iff word changed\n\treturn word_zap_bit_changed(word + (bit >> 6), bit & 63);\n}\n\nSTATIC_INLINE bool\nall_zeros(uint64_t *words)\n{\n\tfor (unsigned w = 0; w < NUM_64b; w++) {\n\t\tif (words[w]) {\n\t\t\treturn 0;\n\t\t}\n\t}\n\treturn 1;\n}\n\nSTATIC_INLINE bool\nZAP_CHANGED_GO_DOWN(uint64_t *word, unsigned bit, bool *is_now_zero)\n{\n\t// returns 1 iff word changed\n\t// sets is_now_zero (when something changed)\n\tbool changed = word_zap_bit_changed_go_down(word + (bit >> 6), bit & 63, is_now_zero);\n\tif (changed && (NUM_64b != 1)) {\n\t\t// One component went entirely zero, now examine all components in the level\n\t\tif (!all_zeros(word)) {\n\t\t\t*is_now_zero = 0;\n\t\t}\n\t}\n\treturn changed;\n}\n\nSTATIC_INLINE bool\nZAP_GO_DOWN(uint64_t *word, unsigned bit)\n{\n\t// returns 1 iff level below should be changed too\n\tbool changed = word_zap_bit_go_down(word + (bit >> 6), bit & 63);\n\tif (changed && (NUM_64b != 1)) {\n\t\t// One component went entirely zero, now examine all components in the level\n\t\tif (!all_zeros(word)) {\n\t\t\treturn 0;\n\t\t}\n\t}\n\treturn changed;\n}\n\nSTATIC_INLINE unsigned\nFFS(uint64_t *word)\n{\n// does NUM_64b memory reads, at most\n#if NB == 6\n\treturn __ffsll(*word);\n#else\n\tfor (unsigned w = 0; w < NUM_64b; w++) {\n\t\tunsigned f = __ffsll(word[w]);\n\t\tif (f) {\n\t\t\treturn f + (w << 6);\n\t\t}\n\t}\n\treturn 0;\n#endif\n}\n\n/******************************** Entry Points ***************************/\n\nsize_t\nbitarray_size(unsigned log_size)\n{\n\tassert(log_size <= MAX_LEVEL * NB);\n\tunsigned num = NUM_64b;\n\tif (log_size > NB) {\n\t\tunsigned level = (log_size - NB - 1) / NB;\n\t\tnum = levels_num_words[level] + (1 << (log_size - 6));\n\t}\n\treturn num * sizeof(uint64_t);\n}\n\nbitarray_t\nbitarray_create(unsigned log_size)\n{\n\treturn calloc(1, bitarray_size(log_size));\n}\n\nbool\nbitarray_get(bitarray_t bits, unsigned log_size, index_t index)\n{\n\tassert(log_size <= MAX_LEVEL * NB);\n\tassert(index < (1 << log_size));\n\tif (log_size <= NB) {\n\t\treturn GET_SIMPLE(bits, index);\n\t}\n\tunsigned level = (log_size - NB - 1) / NB;\n\tunsigned bit;\n\tbit = index & MASKNB;\n\tindex >>= NB;\n\treturn GET_SIMPLE(bits + levels_num_words[level] + index * NUM_64b, bit);\n}\n\nbool\nbitarray_set(bitarray_t bits, unsigned log_size, index_t index)\n{\n\t// returns whether changed\n\tassert(log_size <= MAX_LEVEL * NB);\n\tassert(index < (1 << log_size));\n\tif (log_size <= NB) {\n\t\treturn SET_CHANGED(bits, index);\n\t}\n\tunsigned level = (log_size - NB - 1) / NB;\n\tbool was_non_zero;\n\tunsigned bit;\n\tbit = index & MASKNB;\n\tindex >>= NB;\n\t// printf(\"SET_CHANGED_GO_DOWN(bits + %d, %d,…)\\n\", levels_num_words[level] + index, bit);\n\tif (!SET_CHANGED_GO_DOWN(bits + levels_num_words[level] + index * NUM_64b, bit, &was_non_zero)) {\n\t\treturn 0;\n\t}\n\tif (was_non_zero) {\n\t\treturn 1;\n\t}\n\tswitch (level) {\n\tcase 3:\n\t\tbit = index & MASKNB;\n\t\tindex >>= NB;\n\t\tif (!SET_GO_DOWN(bits + LEVEL2 + index * NUM_64b, bit)) {\n\t\t\treturn 1;\n\t\t}\n\t/* no break */\n\tcase 2:\n\t\tbit = index & MASKNB;\n\t\tindex >>= NB;\n\t\tif (!SET_GO_DOWN(bits + LEVEL1 + index * NUM_64b, bit)) {\n\t\t\treturn 1;\n\t\t}\n\t/* no break */\n\tcase 1:\n\t\tbit = index & MASKNB;\n\t\tindex >>= NB;\n\t\tif (!SET_GO_DOWN(bits + LEVEL0 + index * NUM_64b, bit)) {\n\t\t\treturn 1;\n\t\t}\n\t/* no break */\n\tcase 0:\n\t\tSET_SIMPLE(bits, index & MASKNB);\n\t\treturn 1;\n\tdefault:\n\t\tMALLOC_FATAL_ERROR(level, \"invalid bitarray level\");\n\t}\n}\n\nbool\nbitarray_zap(bitarray_t bits, unsigned log_size, index_t index)\n{\n\tassert(log_size <= MAX_LEVEL * NB);\n\tassert(index < (1 << log_size));\n\tif (log_size <= NB) {\n\t\treturn ZAP_CHANGED(bits, index);\n\t}\n\tunsigned level = (log_size - NB - 1) / NB;\n\tbool is_now_zero;\n\tunsigned bit;\n\tbit = index & MASKNB;\n\tindex >>= NB;\n\tif (!ZAP_CHANGED_GO_DOWN(bits + levels_num_words[level] + index * NUM_64b, bit, &is_now_zero)) {\n\t\treturn 0;\n\t}\n\tif (!is_now_zero) {\n\t\treturn 1;\n\t}\n\tswitch (level) {\n\tcase 3:\n\t\tbit = index & MASKNB;\n\t\tindex >>= NB;\n\t\tif (!ZAP_GO_DOWN(bits + LEVEL2 + index * NUM_64b, bit)) {\n\t\t\treturn 1;\n\t\t}\n\t/* no break */\n\tcase 2:\n\t\tbit = index & MASKNB;\n\t\tindex >>= NB;\n\t\tif (!ZAP_GO_DOWN(bits + LEVEL1 + index * NUM_64b, bit)) {\n\t\t\treturn 1;\n\t\t}\n\t/* no break */\n\tcase 1:\n\t\tbit = index & MASKNB;\n\t\tindex >>= NB;\n\t\tif (!ZAP_GO_DOWN(bits + LEVEL0 + index * NUM_64b, bit)) {\n\t\t\treturn 1;\n\t\t}\n\t/* no break */\n\tcase 0:\n\t\tZAP_SIMPLE(bits, index & MASKNB);\n\t\treturn 1;\n\tdefault:\n\t\tMALLOC_FATAL_ERROR(level, \"invalid bitarray level\");\n\t}\n}\n\n// Note in the following macro that \"words\" and \"base\" are variables being written\n#define ADJUST_OFFSET_FOR_FFS(words, base, current_level)      \\\n\t{                                                          \\\n\t\twords += (1 << (NB * current_level)) * NUM_64b;        \\\n\t\tbase = (base << NB) + FFS(words + base * NUM_64b) - 1; \\\n\t}\n\n// Note in the following macro that \"words\" and \"base\" are variables being written\n#define ADJUST_OFFSET_FOR_FFS_ACROSS_SUMMARIES(words, base, level) \\\n\t{                                                              \\\n\t\tswitch (level) {                                           \\\n\t\tcase 4:                                                    \\\n\t\t\tADJUST_OFFSET_FOR_FFS(words, base, 0);                 \\\n\t\t\tADJUST_OFFSET_FOR_FFS(words, base, 1);                 \\\n\t\t\tADJUST_OFFSET_FOR_FFS(words, base, 2);                 \\\n\t\t\tbreak;                                                 \\\n\t\tcase 3:                                                    \\\n\t\t\tADJUST_OFFSET_FOR_FFS(words, base, 0);                 \\\n\t\t\tADJUST_OFFSET_FOR_FFS(words, base, 1);                 \\\n\t\t\tbreak;                                                 \\\n\t\tcase 2:                                                    \\\n\t\t\tADJUST_OFFSET_FOR_FFS(words, base, 0);                 \\\n\t\t\tbreak;                                                 \\\n\t\tcase 1:                                                    \\\n\t\t\tbreak;                                                 \\\n\t\tdefault:                                                   \\\n\t\t\tMALLOC_FATAL_ERROR(level, \"invalid bitarray level\");   \\\n\t\t}                                                          \\\n\t}\n\n// Note in the following macro that \"ix\" and \"bit\" are variables being written\n#define ZAP_SUMMARIES(bits, ix, level)                             \\\n\t{                                                              \\\n\t\tunsigned bit;                                              \\\n\t\tswitch (level) {                                           \\\n\t\tcase 3:                                                    \\\n\t\t\tbit = ix & MASKNB;                                     \\\n\t\t\tix >>= NB;                                             \\\n\t\t\tif (!ZAP_GO_DOWN(bits + LEVEL2 + ix * NUM_64b, bit)) { \\\n\t\t\t\tbreak;                                             \\\n\t\t\t}                                                      \\\n\t\tcase 2:                                                    \\\n\t\t\tbit = ix & MASKNB;                                     \\\n\t\t\tix >>= NB;                                             \\\n\t\t\tif (!ZAP_GO_DOWN(bits + LEVEL1 + ix * NUM_64b, bit)) { \\\n\t\t\t\tbreak;                                             \\\n\t\t\t}                                                      \\\n\t\tcase 1:                                                    \\\n\t\t\tbit = ix & MASKNB;                                     \\\n\t\t\tix >>= NB;                                             \\\n\t\t\tif (!ZAP_GO_DOWN(bits + LEVEL0 + ix * NUM_64b, bit)) { \\\n\t\t\t\tbreak;                                             \\\n\t\t\t}                                                      \\\n\t\tcase 0:                                                    \\\n\t\t\tZAP_SIMPLE(bits, ix &MASKNB);                          \\\n\t\t\tbreak;                                                 \\\n\t\tdefault:                                                   \\\n\t\t\tMALLOC_FATAL_ERROR(level, \"invalid bitarray level\");   \\\n\t\t}                                                          \\\n\t}\n\nindex_t\nbitarray_first_set(const bitarray_t bits, unsigned log_size)\n{\n\t// return 0 if none set\n\tassert(log_size <= MAX_LEVEL * NB);\n\tuint64_t *words = bits;\n\tunsigned bit = FFS(words);\n\tif (log_size <= NB) {\n\t\treturn bit;\n\t}\n\tif (!bit) {\n\t\treturn 0;\n\t}\n\tunsigned level = (log_size - 1) / NB;\n\tindex_t base = bit - 1; // offset, in number of uin64_t words\n\tADJUST_OFFSET_FOR_FFS_ACROSS_SUMMARIES(words, base, level);\n\twords += (1 << (NB * (level - 1))) * NUM_64b;\n\tbase = (base << NB) + FFS(words + base * NUM_64b) - 1;\n\treturn base + 1; //+1 because bit N is encoded as N+1\n}\n\nbool\nbitarray_zap_first_set(bitarray_t bits, unsigned log_size, index_t *index)\n{\n\tassert(log_size <= MAX_LEVEL * NB);\n\tuint64_t *words = bits;\n\tindex_t ix = FFS(words);\n\tif (!ix) {\n\t\treturn 0;\n\t}\n\tunsigned level = (log_size - 1) / NB;\n\tif (!level) {\n\t\tix--;\n\t\t*index = ix;\n\t\tZAP_SIMPLE(bits, ix);\n\t\treturn 1;\n\t}\n\tindex_t base = ix - 1; // offset, in number of uin64_t words\n\tADJUST_OFFSET_FOR_FFS_ACROSS_SUMMARIES(words, base, level);\n\twords += (1 << (NB * (level - 1))) * NUM_64b;\n\tbase = (base << NB) + FFS(words + base * NUM_64b) - 1;\n\tix = base;\n\t*index = ix;\n\tassert(ix < (1 << log_size));\n\tlevel--;\n\tbool is_now_zero;\n\tunsigned bit;\n\tbit = ix & MASKNB;\n\tix >>= NB;\n\tif (!ZAP_CHANGED_GO_DOWN(bits + levels_num_words[level] + ix * NUM_64b, bit, &is_now_zero)) {\n\t\treturn 1;\n\t}\n\tif (!is_now_zero) {\n\t\treturn 1;\n\t}\n\tZAP_SUMMARIES(bits, ix, level);\n\treturn 1;\n}\n\nstatic unsigned\nFFS_and_zap_word(uint64_t *words, unsigned max, index_t *indices, index_t to_be_added)\n{\n\t// returns the number of bits zapped\n\tunsigned zapped = 0;\n\tfor (unsigned w = 0; w < NUM_64b; w++) {\n\t\tuint64_t word = words[w];\n\t\tif (!word) {\n\t\t\tcontinue;\n\t\t}\n\t\twhile (1) {\n\t\t\tunsigned f = __ffsll(word);\n\t\t\tassert(f);\n\t\t\tf--;\n\t\t\t// printf(\"%d \", f);\n\t\t\tindices[zapped++] = f + (w << 6) + to_be_added;\n\t\t\tword = BIT_ZAP(word, f);\n\t\t\tif (!word) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (zapped >= max) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\twords[w] = word;\n\t\t// printf(\"word=%lld \\n\", word);\n\t\tif (zapped >= max) {\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn zapped;\n}\n\nunsigned\nbitarray_zap_first_set_multiple(bitarray_t bits, unsigned log_size, unsigned max, index_t *indices)\n{\n\tassert(log_size <= MAX_LEVEL * NB);\n\tif (log_size <= NB) {\n\t\treturn FFS_and_zap_word(bits, max, indices, 0);\n\t}\n\tunsigned zapped = 0;\n\tunsigned level = (log_size - 1) / NB;\n\twhile (zapped < max) {\n\t\t/*\n\t\t * the lines in loop could be written just as:\n\t\t *\t\tif (! bitarray_zap_first_set(bits, log_size, indices + zapped)) break;\n\t\t *\t\t\tzapped++;\n\t\t * but the code is faster because it wont go up and down in the summaries\n\t\t */\n\t\tuint64_t *words = bits;\n\t\tindex_t ix = FFS(words);\n\t\tif (!ix) {\n\t\t\treturn zapped; // if the top level summary is 0, no bit is set\n\t\t}\n\t\tindex_t base = ix - 1; // offset, in number of uin64_t words\n\t\tADJUST_OFFSET_FOR_FFS_ACROSS_SUMMARIES(words, base, level);\n\t\twords += (1 << (NB * (level - 1))) * NUM_64b; // the beginning of the non-summarized bitarray\n\t\tuint64_t *word = words + base * NUM_64b;\t  // the first non-zero word\n\t\tix = base;\n\t\t// the idea here is that we zap a whole bunch of bits at once\n\t\tunsigned z = FFS_and_zap_word(word, max - zapped, indices + zapped, base << NB);\n\t\tassert(z);\n\t\tzapped += z;\n\t\tif ((zapped < max) /* entire word was zapped */ || all_zeros(word) /* partial zap, a priori */) {\n\t\t\t// adjust summaries to reflect all zeros in the bitarray\n\t\t\tZAP_SUMMARIES(bits, ix, level - 1);\n\t\t}\n\t}\n\treturn zapped;\n}\n\n#if 0\n/******************************** Test and debug utilities ***************************/\n\nstatic void print_ones(const uint64_t *bits, unsigned num_big_words) {\n\tunsigned base = 0;\n\tunsigned num = num_big_words * NUM_64b;\n\t// printf(\"In print_ones; num=%d, num_big=%d \\n\", num, num_big_words);\n\twhile (num--) {\n\t\tuint64_t word = *(bits++);\n\t\tif (word) {\n\t\t\tfor (unsigned bit = 0; bit < 64; bit++) {\n\t\t\t\tif (word & (1ULL << bit)) { printf(\"%d \", base + bit); }\n\t\t\t}\n\t\t}\n\t\tbase += 64;\n\t}\n}\n\nvoid bitarray_print(bitarray_t bits, unsigned log_size) {\n\tassert(log_size <= MAX_LEVEL * NB);\n\tprintf(\"bitarray %p log_size=%d\\n\", bits, log_size);\n\tif (log_size > 4 * NB) {\n\t\tprintf(\"Level 4: \"); print_ones(bits, 1); printf(\"\\n\");\n\t\tprintf(\"Level 3: \"); print_ones(bits + LEVEL0, 1 << NB); printf(\"\\n\");\n\t\tprintf(\"Level 2: \"); print_ones(bits + LEVEL1, 1 << NB); printf(\"\\n\");\n\t\tprintf(\"Level 1: \"); print_ones(bits + LEVEL2, 1 << NB); printf(\"\\n\");\n\t\tprintf(\"Level 0: \"); print_ones(bits + LEVEL3, 1 << (log_size - NB)); printf(\"\\n\");\n\t} else if (log_size > 3 * NB) {\n\t\tprintf(\"Level 3: \"); print_ones(bits, 1); printf(\"\\n\");\n\t\tprintf(\"Level 2: \"); print_ones(bits + LEVEL0, 1 << NB); printf(\"\\n\");\n\t\tprintf(\"Level 1: \"); print_ones(bits + LEVEL1, 1 << NB); printf(\"\\n\");\n\t\tprintf(\"Level 0: \"); print_ones(bits + LEVEL2, 1 << (log_size - NB)); printf(\"\\n\");\n\t} else if (log_size > 2 * NB) {\n\t\tprintf(\"Level 2: \"); print_ones(bits, 1); printf(\"\\n\");\n\t\tprintf(\"Level 1: \"); print_ones(bits + LEVEL0, 1 << NB); printf(\"\\n\");\n\t\tprintf(\"Level 0: \"); print_ones(bits + LEVEL1, 1 << (log_size - NB)); printf(\"\\n\");\n\t} else if (log_size > NB) {\n\t\tprintf(\"Level 1: \"); print_ones(bits, 1); printf(\"\\n\");\n\t\tprintf(\"Level 0: \"); print_ones(bits + LEVEL0, 1 << (log_size - NB)); printf(\"\\n\");\n\t} else {\n\t\tprintf(\"Level 0: \"); print_ones(bits, 1); printf(\"\\n\");\n\t}\n}\n\nbool compare_to_truth(bitarray_t bits, unsigned nbits, const bool *truth) {\n\tuint64_t     *start = bits;\n\tif (nbits > NB) {\n\t\tunsigned level = (nbits - NB - 1) / NB;\n\t\tstart += levels_num_words[level];\n\t}\n\tbool ok = 1;\n\tfor (unsigned bit = 0; bit < (1 << nbits); bit++) {\n\t\tbool expected = truth[bit];\n\t\tuint64_t word = start[bit >> 6];\n\t\tbool actual = (word >> (bit & 63)) & 1;\n\t\tif (actual != expected) {\n\t\t\tprintf(\"*** # for bit %d, expected=%d actual=%d\\n\", bit, expected, actual);\n\t\t\tok = 0;\n\t\t}\n\t}\n\treturn ok;\n}\n\nunsigned first_set_in_truth(const bool *truth, unsigned log_size) {\n\tfor (unsigned bit = 0; bit < (1 << log_size); bit++) {\n\t\tif (truth[bit]) { return bit + 1; }\n\t}\n\treturn 0;\n}\n\nvoid truth_print(const bool *truth, unsigned log_size) {\n\tprintf(\"Truth:  \");\n\tfor (unsigned bit = 0; bit < (1 << log_size); bit++) {\n\t\tif (truth[bit]) { printf(\"%d \", bit); }\n\t}\n\tprintf(\"\\n\");\n}\n#endif\n\n/* vim: set noet:ts=4:sw=4:cindent: */\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/bitarray.h",
    "content": "/*\n * Copyright (c) 1999, 2000, 2003, 2005, 2008, 2012 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __BITARRAY_H\n#define __BITARRAY_H\n\ntypedef uint64_t *bitarray_t; // array of bits, assumed to be mostly 0\ntypedef uint32_t index_t; // we limit the number of bits to be a 32-bit quantity\n\n/* A bitarray uses a summarization to be able to quickly say what's the first bit that is set to 1;\n All together each of the entry points will do a very small number of memory access (exact number depends on log_size) */\n\nextern size_t bitarray_size(unsigned log_size);\n    // For a bitarray with 1<<log_size bits, returns the number of bytes needed to contain the whole bitarray\n\nextern bitarray_t bitarray_create(unsigned log_size);\n    // creates a bitarray with 1<<log_size bits, all initialized to 0.  \n    // Use free() to free bitarray\n\nextern bool bitarray_get(bitarray_t bits, unsigned log_size, index_t index);\n\nextern bool bitarray_set(bitarray_t bits, unsigned log_size, index_t index);\n    // Set a bit in bitarray\n\nextern bool bitarray_zap(bitarray_t bits, unsigned log_size, index_t index);\n    // Clears a bit in bitarray\n\nextern index_t bitarray_first_set(const bitarray_t bits, unsigned log_size);\n    // Returns the index first bit that's 1, plus 1, or 0 if all the bits are zero\n\nextern bool bitarray_zap_first_set(bitarray_t bits, unsigned log_size, index_t *index);\n    // finds the first bit set, and if found, zaps it and sets index\n\nextern unsigned bitarray_zap_first_set_multiple(bitarray_t bits, unsigned log_size, unsigned max, index_t *indices);\n    // finds all the bits set, up to max, and zaps each and sets the index for each\n    // returns number zapped\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE void\nBITARRAY_SET(uint32_t *bits, msize_t index)\n{\n\t// index >> 5 identifies the uint32_t to manipulate in the conceptually contiguous bits array\n\t// (index >> 5) << 1 identifies the uint32_t allowing for the actual interleaving\n\tbits[(index >> 5) << 1] |= (1 << (index & 31));\n}\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE void\nBITARRAY_CLR(uint32_t *bits, msize_t index)\n{\n\tbits[(index >> 5) << 1] &= ~(1 << (index & 31));\n}\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE boolean_t\nBITARRAY_BIT(uint32_t *bits, msize_t index)\n{\n\treturn ((bits[(index >> 5) << 1]) >> (index & 31)) & 1;\n}\n\n/* Macros used to manipulate the uint32_t quantity mag_bitmap. */\n\n/* BITMAPV variants are used by tiny. */\n#if defined(__LP64__)\n// assert(NUM_SLOTS == 64) in which case (slot >> 5) is either 0 or 1\n#define BITMAPV_SET(bitmap, slot) (bitmap[(slot) >> 5] |= 1 << ((slot)&31))\n#define BITMAPV_CLR(bitmap, slot) (bitmap[(slot) >> 5] &= ~(1 << ((slot)&31)))\n#define BITMAPV_BIT(bitmap, slot) ((bitmap[(slot) >> 5] >> ((slot)&31)) & 1)\n#define BITMAPV_CTZ(bitmap) (__builtin_ctzl(bitmap))\n#else\n// assert(NUM_SLOTS == 32) in which case (slot >> 5) is always 0, so code it that way\n#define BITMAPV_SET(bitmap, slot) (bitmap[0] |= 1 << (slot))\n#define BITMAPV_CLR(bitmap, slot) (bitmap[0] &= ~(1 << (slot)))\n#define BITMAPV_BIT(bitmap, slot) ((bitmap[0] >> (slot)) & 1)\n#define BITMAPV_CTZ(bitmap) (__builtin_ctz(bitmap))\n#endif\n\n/* BITMAPN is used by small. (slot >> 5) takes on values from 0 to 7. */\n#define BITMAPN_SET(bitmap, slot) (bitmap[(slot) >> 5] |= 1 << ((slot)&31))\n#define BITMAPN_CLR(bitmap, slot) (bitmap[(slot) >> 5] &= ~(1 << ((slot)&31)))\n#define BITMAPN_BIT(bitmap, slot) ((bitmap[(slot) >> 5] >> ((slot)&31)) & 1)\n\n/* returns bit # of least-significant one bit, starting at 0 (undefined if !bitmap) */\n#define BITMAP32_CTZ(bitmap) (__builtin_ctz(bitmap[0]))\n\n#endif // __BITARRAY_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/debug.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __DEBUG_H\n#define __DEBUG_H\n\n// set to one to debug malloc itself\n#define DEBUG_MALLOC 0\n// set to one to debug malloc client\n#define DEBUG_CLIENT 0\n#define DEBUG_MADVISE 0\n\n#if DEBUG_MALLOC\n#   warning DEBUG_MALLOC ENABLED\n#   undef MALLOC_INLINE\n#   undef MALLOC_UNUSED\n#   undef MALLOC_ALWAYS_INLINE\n#   undef CHECK_MAGAZINE_PTR_LOCKED\n\n#   define MALLOC_INLINE\n#   define MALLOC_UNUSED\n#   define MALLOC_ALWAYS_INLINE\n#   define CHECK_MAGAZINE_PTR_LOCKED(szone, mag_ptr, fun)\t\t\t\t\\\n\tdo {\t\t\t\t\t\t\t\t\t\t\\\n\t    if (TRY_LOCK(mag_ptr->magazine_lock)) {\t\t\t\t\t\\\n\t\tmalloc_report(ASL_LEVEL_ERR, \"*** magazine_lock was not set %p in %s\\n\",\t\t\\\n\t\tmag_ptr->magazine_lock, fun);\t\t\t\t\t\t\\\n\t    }\t\t\t\t\t\t\t\t\t\t\\\n\t} while (0)\n#endif // DEBUG_MALLOC\n\n#if DEBUG_MALLOC || DEBUG_CLIENT\n#\tdefine CHECK(szone, fun) \\\n\tif ((szone)->debug_flags & CHECK_REGIONS) { \\\n\t\tszone_check_all(szone, fun) \\\n\t}\n#else // DEBUG_MALLOC || DEBUG_CLIENT\n#\tdefine CHECK(szone, fun) \\\n\tdo {} while (0)\n#endif // DEBUG_MALLOC || DEBUG_CLIENT\n\n#endif // __DEBUG_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/dtrace.h",
    "content": "/*\n * Copyright (c) 2016 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __DTRACE_H\n#define __DTRACE_H\n\n#ifndef DARWINTEST\n#include \"magmallocProvider.h\"\n#else\n#define\tMAGMALLOC_ALLOCREGION(arg0, arg1, arg2, arg3)\n#define\tMAGMALLOC_ALLOCREGION_ENABLED() (0)\n#define\tMAGMALLOC_DEALLOCREGION(arg0, arg1, arg2)\n#define\tMAGMALLOC_DEALLOCREGION_ENABLED() (0)\n#define\tMAGMALLOC_DEPOTREGION(arg0, arg1, arg2, arg3, arg4)\n#define\tMAGMALLOC_DEPOTREGION_ENABLED() (0)\n#define\tMAGMALLOC_MADVFREEREGION(arg0, arg1, arg2, arg3)\n#define\tMAGMALLOC_MADVFREEREGION_ENABLED() (0)\n#define\tMAGMALLOC_MALLOCERRORBREAK()\n#define\tMAGMALLOC_MALLOCERRORBREAK_ENABLED() (0)\n#define\tMAGMALLOC_PRESSURERELIEFBEGIN(arg0, arg1, arg2)\n#define\tMAGMALLOC_PRESSURERELIEFBEGIN_ENABLED() (0)\n#define\tMAGMALLOC_PRESSURERELIEFEND(arg0, arg1, arg2, arg3)\n#define\tMAGMALLOC_PRESSURERELIEFEND_ENABLED() (0)\n#define\tMAGMALLOC_RECIRCREGION(arg0, arg1, arg2, arg3, arg4)\n#define\tMAGMALLOC_RECIRCREGION_ENABLED() (0)\n#define\tMAGMALLOC_REFRESHINDEX(arg0, arg1, arg2)\n#define\tMAGMALLOC_REFRESHINDEX_ENABLED() (0)\n#endif\n\n#endif // __DTRACE_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/empty.s",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n/*\n * This file exists to force clang+ld to produce an link-time optimised\n * master object file that contains no bitcode when it is laid down on\n * disk.\n *\n * Adding a non-LTO assembly file to the link step forces ld to perform\n * LTO and produce the master object file.\n */\n\nempty:\n\tnop\n\n.subsections_via_symbols\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/frozen_malloc.c",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"internal.h\"\n\n/********* Support code for emacs unexec ************/\n\n/* History of freezedry version numbers:\n *\n * 1) Old malloc (before the scalable malloc implementation in this file\n *    existed).\n * 2) Original freezedrying code for scalable malloc.  This code was apparently\n *    based on the old freezedrying code and was fundamentally flawed in its\n *    assumption that tracking allocated memory regions was adequate to fake\n *    operations on freezedried memory.  This doesn't work, since scalable\n *    malloc does not store flags in front of large page-aligned allocations.\n * 3) Original szone-based freezedrying code.\n * 4) Fresher malloc with tiny zone\n * 5) 32/64bit compatible malloc\n * 6) Metadata within 1MB and 8MB region for tiny and small\n *\n * No version backward compatibility is provided, but the version number does\n * make it possible for malloc_jumpstart() to return an error if the application\n * was freezedried with an older version of malloc.\n */\n#define MALLOC_FREEZEDRY_VERSION 6\n\ntypedef struct {\n\tunsigned version;\n\tunsigned nszones;\n\tszone_t *szones;\n} malloc_frozen;\n\nstatic void *\nfrozen_malloc(szone_t *zone, size_t new_size)\n{\n\treturn malloc(new_size);\n}\n\nstatic void *\nfrozen_calloc(szone_t *zone, size_t num_items, size_t size)\n{\n\treturn calloc(num_items, size);\n}\n\nstatic void *\nfrozen_valloc(szone_t *zone, size_t new_size)\n{\n\treturn valloc(new_size);\n}\n\nstatic void *\nfrozen_realloc(szone_t *zone, void *ptr, size_t new_size)\n{\n\tsize_t old_size = szone_size(zone, ptr);\n\tvoid *new_ptr;\n\n\tif (new_size <= old_size) {\n\t\treturn ptr;\n\t}\n\tnew_ptr = malloc(new_size);\n\tif (old_size > 0) {\n\t\tmemcpy(new_ptr, ptr, old_size);\n\t}\n\treturn new_ptr;\n}\n\nstatic void\nfrozen_free(szone_t *zone, void *ptr)\n{\n}\n\nstatic void\nfrozen_destroy(szone_t *zone)\n{\n}\n\n/********* Pseudo-private API for emacs unexec ************/\n\n/*\n * malloc_freezedry() records all of the szones in use, so that they can be\n * partially reconstituted by malloc_jumpstart().  Due to the differences\n * between reconstituted memory regions and those created by the szone code,\n * care is taken not to reallocate from the freezedried memory, except in the\n * case of a non-growing realloc().\n *\n * Due to the flexibility provided by the zone registration mechanism, it is\n * impossible to implement generic freezedrying for any zone type.  This code\n * only handles applications that use the szone allocator, so malloc_freezedry()\n * returns 0 (error) if any non-szone zones are encountered.\n */\n\nuintptr_t\nmalloc_freezedry(void)\n{\n\textern unsigned malloc_num_zones;\n\textern malloc_zone_t **malloc_zones;\n\tmalloc_frozen *data;\n\tunsigned i;\n\n\t/* Allocate space in which to store the freezedry state. */\n\tdata = (malloc_frozen *)malloc(sizeof(malloc_frozen));\n\n\t/* Set freezedry version number so that malloc_jumpstart() can check for compatibility. */\n\tdata->version = MALLOC_FREEZEDRY_VERSION;\n\n\t/* Allocate the array of szone pointers. */\n\tdata->nszones = malloc_num_zones;\n\tdata->szones = (szone_t *)calloc(malloc_num_zones, sizeof(szone_t));\n\n\t/*\n\t * Fill in the array of szone structures.  They are copied rather than\n\t * referenced, since the originals are likely to be clobbered during malloc\n\t * initialization.\n\t */\n\tfor (i = 0; i < malloc_num_zones; i++) {\n\t\tif (strcmp(malloc_zones[i]->zone_name, \"DefaultMallocZone\")) {\n\t\t\t/* Unknown zone type. */\n\t\t\tfree(data->szones);\n\t\t\tfree(data);\n\t\t\treturn 0;\n\t\t}\n\t\tmemcpy(&data->szones[i], malloc_zones[i], sizeof(szone_t));\n\t}\n\n\treturn ((uintptr_t)data);\n}\n\nint\nmalloc_jumpstart(uintptr_t cookie)\n{\n\tmalloc_frozen *data = (malloc_frozen *)cookie;\n\tunsigned i;\n\n\tif (data->version != MALLOC_FREEZEDRY_VERSION) {\n\t\t/* Unsupported freezedry version. */\n\t\treturn 1;\n\t}\n\n\tfor (i = 0; i < data->nszones; i++) {\n\t\t/* Set function pointers.  Even the functions that stay the same must be\n\t\t * set, since there are no guarantees that they will be mapped to the\n\t\t * same addresses. */\n\t\tdata->szones[i].basic_zone.size = (void *)szone_size;\n\t\tdata->szones[i].basic_zone.malloc = (void *)frozen_malloc;\n\t\tdata->szones[i].basic_zone.calloc = (void *)frozen_calloc;\n\t\tdata->szones[i].basic_zone.valloc = (void *)frozen_valloc;\n\t\tdata->szones[i].basic_zone.free = (void *)frozen_free;\n\t\tdata->szones[i].basic_zone.realloc = (void *)frozen_realloc;\n\t\tdata->szones[i].basic_zone.destroy = (void *)frozen_destroy;\n\t\tdata->szones[i].basic_zone.introspect = (struct malloc_introspection_t *)&szone_introspect;\n\n\t\t/* Register the freezedried zone. */\n\t\tmalloc_zone_register(&data->szones[i].basic_zone);\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/frozen_malloc.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n\n#ifndef __FROZEN_MALLOC_H\n#define __FROZEN_MALLOC_H\n\nMALLOC_EXPORT\nuintptr_t\nmalloc_freezedry(void);\n\nMALLOC_EXPORT\nint\nmalloc_jumpstart(uintptr_t cookie);\n\n#endif // __FROZEN_MALLOC_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/internal.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __INTERNAL_H\n#define __INTERNAL_H\n\n#define __OS_EXPOSE_INTERNALS__ 1\n\n#include <Availability.h>\n#include <TargetConditionals.h>\n#include <_simple.h>\n#include <platform/string.h>\n#undef memcpy\n#define memcpy _platform_memmove\n#include <platform/compat.h>\n#include <assert.h>\n#include <crt_externs.h>\n#include <dirent.h>\n#include <dlfcn.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <libc.h>\n#include <libkern/OSAtomic.h>\n#include <limits.h>\n#include <mach-o/dyld.h>\n#include <mach-o/dyld_priv.h>\n#include <mach/mach.h>\n#include <mach/mach_init.h>\n#include <mach/mach_types.h>\n#include <mach/mach_vm.h>\n#include <mach/shared_region.h>\n#include <mach/thread_switch.h>\n#include <mach/vm_map.h>\n#include <mach/vm_page_size.h>\n#include <mach/vm_param.h>\n#include <mach/vm_statistics.h>\n#include <os/internal/internal_shared.h>\n#include <os/lock_private.h>\n#include <os/once_private.h>\n#include <os/overflow.h>\n#include <os/tsd.h>\n#include <paths.h>\n#include <signal.h>\n#include <stdarg.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <sys/cdefs.h>\n#include <sys/mman.h>\n#include <sys/param.h>\n#include <sys/stat.h>\n#include <sys/sysctl.h>\n#include <sys/random.h>\n#include <sys/types.h>\n#include <sys/vmparam.h>\n#include <unistd.h>\n#include <xlocale.h>\n\n#include \"dtrace.h\"\n\n#include \"base.h\"\n#include \"trace.h\"\n#include \"platform.h\"\n#include \"debug.h\"\n#include \"locking.h\"\n#include \"bitarray.h\"\n#include \"malloc.h\"\n#include \"printf.h\"\n#include \"frozen_malloc.h\"\n#include \"legacy_malloc.h\"\n#include \"magazine_malloc.h\"\n#include \"malloc_common.h\"\n#include \"nano_malloc_common.h\"\n#include \"nano_malloc.h\"\n#include \"nanov2_malloc.h\"\n#include \"purgeable_malloc.h\"\n#include \"malloc_private.h\"\n#include \"stack_logging.h\"\n#include \"stack_logging_internal.h\"\n#include \"thresholds.h\"\n#include \"vm.h\"\n\n#include \"magazine_rack.h\"\n#include \"magazine_zone.h\"\n#include \"nano_zone_common.h\"\n#include \"nano_zone.h\"\n#include \"nanov2_zone.h\"\n\n#include \"magazine_inline.h\"\n\nextern uint64_t malloc_entropy[2];\n\nMALLOC_NOEXPORT\nextern boolean_t malloc_tracing_enabled;\n\nMALLOC_NOEXPORT\nextern unsigned malloc_debug_flags;\n\nMALLOC_NOEXPORT MALLOC_NOINLINE\nvoid\nmalloc_error_break(void);\n\nMALLOC_NOEXPORT MALLOC_NOINLINE MALLOC_USED\nint\nmalloc_gdb_po_unsafe(void);\n\nMALLOC_NOEXPORT\nextern uint64_t max_lite_mallocs;\n\n#endif // __INTERNAL_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/legacy_malloc.c",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"internal.h\"\n\n/*\n * For use by CheckFix: create a new zone whose behavior is, apart from\n * the use of death-row and per-CPU magazines, that of Leopard.\n */\nstatic MALLOC_NOINLINE void *\nlegacy_valloc(szone_t *szone, size_t size)\n{\n\tvoid *ptr;\n\tsize_t num_kernel_pages;\n\n\tnum_kernel_pages = round_page_quanta(size) >> vm_page_quanta_shift;\n\tptr = large_malloc(szone, num_kernel_pages, 0, TRUE);\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"legacy_valloc returned %p\\n\", ptr);\n\t}\n#endif\n\treturn ptr;\n}\n\nmalloc_zone_t *\ncreate_legacy_scalable_zone(size_t initial_size, unsigned debug_flags)\n{\n\t// legacy always uses 32 small slots\n\tmalloc_zone_t *mzone = create_scalable_zone(initial_size, debug_flags & ~MALLOC_EXTENDED_SMALL_SLOTS);\n\tszone_t *szone = (szone_t *)mzone;\n\n\tif (!szone) {\n\t\treturn NULL;\n\t}\n\n\tszone->is_largemem = 0;\n\tszone->large_threshold = (15 * 1024);\n\tszone->vm_copy_threshold = (40 * 1024);\n\n\tmprotect(szone, sizeof(szone->basic_zone), PROT_READ | PROT_WRITE);\n\tszone->basic_zone.valloc = (void *)legacy_valloc;\n\tszone->basic_zone.free_definite_size = NULL;\n\tmprotect(szone, sizeof(szone->basic_zone), PROT_READ);\n\n\treturn mzone;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/legacy_malloc.h",
    "content": "/*\n * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __LEGACY_MALLOC_H\n#define __LEGACY_MALLOC_H\n\nMALLOC_NOEXPORT\nmalloc_zone_t *\ncreate_legacy_scalable_zone(size_t initial_size, unsigned debug_flags);\n\n#endif // __LEGACY_MALLOC_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/locking.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __LOCKING_H\n#define __LOCKING_H\n\n#if OS_UNFAIR_LOCK_INLINE\n#define os_unfair_lock_lock_with_options(lock, options) \\\n\t\tos_unfair_lock_lock_with_options_inline(lock, options)\n#define os_unfair_lock_trylock(lock) \\\n\t\tos_unfair_lock_trylock_inline(lock)\n#define os_unfair_lock_unlock(lock) \\\n\t\tos_unfair_lock_unlock_inline(lock)\n#endif // OS_UNFAIR_LOCK_INLINE\n\ntypedef os_unfair_lock _malloc_lock_s;\n#define _MALLOC_LOCK_INIT OS_UNFAIR_LOCK_INIT\n\n__attribute__((always_inline))\nstatic inline void\n_malloc_lock_init(_malloc_lock_s *lock) {\n    *lock = OS_UNFAIR_LOCK_INIT;\n}\n\nMALLOC_ALWAYS_INLINE\nstatic inline void\n_malloc_lock_lock(_malloc_lock_s *lock) {\n\treturn os_unfair_lock_lock_with_options(lock,\n\t\t\tOS_UNFAIR_LOCK_DATA_SYNCHRONIZATION);\n}\n\nMALLOC_ALWAYS_INLINE\nstatic inline bool\n_malloc_lock_trylock(_malloc_lock_s *lock) {\n    return os_unfair_lock_trylock(lock);\n}\n\nMALLOC_ALWAYS_INLINE\nstatic inline void\n_malloc_lock_unlock(_malloc_lock_s *lock) {\n    return os_unfair_lock_unlock(lock);\n}\n\nMALLOC_ALWAYS_INLINE\nstatic inline void\n_malloc_lock_assert_owner(_malloc_lock_s *lock) {\n\tos_unfair_lock_assert_owner(lock);\n}\n\n#endif // __LOCKING_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/magazine_inline.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __MAGAZINE_INLINE_H\n#define __MAGAZINE_INLINE_H\n\nextern unsigned int _os_cpu_number_override;\n\n/*\n * MALLOC_ABSOLUTE_MAX_SIZE - There are many instances of addition to a\n * user-specified size_t, which can cause overflow (and subsequent crashes)\n * for values near SIZE_T_MAX.  Rather than add extra \"if\" checks everywhere\n * this occurs, it is easier to just set an absolute maximum request size,\n * and immediately return an error if the requested size exceeds this maximum.\n * Of course, values less than this absolute max can fail later if the value\n * is still too large for the available memory.  The largest value added\n * seems to be PAGE_SIZE (in the macro round_page()), so to be safe, we set\n * the maximum to be 2 * PAGE_SIZE less than SIZE_T_MAX.\n */\n#define MALLOC_ABSOLUTE_MAX_SIZE (SIZE_T_MAX - (2 * PAGE_SIZE))\n\n// Gets the allocation size for a calloc(). Multiples size by num_items and adds\n// extra_size, storing the result in *total_size. Returns 0 on success, -1 (with\n// errno set to ENOMEM) on overflow.\nstatic int MALLOC_INLINE MALLOC_ALWAYS_INLINE\ncalloc_get_size(size_t num_items, size_t size, size_t extra_size, size_t *total_size)\n{\n\tsize_t alloc_size = size;\n\tif (num_items != 1 && (os_mul_overflow(num_items, size, &alloc_size)\n\t\t\t|| alloc_size > MALLOC_ABSOLUTE_MAX_SIZE)) {\n\t\terrno = ENOMEM;\n\t\treturn -1;\n\t}\n\tif (extra_size && (os_add_overflow(alloc_size, extra_size, &alloc_size)\n\t\t\t|| alloc_size > MALLOC_ABSOLUTE_MAX_SIZE)) {\n\t\terrno = ENOMEM;\n\t\treturn -1;\n\t}\n\t*total_size = alloc_size;\n\treturn 0;\n}\n\n/*********************\tFREE LIST UTILITIES  ************************/\n\n// A free list entry is comprised of a pair of pointers, previous and next.\n// These are used to implement a doubly-linked list, which permits efficient\n// extraction.\n//\n// Because the free list entries are previously freed objects, a misbehaved\n// program may write to a pointer after it has called free() on that pointer,\n// either by dereference or buffer overflow from an adjacent pointer. This write\n// would then corrupt the free list's previous and next pointers, leading to a\n// crash.  In order to detect this case, we take advantage of the fact that\n// malloc'd pointers are known to be at least 16 byte aligned, and thus have\n// at least 4 trailing zero bits.\n//\n// When an entry is added to the free list, a checksum of the previous and next\n// pointers is calculated and written to the high four bits of the respective\n// pointers.  Upon detection of an invalid checksum, an error is logged and NULL\n// is returned.  Since all code which un-checksums pointers checks for a NULL\n// return, a potentially crashing or malicious dereference is avoided at the\n// cost of leaking the corrupted block, and any subsequent blocks on the free\n// list of that size.\n\n#pragma mark forward decls\n\nstatic MALLOC_INLINE uintptr_t free_list_gen_checksum(uintptr_t ptr) MALLOC_ALWAYS_INLINE;\nstatic MALLOC_INLINE uintptr_t free_list_checksum_ptr(rack_t *rack, void *p) MALLOC_ALWAYS_INLINE;\nstatic MALLOC_INLINE void *free_list_unchecksum_ptr(rack_t *rack, inplace_union *ptr) MALLOC_ALWAYS_INLINE;\nstatic MALLOC_INLINE unsigned free_list_count(rack_t *rack, free_list_t ptr);\n\nstatic MALLOC_INLINE void recirc_list_extract(rack_t *rack, magazine_t *mag_ptr, region_trailer_t *node) MALLOC_ALWAYS_INLINE;\nstatic MALLOC_INLINE void recirc_list_splice_last(rack_t *rack, magazine_t *mag_ptr, region_trailer_t *node) MALLOC_ALWAYS_INLINE;\nstatic MALLOC_INLINE void recirc_list_splice_first(rack_t *rack, magazine_t *mag_ptr, region_trailer_t *node) MALLOC_ALWAYS_INLINE;\n\nstatic MALLOC_INLINE void\nyield(void)\n{\n\tthread_switch(MACH_PORT_NULL, SWITCH_OPTION_DEPRESS, 1);\n}\n\nstatic MALLOC_INLINE kern_return_t\n_szone_default_reader(task_t task, vm_address_t address, vm_size_t size, void **ptr)\n{\n\t*ptr = (void *)address;\n\treturn 0;\n}\n\n#pragma mark helpers\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE\nuint64_t\nplatform_hw_memsize(void)\n{\n#if CONFIG_HAS_COMMPAGE_MEMSIZE\n\treturn *(uint64_t *)(uintptr_t)_COMM_PAGE_MEMORY_SIZE;\n#else\n\tuint64_t hw_memsize = 0;\n\tsize_t uint64_t_size = sizeof(hw_memsize);\n\t// hw_memsize was always 0 if sysctlbyname failed, so preserve that behaviour\n\t(void)sysctlbyname(\"hw.memsize\", &hw_memsize, &uint64_t_size, 0, 0);\n\treturn hw_memsize;\n#endif\n}\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE\nuint32_t\nplatform_cpu_count(void)\n{\n#if CONFIG_HAS_COMMPAGE_NCPUS\n\treturn *(uint8_t *)(uintptr_t)_COMM_PAGE_NCPUS;\n#else\n\treturn sysconf(_SC_NPROCESSORS_CONF);\n#endif\n}\n\n#pragma mark szone locking\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE void\nSZONE_LOCK(szone_t *szone)\n{\n\t_malloc_lock_lock(&szone->large_szone_lock);\n}\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE void\nSZONE_UNLOCK(szone_t *szone)\n{\n\t_malloc_lock_unlock(&szone->large_szone_lock);\n}\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE bool\nSZONE_TRY_LOCK(szone_t *szone)\n{\n\treturn _malloc_lock_trylock(&szone->large_szone_lock);\n}\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE void\nSZONE_REINIT_LOCK(szone_t *szone)\n{\n\t_malloc_lock_init(&szone->large_szone_lock);\n}\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE void\nSZONE_MAGAZINE_PTR_LOCK(magazine_t *mag_ptr)\n{\n\t_malloc_lock_lock(&mag_ptr->magazine_lock);\n}\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE void\nSZONE_MAGAZINE_PTR_UNLOCK(magazine_t *mag_ptr)\n{\n\t_malloc_lock_unlock(&mag_ptr->magazine_lock);\n}\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE bool\nSZONE_MAGAZINE_PTR_TRY_LOCK(magazine_t *mag_ptr)\n{\n\treturn _malloc_lock_trylock(&mag_ptr->magazine_lock);\n}\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE void\nSZONE_MAGAZINE_PTR_REINIT_LOCK(magazine_t *mag_ptr)\n{\n\t_malloc_lock_init(&mag_ptr->magazine_lock);\n}\n\n#pragma mark free list\n\nstatic MALLOC_NOINLINE void\nfree_list_checksum_botch(rack_t *rack, void *ptr, void *value)\n{\n\tmalloc_zone_error(rack->debug_flags, true,\n\t\t\t\"Incorrect checksum for freed object %p: \"\n\t\t\t\"probably modified after being freed.\\n\"\n\t\t\t\"Corrupt value: %p\\n\", ptr, value);\n}\n\nstatic MALLOC_INLINE uintptr_t\nfree_list_gen_checksum(uintptr_t ptr)\n{\n\tuint8_t chk;\n\n\tchk = (unsigned char)(ptr >> 0);\n\tchk += (unsigned char)(ptr >> 8);\n\tchk += (unsigned char)(ptr >> 16);\n\tchk += (unsigned char)(ptr >> 24);\n#if __LP64__\n\tchk += (unsigned char)(ptr >> 32);\n\tchk += (unsigned char)(ptr >> 40);\n\tchk += (unsigned char)(ptr >> 48);\n\tchk += (unsigned char)(ptr >> 56);\n#endif\n\n\treturn chk;\n}\n\nstatic unsigned\nfree_list_count(rack_t *rack, free_list_t ptr)\n{\n\tunsigned count = 0;\n\n\twhile (ptr.p) {\n\t\tcount++;\n\t\tptr.p = free_list_unchecksum_ptr(rack, &ptr.inplace->next);\n\t}\n\treturn count;\n}\n\n#define NYBBLE 4\n#if __LP64__\n#define ANTI_NYBBLE (64 - NYBBLE)\n#else\n#define ANTI_NYBBLE (32 - NYBBLE)\n#endif\n\nstatic MALLOC_INLINE uintptr_t\nfree_list_checksum_ptr(rack_t *rack, void *ptr)\n{\n\tuintptr_t p = (uintptr_t)ptr;\n\treturn (p >> NYBBLE) | ((free_list_gen_checksum(p ^ rack->cookie) & (uintptr_t)0xF) << ANTI_NYBBLE); // compiles to rotate instruction\n}\n\nstatic MALLOC_INLINE void *\nfree_list_unchecksum_ptr(rack_t *rack, inplace_union *ptr)\n{\n\tinplace_union p;\n\tuintptr_t t = ptr->u;\n\n\tt = (t << NYBBLE) | (t >> ANTI_NYBBLE); // compiles to rotate instruction\n\tp.u = t & ~(uintptr_t)0xF;\n\n\tif ((t ^ free_list_gen_checksum(p.u ^ rack->cookie)) & (uintptr_t)0xF) {\n\t\tfree_list_checksum_botch(rack, ptr, (void *)ptr->u);\n\t\t__builtin_trap();\n\t}\n\treturn p.p;\n}\n\n#undef ANTI_NYBBLE\n#undef NYBBLE\n\n#pragma mark recirc helpers\n\nstatic MALLOC_INLINE void\nrecirc_list_extract(rack_t *rack, magazine_t *mag_ptr, region_trailer_t *node)\n{\n\t// excise node from list\n\tif (NULL == node->prev) {\n\t\tmag_ptr->firstNode = node->next;\n\t} else {\n\t\tnode->prev->next = node->next;\n\t}\n\n\tif (NULL == node->next) {\n\t\tmag_ptr->lastNode = node->prev;\n\t} else {\n\t\tnode->next->prev = node->prev;\n\t}\n\n\tmag_ptr->recirculation_entries--;\n}\n\nstatic MALLOC_INLINE void\nrecirc_list_splice_last(rack_t *rack, magazine_t *mag_ptr, region_trailer_t *node)\n{\n\tif (NULL == mag_ptr->lastNode) {\n\t\tmag_ptr->firstNode = node;\n\t\tnode->prev = NULL;\n\t} else {\n\t\tnode->prev = mag_ptr->lastNode;\n\t\tmag_ptr->lastNode->next = node;\n\t}\n\tmag_ptr->lastNode = node;\n\tnode->next = NULL;\n\tnode->recirc_suitable = FALSE;\n\tmag_ptr->recirculation_entries++;\n}\n\nstatic MALLOC_INLINE void\nrecirc_list_splice_first(rack_t *rack, magazine_t *mag_ptr, region_trailer_t *node)\n{\n\tif (NULL == mag_ptr->firstNode) {\n\t\tmag_ptr->lastNode = node;\n\t\tnode->next = NULL;\n\t} else {\n\t\tnode->next = mag_ptr->firstNode;\n\t\tmag_ptr->firstNode->prev = node;\n\t}\n\tmag_ptr->firstNode = node;\n\tnode->prev = NULL;\n\tnode->recirc_suitable = FALSE;\n\tmag_ptr->recirculation_entries++;\n}\n\n/*******************************************************************************\n * Region hash implementation\n *\n * This is essentially a duplicate of the existing Large allocator hash, minus\n * the ability to remove entries.  The two should be combined eventually.\n ******************************************************************************/\n#pragma mark region hash\n\n/*\n * hash_lookup_region_no_lock - Scan a hash ring looking for an entry for a\n * given region.\n *\n * FIXME: If consecutive queries of the same region are likely, a one-entry\n * cache would likely be a significant performance win here.\n */\nstatic MALLOC_INLINE rgnhdl_t\nhash_lookup_region_no_lock(region_t *regions, size_t num_entries, size_t shift, region_t r)\n{\n\tsize_t index, hash_index;\n\trgnhdl_t entry;\n\n\tif (!num_entries) {\n\t\treturn 0;\n\t}\n\n\t// Multiplicative hash where the multiplier is a prime near (ULONG_MAX / phi). [phi = 1.618033...]\n\t// Since the values of (((uintptr_t)r >> HASH_BLOCKS_ALIGN) are (roughly) an ascending sequence of integers,\n\t// this hash works really well. See Knuth TAOCP, Vol. 3.\n#if __LP64__\n\tindex = hash_index = (((uintptr_t)r >> HASH_BLOCKS_ALIGN) * 11400714819323198549ULL) >> (64 - shift);\n#else\n\tindex = hash_index = (((uintptr_t)r >> HASH_BLOCKS_ALIGN) * 2654435761UL) >> (32 - shift);\n#endif\n\tdo {\n\t\tentry = regions + index;\n\t\tif (*entry == 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (*entry == r) {\n\t\t\treturn entry;\n\t\t}\n\t\tif (++index == num_entries) {\n\t\t\tindex = 0;\n\t\t}\n\t} while (index != hash_index);\n\treturn 0;\n}\n\n/*\n * hash_region_insert_no_lock - Insert a region into the hash ring.\n */\nstatic void\nhash_region_insert_no_lock(region_t *regions, size_t num_entries, size_t shift, region_t r)\n{\n\tsize_t index, hash_index;\n\trgnhdl_t entry;\n\n\t// Multiplicative hash where the multiplier is a prime near (ULONG_MAX / phi). [phi = 1.618033...]\n\t// Since the values of (((uintptr_t)r >> HASH_BLOCKS_ALIGN) are (roughly) an ascending sequence of integers,\n\t// this hash works really well. See Knuth TAOCP, Vol. 3.\n#if __LP64__\n\tindex = hash_index = (((uintptr_t)r >> HASH_BLOCKS_ALIGN) * 11400714819323198549ULL) >> (64 - shift);\n#else\n\tindex = hash_index = (((uintptr_t)r >> HASH_BLOCKS_ALIGN) * 2654435761UL) >> (32 - shift);\n#endif\n\tdo {\n\t\tentry = regions + index;\n\t\tif (*entry == HASHRING_OPEN_ENTRY || *entry == HASHRING_REGION_DEALLOCATED) {\n\t\t\t*entry = r;\n\t\t\treturn;\n\t\t}\n\t\tif (++index == num_entries) {\n\t\t\tindex = 0;\n\t\t}\n\t} while (index != hash_index);\n}\n\n/*\n * hash_regions_alloc_no_lock - Allocate space for a number of entries.  This\n * must be a VM allocation as to avoid recursing between allocating a new small\n * region, and asking the small region to allocate space for the new list of\n * regions.\n */\nstatic region_t *\nhash_regions_alloc_no_lock(size_t num_entries)\n{\n\tsize_t size = num_entries * sizeof(region_t);\n\treturn mvm_allocate_pages(round_page_quanta(size), 0, 0, VM_MEMORY_MALLOC);\n}\n\n/*\n * hash_regions_grow_no_lock - Grow the hash ring, and rehash the entries.\n * Return the new region and new size to update the szone.  Do not deallocate\n * the old entries since someone may still be allocating them.\n */\nstatic MALLOC_INLINE region_t *\nhash_regions_grow_no_lock(region_t *regions, size_t old_size, size_t *mutable_shift, size_t *new_size)\n{\n\t// double in size and allocate memory for the regions\n\t*new_size = old_size + old_size;\n\t*mutable_shift = *mutable_shift + 1;\n\tregion_t *new_regions = hash_regions_alloc_no_lock(*new_size);\n\n\t// rehash the entries into the new list\n\tsize_t index;\n\tfor (index = 0; index < old_size; ++index) {\n\t\tregion_t r = regions[index];\n\t\tif (r != HASHRING_OPEN_ENTRY && r != HASHRING_REGION_DEALLOCATED) {\n\t\t\thash_region_insert_no_lock(new_regions, *new_size, *mutable_shift, r);\n\t\t}\n\t}\n\treturn new_regions;\n}\n\n#pragma mark mag index\n\n/*\n * These commpage routines provide fast access to the logical cpu number\n * of the calling processor assuming no pre-emption occurs.\n */\n\nextern unsigned int hyper_shift;\nextern unsigned int phys_ncpus;\nextern unsigned int logical_ncpus;\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE\nunsigned int\nmag_max_magazines(void)\n{\n    return max_magazines;\n}\n\n#pragma mark mag lock\n\nstatic MALLOC_INLINE magazine_t *\nmag_lock_zine_for_region_trailer(magazine_t *magazines, region_trailer_t *trailer, mag_index_t mag_index)\n{\n\tmag_index_t refreshed_index;\n\tmagazine_t *mag_ptr = &(magazines[mag_index]);\n\n\t// Take the lock  on entry.\n\tSZONE_MAGAZINE_PTR_LOCK(mag_ptr);\n\n\t// Now in the time it took to acquire the lock, the region may have migrated\n\t// from one magazine to another. In which case the magazine lock we obtained\n\t// (namely magazines[mag_index].mag_lock) is stale. If so, keep on tryin' ...\n\twhile (mag_index != (refreshed_index = trailer->mag_index)) { // Note assignment\n\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(mag_ptr);\n\n\t\tmag_index = refreshed_index;\n\t\tmag_ptr = &(magazines[mag_index]);\n\t\tSZONE_MAGAZINE_PTR_LOCK(mag_ptr);\n\t}\n\n\treturn mag_ptr;\n}\n\n#pragma mark tiny allocator\n\n/*\n * tiny_region_for_ptr_no_lock - Returns the tiny region containing the pointer,\n * or NULL if not found.\n */\nstatic MALLOC_INLINE region_t\ntiny_region_for_ptr_no_lock(rack_t *rack, const void *ptr)\n{\n\trgnhdl_t r = hash_lookup_region_no_lock(rack->region_generation->hashed_regions,\n\t\t\track->region_generation->num_regions_allocated,\n\t\t\track->region_generation->num_regions_allocated_shift,\n\t\t\tTINY_REGION_FOR_PTR(ptr));\n\n\treturn r ? *r : r;\n}\n\n/*\n * Obtain the size of a free tiny block (in msize_t units).\n */\nstatic msize_t\nget_tiny_free_size(const void *ptr)\n{\n\tvoid *next_block = (void *)((uintptr_t)ptr + TINY_QUANTUM);\n\tvoid *region_end = TINY_REGION_END(TINY_REGION_FOR_PTR(ptr));\n\n\t// check whether the next block is outside the tiny region or a block header\n\t// if so, then the size of this block is one, and there is no stored size.\n\tif (next_block < region_end) {\n\t\tuint32_t *next_header = TINY_BLOCK_HEADER_FOR_PTR(next_block);\n\t\tmsize_t next_index = TINY_INDEX_FOR_PTR(next_block);\n\n\t\tif (!BITARRAY_BIT(next_header, next_index)) {\n\t\t\treturn TINY_FREE_SIZE(ptr);\n\t\t}\n\t}\n\treturn 1;\n}\n\nstatic MALLOC_INLINE msize_t\nget_tiny_meta_header(const void *ptr, boolean_t *is_free)\n{\n\t// returns msize and is_free\n\t// may return 0 for the msize component (meaning 65536)\n\tuint32_t *block_header;\n\tmsize_t index;\n\n\tblock_header = TINY_BLOCK_HEADER_FOR_PTR(ptr);\n\tindex = TINY_INDEX_FOR_PTR(ptr);\n\n\tmsize_t midx = (index >> 5) << 1;\n\tuint32_t mask = 1 << (index & 31);\n\t*is_free = 0;\n\tif (0 == (block_header[midx] & mask)) { // if (!BITARRAY_BIT(block_header, index))\n\t\treturn 0;\n\t}\n\tif (0 == (block_header[midx + 1] & mask)) { // if (!BITARRAY_BIT(in_use, index))\n\t\t*is_free = 1;\n\t\treturn get_tiny_free_size(ptr);\n\t}\n\n\t// index >> 5 identifies the uint32_t to manipulate in the conceptually contiguous bits array\n\t// (index >> 5) << 1 identifies the uint32_t allowing for the actual interleaving\n#if defined(__LP64__)\n\t// The return value, msize, is computed as the distance to the next 1 bit in block_header.\n\t// That's guaranteed to be somewhere in the next 64 bits. And those bits could span three\n\t// uint32_t block_header elements. Collect the bits into a single uint64_t and measure up with ffsl.\n\tuint32_t *addr = ((uint32_t *)block_header) + ((index >> 5) << 1);\n\tuint32_t bitidx = index & 31;\n\tuint64_t word_lo = addr[0];\n\tuint64_t word_mid = addr[2];\n\tuint64_t word_hi = addr[4];\n\tuint64_t word_lomid = (word_lo >> bitidx) | (word_mid << (32 - bitidx));\n\tuint64_t word = bitidx ? word_lomid | (word_hi << (64 - bitidx)) : word_lomid;\n\tuint32_t result = __builtin_ffsl(word >> 1);\n#else\n\t// The return value, msize, is computed as the distance to the next 1 bit in block_header.\n\t// That's guaranteed to be somewhere in the next 32 bits. And those bits could span two\n\t// uint32_t block_header elements. Collect the bits into a single uint32_t and measure up with ffs.\n\tuint32_t *addr = ((uint32_t *)block_header) + ((index >> 5) << 1);\n\tuint32_t bitidx = index & 31;\n\tuint32_t word = bitidx ? (addr[0] >> bitidx) | (addr[2] << (32 - bitidx)) : addr[0];\n\tuint32_t result = __builtin_ffs(word >> 1);\n#endif\n\treturn result;\n}\n\n#pragma mark small allocator\n\n/*\n * small_region_for_ptr_no_lock - Returns the small region containing the pointer,\n * or NULL if not found.\n */\nstatic MALLOC_INLINE region_t\nsmall_region_for_ptr_no_lock(rack_t *rack, const void *ptr)\n{\n\trgnhdl_t r = hash_lookup_region_no_lock(rack->region_generation->hashed_regions,\n\t\t\track->region_generation->num_regions_allocated, rack->region_generation->num_regions_allocated_shift,\n\t\t\tSMALL_REGION_FOR_PTR(ptr));\n\treturn r ? *r : r;\n}\n\n#endif // __MAGAZINE_INLINE_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/magazine_large.c",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"internal.h\"\n\n#if DEBUG_MALLOC\nstatic void\nlarge_debug_print(szone_t *szone)\n{\n\tunsigned index;\n\tlarge_entry_t *range;\n\t_SIMPLE_STRING b = _simple_salloc();\n\n\tif (b) {\n\t\tfor (index = 0, range = szone->large_entries; index < szone->num_large_entries; index++, range++) {\n\t\t\tif (range->address) {\n\t\t\t\t_simple_sprintf(b, \"%d: %p(%y);  \", index, range->address, range->size);\n\t\t\t}\n\t\t}\n\n\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"%s\\n\", _simple_string(b));\n\t\t_simple_sfree(b);\n\t}\n}\n#endif\n\n/*\n * Scan the hash ring looking for an entry containing a given pointer.\n */\nstatic large_entry_t *\nlarge_entry_containing_pointer_no_lock(szone_t *szone, const void *ptr)\n{\n\t// result only valid with lock held\n\tunsigned num_large_entries = szone->num_large_entries;\n\tunsigned hash_index;\n\tunsigned index;\n\tlarge_entry_t *range;\n\n\tif (!num_large_entries) {\n\t\treturn NULL;\n\t}\n\n\thash_index = ((uintptr_t)ptr >> vm_page_quanta_shift) % num_large_entries;\n\tindex = hash_index;\n\n\tdo {\n\t\trange = szone->large_entries + index;\n\t\tif (range->address == (vm_address_t)ptr) {\n\t\t\treturn range;\n\t\t} else if ((vm_address_t)ptr >= range->address\n\t\t\t\t&& (vm_address_t)ptr < range->address + range->size) {\n\t\t\treturn range;\n\t\t}\n\n\t\t// Since we may be looking for an inner pointer, we might not get an\n\t\t// exact match on the address, so we need to scan further and to skip\n\t\t// over empty entries. It will usually be faster to scan backwards.\n\t\tindex = index == 0 ? num_large_entries - 1 : index - 1;\n\t} while (index != hash_index);\n\n\treturn NULL;\n}\n\n/*\n * Scan the hash ring looking for an entry for the given pointer.\n */\nlarge_entry_t *\nlarge_entry_for_pointer_no_lock(szone_t *szone, const void *ptr)\n{\n\t// result only valid with lock held\n\tunsigned num_large_entries = szone->num_large_entries;\n\tunsigned hash_index;\n\tunsigned index;\n\tlarge_entry_t *range;\n\n\tif (!num_large_entries) {\n\t\treturn NULL;\n\t}\n\n\thash_index = ((uintptr_t)ptr >> vm_page_quanta_shift) % num_large_entries;\n\tindex = hash_index;\n\n\tdo {\n\t\trange = szone->large_entries + index;\n\t\tif (range->address == (vm_address_t)ptr) {\n\t\t\treturn range;\n\t\t}\n\t\tif (0 == range->address) {\n\t\t\treturn NULL; // end of chain\n\t\t}\n\t\tindex++;\n\t\tif (index == num_large_entries) {\n\t\t\tindex = 0;\n\t\t}\n\t} while (index != hash_index);\n\n\treturn NULL;\n}\n\nstatic void\nlarge_entry_insert_no_lock(szone_t *szone, large_entry_t range)\n{\n\tunsigned num_large_entries = szone->num_large_entries;\n\tunsigned hash_index = (((uintptr_t)(range.address)) >> vm_page_quanta_shift) % num_large_entries;\n\tunsigned index = hash_index;\n\tlarge_entry_t *entry;\n\n\t// assert(szone->num_large_objects_in_use < szone->num_large_entries); /* must be called with room to spare */\n\n\tdo {\n\t\tentry = szone->large_entries + index;\n\t\tif (0 == entry->address) {\n\t\t\t*entry = range;\n\t\t\treturn; // end of chain\n\t\t}\n\t\tindex++;\n\t\tif (index == num_large_entries) {\n\t\t\tindex = 0;\n\t\t}\n\t} while (index != hash_index);\n\n\t// assert(0); /* must not fallthrough! */\n}\n\n// FIXME: can't we simply swap the (now empty) entry with the last entry on the collision chain for this hash slot?\nstatic MALLOC_INLINE void\nlarge_entries_rehash_after_entry_no_lock(szone_t *szone, large_entry_t *entry)\n{\n\tunsigned num_large_entries = szone->num_large_entries;\n\tuintptr_t hash_index = entry - szone->large_entries;\n\tuintptr_t index = hash_index;\n\tlarge_entry_t range;\n\n\t// assert(entry->address == 0) /* caller must have cleared *entry */\n\n\tdo {\n\t\tindex++;\n\t\tif (index == num_large_entries) {\n\t\t\tindex = 0;\n\t\t}\n\t\trange = szone->large_entries[index];\n\t\tif (0 == range.address) {\n\t\t\treturn;\n\t\t}\n\t\tszone->large_entries[index].address = (vm_address_t)0;\n\t\tszone->large_entries[index].size = 0;\n\t\tszone->large_entries[index].did_madvise_reusable = FALSE;\n\t\tlarge_entry_insert_no_lock(szone, range); // this will reinsert in the\n\t\t// proper place\n\t} while (index != hash_index);\n\n\t// assert(0); /* since entry->address == 0, must not fallthrough! */\n}\n\n// FIXME: num should probably be a size_t, since you can theoretically allocate\n// more than 2^32-1 large_threshold objects in 64 bit.\nstatic MALLOC_INLINE large_entry_t *\nlarge_entries_alloc_no_lock(unsigned num)\n{\n\tsize_t size = num * sizeof(large_entry_t);\n\n\t// Note that we allocate memory (via a system call) under a spin lock\n\t// That is certainly evil, however it's very rare in the lifetime of a process\n\t// The alternative would slow down the normal case\n\treturn mvm_allocate_pages(round_page_quanta(size), 0, 0, VM_MEMORY_MALLOC_LARGE);\n}\n\nvoid\nlarge_entries_free_no_lock(szone_t *szone, large_entry_t *entries, unsigned num, vm_range_t *range_to_deallocate)\n{\n\tsize_t size = num * sizeof(large_entry_t);\n\n\trange_to_deallocate->address = (vm_address_t)entries;\n\trange_to_deallocate->size = round_page_quanta(size);\n}\n\nstatic large_entry_t *\nlarge_entries_grow_no_lock(szone_t *szone, vm_range_t *range_to_deallocate)\n{\n\t// sets range_to_deallocate\n\tunsigned old_num_entries = szone->num_large_entries;\n\tlarge_entry_t *old_entries = szone->large_entries;\n\t// always an odd number for good hashing\n\tunsigned new_num_entries =\n\t(old_num_entries) ? old_num_entries * 2 + 1 : (unsigned)((vm_page_quanta_size / sizeof(large_entry_t)) - 1);\n\tlarge_entry_t *new_entries = large_entries_alloc_no_lock(new_num_entries);\n\tunsigned index = old_num_entries;\n\tlarge_entry_t oldRange;\n\n\t// if the allocation of new entries failed, bail\n\tif (new_entries == NULL) {\n\t\treturn NULL;\n\t}\n\n\tszone->num_large_entries = new_num_entries;\n\tszone->large_entries = new_entries;\n\n\t/* rehash entries into the new list */\n\twhile (index--) {\n\t\toldRange = old_entries[index];\n\t\tif (oldRange.address) {\n\t\t\tlarge_entry_insert_no_lock(szone, oldRange);\n\t\t}\n\t}\n\n\tif (old_entries) {\n\t\tlarge_entries_free_no_lock(szone, old_entries, old_num_entries, range_to_deallocate);\n\t} else {\n\t\trange_to_deallocate->address = (vm_address_t)0;\n\t\trange_to_deallocate->size = 0;\n\t}\n\n\treturn new_entries;\n}\n\n// frees the specific entry in the size table\n// returns a range to truly deallocate\nstatic vm_range_t\nlarge_entry_free_no_lock(szone_t *szone, large_entry_t *entry)\n{\n\tvm_range_t range;\n\n\tMALLOC_TRACE(TRACE_large_free, (uintptr_t)szone, (uintptr_t)entry->address, entry->size, 0);\n\n\trange.address = entry->address;\n\trange.size = entry->size;\n\n\tif (szone->debug_flags & MALLOC_ADD_GUARD_PAGES) {\n\t\tmvm_protect((void *)range.address, range.size, PROT_READ | PROT_WRITE, szone->debug_flags);\n\t\trange.address -= vm_page_quanta_size;\n\t\trange.size += 2 * vm_page_quanta_size;\n\t}\n\n\tentry->address = 0;\n\tentry->size = 0;\n\tentry->did_madvise_reusable = FALSE;\n\tlarge_entries_rehash_after_entry_no_lock(szone, entry);\n\n#if DEBUG_MALLOC\n\tif (large_entry_for_pointer_no_lock(szone, (void *)range.address)) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"*** freed entry %p still in use; num_large_entries=%d\\n\", range.address, szone->num_large_entries);\n\t\tlarge_debug_print(szone);\n\t\tszone_sleep();\n\t}\n#endif\n\treturn range;\n}\n\nkern_return_t\nlarge_in_use_enumerator(task_t task,\n\t\t\t\t\t\tvoid *context,\n\t\t\t\t\t\tunsigned type_mask,\n\t\t\t\t\t\tvm_address_t large_entries_address,\n\t\t\t\t\t\tunsigned num_entries,\n\t\t\t\t\t\tmemory_reader_t reader,\n\t\t\t\t\t\tvm_range_recorder_t recorder)\n{\n\tunsigned index = 0;\n\tvm_range_t buffer[MAX_RECORDER_BUFFER];\n\tunsigned count = 0;\n\tlarge_entry_t *entries;\n\tkern_return_t err;\n\tvm_range_t range;\n\tlarge_entry_t entry;\n\n\terr = reader(task, large_entries_address, sizeof(large_entry_t) * num_entries, (void **)&entries);\n\tif (err) {\n\t\treturn err;\n\t}\n\n\tindex = num_entries;\n\tif (type_mask & MALLOC_ADMIN_REGION_RANGE_TYPE) {\n\t\trange.address = large_entries_address;\n\t\trange.size = round_page_quanta(num_entries * sizeof(large_entry_t));\n\t\trecorder(task, context, MALLOC_ADMIN_REGION_RANGE_TYPE, &range, 1);\n\t}\n\tif (type_mask & (MALLOC_PTR_IN_USE_RANGE_TYPE | MALLOC_PTR_REGION_RANGE_TYPE)) {\n\t\twhile (index--) {\n\t\t\tentry = entries[index];\n\t\t\tif (entry.address) {\n\t\t\t\trange.address = entry.address;\n\t\t\t\trange.size = entry.size;\n\t\t\t\tbuffer[count++] = range;\n\t\t\t\tif (count >= MAX_RECORDER_BUFFER) {\n\t\t\t\t\trecorder(task, context, MALLOC_PTR_IN_USE_RANGE_TYPE | MALLOC_PTR_REGION_RANGE_TYPE, buffer, count);\n\t\t\t\t\tcount = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif (count) {\n\t\trecorder(task, context, MALLOC_PTR_IN_USE_RANGE_TYPE | MALLOC_PTR_REGION_RANGE_TYPE, buffer, count);\n\t}\n\treturn 0;\n}\n\nvoid *\nlarge_malloc(szone_t *szone, size_t num_kernel_pages, unsigned char alignment, boolean_t cleared_requested)\n{\n\tvoid *addr;\n\tvm_range_t range_to_deallocate;\n\tsize_t size;\n\tlarge_entry_t large_entry;\n\n\tMALLOC_TRACE(TRACE_large_malloc, (uintptr_t)szone, num_kernel_pages, alignment, cleared_requested);\n\n\tif (!num_kernel_pages) {\n\t\tnum_kernel_pages = 1; // minimal allocation size for this szone\n\t}\n\tsize = (size_t)num_kernel_pages << vm_page_quanta_shift;\n\trange_to_deallocate.size = 0;\n\trange_to_deallocate.address = 0;\n\n#if CONFIG_LARGE_CACHE\n\tif (size < LARGE_CACHE_SIZE_ENTRY_LIMIT) { // Look for a large_entry_t on the death-row cache?\n\t\tSZONE_LOCK(szone);\n\n\t\tint i, best = -1, idx = szone->large_entry_cache_newest, stop_idx = szone->large_entry_cache_oldest;\n\t\tsize_t best_size = SIZE_T_MAX;\n\n\t\twhile (1) { // Scan large_entry_cache for best fit, starting with most recent entry\n\t\t\tsize_t this_size = szone->large_entry_cache[idx].size;\n\t\t\taddr = (void *)szone->large_entry_cache[idx].address;\n\n\t\t\tif (0 == alignment || 0 == (((uintptr_t)addr) & (((uintptr_t)1 << alignment) - 1))) {\n\t\t\t\tif (size == this_size) { // size match!\n\t\t\t\t\tbest = idx;\n\t\t\t\t\tbest_size = this_size;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (size <= this_size && this_size < best_size) { // improved fit?\n\t\t\t\t\tbest = idx;\n\t\t\t\t\tbest_size = this_size;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (idx == stop_idx) { // exhausted live ring?\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (idx) {\n\t\t\t\tidx--; // bump idx down\n\t\t\t} else {\n\t\t\t\tidx = LARGE_ENTRY_CACHE_SIZE - 1; // wrap idx\n\t\t\t}\n\t\t}\n\n\t\tif (best > -1 && (best_size - size) < size) { // limit fragmentation to 50%\n\t\t\taddr = (void *)szone->large_entry_cache[best].address;\n\t\t\tboolean_t was_madvised_reusable = szone->large_entry_cache[best].did_madvise_reusable;\n\n\t\t\t// Compact live ring to fill entry now vacated at large_entry_cache[best]\n\t\t\t// while preserving time-order\n\t\t\tif (szone->large_entry_cache_oldest < szone->large_entry_cache_newest) {\n\t\t\t\t// Ring hasn't wrapped. Fill in from right.\n\t\t\t\tfor (i = best; i < szone->large_entry_cache_newest; ++i) {\n\t\t\t\t\tszone->large_entry_cache[i] = szone->large_entry_cache[i + 1];\n\t\t\t\t}\n\n\t\t\t\tszone->large_entry_cache_newest--; // Pull in right endpoint.\n\n\t\t\t} else if (szone->large_entry_cache_newest < szone->large_entry_cache_oldest) {\n\t\t\t\t// Ring has wrapped. Arrange to fill in from the contiguous side.\n\t\t\t\tif (best <= szone->large_entry_cache_newest) {\n\t\t\t\t\t// Fill from right.\n\t\t\t\t\tfor (i = best; i < szone->large_entry_cache_newest; ++i) {\n\t\t\t\t\t\tszone->large_entry_cache[i] = szone->large_entry_cache[i + 1];\n\t\t\t\t\t}\n\n\t\t\t\t\tif (0 < szone->large_entry_cache_newest) {\n\t\t\t\t\t\tszone->large_entry_cache_newest--;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tszone->large_entry_cache_newest = LARGE_ENTRY_CACHE_SIZE - 1;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Fill from left.\n\t\t\t\t\tfor (i = best; i > szone->large_entry_cache_oldest; --i) {\n\t\t\t\t\t\tszone->large_entry_cache[i] = szone->large_entry_cache[i - 1];\n\t\t\t\t\t}\n\n\t\t\t\t\tif (szone->large_entry_cache_oldest < LARGE_ENTRY_CACHE_SIZE - 1) {\n\t\t\t\t\t\tszone->large_entry_cache_oldest++;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tszone->large_entry_cache_oldest = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\t// By trichotomy, large_entry_cache_newest == large_entry_cache_oldest.\n\t\t\t\t// That implies best == large_entry_cache_newest == large_entry_cache_oldest\n\t\t\t\t// and the ring is now empty.\n\t\t\t\tszone->large_entry_cache[best].address = 0;\n\t\t\t\tszone->large_entry_cache[best].size = 0;\n\t\t\t\tszone->large_entry_cache[best].did_madvise_reusable = FALSE;\n\t\t\t}\n\n\t\t\tif ((szone->num_large_objects_in_use + 1) * 4 > szone->num_large_entries) {\n\t\t\t\t// density of hash table too high; grow table\n\t\t\t\t// we do that under lock to avoid a race\n\t\t\t\tlarge_entry_t *entries = large_entries_grow_no_lock(szone, &range_to_deallocate);\n\t\t\t\tif (entries == NULL) {\n\t\t\t\t\tSZONE_UNLOCK(szone);\n\t\t\t\t\treturn NULL;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlarge_entry.address = (vm_address_t)addr;\n\t\t\tlarge_entry.size = best_size;\n\t\t\tlarge_entry.did_madvise_reusable = FALSE;\n\t\t\tlarge_entry_insert_no_lock(szone, large_entry);\n\n\t\t\tszone->num_large_objects_in_use++;\n\t\t\tszone->num_bytes_in_large_objects += best_size;\n\t\t\tif (!was_madvised_reusable) {\n\t\t\t\tszone->large_entry_cache_reserve_bytes -= best_size;\n\t\t\t}\n\n\t\t\tszone->large_entry_cache_bytes -= best_size;\n\n\t\t\tif (szone->flotsam_enabled && szone->large_entry_cache_bytes < SZONE_FLOTSAM_THRESHOLD_LOW) {\n\t\t\t\tszone->flotsam_enabled = FALSE;\n\t\t\t}\n\n\t\t\tSZONE_UNLOCK(szone);\n\n\t\t\tif (range_to_deallocate.size) {\n\t\t\t\t// we deallocate outside the lock\n\t\t\t\tmvm_deallocate_pages((void *)range_to_deallocate.address, range_to_deallocate.size, 0);\n\t\t\t}\n\n\t\t\tif (cleared_requested) {\n\t\t\t\tmemset(addr, 0, size);\n\t\t\t}\n\n\t\t\treturn addr;\n\t\t} else {\n\t\t\tSZONE_UNLOCK(szone);\n\t\t}\n\t}\n\n\trange_to_deallocate.size = 0;\n\trange_to_deallocate.address = 0;\n#endif /* CONFIG_LARGE_CACHE */\n\n\taddr = mvm_allocate_pages(size, alignment, szone->debug_flags, VM_MEMORY_MALLOC_LARGE);\n\tif (addr == NULL) {\n\t\treturn NULL;\n\t}\n\n\tSZONE_LOCK(szone);\n\tif ((szone->num_large_objects_in_use + 1) * 4 > szone->num_large_entries) {\n\t\t// density of hash table too high; grow table\n\t\t// we do that under lock to avoid a race\n\t\tlarge_entry_t *entries = large_entries_grow_no_lock(szone, &range_to_deallocate);\n\t\tif (entries == NULL) {\n\t\t\tSZONE_UNLOCK(szone);\n\t\t\treturn NULL;\n\t\t}\n\t}\n\n\tlarge_entry.address = (vm_address_t)addr;\n\tlarge_entry.size = size;\n\tlarge_entry.did_madvise_reusable = FALSE;\n\tlarge_entry_insert_no_lock(szone, large_entry);\n\n\tszone->num_large_objects_in_use++;\n\tszone->num_bytes_in_large_objects += size;\n\tSZONE_UNLOCK(szone);\n\n\tif (range_to_deallocate.size) {\n\t\t// we deallocate outside the lock\n\t\tmvm_deallocate_pages((void *)range_to_deallocate.address, range_to_deallocate.size, 0);\n\t}\n\treturn addr;\n}\n\nvoid\nfree_large(szone_t *szone, void *ptr)\n{\n\t// We have established ptr is page-aligned and neither tiny nor small\n\tlarge_entry_t *entry;\n\tvm_range_t vm_range_to_deallocate;\n\n\tSZONE_LOCK(szone);\n\tentry = large_entry_for_pointer_no_lock(szone, ptr);\n\tif (entry) {\n#if CONFIG_LARGE_CACHE\n\t\tif (entry->size < LARGE_CACHE_SIZE_ENTRY_LIMIT &&\n\t\t\t-1 != madvise((void *)(entry->address), entry->size,\n\t\t\t\t\t\t  MADV_CAN_REUSE)) { // Put the large_entry_t on the death-row cache?\n\t\t\t\tint idx = szone->large_entry_cache_newest, stop_idx = szone->large_entry_cache_oldest;\n\t\t\t\tlarge_entry_t this_entry = *entry; // Make a local copy, \"entry\" is volatile when lock is let go.\n\t\t\t\tboolean_t reusable = TRUE;\n\t\t\t\tboolean_t should_madvise =\n\t\t\t\tszone->large_entry_cache_reserve_bytes + this_entry.size > szone->large_entry_cache_reserve_limit;\n\n\t\t\t\t// Already freed?\n\t\t\t\t// [Note that repeated entries in death-row risk vending the same entry subsequently\n\t\t\t\t// to two different malloc() calls. By checking here the (illegal) double free\n\t\t\t\t// is accommodated, matching the behavior of the previous implementation.]\n\t\t\t\twhile (1) { // Scan large_entry_cache starting with most recent entry\n\t\t\t\t\tif (szone->large_entry_cache[idx].address == entry->address) {\n\t\t\t\t\t\tmalloc_zone_error(szone->debug_flags, true, \"pointer %p being freed already on death-row\\n\", ptr);\n\t\t\t\t\t\tSZONE_UNLOCK(szone);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (idx == stop_idx) { // exhausted live ring?\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (idx) {\n\t\t\t\t\t\tidx--; // bump idx down\n\t\t\t\t\t} else {\n\t\t\t\t\t\tidx = LARGE_ENTRY_CACHE_SIZE - 1; // wrap idx\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tSZONE_UNLOCK(szone);\n\n\t\t\t\tif (szone->debug_flags & MALLOC_PURGEABLE) { // Are we a purgable zone?\n\t\t\t\t\tint state = VM_PURGABLE_NONVOLATILE;\t\t\t  // restore to default condition\n\n\t\t\t\t\tif (KERN_SUCCESS != vm_purgable_control(mach_task_self(), this_entry.address, VM_PURGABLE_SET_STATE, &state)) {\n\t\t\t\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** can't vm_purgable_control(..., VM_PURGABLE_SET_STATE) for large freed block at %p\\n\",\n\t\t\t\t\t\t\t\t\t  (void *)this_entry.address);\n\t\t\t\t\t\treusable = FALSE;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (szone->large_legacy_reset_mprotect) { // Linked for Leopard?\n\t\t\t\t\t// Accomodate Leopard apps that (illegally) mprotect() their own guard pages on large malloc'd allocations\n\t\t\t\t\tint err = mprotect((void *)(this_entry.address), this_entry.size, PROT_READ | PROT_WRITE);\n\t\t\t\t\tif (err) {\n\t\t\t\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** can't reset protection for large freed block at %p\\n\", (void *)this_entry.address);\n\t\t\t\t\t\treusable = FALSE;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// madvise(..., MADV_REUSABLE) death-row arrivals if hoarding would exceed large_entry_cache_reserve_limit\n\t\t\t\tif (should_madvise) {\n\t\t\t\t\t// Issue madvise to avoid paging out the dirtied free()'d pages in \"entry\"\n\t\t\t\t\tMAGMALLOC_MADVFREEREGION((void *)szone, (void *)0, (void *)(this_entry.address), (int)this_entry.size); // DTrace USDT Probe\n\n\t\t\t\t\t// Ok to do this madvise on embedded because we won't call MADV_FREE_REUSABLE on a large\n\t\t\t\t\t// cache block twice without MADV_FREE_REUSE in between.\n\n\t\t\t\t\tif (-1 == madvise((void *)(this_entry.address), this_entry.size, MADV_FREE_REUSABLE)) {\n\t\t\t\t\t\t/* -1 return: VM map entry change makes this unfit for reuse. */\n#if DEBUG_MADVISE\n\t\t\t\t\t\tmalloc_zone_error(szone->debug_flags, false,\n\t\t\t\t\t\t\t\t\t\"free_large madvise(..., MADV_FREE_REUSABLE) failed for %p, length=%d\\n\",\n\t\t\t\t\t\t\t\t\t(void *)this_entry.address, this_entry.size);\n#endif\n\t\t\t\t\t\treusable = FALSE;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tSZONE_LOCK(szone);\n\n\t\t\t\t// Re-acquire \"entry\" after interval just above where we let go the lock.\n\t\t\t\tentry = large_entry_for_pointer_no_lock(szone, ptr);\n\t\t\t\tif (NULL == entry) {\n\t\t\t\t\tmalloc_zone_error(szone->debug_flags, true, \"entry for pointer %p being freed from death-row vanished\\n\", ptr);\n\t\t\t\t\tSZONE_UNLOCK(szone);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Add \"entry\" to death-row ring\n\t\t\t\tif (reusable) {\n\t\t\t\t\tint idx = szone->large_entry_cache_newest; // Most recently occupied\n\t\t\t\t\tvm_address_t addr;\n\t\t\t\t\tsize_t adjsize;\n\n\t\t\t\t\tif (szone->large_entry_cache_newest == szone->large_entry_cache_oldest &&\n\t\t\t\t\t\t0 == szone->large_entry_cache[idx].address) {\n\t\t\t\t\t\t// Ring is empty, idx is good as it stands\n\t\t\t\t\t\taddr = 0;\n\t\t\t\t\t\tadjsize = 0;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Extend the queue to the \"right\" by bumping up large_entry_cache_newest\n\t\t\t\t\t\tif (idx == LARGE_ENTRY_CACHE_SIZE - 1) {\n\t\t\t\t\t\t\tidx = 0; // Wrap index\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tidx++; // Bump index\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (idx == szone->large_entry_cache_oldest) { // Fully occupied\n\t\t\t\t\t\t\t// Drop this entry from the cache and deallocate the VM\n\t\t\t\t\t\t\taddr = szone->large_entry_cache[idx].address;\n\t\t\t\t\t\t\tadjsize = szone->large_entry_cache[idx].size;\n\t\t\t\t\t\t\tszone->large_entry_cache_bytes -= adjsize;\n\t\t\t\t\t\t\tif (!szone->large_entry_cache[idx].did_madvise_reusable) {\n\t\t\t\t\t\t\t\tszone->large_entry_cache_reserve_bytes -= adjsize;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Using an unoccupied cache slot\n\t\t\t\t\t\t\taddr = 0;\n\t\t\t\t\t\t\tadjsize = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif ((szone->debug_flags & MALLOC_DO_SCRIBBLE)) {\n\t\t\t\t\t\tmemset((void *)(entry->address), should_madvise ? SCRUBBLE_BYTE : SCRABBLE_BYTE, entry->size);\n\t\t\t\t\t}\n\n\t\t\t\t\tentry->did_madvise_reusable = should_madvise; // Was madvise()'d above?\n\t\t\t\t\tif (!should_madvise) {\t\t\t\t\t\t  // Entered on death-row without madvise() => up the hoard total\n\t\t\t\t\t\tszone->large_entry_cache_reserve_bytes += entry->size;\n\t\t\t\t\t}\n\n\t\t\t\t\tszone->large_entry_cache_bytes += entry->size;\n\n\t\t\t\t\tif (!szone->flotsam_enabled && szone->large_entry_cache_bytes > SZONE_FLOTSAM_THRESHOLD_HIGH) {\n\t\t\t\t\t\tszone->flotsam_enabled = TRUE;\n\t\t\t\t\t}\n\n\t\t\t\t\tszone->large_entry_cache[idx] = *entry;\n\t\t\t\t\tszone->large_entry_cache_newest = idx;\n\n\t\t\t\t\tszone->num_large_objects_in_use--;\n\t\t\t\t\tszone->num_bytes_in_large_objects -= entry->size;\n\n\t\t\t\t\t(void)large_entry_free_no_lock(szone, entry);\n\n\t\t\t\t\tif (0 == addr) {\n\t\t\t\t\t\tSZONE_UNLOCK(szone);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fall through to drop large_entry_cache_oldest from the cache,\n\t\t\t\t\t// and then deallocate its pages.\n\n\t\t\t\t\t// Trim the queue on the \"left\" by bumping up large_entry_cache_oldest\n\t\t\t\t\tif (szone->large_entry_cache_oldest == LARGE_ENTRY_CACHE_SIZE - 1) {\n\t\t\t\t\t\tszone->large_entry_cache_oldest = 0;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tszone->large_entry_cache_oldest++;\n\t\t\t\t\t}\n\n\t\t\t\t\t// we deallocate_pages, including guard pages, outside the lock\n\t\t\t\t\tSZONE_UNLOCK(szone);\n\t\t\t\t\tmvm_deallocate_pages((void *)addr, (size_t)adjsize, 0);\n\t\t\t\t\treturn;\n\t\t\t\t} else {\n\t\t\t\t\t/* fall through to discard an allocation that is not reusable */\n\t\t\t\t}\n\t\t\t}\n#endif /* CONFIG_LARGE_CACHE */\n\n\t\tszone->num_large_objects_in_use--;\n\t\tszone->num_bytes_in_large_objects -= entry->size;\n\n\t\tvm_range_to_deallocate = large_entry_free_no_lock(szone, entry);\n\t} else {\n#if DEBUG_MALLOC\n\t\tlarge_debug_print(szone);\n#endif\n\t\tmalloc_zone_error(szone->debug_flags, true, \"pointer %p being freed was not allocated\\n\", ptr);\n\t\tSZONE_UNLOCK(szone);\n\t\treturn;\n\t}\n\tSZONE_UNLOCK(szone); // we release the lock asap\n\tCHECK(szone, __PRETTY_FUNCTION__);\n\n\t// we deallocate_pages, including guard pages, outside the lock\n\tif (vm_range_to_deallocate.address) {\n#if DEBUG_MALLOC\n\t\t// FIXME: large_entry_for_pointer_no_lock() needs the lock held ...\n\t\tif (large_entry_for_pointer_no_lock(szone, (void *)vm_range_to_deallocate.address)) {\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** invariant broken: %p still in use num_large_entries=%d\\n\",\n\t\t\t\t\tvm_range_to_deallocate.address, szone->num_large_entries);\n\t\t\tlarge_debug_print(szone);\n\t\t\tszone_sleep();\n\t\t}\n#endif\n\t\tmvm_deallocate_pages((void *)vm_range_to_deallocate.address, (size_t)vm_range_to_deallocate.size, 0);\n\t}\n}\n\nvoid *\nlarge_try_shrink_in_place(szone_t *szone, void *ptr, size_t old_size, size_t new_good_size)\n{\n\tsize_t shrinkage = old_size - new_good_size;\n\n\tif (shrinkage) {\n\t\tSZONE_LOCK(szone);\n\t\t/* contract existing large entry */\n\t\tlarge_entry_t *large_entry = large_entry_for_pointer_no_lock(szone, ptr);\n\t\tif (!large_entry) {\n\t\t\tmalloc_zone_error(szone->debug_flags, true, \"large entry %p reallocated is not properly in table\\n\", ptr);\n\t\t\tSZONE_UNLOCK(szone);\n\t\t\treturn ptr;\n\t\t}\n\n\t\tlarge_entry->address = (vm_address_t)ptr;\n\t\tlarge_entry->size = new_good_size;\n\t\tszone->num_bytes_in_large_objects -= shrinkage;\n\t\tboolean_t guarded = szone->debug_flags & MALLOC_ADD_GUARD_PAGES;\n\t\tSZONE_UNLOCK(szone); // we release the lock asap\n\n\t\tif (guarded) {\n\t\t\t// Keep the page above the new end of the allocation as the\n\t\t\t// postlude guard page.\n\t\t\tkern_return_t err;\n\t\t\terr = mprotect((void *)((uintptr_t)ptr + new_good_size), vm_page_quanta_size, 0);\n\t\t\tif (err) {\n\t\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** can't mvm_protect(0x0) region for new postlude guard page at %p\\n\",\n\t\t\t\t\t\t  ptr + new_good_size);\n\t\t\t}\n\t\t\tnew_good_size += vm_page_quanta_size;\n\t\t\tshrinkage -= vm_page_quanta_size;\n\t\t}\n\n\t\tmvm_deallocate_pages((void *)((uintptr_t)ptr + new_good_size), shrinkage, 0);\n\t}\n\treturn ptr;\n}\n\nint\nlarge_try_realloc_in_place(szone_t *szone, void *ptr, size_t old_size, size_t new_size)\n{\n\tvm_address_t addr = (vm_address_t)ptr + old_size;\n\tlarge_entry_t *large_entry;\n\tkern_return_t err;\n\n\tSZONE_LOCK(szone);\n\tlarge_entry = large_entry_for_pointer_no_lock(szone, (void *)addr);\n\tSZONE_UNLOCK(szone);\n\n\tif (large_entry) { // check if \"addr = ptr + old_size\" is already spoken for\n\t\treturn 0;\t  // large pointer already exists in table - extension is not going to work\n\t}\n\n\tnew_size = round_page_quanta(new_size);\n\t/*\n\t * Ask for allocation at a specific address, and mark as realloc\n\t * to request coalescing with previous realloc'ed extensions.\n\t */\n\terr = vm_allocate(mach_task_self(), &addr, new_size - old_size, VM_MAKE_TAG(VM_MEMORY_REALLOC));\n\tif (err != KERN_SUCCESS) {\n\t\treturn 0;\n\t}\n\n\tSZONE_LOCK(szone);\n\t/* extend existing large entry */\n\tlarge_entry = large_entry_for_pointer_no_lock(szone, ptr);\n\tif (!large_entry) {\n\t\tmalloc_zone_error(szone->debug_flags, true, \"large entry %p reallocated is not properly in table\\n\", ptr);\n\t\tSZONE_UNLOCK(szone);\n\t\treturn 0; // Bail, leaking \"addr\"\n\t}\n\t\n\tlarge_entry->address = (vm_address_t)ptr;\n\tlarge_entry->size = new_size;\n\tszone->num_bytes_in_large_objects += new_size - old_size;\n\tSZONE_UNLOCK(szone); // we release the lock asap\n\t\n\treturn 1;\n}\n\nboolean_t\nlarge_claimed_address(szone_t *szone, void *ptr)\n{\n\tSZONE_LOCK(szone);\n\tboolean_t result = large_entry_containing_pointer_no_lock(szone,\n\t\t\t(void *)trunc_page((uintptr_t)ptr)) != NULL;\n\tSZONE_UNLOCK(szone);\n\treturn result;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/magazine_lite.c",
    "content": "/*\n * Copyright (c) 2016, Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"internal.h\"\n\ntypedef uint64_t malloc_stack_id;\n\nuint64_t max_lite_mallocs = 0;\n\nstatic malloc_stack_id\nget_stack_id_from_ptr(void *ptr, size_t ptr_size)\n{\n\tvoid *idptr = ptr + ptr_size - sizeof(malloc_stack_id);\n\t\n\treturn * (malloc_stack_id *) idptr;\n}\n\nstatic void\nset_stack_id_in_ptr(void *ptr, size_t requested_size, size_t ptr_size, malloc_stack_id\tstack_id)\n{\n\tvoid *idptr = ptr + ptr_size - sizeof(malloc_stack_id);\n\t* (malloc_stack_id *) idptr = stack_id;\n\tvoid *padding = ptr + requested_size;\n\tbzero(padding, ptr_size - requested_size - sizeof(malloc_stack_id));\n}\n\nstatic void\nadd_stack_to_ptr(szone_t *szone, size_t requested_size, void *ptr)\n{\n\t// enter the stack into the unique table\n\tvm_address_t self_thread = (vm_address_t)_os_tsd_get_direct(__TSD_THREAD_SELF);\n\t\n\tsize_t ptr_size = szone_size(szone, ptr);\n\t\n\t__malloc_lock_stack_logging();\n\t\n\t// if stack logging was turned off behind our backs\n\tif (!is_stack_logging_lite_enabled()) {\n\t\t__malloc_unlock_stack_logging();\n\t\treturn;\n\t}\n\n\tmalloc_stack_id stack_id = __enter_stack_into_table_while_locked(self_thread, 0, false, ptr_size);\n\t\n\t__malloc_unlock_stack_logging();\n\t\n\tif (stack_id == __invalid_stack_id) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"bad stack id. turning off stack logging\\n\");\n\t\tturn_off_stack_logging();\n\t} else {\n\t\tset_stack_id_in_ptr(ptr, requested_size, ptr_size, stack_id);\n\t}\n}\n\nstatic boolean_t stack_logging_lite_enabled = false;\n\nboolean_t is_stack_logging_lite_enabled(void) {\n\treturn stack_logging_lite_enabled;\n}\n\nvoid\nenable_stack_logging_lite()\n{\n\tstack_logging_lite_enabled = true;\n}\n\nvoid\ndisable_stack_logging_lite()\n{\n\tstack_logging_lite_enabled = false;\n}\n\nstatic void *\nstack_logging_lite_malloc(malloc_zone_t *zone, size_t size)\n{\n\tszone_t *szone = (szone_t *) zone;\n\tvoid* p = NULL;\n\tstatic uint64_t num_mallocs = 0;\n\t\n\tif (stack_logging_lite_enabled) {\n\t\t__prepare_to_log_stacks(true);\t// do this again in case stack logging was postponed\n\t\t\n\t\tp = szone_malloc(szone, size + sizeof(malloc_stack_id));\n\t\t\n\t\tif (p) {\n\t\t\tadd_stack_to_ptr(szone, size, p);\n\t\t}\n\t\t\n\t\t// this value doesn't need to be exact, so no need for atomic operations\n\t\tnum_mallocs++;\n\t\t\n\t\tif (max_lite_mallocs > 0 && num_mallocs > max_lite_mallocs) {\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"lite allocations exceeded limit. disabling lite mode\\n\");\n\t\t\tdisable_stack_logging_lite();\n\t\t}\n\t} else {\n\t\tp = szone->helper_zone->basic_zone.malloc((malloc_zone_t *) szone->helper_zone, size);\n\t}\n\t\n\treturn p;\n}\n\nstatic void *\nstack_logging_lite_calloc(struct _malloc_zone_t *zone, size_t num_items, size_t size)\n{\n\tszone_t *szone = (szone_t *) zone;\n\tvoid *p = NULL;\n\t\n\tif (stack_logging_lite_enabled) {\n\t\tsize_t total_bytes;\n\t\t\n\t\tif (calloc_get_size(num_items, size, sizeof(malloc_stack_id), &total_bytes)) {\n\t\t\treturn NULL;\n\t\t}\n\t\t\n\t\tp = szone_malloc_should_clear(szone, total_bytes, 1);\n\t\t\n\t\tif (p) {\n\t\t\tadd_stack_to_ptr(szone, total_bytes - sizeof(malloc_stack_id), p);\n\t\t}\n\t} else {\n\t\tp = szone->helper_zone->basic_zone.calloc((malloc_zone_t *) szone->helper_zone, num_items, size);\n\t}\n\t\n\treturn p;\n}\n\nstatic void *\nstack_logging_lite_valloc(malloc_zone_t *zone, size_t size)\n{\n\tszone_t *szone = (szone_t *) zone;\n\tvoid *p = NULL;\n\t\n\tif (stack_logging_lite_enabled) {\n\t\tp = szone_valloc(szone, size + sizeof(malloc_stack_id));\n\t\t\n\t\tif (p) {\n\t\t\tadd_stack_to_ptr(szone, size, p);\n\t\t}\n\t} else {\n\t\tp = szone->helper_zone->basic_zone.valloc((malloc_zone_t *) szone->helper_zone, size);\n\t}\n\t\n\treturn p;\n}\n\nstatic void\nstack_logging_lite_free(malloc_zone_t *zone, void *ptr)\n{\n\tszone_t *szone = (szone_t *) zone;\n\tsize_t size = szone_size(szone, ptr);\n\t\n\t// see if it's in our zone\n\tif (size) {\n\t\tmalloc_stack_id stack_id = get_stack_id_from_ptr(ptr, size);\n\t\t__decrement_table_slot_refcount(stack_id, size);\n\t\tszone_free(szone, ptr);\n\t} else {\n\t\tszone->helper_zone->basic_zone.free((malloc_zone_t *) szone->helper_zone, ptr);\n\t}\n}\n\nstatic void\nstack_logging_lite_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size)\n{\n\t// because we've messed with the size, don't try to be fancy and just call free\n\tstack_logging_lite_free(zone, ptr);\n}\n\n// Three paths:\n// 1. do a szone_realloc with padding and add stack id\n// 2. do a szone_realloc on the helper zone\n// 3. do a manual free / malloc\n\nstatic void *\nstack_logging_lite_realloc(malloc_zone_t *zone, void *ptr, size_t new_size)\n{\n\tszone_t *szone = (szone_t *) zone;\n\tvoid *new_ptr = NULL;\n\t\n\tsize_t old_size = szone_size(szone, ptr);\n\t\n\t// if we own the ptr and lite enabled do our thing\n\tif (old_size && stack_logging_lite_enabled) {\n\t\t// need to get the old stackid and decrement\n\t\tmalloc_stack_id stack_id = get_stack_id_from_ptr(ptr, old_size);\n\t\tnew_ptr = szone_realloc(szone, ptr, new_size + sizeof(malloc_stack_id));\n\t\t\n\t\tif (new_ptr) {\n\t\t\t__decrement_table_slot_refcount(stack_id, old_size);\n\t\t\tadd_stack_to_ptr(szone, new_size, new_ptr);\n\t\t}\n\t} else if (!old_size && !stack_logging_lite_enabled) {\n\t\t// we don't own the pointer and lite mode is disabled, so just pass the realloc on to the helper zone\n\t\treturn szone->helper_zone->basic_zone.realloc((malloc_zone_t *) szone->helper_zone, ptr, new_size);\n\t} else {\n\t\t// otherwise perform the realloc by hand:\n\t\t// 1. malloc new ptr\n\t\t// 2. copy existing data to new ptr\n\t\t// 3. free old ptr\n\t\t\n\t\t// this will add the stack id if needed\n\t\tnew_ptr = stack_logging_lite_malloc(zone, new_size);\n\t\t\n\t\tif (new_ptr) {\n\t\t\tsize_t old_size = malloc_size(ptr);\n\t\t\tsize_t new_size = malloc_size(new_ptr);\n\t\t\t\n\t\t\t// copy as much old data as possible\n\t\t\tsize_t copy_size = MIN(old_size, new_size);\n\t\t\tmemcpy(new_ptr, ptr, copy_size);\n\t\t}\n\t\t\n\t\tstack_logging_lite_free(zone, ptr);\n\t}\n\t\n\treturn new_ptr;\n}\n\nstatic void * MALLOC_NOINLINE\nstack_logging_lite_memalign(malloc_zone_t *zone, size_t alignment, size_t size)\n{\n\tszone_t *szone = (szone_t *) zone;\n\tvoid *ptr = NULL;\n\t\n\tif (stack_logging_lite_enabled) {\n\t\tptr = szone_memalign(szone, alignment, size + sizeof(malloc_stack_id));\n\t\t\n\t\tif (ptr) {\n\t\t\tadd_stack_to_ptr(szone, size, ptr);\n\t\t}\n\t} else {\n\t\tptr = szone->helper_zone->basic_zone.memalign((malloc_zone_t *) szone->helper_zone, alignment, size);\n\t}\n\t\n\treturn ptr;\n}\n\nstatic size_t\nstack_logging_lite_size(malloc_zone_t *zone, const void *ptr)\n{\n\tszone_t *szone = (szone_t *) zone;\n\tsize_t size = szone_size(szone, ptr);\n\t\n\tif (size) {\n\t\tsize -= sizeof(malloc_stack_id);\n\t} else {\n\t\tsize = szone->helper_zone->basic_zone.size((malloc_zone_t *) szone->helper_zone, ptr);\n\t}\n\t\n\treturn size;\n}\n\nunsigned\nstack_logging_lite_batch_malloc(szone_t *szone, size_t size, void **results, unsigned count)\n{\n\tunsigned num_allocated = 0;\n\t\n\tif (stack_logging_lite_enabled) {\n\t\tnum_allocated = szone_batch_malloc(szone, size + sizeof(malloc_stack_id), results, count);\n\t\t\n\t\tfor (unsigned i = 0; i < num_allocated; i++) {\n\t\t\tadd_stack_to_ptr(szone, size, results[i]);\n\t\t}\n\t} else {\n\t\tnum_allocated = szone->helper_zone->basic_zone.batch_malloc((malloc_zone_t *) szone->helper_zone, size, results, count);\n\t}\n\t\n\treturn num_allocated;\n}\n\nvoid\nstack_logging_lite_batch_free(szone_t *szone, void **to_be_freed, unsigned count)\n{\n\tfor (unsigned i = 0; i < count; i++) {\n\t\tvoid *p = to_be_freed[i];\n\t\t\n\t\tif (p) {\n\t\t\tsize_t size = szone_size(szone, p);\n\t\t\t\n\t\t\t// see if it's in our zone\n\t\t\tif (size) {\n\t\t\t\tmalloc_stack_id stack_id = get_stack_id_from_ptr(p, size);\n\t\t\t\t__decrement_table_slot_refcount(stack_id, size);\n\t\t\t\tszone_free(szone, p);\n\t\t\t} else {\n\t\t\t\tszone->helper_zone->basic_zone.free((malloc_zone_t *) szone->helper_zone, p);\n\t\t\t}\n\t\t}\n\t}\n}\n\n\nmalloc_zone_t *\ncreate_stack_logging_lite_zone(size_t initial_size, malloc_zone_t *helper_zone, unsigned debug_flags)\n{\n\tszone_t* zone = create_scalable_szone(initial_size, debug_flags);\n\t\n\t// unprotect function pointers\n\tmprotect(zone, sizeof(zone->basic_zone), PROT_READ | PROT_WRITE);\n\t\n\t// set the function pointers\n\tzone->basic_zone.malloc = stack_logging_lite_malloc;\n\tzone->basic_zone.calloc = stack_logging_lite_calloc;\n\tzone->basic_zone.valloc = stack_logging_lite_valloc;\n\tzone->basic_zone.realloc = stack_logging_lite_realloc;\n\tzone->basic_zone.batch_malloc = (void *) stack_logging_lite_batch_malloc;\n\tzone->basic_zone.batch_free = (void *) stack_logging_lite_batch_free;\n\tzone->basic_zone.memalign = stack_logging_lite_memalign;\n\tzone->basic_zone.free = stack_logging_lite_free;\n\tzone->basic_zone.free_definite_size = stack_logging_lite_free_definite_size;\n\tzone->basic_zone.size = stack_logging_lite_size;\n\t\n\t// protect function pointers\n\tmprotect(zone, sizeof(zone->basic_zone), PROT_READ);\n\t\n\t// set helper zone\n\tzone->helper_zone = (szone_t*) helper_zone;\n\t\n\treturn (malloc_zone_t*) zone;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/magazine_malloc.c",
    "content": "/*\n * Copyright (c) 1999, 2006, 2008 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n/* Author: Bertrand Serlet, August 1999 */\n\n/*\n * Multithread enhancements for \"tiny\" allocations introduced February 2008.\n * These are in the spirit of \"Hoard\". See:\n * Berger, E.D.; McKinley, K.S.; Blumofe, R.D.; Wilson, P.R. (2000).\n * \"Hoard: a scalable memory allocator for multithreaded applications\".\n * ACM SIGPLAN Notices 35 (11): 117-128. Berger2000.\n * <http://portal.acm.org/citation.cfm?id=356989.357000>\n * Retrieved on 2008-02-22.\n */\n\n#include \"internal.h\"\n\n#if DEBUG_MALLOC\n#define LOG(szone, ptr) (szone->log_address && (((uintptr_t)szone->log_address == -1) || (szone->log_address == (void *)(ptr))))\n#else\n#define LOG(szone, ptr) 0\n#endif\n\n// Maximum number of magazines, set from the number of logical CPUS and\n// possibly limited by the MallocMaxMagazines environment variable.\nint max_magazines;\n\n// Number of regions to retain in a recirc depot.\n#if CONFIG_RECIRC_DEPOT\nint recirc_retained_regions = DEFAULT_RECIRC_RETAINED_REGIONS;\n#endif // CONFIG_RECIRC_DEPOT\n\n/*********************\tZone call backs\t************************/\n/*\n * Mark these MALLOC_NOINLINE to avoid bloating the purgeable zone call backs\n */\nvoid\nszone_free(szone_t *szone, void *ptr)\n{\n\tregion_t tiny_region;\n\tregion_t small_region;\n\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"in szone_free with %p\\n\", ptr);\n\t}\n#endif\n\tif (!ptr) {\n\t\treturn;\n\t}\n\t/*\n\t * Try to free to a tiny region.\n\t */\n\tif ((uintptr_t)ptr & (TINY_QUANTUM - 1)) {\n\t\tmalloc_zone_error(szone->debug_flags, true, \"Non-aligned pointer %p being freed\\n\", ptr);\n\t\treturn;\n\t}\n\tif ((tiny_region = tiny_region_for_ptr_no_lock(&szone->tiny_rack, ptr)) != NULL) {\n\t\tif (TINY_INDEX_FOR_PTR(ptr) >= NUM_TINY_BLOCKS) {\n\t\t\tmalloc_zone_error(szone->debug_flags, true, \"Pointer %p to metadata being freed\\n\", ptr);\n\t\t\treturn;\n\t\t}\n\t\tfree_tiny(&szone->tiny_rack, ptr, tiny_region, 0);\n\t\treturn;\n\t}\n\n\t/*\n\t * Try to free to a small region.\n\t */\n\tif ((uintptr_t)ptr & (SMALL_QUANTUM - 1)) {\n\t\tmalloc_zone_error(szone->debug_flags, true, \"Non-aligned pointer %p being freed (2)\\n\", ptr);\n\t\treturn;\n\t}\n\tif ((small_region = small_region_for_ptr_no_lock(&szone->small_rack, ptr)) != NULL) {\n\t\tif (SMALL_META_INDEX_FOR_PTR(ptr) >= NUM_SMALL_BLOCKS) {\n\t\t\tmalloc_zone_error(szone->debug_flags, true, \"Pointer %p to metadata being freed (2)\\n\", ptr);\n\t\t\treturn;\n\t\t}\n\t\tfree_small(&szone->small_rack, ptr, small_region, 0);\n\t\treturn;\n\t}\n\n\t/* check that it's a legal large allocation */\n\tif ((uintptr_t)ptr & (vm_page_quanta_size - 1)) {\n\t\tmalloc_zone_error(szone->debug_flags, true, \"non-page-aligned, non-allocated pointer %p being freed\\n\", ptr);\n\t\treturn;\n\t}\n\tfree_large(szone, ptr);\n}\n\nvoid\nszone_free_definite_size(szone_t *szone, void *ptr, size_t size)\n{\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"in szone_free_definite_size with %p\\n\", ptr);\n\t}\n\n\tif (0 == size) {\n\t\tmalloc_zone_error(szone->debug_flags, true, \"pointer %p of size zero being freed\\n\", ptr);\n\t\treturn;\n\t}\n\n#endif\n\tif (!ptr) {\n\t\treturn;\n\t}\n\n\t/*\n\t * Try to free to a tiny region.\n\t */\n\tif ((uintptr_t)ptr & (TINY_QUANTUM - 1)) {\n\t\tmalloc_zone_error(szone->debug_flags, true, \"Non-aligned pointer %p being freed\\n\", ptr);\n\t\treturn;\n\t}\n\tif (size <= SMALL_THRESHOLD) {\n\t\tif (TINY_INDEX_FOR_PTR(ptr) >= NUM_TINY_BLOCKS) {\n\t\t\tmalloc_zone_error(szone->debug_flags, true, \"Pointer %p to metadata being freed\\n\", ptr);\n\t\t\treturn;\n\t\t}\n\t\tfree_tiny(&szone->tiny_rack, ptr, TINY_REGION_FOR_PTR(ptr), size);\n\t\treturn;\n\t}\n\n\t/*\n\t * Try to free to a small region.\n\t */\n\tif ((uintptr_t)ptr & (SMALL_QUANTUM - 1)) {\n\t\tmalloc_zone_error(szone->debug_flags, true, \"Non-aligned pointer %p being freed (2)\\n\", ptr);\n\t\treturn;\n\t}\n\tif (size <= szone->large_threshold) {\n\t\tif (SMALL_META_INDEX_FOR_PTR(ptr) >= NUM_SMALL_BLOCKS) {\n\t\t\tmalloc_zone_error(szone->debug_flags, true, \"Pointer %p to metadata being freed (2)\\n\", ptr);\n\t\t\treturn;\n\t\t}\n\t\tfree_small(&szone->small_rack, ptr, SMALL_REGION_FOR_PTR(ptr), size);\n\t\treturn;\n\t}\n\n\t/* check that it's a legal large allocation */\n\tif ((uintptr_t)ptr & (vm_page_quanta_size - 1)) {\n\t\tmalloc_zone_error(szone->debug_flags, true, \"non-page-aligned, non-allocated pointer %p being freed\\n\", ptr);\n\t\treturn;\n\t}\n\tfree_large(szone, ptr);\n}\n\nMALLOC_NOINLINE void *\nszone_malloc_should_clear(szone_t *szone, size_t size, boolean_t cleared_requested)\n{\n\tvoid *ptr;\n\tmsize_t msize;\n\n\tif (size <= SMALL_THRESHOLD) {\n\t\t// tiny size: <=1008 bytes (64-bit), <=496 bytes (32-bit)\n\t\t// think tiny\n\t\tmsize = TINY_MSIZE_FOR_BYTES(size + TINY_QUANTUM - 1);\n\t\tif (!msize) {\n\t\t\tmsize = 1;\n\t\t}\n\t\tptr = tiny_malloc_should_clear(&szone->tiny_rack, msize, cleared_requested);\n\t} else if (size <= szone->large_threshold) {\n\t\t// small size: <=15k (iOS), <=64k (large iOS), <=128k (macOS)\n\t\t// think small\n\t\tmsize = SMALL_MSIZE_FOR_BYTES(size + SMALL_QUANTUM - 1);\n\t\tif (!msize) {\n\t\t\tmsize = 1;\n\t\t}\n\t\tptr = small_malloc_should_clear(&szone->small_rack, msize, cleared_requested);\n\t} else {\n\t\t// large: all other allocations\n\t\tsize_t num_kernel_pages = round_page_quanta(size) >> vm_page_quanta_shift;\n\t\tif (num_kernel_pages == 0) { /* Overflowed */\n\t\t\tptr = 0;\n\t\t} else {\n\t\t\tptr = large_malloc(szone, num_kernel_pages, 0, cleared_requested);\n\t\t}\n\t}\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"szone_malloc returned %p\\n\", ptr);\n\t}\n#endif\n\t/*\n\t * If requested, scribble on allocated memory.\n\t */\n\tif ((szone->debug_flags & MALLOC_DO_SCRIBBLE) && ptr && !cleared_requested && size) {\n\t\tmemset(ptr, SCRIBBLE_BYTE, szone_size(szone, ptr));\n\t}\n\n\treturn ptr;\n}\n\nvoid *\nszone_malloc(szone_t *szone, size_t size)\n{\n\treturn szone_malloc_should_clear(szone, size, 0);\n}\n\nvoid *\nszone_calloc(szone_t *szone, size_t num_items, size_t size)\n{\n\tsize_t total_bytes;\n\tif (calloc_get_size(num_items, size, 0, &total_bytes)) {\n\t\treturn NULL;\n\t}\n\treturn szone_malloc_should_clear(szone, total_bytes, 1);\n}\n\nvoid *\nszone_valloc(szone_t *szone, size_t size)\n{\n\tvoid *ptr;\n\n\tif (size <= szone->large_threshold) {\n\t\tptr = szone_memalign(szone, vm_page_quanta_size, size);\n\t} else {\n\t\tsize_t num_kernel_pages;\n\n\t\tnum_kernel_pages = round_page_quanta(size) >> vm_page_quanta_shift;\n\t\tptr = large_malloc(szone, num_kernel_pages, 0, 0);\n\t}\n\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"szone_valloc returned %p\\n\", ptr);\n\t}\n#endif\n\treturn ptr;\n}\n\n/* Isolate PIC-base load here. */\nsize_t\nszone_size_try_large(szone_t *szone, const void *ptr)\n{\n\tsize_t size = 0;\n\tlarge_entry_t *entry;\n\n\tSZONE_LOCK(szone);\n\tentry = large_entry_for_pointer_no_lock(szone, ptr);\n\tif (entry) {\n\t\tsize = entry->size;\n\t}\n\tSZONE_UNLOCK(szone);\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"szone_size for %p returned %d\\n\", ptr, (unsigned)size);\n\t}\n#endif\n\treturn size;\n}\n\nsize_t\nszone_size(szone_t *szone, const void *ptr)\n{\n\tsize_t sz = 0;\n\n\tif (!ptr) {\n\t\treturn 0;\n\t}\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"in szone_size for %p (szone=%p)\\n\", ptr, szone);\n\t}\n#endif\n\n\t/*\n\t * Look for it in a tiny region.\n\t */\n\tif ((uintptr_t)ptr & (TINY_QUANTUM - 1)) {\n\t\treturn 0;\n\t}\n\n\tsz = tiny_size(&szone->tiny_rack, ptr);\n\tif (sz) {\n\t\treturn sz;\n\t}\n\n\t/*\n\t * Look for it in a small region.\n\t */\n\tif ((uintptr_t)ptr & (SMALL_QUANTUM - 1)) {\n\t\treturn 0;\n\t}\n\n\tsz = small_size(&szone->small_rack, ptr);\n\tif (sz) {\n\t\treturn sz;\n\t}\n\n\t/*\n\t * If not page-aligned, it cannot have come from a large allocation.\n\t */\n\tif ((uintptr_t)ptr & (vm_page_quanta_size - 1)) {\n\t\treturn 0;\n\t}\n\n\t/*\n\t * Look for it in a large entry.\n\t */\n\treturn szone_size_try_large(szone, ptr);\n}\n\nvoid *\nszone_realloc(szone_t *szone, void *ptr, size_t new_size)\n{\n\tsize_t old_size, new_good_size, valid_size;\n\tvoid *new_ptr;\n\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"in szone_realloc for %p, %d\\n\", ptr, (unsigned)new_size);\n\t}\n#endif\n\tif (NULL == ptr) {\n\t\t// If ptr is a null pointer, realloc() shall be equivalent to malloc() for the specified size.\n\t\treturn szone_malloc(szone, new_size);\n\t} else if (0 == new_size) {\n\t\t// If size is 0 and ptr is not a null pointer, the object pointed to is freed.\n\t\tszone_free(szone, ptr);\n\t\t// If size is 0, either a null pointer or a unique pointer that can be successfully passed\n\t\t// to free() shall be returned.\n\t\treturn szone_malloc(szone, 1);\n\t}\n\n\told_size = szone_size(szone, ptr);\n\tif (!old_size) {\n\t\tmalloc_zone_error(szone->debug_flags, true, \"pointer %p being reallocated was not allocated\\n\", ptr);\n\t\treturn NULL;\n\t}\n\n\tnew_good_size = szone_good_size(szone, new_size);\n\tif (new_good_size == old_size) { // Existing allocation is best fit evar?\n\t\treturn ptr;\n\t}\n\n\t/*\n\t * If the new size suits the tiny allocator and the pointer being resized\n\t * belongs to a tiny region, try to reallocate in-place.\n\t */\n\tif (new_good_size <= SMALL_THRESHOLD) {\n\t\tif (old_size <= SMALL_THRESHOLD) {\n\t\t\tif (new_good_size <= (old_size >> 1)) {\n\t\t\t\t/*\n\t\t\t\t * Serious shrinkage (more than half). free() the excess.\n\t\t\t\t */\n\t\t\t\treturn tiny_try_shrink_in_place(&szone->tiny_rack, ptr, old_size, new_good_size);\n\t\t\t} else if (new_good_size <= old_size) {\n\t\t\t\t/*\n\t\t\t\t * new_good_size smaller than old_size but not by much (less than half).\n\t\t\t\t * Avoid thrashing at the expense of some wasted storage.\n\t\t\t\t */\n\t\t\t\tif (szone->debug_flags & MALLOC_DO_SCRIBBLE) {\n\t\t\t\t\tmemset(ptr + new_size, SCRIBBLE_BYTE, old_size - new_size);\n\t\t\t\t}\n\t\t\t\treturn ptr;\n\t\t\t} else if (tiny_try_realloc_in_place(&szone->tiny_rack, ptr, old_size, new_good_size)) { // try to grow the allocation\n\t\t\t\tif (szone->debug_flags & MALLOC_DO_SCRIBBLE) {\n\t\t\t\t\tmemset(ptr + old_size, SCRIBBLE_BYTE, new_good_size - old_size);\n\t\t\t\t}\n\t\t\t\treturn ptr;\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t * Else if the new size suits the small allocator and the pointer being resized\n\t\t * belongs to a small region, and we're not protecting the small allocations\n\t\t * try to reallocate in-place.\n\t\t */\n\t} else if (new_good_size <= szone->large_threshold) {\n\t\tif (SMALL_THRESHOLD < old_size && old_size <= szone->large_threshold) {\n\t\t\tif (new_good_size <= (old_size >> 1)) {\n\t\t\t\treturn small_try_shrink_in_place(&szone->small_rack, ptr, old_size, new_good_size);\n\t\t\t} else if (new_good_size <= old_size) {\n\t\t\t\tif (szone->debug_flags & MALLOC_DO_SCRIBBLE) {\n\t\t\t\t\tmemset(ptr + new_size, SCRIBBLE_BYTE, old_size - new_size);\n\t\t\t\t}\n\t\t\t\treturn ptr;\n\t\t\t} else if (small_try_realloc_in_place(&szone->small_rack, ptr, old_size, new_good_size)) {\n\t\t\t\tif (szone->debug_flags & MALLOC_DO_SCRIBBLE) {\n\t\t\t\t\tmemset(ptr + old_size, SCRIBBLE_BYTE, new_good_size - old_size);\n\t\t\t\t}\n\t\t\t\treturn ptr;\n\t\t\t}\n\t\t}\n\t\t/*\n\t\t * Else if the allocation's a large allocation, try to reallocate in-place there.\n\t\t */\n\t} else if (!(szone->debug_flags & MALLOC_PURGEABLE) && // purgeable needs fresh allocation\n\t\t\t   (old_size > szone->large_threshold) && (new_good_size > szone->large_threshold)) {\n\t\tif (new_good_size <= (old_size >> 1)) {\n\t\t\treturn large_try_shrink_in_place(szone, ptr, old_size, new_good_size);\n\t\t} else if (new_good_size <= old_size) {\n\t\t\tif (szone->debug_flags & MALLOC_DO_SCRIBBLE) {\n\t\t\t\tmemset(ptr + new_size, SCRIBBLE_BYTE, old_size - new_size);\n\t\t\t}\n\t\t\treturn ptr;\n\t\t} else if (large_try_realloc_in_place(szone, ptr, old_size, new_good_size)) {\n\t\t\tif (szone->debug_flags & MALLOC_DO_SCRIBBLE) {\n\t\t\t\tmemset(ptr + old_size, SCRIBBLE_BYTE, new_good_size - old_size);\n\t\t\t}\n\t\t\treturn ptr;\n\t\t}\n\t}\n\n\t/*\n\t * Can't reallocate in place for whatever reason; allocate a new buffer and copy.\n\t */\n\tif (new_good_size <= (old_size >> 1)) {\n\t\t/* Serious shrinkage (more than half). FALL THROUGH to alloc/copy/free. */\n\t} else if (new_good_size <= old_size) {\n\t\tif (szone->debug_flags & MALLOC_DO_SCRIBBLE) {\n\t\t\tmemset(ptr + new_size, SCRIBBLE_BYTE, old_size - new_size);\n\t\t}\n\t\treturn ptr;\n\t}\n\n\tnew_ptr = szone_malloc(szone, new_size);\n\tif (new_ptr == NULL) {\n\t\treturn NULL;\n\t}\n\n\t/*\n\t * If the allocation's large enough, try to copy using VM.  If that fails, or\n\t * if it's too small, just copy by hand.\n\t */\n\tvalid_size = MIN(old_size, new_size);\n\tif ((valid_size <= szone->vm_copy_threshold) ||\n\t\t\tvm_copy(mach_task_self(), (vm_address_t)ptr, valid_size, (vm_address_t)new_ptr)) {\n\t\tmemcpy(new_ptr, ptr, valid_size);\n\t}\n\tszone_free(szone, ptr);\n\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"szone_realloc returned %p for %d\\n\", new_ptr, (unsigned)new_size);\n\t}\n#endif\n\treturn new_ptr;\n}\n\nvoid *\nszone_memalign(szone_t *szone, size_t alignment, size_t size)\n{\n\tif (size == 0) {\n\t\tsize = 1; // Ensures we'll return an aligned free()-able pointer\n\t}\n\tif ((size + alignment) < size) { // size_t arithmetic wrapped!\n\t\treturn NULL;\n\t}\n\n\t// alignment is gauranteed a power of 2 at least as large as sizeof(void *), hence non-zero.\n\t// Since size + alignment didn't wrap, 0 <= size + alignment - 1 < size + alignment\n\tsize_t span = size + alignment - 1;\n\n\tif (alignment <= TINY_QUANTUM) {\n\t\treturn szone_malloc(szone, size); // Trivially satisfied by tiny, small, or large\n\t}\n\tif (span <= SMALL_THRESHOLD) {\n\t\treturn tiny_memalign(szone, alignment, size, span);\n\t}\n\tif (SMALL_THRESHOLD < size && alignment <= SMALL_QUANTUM) {\n\t\treturn szone_malloc(szone, size); // Trivially satisfied by small or large\n\t}\n\tif (size <= SMALL_THRESHOLD) {\n\t\t// ensure block allocated by small does not have a tiny-possible size\n\t\tsize = SMALL_THRESHOLD + TINY_QUANTUM;\n\t\tspan = size + alignment - 1;\n\t}\n\tif (span <= szone->large_threshold) {\n\t\treturn small_memalign(szone, alignment, size, span);\n\t}\n\tif (szone->large_threshold < size && alignment <= vm_page_quanta_size) {\n\t\treturn szone_malloc(szone, size); // Trivially satisfied by large\n\t}\n\t// ensure block allocated by large does not have a small-possible size\n\tsize_t num_kernel_pages = round_page_quanta(MAX(szone->large_threshold + 1,\n\t\t\tsize)) >> vm_page_quanta_shift;\n\tif (num_kernel_pages == 0) { /* Overflowed */\n\t\treturn NULL;\n\t} else {\n\t\treturn large_malloc(szone, num_kernel_pages,\n\t\t\t\tMAX(vm_page_quanta_shift, __builtin_ctz((unsigned)alignment)), 0);\n\t}\n\t/* NOTREACHED */\n}\n\n// Given a size, returns the number of pointers allocated capable of holding\n// that size, up to the limit specified by the 'count' argument.  These pointers\n// are stored in the 'results' array, which must be allocated by the caller.\n// May return zero, since this function is only a best attempt at allocating\n// the pointers. Clients should be prepared to call malloc for any additional\n// blocks they need.\nunsigned\nszone_batch_malloc(szone_t *szone, size_t size, void **results, unsigned count)\n{\n\t// only bother implementing this for tiny\n\tif (size <= SMALL_THRESHOLD) {\n\t\treturn tiny_batch_malloc(szone, size, results, count);\n\t}\n\treturn 0;\n}\n\nvoid\nszone_batch_free(szone_t *szone, void **to_be_freed, unsigned count)\n{\n\t// frees all the pointers in to_be_freed\n\t// note that to_be_freed may be overwritten during the process\n\tif (!count) {\n\t\treturn;\n\t}\n\n\tCHECK(szone, __PRETTY_FUNCTION__);\n\n\t// We only support batch malloc in tiny. Let it free all of the pointers\n\t// that belong to it, then let the standard free deal with the rest.\n\ttiny_batch_free(szone, to_be_freed, count);\n\t\n\tCHECK(szone, __PRETTY_FUNCTION__);\n\twhile (count--) {\n\t\tvoid *ptr = to_be_freed[count];\n\t\tif (ptr) {\n\t\t\tszone_free(szone, ptr);\n\t\t}\n\t}\n}\n\n// FIXME: Suppose one of the locks is held?\nstatic void\nszone_destroy(szone_t *szone)\n{\n\tsize_t index;\n\tlarge_entry_t *large;\n\tvm_range_t range_to_deallocate;\n\n#if CONFIG_LARGE_CACHE\n\tSZONE_LOCK(szone);\n\n\t/* disable any memory pressure responder */\n\tszone->flotsam_enabled = FALSE;\n\n\t// stack allocated copy of the death-row cache\n\tint idx = szone->large_entry_cache_oldest, idx_max = szone->large_entry_cache_newest;\n\tlarge_entry_t local_entry_cache[LARGE_ENTRY_CACHE_SIZE];\n\n\tmemcpy((void *)local_entry_cache, (void *)szone->large_entry_cache, sizeof(local_entry_cache));\n\n\tszone->large_entry_cache_oldest = szone->large_entry_cache_newest = 0;\n\tszone->large_entry_cache[0].address = 0x0;\n\tszone->large_entry_cache[0].size = 0;\n\tszone->large_entry_cache_bytes = 0;\n\tszone->large_entry_cache_reserve_bytes = 0;\n\n\tSZONE_UNLOCK(szone);\n\n\t// deallocate the death-row cache outside the zone lock\n\twhile (idx != idx_max) {\n\t\tmvm_deallocate_pages((void *)local_entry_cache[idx].address, local_entry_cache[idx].size, 0);\n\t\tif (++idx == LARGE_ENTRY_CACHE_SIZE) {\n\t\t\tidx = 0;\n\t\t}\n\t}\n\tif (0 != local_entry_cache[idx].address && 0 != local_entry_cache[idx].size) {\n\t\tmvm_deallocate_pages((void *)local_entry_cache[idx].address, local_entry_cache[idx].size, 0);\n\t}\n#endif\n\n\t/* destroy large entries */\n\tindex = szone->num_large_entries;\n\twhile (index--) {\n\t\tlarge = szone->large_entries + index;\n\t\tif (large->address) {\n\t\t\t// we deallocate_pages, including guard pages\n\t\t\tmvm_deallocate_pages((void *)(large->address), large->size, szone->debug_flags);\n\t\t}\n\t}\n\tlarge_entries_free_no_lock(szone, szone->large_entries, szone->num_large_entries, &range_to_deallocate);\n\tif (range_to_deallocate.size) {\n\t\tmvm_deallocate_pages((void *)range_to_deallocate.address, (size_t)range_to_deallocate.size, 0);\n\t}\n\n\t/* destroy allocator regions */\n\track_destroy_regions(&szone->tiny_rack, TINY_REGION_SIZE);\n\track_destroy_regions(&szone->small_rack, SMALL_REGION_SIZE);\n\n\t/* destroy rack region hash rings and racks themselves */\n\track_destroy(&szone->tiny_rack);\n\track_destroy(&szone->small_rack);\n\n\tmvm_deallocate_pages((void *)szone, SZONE_PAGED_SIZE, 0);\n}\n\nsize_t\nszone_good_size(szone_t *szone, size_t size)\n{\n\tmsize_t msize;\n\n\t// Find a good size for this tiny allocation.\n\tif (size <= SMALL_THRESHOLD) {\n\t\tmsize = TINY_MSIZE_FOR_BYTES(size + TINY_QUANTUM - 1);\n\t\tif (!msize) {\n\t\t\tmsize = 1;\n\t\t}\n\t\treturn TINY_BYTES_FOR_MSIZE(msize);\n\t}\n\n\t// Find a good size for this small allocation.\n\tif (size <= szone->large_threshold) {\n\t\tmsize = SMALL_MSIZE_FOR_BYTES(size + SMALL_QUANTUM - 1);\n\t\tif (!msize) {\n\t\t\tmsize = 1;\n\t\t}\n\t\treturn SMALL_BYTES_FOR_MSIZE(msize);\n\t}\n\n\t// Check for integer overflow on the size, since unlike the two cases above,\n\t// there is no upper bound on allocation size at this point.\n\tif (size > round_page_quanta(size)) {\n\t\treturn (size_t)(-1LL);\n\t}\n\n#if DEBUG_MALLOC\n\t// It is not acceptable to see a size of zero here, since that means we\n\t// failed to catch a request for zero bytes in the tiny check, or the size\n\t// overflowed to zero during some arithmetic.\n\tif (size == 0) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"szone_good_size() invariant broken %y\\n\", size);\n\t}\n#endif\n\treturn round_page_quanta(size);\n}\n\nboolean_t\nszone_claimed_address(szone_t *szone, void *ptr)\n{\n\treturn tiny_claimed_address(&szone->tiny_rack, ptr)\n\t\t\t|| small_claimed_address(&szone->small_rack, ptr)\n\t\t\t|| large_claimed_address(szone, ptr);\n}\n\nunsigned szone_check_counter = 0;\nunsigned szone_check_start = 0;\nunsigned szone_check_modulo = 1;\n\nstatic MALLOC_NOINLINE boolean_t\nszone_check_all(szone_t *szone, const char *function)\n{\n\tsize_t index;\n\n\t/* check tiny regions - chould check region count */\n\tfor (index = 0; index < szone->tiny_rack.region_generation->num_regions_allocated; ++index) {\n\t\tregion_t tiny = szone->tiny_rack.region_generation->hashed_regions[index];\n\n\t\tif (HASHRING_REGION_DEALLOCATED == tiny) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (tiny) {\n\t\t\tmagazine_t *tiny_mag_ptr = mag_lock_zine_for_region_trailer(szone->tiny_rack.magazines,\n\t\t\t\t\tREGION_TRAILER_FOR_TINY_REGION(tiny),\n\t\t\t\t\tMAGAZINE_INDEX_FOR_TINY_REGION(tiny));\n\n\t\t\tif (!tiny_check_region(&szone->tiny_rack, tiny, index, szone_check_counter)) {\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\t\tszone->debug_flags &= ~CHECK_REGIONS;\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t}\n\t}\n\t/* check tiny free lists */\n\tfor (index = 0; index < NUM_TINY_SLOTS; ++index) {\n\t\tif (!tiny_free_list_check(&szone->tiny_rack, (grain_t)index, szone_check_counter)) {\n\t\t\tszone->debug_flags &= ~CHECK_REGIONS;\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/* check small regions - could check region count */\n\tfor (index = 0; index < szone->small_rack.region_generation->num_regions_allocated; ++index) {\n\t\tregion_t small = szone->small_rack.region_generation->hashed_regions[index];\n\n\t\tif (HASHRING_REGION_DEALLOCATED == small) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (small) {\n\t\t\tmagazine_t *small_mag_ptr = mag_lock_zine_for_region_trailer(szone->small_rack.magazines,\n\t\t\t\t\tREGION_TRAILER_FOR_SMALL_REGION(small),\n\t\t\t\t\tMAGAZINE_INDEX_FOR_SMALL_REGION(small));\n\n\t\t\tif (!small_check_region(&szone->small_rack, small, index, szone_check_counter)) {\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\t\tszone->debug_flags &= ~CHECK_REGIONS;\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t}\n\t}\n\t/* check small free lists */\n\tfor (index = 0; index < SMALL_FREE_SLOT_COUNT(&szone->small_rack); ++index) {\n\t\tif (!small_free_list_check(&szone->small_rack, (grain_t)index, szone_check_counter)) {\n\t\t\tszone->debug_flags &= ~CHECK_REGIONS;\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\treturn 1;\n}\n\nstatic boolean_t\nszone_check(szone_t *szone)\n{\n\tif ((++szone_check_counter % 10000) == 0) {\n\t\tmalloc_report(ASL_LEVEL_NOTICE, \"at szone_check counter=%d\\n\", szone_check_counter);\n\t}\n\n\tif (szone_check_counter < szone_check_start) {\n\t\treturn 1;\n\t}\n\n\tif (szone_check_counter % szone_check_modulo) {\n\t\treturn 1;\n\t}\n\n\treturn szone_check_all(szone, \"\");\n}\n\nstatic kern_return_t\nszone_ptr_in_use_enumerator(task_t task,\n\t\tvoid *context,\n\t\tunsigned type_mask,\n\t\tvm_address_t zone_address,\n\t\tmemory_reader_t reader,\n\t\tvm_range_recorder_t recorder)\n{\n\tszone_t *szone;\n\tkern_return_t err;\n\n\tif (!reader) {\n\t\treader = _szone_default_reader;\n\t}\n\n\terr = reader(task, zone_address, sizeof(szone_t), (void **)&szone);\n\tif (err) {\n\t\treturn err;\n\t}\n\n\terr = tiny_in_use_enumerator(task, context, type_mask, szone, reader, recorder);\n\tif (err) {\n\t\treturn err;\n\t}\n\n\terr = small_in_use_enumerator(task, context, type_mask, szone, reader, recorder);\n\tif (err) {\n\t\treturn err;\n\t}\n\n\terr = large_in_use_enumerator(\n\t\t\ttask, context, type_mask, (vm_address_t)szone->large_entries, szone->num_large_entries, reader, recorder);\n\treturn err;\n}\n\n// Following method is deprecated:  use scalable_zone_statistics instead\nvoid\nscalable_zone_info(malloc_zone_t *zone, unsigned *info_to_fill, unsigned count)\n{\n\tszone_t *szone = (void *)zone;\n\tunsigned info[13];\n\n\t// We do not lock to facilitate debug\n\n\tsize_t s = 0;\n\tunsigned t = 0;\n\tsize_t u = 0;\n\tmag_index_t mag_index;\n\n\tfor (mag_index = -1; mag_index < szone->tiny_rack.num_magazines; mag_index++) {\n\t\ts += szone->tiny_rack.magazines[mag_index].mag_bytes_free_at_start;\n\t\ts += szone->tiny_rack.magazines[mag_index].mag_bytes_free_at_end;\n\t\tt += szone->tiny_rack.magazines[mag_index].mag_num_objects;\n\t\tu += szone->tiny_rack.magazines[mag_index].mag_num_bytes_in_objects;\n\t}\n\n\tinfo[4] = (unsigned)t;\n\tinfo[5] = (unsigned)u;\n\n\tfor (t = 0, u = 0, mag_index = -1; mag_index < szone->small_rack.num_magazines; mag_index++) {\n\t\ts += szone->small_rack.magazines[mag_index].mag_bytes_free_at_start;\n\t\ts += szone->small_rack.magazines[mag_index].mag_bytes_free_at_end;\n\t\tt += szone->small_rack.magazines[mag_index].mag_num_objects;\n\t\tu += szone->small_rack.magazines[mag_index].mag_num_bytes_in_objects;\n\t}\n\n\tinfo[6] = (unsigned)t;\n\tinfo[7] = (unsigned)u;\n\n\tinfo[8] = (unsigned)szone->num_large_objects_in_use;\n\tinfo[9] = (unsigned)szone->num_bytes_in_large_objects;\n\n\tinfo[10] = 0; // DEPRECATED szone->num_huge_entries;\n\tinfo[11] = 0; // DEPRECATED szone->num_bytes_in_huge_objects;\n\n\tinfo[12] = szone->debug_flags;\n\n\tinfo[0] = info[4] + info[6] + info[8] + info[10];\n\tinfo[1] = info[5] + info[7] + info[9] + info[11];\n\n\tinfo[3] = (unsigned)(szone->tiny_rack.num_regions - szone->tiny_rack.num_regions_dealloc) * TINY_REGION_SIZE +\n\t\t\t  (unsigned)(szone->small_rack.num_regions - szone->small_rack.num_regions_dealloc) * SMALL_REGION_SIZE + info[9] + info[11];\n\n\tinfo[2] = info[3] - (unsigned)s;\n\tmemcpy(info_to_fill, info, sizeof(unsigned) * count);\n}\n\n// FIXME: consistent picture requires locking!\nstatic MALLOC_NOINLINE void\nszone_print(szone_t *szone, boolean_t verbose)\n{\n\tunsigned info[13];\n\tsize_t index;\n\tregion_t region;\n\n\tscalable_zone_info((void *)szone, info, 13);\n\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\"Scalable zone %p: inUse=%u(%y) touched=%y allocated=%y flags=%d\\n\", szone, info[0], info[1], info[2], info[3],\n\t\t\tinfo[12]);\n\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"\\ttiny=%u(%y) small=%u(%y) large=%u(%y) huge=%u(%y)\\n\", info[4],\n\t\t\tinfo[5], info[6], info[7], info[8], info[9], info[10], info[11]);\n\t// tiny\n\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"%lu tiny regions:\\n\", szone->tiny_rack.num_regions);\n\tif (szone->tiny_rack.num_regions_dealloc) {\n\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"[%lu tiny regions have been vm_deallocate'd]\\n\",\n\t\t\t\tszone->tiny_rack.num_regions_dealloc);\n\t}\n\tfor (index = 0; index < szone->tiny_rack.region_generation->num_regions_allocated; ++index) {\n\t\tregion = szone->tiny_rack.region_generation->hashed_regions[index];\n\t\tif (HASHRING_OPEN_ENTRY != region && HASHRING_REGION_DEALLOCATED != region) {\n\t\t\tmag_index_t mag_index = MAGAZINE_INDEX_FOR_TINY_REGION(region);\n\t\t\tprint_tiny_region(verbose, region, (region == szone->tiny_rack.magazines[mag_index].mag_last_region)\n\t\t\t\t\t\t\t\t\t\t\t\t\t   ? szone->tiny_rack.magazines[mag_index].mag_bytes_free_at_start\n\t\t\t\t\t\t\t\t\t\t\t\t\t   : 0,\n\t\t\t\t\t(region == szone->tiny_rack.magazines[mag_index].mag_last_region)\n\t\t\t\t\t\t\t? szone->tiny_rack.magazines[mag_index].mag_bytes_free_at_end\n\t\t\t\t\t\t\t: 0);\n\t\t}\n\t}\n\tif (verbose) {\n\t\tprint_tiny_free_list(&szone->tiny_rack);\n\t}\n\t// small\n\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"%lu small regions:\\n\", szone->small_rack.num_regions);\n\tif (szone->small_rack.num_regions_dealloc) {\n\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"[%lu small regions have been vm_deallocate'd]\\n\",\n\t\t\t\tszone->small_rack.num_regions_dealloc);\n\t}\n\tfor (index = 0; index < szone->small_rack.region_generation->num_regions_allocated; ++index) {\n\t\tregion = szone->small_rack.region_generation->hashed_regions[index];\n\t\tif (HASHRING_OPEN_ENTRY != region && HASHRING_REGION_DEALLOCATED != region) {\n\t\t\tmag_index_t mag_index = MAGAZINE_INDEX_FOR_SMALL_REGION(region);\n\t\t\tprint_small_region(szone, verbose, region, (region == szone->small_rack.magazines[mag_index].mag_last_region)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   ? szone->small_rack.magazines[mag_index].mag_bytes_free_at_start\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   : 0,\n\t\t\t\t\t(region == szone->small_rack.magazines[mag_index].mag_last_region)\n\t\t\t\t\t\t\t? szone->small_rack.magazines[mag_index].mag_bytes_free_at_end\n\t\t\t\t\t\t\t: 0);\n\t\t}\n\t}\n\tif (verbose) {\n\t\tprint_small_free_list(&szone->small_rack);\n\t}\n}\n\nstatic void\nszone_log(malloc_zone_t *zone, void *log_address)\n{\n\tszone_t *szone = (szone_t *)zone;\n\n\tszone->log_address = log_address;\n}\n\n// <rdar://problem/18001324>\n// When forcing the lock on the entire zone, make sure we are out of the critical section in each magazine\nstatic MALLOC_INLINE void\nszone_force_lock_magazine(szone_t *szone, magazine_t *mag)\n{\n\twhile (1) {\n\t\tSZONE_MAGAZINE_PTR_LOCK(mag);\n\t\tif (!mag->alloc_underway) {\n\t\t\treturn;\n\t\t}\n\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(mag);\n\t\tyield();\n\t}\n}\n\nstatic void\nszone_force_lock(szone_t *szone)\n{\n\tmag_index_t i;\n\n\tfor (i = 0; i < szone->tiny_rack.num_magazines; ++i) {\n\t\tszone_force_lock_magazine(szone, &szone->tiny_rack.magazines[i]);\n\t}\n\tszone_force_lock_magazine(szone, &szone->tiny_rack.magazines[DEPOT_MAGAZINE_INDEX]);\n\n\tfor (i = 0; i < szone->small_rack.num_magazines; ++i) {\n\t\tszone_force_lock_magazine(szone, &szone->small_rack.magazines[i]);\n\t}\n\tszone_force_lock_magazine(szone, &szone->small_rack.magazines[DEPOT_MAGAZINE_INDEX]);\n\n\tSZONE_LOCK(szone);\n}\n\nstatic void\nszone_force_unlock(szone_t *szone)\n{\n\tmag_index_t i;\n\n\tSZONE_UNLOCK(szone);\n\n\tfor (i = -1; i < szone->small_rack.num_magazines; ++i) {\n\t\tSZONE_MAGAZINE_PTR_UNLOCK((&(szone->small_rack.magazines[i])));\n\t}\n\n\tfor (i = -1; i < szone->tiny_rack.num_magazines; ++i) {\n\t\tSZONE_MAGAZINE_PTR_UNLOCK((&(szone->tiny_rack.magazines[i])));\n\t}\n}\n\nstatic void\nszone_reinit_lock(szone_t *szone)\n{\n\tmag_index_t i;\n\n\tSZONE_REINIT_LOCK(szone);\n\n\tfor (i = -1; i < szone->small_rack.num_magazines; ++i) {\n\t\tSZONE_MAGAZINE_PTR_REINIT_LOCK((&(szone->small_rack.magazines[i])));\n\t}\n\n\tfor (i = -1; i < szone->tiny_rack.num_magazines; ++i) {\n\t\tSZONE_MAGAZINE_PTR_REINIT_LOCK((&(szone->tiny_rack.magazines[i])));\n\t}\n}\n\nstatic boolean_t\nszone_locked(szone_t *szone)\n{\n\tmag_index_t i;\n\tint tookLock;\n\n\ttookLock = SZONE_TRY_LOCK(szone);\n\tif (tookLock == 0) {\n\t\treturn 1;\n\t}\n\tSZONE_UNLOCK(szone);\n\n\tfor (i = -1; i < szone->small_rack.num_magazines; ++i) {\n\t\ttookLock = SZONE_MAGAZINE_PTR_TRY_LOCK((&(szone->small_rack.magazines[i])));\n\t\tif (tookLock == 0) {\n\t\t\treturn 1;\n\t\t}\n\t\tSZONE_MAGAZINE_PTR_UNLOCK((&(szone->small_rack.magazines[i])));\n\t}\n\n\tfor (i = -1; i < szone->tiny_rack.num_magazines; ++i) {\n\t\ttookLock = SZONE_MAGAZINE_PTR_TRY_LOCK((&(szone->tiny_rack.magazines[i])));\n\t\tif (tookLock == 0) {\n\t\t\treturn 1;\n\t\t}\n\t\tSZONE_MAGAZINE_PTR_UNLOCK((&(szone->tiny_rack.magazines[i])));\n\t}\n\treturn 0;\n}\n\nsize_t\nszone_pressure_relief(szone_t *szone, size_t goal)\n{\n\tsize_t total = 0;\n\n\tMAGMALLOC_PRESSURERELIEFBEGIN((void *)szone, szone->basic_zone.zone_name, (int)goal); // DTrace USDT Probe\n\tMALLOC_TRACE(TRACE_malloc_memory_pressure | DBG_FUNC_START, (uint64_t)szone, goal, 0, 0);\n\n#if CONFIG_MADVISE_PRESSURE_RELIEF\n\tmag_index_t mag_index;\n\n\tmagazine_t *tiny_depot_ptr = (&szone->tiny_rack.magazines[DEPOT_MAGAZINE_INDEX]);\n\tmagazine_t *small_depot_ptr = (&szone->small_rack.magazines[DEPOT_MAGAZINE_INDEX]);\n\n\tfor (mag_index = 0; mag_index < szone->tiny_rack.num_magazines; mag_index++) {\n\t\tsize_t index;\n\t\tfor (index = 0; index < szone->tiny_rack.region_generation->num_regions_allocated; ++index) {\n\t\t\tSZONE_LOCK(szone);\n\n\t\t\tregion_t tiny = szone->tiny_rack.region_generation->hashed_regions[index];\n\t\t\tif (!tiny || tiny == HASHRING_REGION_DEALLOCATED) {\n\t\t\t\tSZONE_UNLOCK(szone);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tmagazine_t *mag_ptr = mag_lock_zine_for_region_trailer(szone->tiny_rack.magazines,\n\t\t\t\t\tREGION_TRAILER_FOR_TINY_REGION(tiny),\n\t\t\t\t\tMAGAZINE_INDEX_FOR_TINY_REGION(tiny));\n\t\t\tSZONE_UNLOCK(szone);\n\n\t\t\t/* Ordering is important here, the magazine of a region may potentially change\n\t\t\t * during mag_lock_zine_for_region_trailer, so src_mag_index must be taken\n\t\t\t * after we've obtained the lock.\n\t\t\t */\n\t\t\tmag_index_t src_mag_index = MAGAZINE_INDEX_FOR_TINY_REGION(tiny);\n\n\t\t\t/* We can (and must) ignore magazines that are already in the recirc depot. */\n\t\t\tif (src_mag_index == DEPOT_MAGAZINE_INDEX) {\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(mag_ptr);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (tiny == mag_ptr->mag_last_region && (mag_ptr->mag_bytes_free_at_end || mag_ptr->mag_bytes_free_at_start)) {\n\t\t\t\ttiny_finalize_region(&szone->tiny_rack, mag_ptr);\n\t\t\t}\n\n\t\t\t/* Because this region is currently in use, we can't safely madvise it while\n\t\t\t * it's attached to the magazine. For this operation we have to remove it from\n\t\t\t * the current mag, attach it to the depot and then madvise.\n\t\t\t */\n\n\t\t\trecirc_list_extract(&szone->tiny_rack, mag_ptr, REGION_TRAILER_FOR_TINY_REGION(tiny));\n\t\t\tint objects_in_use = tiny_free_detach_region(&szone->tiny_rack, mag_ptr, tiny);\n\n\t\t\tSZONE_MAGAZINE_PTR_LOCK(tiny_depot_ptr);\n\t\t\tMAGAZINE_INDEX_FOR_TINY_REGION(tiny) = DEPOT_MAGAZINE_INDEX;\n\t\t\tREGION_TRAILER_FOR_TINY_REGION(tiny)->pinned_to_depot = 0;\n\n\t\t\tsize_t bytes_inplay = tiny_free_reattach_region(&szone->tiny_rack, tiny_depot_ptr, tiny);\n\n\t\t\t/* Fix up the metadata of the target magazine while the region is in the depot. */\n\t\t\tmag_ptr->mag_num_bytes_in_objects -= bytes_inplay;\n\t\t\tmag_ptr->num_bytes_in_magazine -= TINY_REGION_PAYLOAD_BYTES;\n\t\t\tmag_ptr->mag_num_objects -= objects_in_use;\n\n\t\t\t/* Now we can drop the magazine lock of the source mag. */\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(mag_ptr);\n\n\t\t\ttiny_depot_ptr->mag_num_bytes_in_objects += bytes_inplay;\n\t\t\ttiny_depot_ptr->num_bytes_in_magazine += TINY_REGION_PAYLOAD_BYTES;\n\t\t\ttiny_depot_ptr->mag_num_objects -= objects_in_use;\n\n\t\t\trecirc_list_splice_last(&szone->tiny_rack, tiny_depot_ptr, REGION_TRAILER_FOR_TINY_REGION(tiny));\n\n\t\t\t/* Actually do the scan, done holding the depot lock, the call will drop the lock\n\t\t\t * around the actual madvise syscalls.\n\t\t\t */\n\t\t\ttiny_free_scan_madvise_free(&szone->tiny_rack, tiny_depot_ptr, tiny);\n\n\t\t\t/* Now the region is in the recirc depot, the next allocations to require more\n\t\t\t * blocks will come along and take one of these regions back out of the depot.\n\t\t\t * As OS X madvise's reuse on an per-region basis, we leave as many of these\n\t\t\t * regions in the depot as possible after memory pressure.\n\t\t\t */\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_depot_ptr);\n\t\t}\n\t}\n\n\tfor (mag_index = 0; mag_index < szone->small_rack.num_magazines; mag_index++) {\n\t\tsize_t index;\n\t\tfor (index = 0; index < szone->small_rack.region_generation->num_regions_allocated; ++index) {\n\t\t\tSZONE_LOCK(szone);\n\n\t\t\tregion_t small = szone->small_rack.region_generation->hashed_regions[index];\n\t\t\tif (!small || small == HASHRING_REGION_DEALLOCATED) {\n\t\t\t\tSZONE_UNLOCK(szone);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tmagazine_t *mag_ptr = mag_lock_zine_for_region_trailer(szone->small_rack.magazines,\n\t\t\t\t\tREGION_TRAILER_FOR_SMALL_REGION(small),\n\t\t\t\t\tMAGAZINE_INDEX_FOR_SMALL_REGION(small));\n\t\t\tSZONE_UNLOCK(szone);\n\n\t\t\t/* Ordering is important here, the magazine of a region may potentially change\n\t\t\t * during mag_lock_zine_for_region_trailer, so src_mag_index must be taken\n\t\t\t * after we've obtained the lock.\n\t\t\t */\n\t\t\tmag_index_t src_mag_index = MAGAZINE_INDEX_FOR_SMALL_REGION(small);\n\n\t\t\t/* We can (and must) ignore magazines that are already in the recirc depot. */\n\t\t\tif (src_mag_index == DEPOT_MAGAZINE_INDEX) {\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(mag_ptr);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (small == mag_ptr->mag_last_region && (mag_ptr->mag_bytes_free_at_end || mag_ptr->mag_bytes_free_at_start)) {\n\t\t\t\tsmall_finalize_region(&szone->small_rack, mag_ptr);\n\t\t\t}\n\n\t\t\t/* Because this region is currently in use, we can't safely madvise it while\n\t\t\t * it's attached to the magazine. For this operation we have to remove it from\n\t\t\t * the current mag, attach it to the depot and then madvise.\n\t\t\t */\n\n\t\t\trecirc_list_extract(&szone->small_rack, mag_ptr, REGION_TRAILER_FOR_SMALL_REGION(small));\n\t\t\tint objects_in_use = small_free_detach_region(&szone->small_rack, mag_ptr, small);\n\n\t\t\tSZONE_MAGAZINE_PTR_LOCK(small_depot_ptr);\n\t\t\tMAGAZINE_INDEX_FOR_SMALL_REGION(small) = DEPOT_MAGAZINE_INDEX;\n\t\t\tREGION_TRAILER_FOR_SMALL_REGION(small)->pinned_to_depot = 0;\n\n\t\t\tsize_t bytes_inplay = small_free_reattach_region(&szone->small_rack, small_depot_ptr, small);\n\n\t\t\t/* Fix up the metadata of the target magazine while the region is in the depot. */\n\t\t\tmag_ptr->mag_num_bytes_in_objects -= bytes_inplay;\n\t\t\tmag_ptr->num_bytes_in_magazine -= SMALL_REGION_PAYLOAD_BYTES;\n\t\t\tmag_ptr->mag_num_objects -= objects_in_use;\n\n\t\t\t/* Now we can drop the magazine lock of the source mag. */\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(mag_ptr);\n\n\t\t\tsmall_depot_ptr->mag_num_bytes_in_objects += bytes_inplay;\n\t\t\tsmall_depot_ptr->num_bytes_in_magazine += SMALL_REGION_PAYLOAD_BYTES;\n\t\t\tsmall_depot_ptr->mag_num_objects -= objects_in_use;\n\n\t\t\trecirc_list_splice_last(&szone->small_rack, small_depot_ptr, REGION_TRAILER_FOR_SMALL_REGION(small));\n\n\t\t\t/* Actually do the scan, done holding the depot lock, the call will drop the lock\n\t\t\t * around the actual madvise syscalls.\n\t\t\t */\n\t\t\tsmall_free_scan_madvise_free(&szone->small_rack, small_depot_ptr, small);\n\n\t\t\t/* Now the region is in the recirc depot, the next allocations to require more\n\t\t\t * blocks will come along and take one of these regions back out of the depot.\n\t\t\t * As OS X madvise's reuse on an per-region basis, we leave as many of these\n\t\t\t * regions in the depot as possible after memory pressure.\n\t\t\t */\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_depot_ptr);\n\t\t}\n\t}\n#endif\n\n#if CONFIG_LARGE_CACHE\n\tif (szone->flotsam_enabled) {\n\t\tSZONE_LOCK(szone);\n\n\t\t// stack allocated copy of the death-row cache\n\t\tint idx = szone->large_entry_cache_oldest, idx_max = szone->large_entry_cache_newest;\n\t\tlarge_entry_t local_entry_cache[LARGE_ENTRY_CACHE_SIZE];\n\n\t\tmemcpy((void *)local_entry_cache, (void *)szone->large_entry_cache, sizeof(local_entry_cache));\n\n\t\tszone->large_entry_cache_oldest = szone->large_entry_cache_newest = 0;\n\t\tszone->large_entry_cache[0].address = 0x0;\n\t\tszone->large_entry_cache[0].size = 0;\n\t\tszone->large_entry_cache_bytes = 0;\n\t\tszone->large_entry_cache_reserve_bytes = 0;\n\n\t\tszone->flotsam_enabled = FALSE;\n\n\t\tSZONE_UNLOCK(szone);\n\n\t\t// deallocate the death-row cache outside the zone lock\n\t\tsize_t total = 0;\n\t\twhile (idx != idx_max) {\n\t\t\tmvm_deallocate_pages((void *)local_entry_cache[idx].address, local_entry_cache[idx].size, 0);\n\t\t\ttotal += local_entry_cache[idx].size;\n\t\t\tif (++idx == LARGE_ENTRY_CACHE_SIZE) {\n\t\t\t\tidx = 0;\n\t\t\t}\n\t\t}\n\t\tif (0 != local_entry_cache[idx].address && 0 != local_entry_cache[idx].size) {\n\t\t\tmvm_deallocate_pages((void *)local_entry_cache[idx].address, local_entry_cache[idx].size, 0);\n\t\t\ttotal += local_entry_cache[idx].size;\n\t\t}\n\t}\n#endif\n\n\tMAGMALLOC_PRESSURERELIEFEND((void *)szone, szone->basic_zone.zone_name, (int)goal, (int)total); // DTrace USDT Probe\n\tMALLOC_TRACE(TRACE_malloc_memory_pressure | DBG_FUNC_END, (uint64_t)szone, goal, total, 0);\n\n\treturn total;\n}\n\nboolean_t\nscalable_zone_statistics(malloc_zone_t *zone, malloc_statistics_t *stats, unsigned subzone)\n{\n\tszone_t *szone = (szone_t *)zone;\n\n\tswitch (subzone) {\n\tcase 0: {\n\t\tsize_t s = 0;\n\t\tunsigned t = 0;\n\t\tsize_t u = 0;\n\t\tmag_index_t mag_index;\n\n\t\tfor (mag_index = -1; mag_index < szone->tiny_rack.num_magazines; mag_index++) {\n\t\t\ts += szone->tiny_rack.magazines[mag_index].mag_bytes_free_at_start;\n\t\t\ts += szone->tiny_rack.magazines[mag_index].mag_bytes_free_at_end;\n\t\t\tt += szone->tiny_rack.magazines[mag_index].mag_num_objects;\n\t\t\tu += szone->tiny_rack.magazines[mag_index].mag_num_bytes_in_objects;\n\t\t}\n\n\t\tstats->blocks_in_use = t;\n\t\tstats->size_in_use = u;\n\t\tstats->size_allocated = (szone->tiny_rack.num_regions - szone->tiny_rack.num_regions_dealloc) * TINY_REGION_SIZE;\n\t\tstats->max_size_in_use = stats->size_allocated - s;\n\t\treturn 1;\n\t}\n\tcase 1: {\n\t\tsize_t s = 0;\n\t\tunsigned t = 0;\n\t\tsize_t u = 0;\n\t\tmag_index_t mag_index;\n\n\t\tfor (mag_index = -1; mag_index < szone->small_rack.num_magazines; mag_index++) {\n\t\t\ts += szone->small_rack.magazines[mag_index].mag_bytes_free_at_start;\n\t\t\ts += szone->small_rack.magazines[mag_index].mag_bytes_free_at_end;\n\t\t\tt += szone->small_rack.magazines[mag_index].mag_num_objects;\n\t\t\tu += szone->small_rack.magazines[mag_index].mag_num_bytes_in_objects;\n\t\t}\n\n\t\tstats->blocks_in_use = t;\n\t\tstats->size_in_use = u;\n\t\tstats->size_allocated = (szone->small_rack.num_regions - szone->small_rack.num_regions_dealloc) * SMALL_REGION_SIZE;\n\t\tstats->max_size_in_use = stats->size_allocated - s;\n\t\treturn 1;\n\t}\n\tcase 2:\n\t\tstats->blocks_in_use = szone->num_large_objects_in_use;\n\t\tstats->size_in_use = szone->num_bytes_in_large_objects;\n\t\tstats->max_size_in_use = stats->size_allocated = stats->size_in_use;\n\t\treturn 1;\n\tcase 3:\n\t\tstats->blocks_in_use = 0; // DEPRECATED szone->num_huge_entries;\n\t\tstats->size_in_use = 0;   // DEPRECATED szone->num_bytes_in_huge_objects;\n\t\tstats->max_size_in_use = stats->size_allocated = 0;\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nstatic void\nszone_statistics(szone_t *szone, malloc_statistics_t *stats)\n{\n\tsize_t large;\n\n\tsize_t s = 0;\n\tunsigned t = 0;\n\tsize_t u = 0;\n\tmag_index_t mag_index;\n\n\tfor (mag_index = -1; mag_index < szone->tiny_rack.num_magazines; mag_index++) {\n\t\ts += szone->tiny_rack.magazines[mag_index].mag_bytes_free_at_start;\n\t\ts += szone->tiny_rack.magazines[mag_index].mag_bytes_free_at_end;\n\t\tt += szone->tiny_rack.magazines[mag_index].mag_num_objects;\n\t\tu += szone->tiny_rack.magazines[mag_index].mag_num_bytes_in_objects;\n\t}\n\n\tfor (mag_index = -1; mag_index < szone->small_rack.num_magazines; mag_index++) {\n\t\ts += szone->small_rack.magazines[mag_index].mag_bytes_free_at_start;\n\t\ts += szone->small_rack.magazines[mag_index].mag_bytes_free_at_end;\n\t\tt += szone->small_rack.magazines[mag_index].mag_num_objects;\n\t\tu += szone->small_rack.magazines[mag_index].mag_num_bytes_in_objects;\n\t}\n\n\tlarge = szone->num_bytes_in_large_objects + 0; // DEPRECATED szone->num_bytes_in_huge_objects;\n\n\tstats->blocks_in_use = t + szone->num_large_objects_in_use + 0; // DEPRECATED szone->num_huge_entries;\n\tstats->size_in_use = u + large;\n\tstats->max_size_in_use = stats->size_allocated =\n\t\t\t(szone->tiny_rack.num_regions - szone->tiny_rack.num_regions_dealloc) * TINY_REGION_SIZE +\n\t\t\t(szone->small_rack.num_regions - szone->small_rack.num_regions_dealloc) * SMALL_REGION_SIZE + large;\n\t// Now we account for the untouched areas\n\tstats->max_size_in_use -= s;\n}\n\nconst struct malloc_introspection_t szone_introspect = {\n\t\t(void *)szone_ptr_in_use_enumerator, (void *)szone_good_size, (void *)szone_check, (void *)szone_print, szone_log,\n\t\t(void *)szone_force_lock, (void *)szone_force_unlock, (void *)szone_statistics, (void *)szone_locked, NULL, NULL, NULL,\n\t\tNULL, /* Zone enumeration version 7 and forward. */\n\t\t(void *)szone_reinit_lock, // reinit_lock version 9 and foward\n}; // marked as const to spare the DATA section\n\nszone_t *\ncreate_scalable_szone(size_t initial_size, unsigned debug_flags)\n{\n\tszone_t *szone;\n\n#if defined(__i386__) || defined(__x86_64__)\n\tif (_COMM_PAGE_VERSION_REQD > (*((uint16_t *)_COMM_PAGE_VERSION))) {\n\t\tMALLOC_REPORT_FATAL_ERROR((*((uint16_t *)_COMM_PAGE_VERSION)), \"comm page version mismatch\");\n\t}\n#endif\n\n\t/* get memory for the zone. */\n\tszone = mvm_allocate_pages(SZONE_PAGED_SIZE, 0, 0, VM_MEMORY_MALLOC);\n\tif (!szone) {\n\t\treturn NULL;\n\t}\n\n/* set up the szone structure */\n#if 0\n#warning CHECK_REGIONS enabled\n\tdebug_flags |= CHECK_REGIONS;\n#endif\n#if 0\n#warning LOG enabled\n\tszone->log_address = ~0;\n#endif\n\n\tif (mvm_aslr_enabled()) {\n\t\tdebug_flags &= ~DISABLE_ASLR;\n\t} else {\n\t\tdebug_flags |= DISABLE_ASLR;\n\t}\n\n#if CONFIG_SMALL_CUTOFF_DYNAMIC || CONFIG_LARGE_CACHE\n\tuint64_t memsize = platform_hw_memsize();\n#endif\n\n\tbool is_largemem = false;\n#if CONFIG_SMALL_CUTOFF_LARGEMEM\n\tis_largemem = true;\n#elif CONFIG_SMALL_CUTOFF_DYNAMIC\n\t// TODO: rdar://problem/35395572\n\t// switch to largemem thresholds on devices with > 2 cores and > 2gb of memory\n\tuint32_t nproc = platform_cpu_count();\n\tis_largemem = (nproc > 2) && (memsize > (2ull << 30));\n#endif\n\tif (is_largemem) {\n\t\tdebug_flags |= MALLOC_EXTENDED_SMALL_SLOTS;\n\t\tszone->is_largemem = 1;\n\t\tszone->large_threshold = LARGE_THRESHOLD_LARGEMEM;\n\t\tszone->vm_copy_threshold = VM_COPY_THRESHOLD_LARGEMEM;\n\t} else {\n\t\tdebug_flags &= ~MALLOC_EXTENDED_SMALL_SLOTS;\n\t\tszone->is_largemem = 0;\n\t\tszone->large_threshold = LARGE_THRESHOLD;\n\t\tszone->vm_copy_threshold = VM_COPY_THRESHOLD;\n\t}\n\n\t// Query the number of configured processors.\n\t// Uniprocessor case gets just one tiny and one small magazine (whose index is zero). This gives\n\t// the same behavior as the original scalable malloc. MP gets per-CPU magazines\n\t// that scale (way) better.\n\tunsigned int max_mags = mag_max_magazines();\n\tuint32_t num_magazines = (max_mags > 1) ? MIN(max_mags, TINY_MAX_MAGAZINES) : 1;\n\track_init(&szone->tiny_rack, RACK_TYPE_TINY, num_magazines, debug_flags);\n\track_init(&szone->small_rack, RACK_TYPE_SMALL, num_magazines, debug_flags);\n\n#if CONFIG_LARGE_CACHE\n\t// madvise(..., MADV_REUSABLE) death-row arrivals above this threshold [~0.1%]\n\tszone->large_entry_cache_reserve_limit = (size_t)(memsize >> 10);\n\n\t/* <rdar://problem/6610904> Reset protection when returning a previous large allocation? */\n\tint32_t libSystemVersion = NSVersionOfLinkTimeLibrary(\"System\");\n\tif ((-1 != libSystemVersion) && ((libSystemVersion >> 16) < 112) /* CFSystemVersionSnowLeopard */) {\n\t\tszone->large_legacy_reset_mprotect = TRUE;\n\t} else {\n\t\tszone->large_legacy_reset_mprotect = FALSE;\n\t}\n#endif\n\n\t// Initialize the security token.\n\tszone->cookie = (uintptr_t)malloc_entropy[0];\n\n\tszone->basic_zone.version = 10;\n\tszone->basic_zone.size = (void *)szone_size;\n\tszone->basic_zone.malloc = (void *)szone_malloc;\n\tszone->basic_zone.calloc = (void *)szone_calloc;\n\tszone->basic_zone.valloc = (void *)szone_valloc;\n\tszone->basic_zone.free = (void *)szone_free;\n\tszone->basic_zone.realloc = (void *)szone_realloc;\n\tszone->basic_zone.destroy = (void *)szone_destroy;\n\tszone->basic_zone.batch_malloc = (void *)szone_batch_malloc;\n\tszone->basic_zone.batch_free = (void *)szone_batch_free;\n\tszone->basic_zone.introspect = (struct malloc_introspection_t *)&szone_introspect;\n\tszone->basic_zone.memalign = (void *)szone_memalign;\n\tszone->basic_zone.free_definite_size = (void *)szone_free_definite_size;\n\tszone->basic_zone.pressure_relief = (void *)szone_pressure_relief;\n\tszone->basic_zone.claimed_address = (void *)szone_claimed_address;\n\n\t/* Set to zero once and for all as required by CFAllocator. */\n\tszone->basic_zone.reserved1 = 0;\n\t/* Set to zero once and for all as required by CFAllocator. */\n\tszone->basic_zone.reserved2 = 0;\n\n\t/* Prevent overwriting the function pointers in basic_zone. */\n\tmprotect(szone, sizeof(szone->basic_zone), PROT_READ);\n\n\tszone->debug_flags = debug_flags;\n\t_malloc_lock_init(&szone->large_szone_lock);\n\n\tszone->cpu_id_key = -1UL; // Unused.\n\n\tCHECK(szone, __PRETTY_FUNCTION__);\n\treturn szone;\n}\n\nmalloc_zone_t *\ncreate_scalable_zone(size_t initial_size, unsigned debug_flags) {\n\treturn (malloc_zone_t *) create_scalable_szone(initial_size, debug_flags);\n}\n\n/* vim: set noet:ts=4:sw=4:cindent: */\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/magazine_malloc.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __MAGAZINE_MALLOC_H\n#define __MAGAZINE_MALLOC_H\n\n// MARK: magazine_malloc\n\nMALLOC_NOEXPORT\nmalloc_zone_t *\ncreate_scalable_zone(size_t initial_size, unsigned debug_flags);\n\nMALLOC_NOEXPORT\nszone_t *\ncreate_scalable_szone(size_t initial_size, unsigned debug_flags);\n\nMALLOC_EXPORT\nboolean_t\nscalable_zone_statistics(malloc_zone_t *zone, malloc_statistics_t *stats, unsigned subzone);\n\nMALLOC_NOEXPORT\nextern int max_magazines;\n\nMALLOC_NOEXPORT\nextern int recirc_retained_regions;\n\n// MARK: magazine_malloc utility functions\n\nMALLOC_NOEXPORT\nextern const\nstruct malloc_introspection_t szone_introspect;\n\nMALLOC_NOEXPORT\nvoid\nszone_batch_free(szone_t *szone, void **to_be_freed, unsigned count);\n\nMALLOC_NOEXPORT\nunsigned\nszone_batch_malloc(szone_t *szone, size_t size, void **results, unsigned count);\n\nMALLOC_NOEXPORT\nvoid *\nszone_calloc(szone_t *szone, size_t num_items, size_t size);\n\nMALLOC_NOEXPORT\nvoid\nszone_free(szone_t *szone, void *ptr);\n\nMALLOC_NOEXPORT\nvoid\nszone_free_definite_size(szone_t *szone, void *ptr, size_t size);\n\nMALLOC_NOEXPORT\nsize_t\nszone_good_size(szone_t *szone, size_t size);\n\nMALLOC_NOEXPORT\nvoid *\nszone_malloc(szone_t *szone, size_t size);\n\nMALLOC_NOEXPORT\nvoid *\nszone_memalign(szone_t *szone, size_t alignment, size_t size);\n\nMALLOC_NOEXPORT\nsize_t\nszone_pressure_relief(szone_t *szone, size_t goal);\n\nMALLOC_NOEXPORT\nboolean_t\nszone_claimed_address(szone_t *szone, void *ptr);\n\nMALLOC_NOEXPORT\nvoid *\nszone_realloc(szone_t *szone, void *ptr, size_t new_size);\n\nMALLOC_NOEXPORT\nsize_t\nszone_size(szone_t *szone, const void *ptr);\n\nMALLOC_NOEXPORT\nsize_t\nszone_size_try_large(szone_t *szone, const void *ptr);\n\nMALLOC_NOEXPORT\nvoid *\nszone_valloc(szone_t *szone, size_t size);\n\n// MARK: tiny region allocator functions\n\nMALLOC_NOEXPORT\nboolean_t\ntiny_check_region(rack_t *rack, region_t region, size_t region_index,\n\t\tunsigned counter);\n\nMALLOC_NOEXPORT\nvoid\ntiny_finalize_region(rack_t *rack, magazine_t *tiny_mag_ptr);\n\nMALLOC_NOEXPORT\nint\ntiny_free_detach_region(rack_t *rack, magazine_t *tiny_mag_ptr, region_t r);\n\nMALLOC_NOEXPORT\nboolean_t\ntiny_free_list_check(rack_t *rack, grain_t slot, unsigned counter);\n\nMALLOC_NOEXPORT\nboolean_t\ntiny_free_no_lock(rack_t *rack, magazine_t *tiny_mag_ptr, mag_index_t mag_index, region_t region, void *ptr, msize_t msize);\n\nMALLOC_NOEXPORT\nsize_t\ntiny_free_reattach_region(rack_t *rack, magazine_t *tiny_mag_ptr, region_t r);\n\nMALLOC_NOEXPORT\nvoid\ntiny_free_scan_madvise_free(rack_t *rack, magazine_t *depot_ptr, region_t r);\n\nMALLOC_NOEXPORT\nkern_return_t\ntiny_in_use_enumerator(task_t task, void *context, unsigned type_mask, szone_t *szone, memory_reader_t reader,\n\t\tvm_range_recorder_t recorder);\n\nMALLOC_NOEXPORT\nvoid *\ntiny_malloc_from_free_list(rack_t *rack, magazine_t *tiny_mag_ptr, mag_index_t mag_index, msize_t msize);\n\nMALLOC_NOEXPORT\nvoid *\ntiny_malloc_should_clear(rack_t *rack, msize_t msize, boolean_t cleared_requested);\n\nMALLOC_NOEXPORT\nvoid *\ntiny_memalign(szone_t *szone, size_t alignment, size_t size, size_t span);\n\nMALLOC_NOEXPORT\nboolean_t\ntiny_claimed_address(rack_t *rack, void *ptr);\n\nMALLOC_NOEXPORT\nvoid *\ntiny_try_shrink_in_place(rack_t *rack, void *ptr, size_t old_size, size_t new_good_size);\n\nMALLOC_NOEXPORT\nboolean_t\ntiny_try_realloc_in_place(rack_t *rack, void *ptr, size_t old_size, size_t new_size);\n\nMALLOC_NOEXPORT\nvoid\nfree_tiny(rack_t *rack, void *ptr, region_t tiny_region, size_t known_size);\n\nMALLOC_NOEXPORT\nsize_t\ntiny_size(rack_t *rack, const void *ptr);\n\nMALLOC_NOEXPORT\nunsigned\ntiny_batch_malloc(szone_t *szone, size_t size, void **results, unsigned count);\n\nMALLOC_NOEXPORT\nvoid\ntiny_batch_free(szone_t *szone, void **to_be_freed, unsigned count);\n\nMALLOC_NOEXPORT\nvoid\nprint_tiny_free_list(rack_t *rack);\n\nMALLOC_NOEXPORT\nvoid\nprint_tiny_region(boolean_t verbose, region_t region, size_t bytes_at_start, size_t bytes_at_end);\n\n// MARK: small region allocation functions\n\nMALLOC_NOEXPORT\nboolean_t\nsmall_check_region(rack_t *rack, region_t region, size_t region_index,\n\t\tunsigned counter);\n\nMALLOC_NOEXPORT\nvoid\nsmall_finalize_region(rack_t *rack, magazine_t *small_mag_ptr);\n\nMALLOC_NOEXPORT\nint\nsmall_free_detach_region(rack_t *rack, magazine_t *small_mag_ptr, region_t r);\n\nMALLOC_NOEXPORT\nboolean_t\nsmall_free_list_check(rack_t *rack, grain_t slot, unsigned counter);\n\nMALLOC_NOEXPORT\nsize_t\nsmall_free_reattach_region(rack_t *rack, magazine_t *small_mag_ptr, region_t r);\n\nMALLOC_NOEXPORT\nvoid\nsmall_free_scan_madvise_free(rack_t *rack, magazine_t *depot_ptr, region_t r);\n\nMALLOC_NOEXPORT\nkern_return_t\nsmall_in_use_enumerator(task_t task, void *context, unsigned type_mask, szone_t *szone, memory_reader_t reader,\n\t\tvm_range_recorder_t recorder);\n\nMALLOC_NOEXPORT\nvoid *\nsmall_malloc_should_clear(rack_t *rack, msize_t msize, boolean_t cleared_requested);\n\nMALLOC_NOEXPORT\nvoid *\nsmall_memalign(szone_t *szone, size_t alignment, size_t size, size_t span);\n\nMALLOC_NOEXPORT\nboolean_t\nsmall_claimed_address(rack_t *rack, void *ptr);\n\nMALLOC_NOEXPORT\nvoid *\nsmall_try_shrink_in_place(rack_t *rack, void *ptr, size_t old_size, size_t new_good_size);\n\nMALLOC_NOEXPORT\nboolean_t\nsmall_try_realloc_in_place(rack_t *rack, void *ptr, size_t old_size, size_t new_size);\n\nMALLOC_NOEXPORT\nvoid\nfree_small(rack_t *rack, void *ptr, region_t small_region, size_t known_size);\n\nMALLOC_NOEXPORT\nsize_t\nsmall_size(rack_t *rack, const void *ptr);\n\nMALLOC_NOEXPORT\nvoid\nprint_small_free_list(rack_t *rack);\n\nMALLOC_NOEXPORT\nvoid\nprint_small_region(szone_t *szone, boolean_t verbose, region_t region, size_t bytes_at_start, size_t bytes_at_end);\n\n// MARK: large region allocator functions\n\nMALLOC_NOEXPORT\nvoid\nfree_large(szone_t *szone, void *ptr);\n\nMALLOC_NOEXPORT\nvoid\nlarge_entries_free_no_lock(szone_t *szone, large_entry_t *entries, unsigned num, vm_range_t *range_to_deallocate);\n\nMALLOC_NOEXPORT\nlarge_entry_t *\nlarge_entry_for_pointer_no_lock(szone_t *szone, const void *ptr);\n\nMALLOC_NOEXPORT\nkern_return_t\nlarge_in_use_enumerator(task_t task, void *context, unsigned type_mask, vm_address_t large_entries_address, unsigned num_entries,\n\t\tmemory_reader_t reader, vm_range_recorder_t recorder);\n\nMALLOC_NOEXPORT\nint\nlarge_try_realloc_in_place(szone_t *szone, void *ptr, size_t old_size, size_t new_size);\n\nMALLOC_NOEXPORT\nvoid *\nlarge_try_shrink_in_place(szone_t *szone, void *ptr, size_t old_size, size_t new_good_size);\n\nMALLOC_NOEXPORT\nvoid *\nlarge_malloc(szone_t *szone, size_t num_kernel_pages, unsigned char alignment, boolean_t cleared_requested);\n\nMALLOC_NOEXPORT\nboolean_t\nlarge_claimed_address(szone_t *szone, void *ptr);\n\nMALLOC_NOEXPORT\nvoid *\nszone_malloc_should_clear(szone_t *szone, size_t size, boolean_t cleared_requested);\n\n// MARK: stack logging lite functionality\n\n#define MALLOC_STOCK_LOGGING_LITE_ZONE_NAME \"MallocStackLoggingLiteZone\"\n\n// These enable/disable stack logging lite for malloc allocations, not VM-only lite mode\nMALLOC_NOEXPORT\nvoid\nenable_stack_logging_lite();\n\nMALLOC_NOEXPORT\nvoid\ndisable_stack_logging_lite();\n\nMALLOC_NOEXPORT\nmalloc_zone_t *\ncreate_stack_logging_lite_zone(size_t initial_size, malloc_zone_t *helper_zone, unsigned debug_flags);\n\n#endif // __MAGAZINE_MALLOC_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/magazine_rack.c",
    "content": "/*\n * Copyright (c) 2016 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"internal.h\"\n\nvoid\nrack_init(rack_t *rack, rack_type_t type, uint32_t num_magazines, uint32_t debug_flags)\n{\n\track->type = type;\n\track->rg[0].nextgen = &rack->rg[1];\n\track->rg[1].nextgen = &rack->rg[0];\n\track->region_generation = &rack->rg[0];\n\n\track->region_generation->hashed_regions = rack->initial_regions;\n\track->region_generation->num_regions_allocated = INITIAL_NUM_REGIONS;\n\track->region_generation->num_regions_allocated_shift = INITIAL_NUM_REGIONS_SHIFT;\n\n\tmemset(rack->initial_regions, '\\0', sizeof(region_t) * INITIAL_NUM_REGIONS);\n\n\track->cookie = (uintptr_t)malloc_entropy[0];\n\n\tif (type == RACK_TYPE_SMALL) {\n\t\t// Flip the cookie for SMALL regions so that tiny and small free list\n\t\t// entries will trap when used if used in opposing region types.\n\t\track->cookie = ~rack->cookie;\n\t}\n\n\track->debug_flags = debug_flags;\n\track->num_magazines = num_magazines;\n\track->num_regions = 0;\n\track->num_regions_dealloc = 0;\n\track->magazines = NULL;\n\n\tif (num_magazines > 0) {\n\t\t// num_magazines + 1, the [-1] index will become the depot magazine\n\t\tsize_t magsize = round_page_quanta(sizeof(magazine_t) * (num_magazines + 1));\n\t\tmagazine_t *magazines = mvm_allocate_pages(magsize, 0, MALLOC_ADD_GUARD_PAGES, VM_MEMORY_MALLOC);\n\t\tif (!magazines) {\n\t\t\tMALLOC_REPORT_FATAL_ERROR(0, \"unable to allocate magazine array\");\n\t\t}\n\n\t\track->magazines = &magazines[1];\n\t\track->num_magazines_mask_shift = 0;\n\n\t\t// The magazines are indexed in [0 .. (num_magazines - 1)]\n\t\t// Find the smallest power of 2 that exceeds (num_magazines - 1)\n\t\tint i = 1;\n\t\twhile (i <= (num_magazines - 1)) {\n\t\t\track->num_magazines_mask_shift++;\n\t\t\ti <<= 1;\n\t\t}\n\n\t\t// Reduce i by 1 to obtain a mask covering [0 .. (num_tiny_magazines - 1)]\n\t\track->num_magazines_mask = i - 1;\n\t\track->last_madvise = 0;\n\n\t\t_malloc_lock_init(&rack->region_lock);\n\t\t_malloc_lock_init(&rack->magazines[DEPOT_MAGAZINE_INDEX].magazine_lock);\n\n\t\tfor (int i=0; i < rack->num_magazines; i++) {\n\t\t\t_malloc_lock_init(&rack->magazines[i].magazine_lock);\n\t\t}\n\t}\n}\n\nvoid\nrack_destroy_regions(rack_t *rack, size_t region_size)\n{\n\t/* destroy regions attached to this rack */\n\tfor (int i=0; i < rack->region_generation->num_regions_allocated; i++) {\n\t\tif ((rack->region_generation->hashed_regions[i] != HASHRING_OPEN_ENTRY) &&\n\t\t\t(rack->region_generation->hashed_regions[i] != HASHRING_REGION_DEALLOCATED))\n\t\t{\n\t\t\tmvm_deallocate_pages(rack->region_generation->hashed_regions[i], region_size, 0);\n\t\t\track->region_generation->hashed_regions[i] = HASHRING_REGION_DEALLOCATED;\n\t\t}\n\t}\n}\n\nvoid\nrack_destroy(rack_t *rack)\n{\n\t/* if the rack has additional regions, then deallocate them */\n\tif (rack->region_generation->hashed_regions != rack->initial_regions) {\n\t\tsize_t size = round_page_quanta(rack->region_generation->num_regions_allocated * sizeof(region_t));\n\t\tmvm_deallocate_pages(rack->region_generation->hashed_regions, size, 0);\n\t}\n\n\tif (rack->num_magazines > 0) {\n\t\tsize_t size = round_page_quanta(sizeof(magazine_t) * (rack->num_magazines + 1));\n\t\tmvm_deallocate_pages(&rack->magazines[-1], size, MALLOC_ADD_GUARD_PAGES);\n\t\track->magazines = NULL;\n\t}\n}\n\nvoid\nrack_region_insert(rack_t *rack, region_t region)\n{\n\t// Here find the only place in rackland that (infrequently) takes the tiny_regions_lock.\n\t// Only one thread at a time should be permitted to assess the density of the hash\n\t// ring and adjust if needed.\n\t// Only one thread at a time should be permitted to insert its new region on\n\t// the hash ring.\n\t// It is safe for all other threads to read the hash ring (hashed_regions) and\n\t// the associated sizes (num_regions_allocated and num_tiny_regions).\n\n\t_malloc_lock_lock(&rack->region_lock);\n\n\t// Check to see if the hash ring of tiny regions needs to grow.  Try to\n\t// avoid the hash ring becoming too dense.\n\tif (rack->region_generation->num_regions_allocated < (2 * rack->num_regions)) {\n\t\tregion_t *new_regions;\n\t\tsize_t new_size;\n\t\tsize_t new_shift = rack->region_generation->num_regions_allocated_shift; // In/Out parameter\n\t\tnew_regions = hash_regions_grow_no_lock(rack->region_generation->hashed_regions,\n\t\t\t\t\t\t\t\t\t\t\t\track->region_generation->num_regions_allocated, &new_shift, &new_size);\n\t\t// Do not deallocate the current hashed_regions allocation since someone may\n\t\t// be iterating it.  Instead, just leak it.\n\n\t\t// Prepare to advance to the \"next generation\" of the hash ring.\n\t\track->region_generation->nextgen->hashed_regions = new_regions;\n\t\track->region_generation->nextgen->num_regions_allocated = new_size;\n\t\track->region_generation->nextgen->num_regions_allocated_shift = new_shift;\n\n\t\t// Throw the switch to atomically advance to the next generation.\n\t\track->region_generation = rack->region_generation->nextgen;\n\t\t// Ensure everyone sees the advance.\n\t\tOSMemoryBarrier();\n\t}\n\n\t// Insert the new region into the hash ring, and update malloc statistics\n\thash_region_insert_no_lock(rack->region_generation->hashed_regions,\n\t\t\t\t\t\t\t   rack->region_generation->num_regions_allocated,\n\t\t\t\t\t\t\t   rack->region_generation->num_regions_allocated_shift,\n\t\t\t\t\t\t\t   region);\n\n\track->num_regions++;\n\t_malloc_lock_unlock(&rack->region_lock);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/magazine_rack.h",
    "content": "/*\n * Copyright (c) 2016 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __MAGAZINE_RACK_H\n#define __MAGAZINE_RACK_H\n\n/*******************************************************************************\n * Definitions for region hash\n ******************************************************************************/\n\ntypedef void *region_t;\ntypedef region_t *rgnhdl_t; /* A pointer into hashed_regions array. */\n\n#define INITIAL_NUM_REGIONS_SHIFT 6\t\t\t\t\t\t\t // log2(INITIAL_NUM_REGIONS)\n#define INITIAL_NUM_REGIONS (1 << INITIAL_NUM_REGIONS_SHIFT) // Must be a power of 2!\n#define HASHRING_OPEN_ENTRY ((region_t)0)\t\t\t\t\t // Initial value and sentinel marking end of collision chain\n#define HASHRING_REGION_DEALLOCATED ((region_t)-1)\t\t\t // Region at this slot reclaimed by OS\n#define HASH_BLOCKS_ALIGN TINY_BLOCKS_ALIGN\t\t\t\t\t // MIN( TINY_BLOCKS_ALIGN, SMALL_BLOCKS_ALIGN, ... )\n\ntypedef struct region_hash_generation {\n\tsize_t num_regions_allocated;\n\tsize_t num_regions_allocated_shift; // log2(num_regions_allocated)\n\tregion_t *hashed_regions;\t\t\t// hashed by location\n\tstruct region_hash_generation *nextgen;\n} region_hash_generation_t;\n\nOS_ENUM(rack_type, uint32_t,\n\tRACK_TYPE_NONE = 0,\n\tRACK_TYPE_TINY,\n\tRACK_TYPE_SMALL,\n);\n\n/*******************************************************************************\n * Per-allocator collection of regions and magazines\n ******************************************************************************/\n\ntypedef struct rack_s {\n\t/* Regions for tiny objects */\n\t_malloc_lock_s region_lock MALLOC_CACHE_ALIGN;\n\n\track_type_t type;\n\tsize_t num_regions;\n\tsize_t num_regions_dealloc;\n\tregion_hash_generation_t *region_generation;\n\tregion_hash_generation_t rg[2];\n\tregion_t initial_regions[INITIAL_NUM_REGIONS];\n\n\tint num_magazines;\n\tunsigned num_magazines_mask;\n\tint num_magazines_mask_shift;\n\tuint32_t debug_flags;\n\n\t// array of per-processor magazines\n\tmagazine_t *magazines;\n\n\tuintptr_t cookie;\n\tuintptr_t last_madvise;\n} rack_t;\n\n\nMALLOC_NOEXPORT\nvoid\nrack_init(rack_t *rack, rack_type_t type, uint32_t num_magazines, uint32_t debug_flags);\n\nMALLOC_NOEXPORT\nvoid\nrack_destroy_regions(rack_t *rack, size_t region_size);\n\nMALLOC_NOEXPORT\nvoid\nrack_destroy(rack_t *rack);\n\nMALLOC_NOEXPORT\nvoid\nrack_region_insert(rack_t *rack, region_t region);\n\n#endif // __MAGAZINE_RACK_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/magazine_small.c",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"internal.h\"\n\n\n/*********************\tSMALL FREE LIST UTILITIES\t************************/\n\n#pragma mark meta header helpers\n\n/*\n * Mark a block as free.  Only the first quantum of a block is marked thusly,\n * the remainder are marked \"middle\".\n */\nstatic MALLOC_INLINE void\nsmall_meta_header_set_is_free(msize_t *meta_headers, msize_t index, msize_t msize)\n{\n\tmeta_headers[index] = msize | SMALL_IS_FREE;\n}\n\n/*\n * Mark a block as not free, preserving its size.\n */\nstatic MALLOC_INLINE void\nsmall_meta_header_set_not_free(msize_t *meta_headers, msize_t index)\n{\n\tmeta_headers[index] &= ~SMALL_IS_FREE;\n}\n\n/*\n * Mark a block as in use.  Only the first quantum of a block is marked thusly,\n * the remainder are marked \"middle\".\n */\nstatic MALLOC_INLINE void\nsmall_meta_header_set_in_use(msize_t *meta_headers, msize_t index, msize_t msize)\n{\n\tmeta_headers[index] = msize;\n}\n\n/*\n * Mark a quantum as being the second or later in a block.\n */\nstatic MALLOC_INLINE void\nsmall_meta_header_set_middle(msize_t *meta_headers, msize_t index)\n{\n\tmeta_headers[index] = 0;\n}\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE\nmag_index_t\nsmall_mag_get_thread_index(void)\n{\n#if CONFIG_SMALL_USES_HYPER_SHIFT\n\tif (os_likely(_os_cpu_number_override == -1)) {\n\t\treturn _os_cpu_number() >> hyper_shift;\n\t} else {\n\t\treturn _os_cpu_number_override >> hyper_shift;\n\t}\n#else // CONFIG_SMALL_USES_HYPER_SHIFT\n\tif (os_likely(_os_cpu_number_override == -1)) {\n\t\treturn _os_cpu_number();\n\t} else {\n\t\treturn _os_cpu_number_override;\n\t}\n#endif // CONFIG_SMALL_USES_HYPER_SHIFT\n}\n\n#pragma mark in-place free list\n\nstatic MALLOC_INLINE void\nsmall_inplace_checksum_ptr(rack_t *rack, inplace_linkage_s *linkage, void *ptr)\n{\n\tuintptr_t checksum = free_list_gen_checksum((uintptr_t)ptr ^ rack->cookie ^ (uintptr_t)rack);\n\tlinkage->checksum = checksum;\n\tlinkage->ptr = ptr;\n}\n\nstatic MALLOC_INLINE free_list_t\nsmall_inplace_unchecksum_ptr(rack_t *rack, inplace_linkage_s *linkage)\n{\n\tif (linkage->checksum != (uint8_t)free_list_gen_checksum((uintptr_t)linkage->ptr ^ rack->cookie ^ (uintptr_t)rack)) {\n\t\tfree_list_checksum_botch(rack, linkage, linkage->ptr);\n\t\t__builtin_trap();\n\t}\n\n\treturn (free_list_t){ .p = linkage->ptr };\n}\n\nstatic MALLOC_INLINE free_list_t\nsmall_inplace_free_entry_get_previous(rack_t *rack, small_inplace_free_entry_t ptr)\n{\n\treturn small_inplace_unchecksum_ptr(rack, &ptr->previous);\n}\n\nstatic MALLOC_INLINE void\nsmall_inplace_free_entry_set_previous(rack_t *rack, small_inplace_free_entry_t entry, free_list_t previous)\n{\n\tsmall_inplace_checksum_ptr(rack, &entry->previous, previous.p);\n}\n\nstatic MALLOC_INLINE free_list_t\nsmall_inplace_free_entry_get_next(rack_t *rack, small_inplace_free_entry_t ptr)\n{\n\treturn small_inplace_unchecksum_ptr(rack, &ptr->next);\n}\n\nstatic MALLOC_INLINE void\nsmall_inplace_free_entry_set_next(rack_t *rack, small_inplace_free_entry_t entry, free_list_t next)\n{\n\tsmall_inplace_checksum_ptr(rack, &entry->next, next.p);\n}\n\n#pragma mark OOB free list\n\n// Returns true if the address and size of the free list entry would result\n// in the free entry being the only data on a given page.\nstatic MALLOC_INLINE boolean_t\nsmall_needs_oob_free_entry(void *ptr, msize_t msize)\n{\n\treturn ((trunc_page_quanta((uintptr_t)ptr) == (uintptr_t)ptr) && (SMALL_BYTES_FOR_MSIZE(msize) >= vm_kernel_page_size));\n}\n\n// Returns true if the address given lies within the region's OOB free\n// list entries, rather than a free_list_t in the region's heap space.\nstatic MALLOC_INLINE boolean_t\nsmall_is_oob_free_entry(free_list_t ptr)\n{\n\tsmall_region_t region = SMALL_REGION_FOR_PTR(ptr.p);\n\treturn (((uintptr_t)ptr.p >= (uintptr_t)&region->small_oob_free_entries[0]) &&\n\t\t\t((uintptr_t)ptr.p < (uintptr_t)&region->small_oob_free_entries[SMALL_OOB_COUNT]));\n}\n\nstatic MALLOC_INLINE void\nsmall_oob_free_entry_set_previous(oob_free_entry_t oobe, free_list_t previous)\n{\n\toobe->prev = (uintptr_t)previous.p;\n}\n\nstatic MALLOC_INLINE free_list_t\nsmall_oob_free_entry_get_previous(oob_free_entry_t oobe)\n{\n\treturn (free_list_t){ .p = (void *)oobe->prev };\n}\n\nstatic MALLOC_INLINE void\nsmall_oob_free_entry_set_next(oob_free_entry_t oobe, free_list_t next)\n{\n\toobe->next = (uintptr_t)next.p;\n}\n\nstatic MALLOC_INLINE free_list_t\nsmall_oob_free_entry_get_next(oob_free_entry_t oobe)\n{\n\treturn (free_list_t){ .p = (void *)oobe->next };\n}\n\nstatic MALLOC_INLINE void *\nsmall_oob_free_entry_get_ptr(oob_free_entry_t oobe)\n{\n\tsmall_region_t region = SMALL_REGION_FOR_PTR(oobe);\n\tuint16_t block = oobe->ptr & ~SMALL_IS_OOB;\n\treturn (void *)((uintptr_t)region + (block << SHIFT_SMALL_QUANTUM));\n}\n\nstatic MALLOC_INLINE void\nsmall_oob_free_entry_set_ptr(oob_free_entry_t oobe, void *ptr)\n{\n\toobe->ptr = SMALL_IS_OOB | (SMALL_OFFSET_FOR_PTR(ptr) >> SHIFT_SMALL_QUANTUM);\n}\n\nstatic MALLOC_INLINE void\nsmall_oob_free_entry_set_free(oob_free_entry_t oobe)\n{\n\toobe->prev = ~0;\n\toobe->next = ~0;\n\toobe->ptr = 0;\n}\n\n// Finds the first unused OOB free list entry in the pointer's region.\n// Returns NULL if all of the OOB entries are used.\nstatic MALLOC_INLINE oob_free_entry_t\nsmall_oob_free_find_empty(void *ptr, msize_t msize)\n{\n\tsmall_region_t region = SMALL_REGION_FOR_PTR(ptr);\n\n\t// There are 61 of these entries at the end of a small region.\n\t// If this changes, then a linear search through the list may\n\t// become an unsuitable choice.\n\tfor (int i=0; i < SMALL_OOB_COUNT; i++) {\n\t\tif (region->small_oob_free_entries[i].ptr == 0) {\n\t\t\treturn &region->small_oob_free_entries[i];\n\t\t}\n\t}\n\n#if DEBUG_MALLOC\n\tmalloc_report(ASL_LEVEL_INFO, \"used all slots of OOB entries\\n\");\n#endif\n\treturn NULL;\n}\n\nstatic MALLOC_INLINE oob_free_entry_t\nsmall_oob_free_find_ptr(void *ptr, msize_t msize)\n{\n\tsmall_region_t region = SMALL_REGION_FOR_PTR(ptr);\n\n\t// There are 61 of these entries at the end of a small region.\n\t// If this changes, then a linear search through the list may\n\t// become an unsuitable choice.\n\tfor (int i=0; i < SMALL_OOB_COUNT; i++) {\n\t\tif (small_oob_free_entry_get_ptr(&region->small_oob_free_entries[i]) == ptr) {\n\t\t\treturn &region->small_oob_free_entries[i];\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\n#pragma mark generic free list\n\nstatic MALLOC_INLINE void\nsmall_free_list_set_previous(rack_t *rack, free_list_t entry, free_list_t previous)\n{\n\tif (small_is_oob_free_entry(entry)) {\n\t\tsmall_oob_free_entry_set_previous(entry.oob, previous);\n\t} else {\n\t\tsmall_inplace_free_entry_set_previous(rack, entry.small_inplace, previous);\n\t}\n}\n\nstatic MALLOC_INLINE free_list_t\nsmall_free_list_get_previous(rack_t *rack, free_list_t ptr)\n{\n\tMALLOC_ASSERT(ptr.p);\n\tif (small_is_oob_free_entry(ptr)) {\n\t\treturn small_oob_free_entry_get_previous(ptr.oob);\n\t} else {\n\t\treturn small_inplace_free_entry_get_previous(rack, ptr.small_inplace);\n\t}\n}\n\nstatic MALLOC_INLINE void\nsmall_free_list_set_next(rack_t *rack, free_list_t entry, free_list_t next)\n{\n\tif (small_is_oob_free_entry(entry)) {\n\t\tsmall_oob_free_entry_set_next(entry.oob, next);\n\t} else {\n\t\tsmall_inplace_free_entry_set_next(rack, entry.small_inplace, next);\n\t}\n}\n\nstatic MALLOC_INLINE free_list_t\nsmall_free_list_get_next(rack_t *rack, free_list_t ptr)\n{\n\tMALLOC_ASSERT(ptr.p);\n\tif (small_is_oob_free_entry(ptr)) {\n\t\treturn small_oob_free_entry_get_next(ptr.oob);\n\t} else {\n\t\treturn small_inplace_free_entry_get_next(rack, ptr.small_inplace);\n\t}\n}\n\nstatic MALLOC_INLINE void *\nsmall_free_list_get_ptr(rack_t *rack, free_list_t ptr)\n{\n\tif (!ptr.p) {\n\t\treturn NULL;\n\t} else if (small_is_oob_free_entry(ptr)) {\n\t\treturn small_oob_free_entry_get_ptr(ptr.oob);\n\t} else {\n\t\treturn (void *)ptr.p;\n\t}\n}\n\n// Returns a free_list_t that is either inline or not based on the\n// pointer and msize.\nstatic MALLOC_INLINE free_list_t\nsmall_free_list_from_ptr(rack_t *rack, void *ptr, msize_t msize)\n{\n\tMALLOC_ASSERT(msize);\n\n\t// The default is to put the free_list_t in the memory that\n\t// the pointer leads to.\n\tfree_list_t entry;\n\tentry.p = ptr;\n\n\t// If the pointer is page aligned, and the msize is greater\n\t// than a whole page, then we try and put the entry in\n\t// the out-of-band area instead.\n\tif (small_needs_oob_free_entry(ptr, msize)) {\n\t\toob_free_entry_t oobe = small_oob_free_find_empty(ptr, msize);\n\t\tif (oobe) {\n\t\t\tsmall_oob_free_entry_set_ptr(oobe, ptr);\n\t\t\tentry.oob = oobe;\n\t\t}\n\t}\n\n\treturn entry;\n}\n\nstatic MALLOC_INLINE void\nsmall_free_mark_free(rack_t *rack, free_list_t entry, msize_t msize)\n{\n\t// Marks both the start and end block of a free-list entry as free.\n\tvoid *ptr = small_free_list_get_ptr(rack, entry);\n\tmsize_t *meta_headers = SMALL_META_HEADER_FOR_PTR(ptr);\n\tuintptr_t start_index = SMALL_META_INDEX_FOR_PTR(ptr);\n\tuintptr_t end_index = SMALL_META_INDEX_FOR_PTR(ptr + SMALL_BYTES_FOR_MSIZE(msize) - 1);\n\tMALLOC_ASSERT(start_index <= end_index);\n\n\tsmall_meta_header_set_is_free(meta_headers, start_index, msize);\n\tsmall_meta_header_set_is_free(meta_headers, end_index, msize);\n}\n\nstatic MALLOC_INLINE void\nsmall_free_mark_middle(rack_t *rack, free_list_t entry, msize_t msize)\n{\n\t// Marks both the start and end block of a free-list entry as \"middle\" (unfree).\n\tvoid *ptr = small_free_list_get_ptr(rack, entry);\n\tmsize_t *meta_headers = SMALL_META_HEADER_FOR_PTR(ptr);\n\tuintptr_t start_index = SMALL_META_INDEX_FOR_PTR(ptr);\n\tuintptr_t end_index = SMALL_META_INDEX_FOR_PTR(ptr + SMALL_BYTES_FOR_MSIZE(msize) - 1);\n\tMALLOC_ASSERT(start_index <= end_index);\n\tMALLOC_ASSERT((meta_headers[start_index] & ~SMALL_IS_FREE) == msize);\n\n\tsmall_meta_header_set_middle(meta_headers, start_index);\n\tsmall_meta_header_set_middle(meta_headers, end_index);\n}\n\nstatic MALLOC_INLINE void\nsmall_free_mark_unfree(rack_t *rack, free_list_t entry, msize_t msize)\n{\n\t// Marks both the start and end block of a free-list entry as not free.\n\tvoid *ptr = small_free_list_get_ptr(rack, entry);\n\tmsize_t *meta_headers = SMALL_META_HEADER_FOR_PTR(ptr);\n\tuintptr_t start_index = SMALL_META_INDEX_FOR_PTR(ptr);\n\tuintptr_t end_index = SMALL_META_INDEX_FOR_PTR(ptr + SMALL_BYTES_FOR_MSIZE(msize) - 1);\n\tMALLOC_ASSERT(start_index <= end_index);\n\n\tsmall_meta_header_set_not_free(meta_headers, start_index);\n\tsmall_meta_header_set_not_free(meta_headers, end_index);\n}\n\nstatic MALLOC_INLINE unsigned int\nsmall_free_list_count(rack_t *rack, free_list_t ptr)\n{\n\tunsigned int count = 0;\n\twhile (ptr.p) {\n\t\tcount++;\n\t\tptr = small_free_list_get_next(rack, ptr);\n\t}\n\treturn count;\n}\n\n/*\n * Adds an item to the proper free list, and also marks the meta-header of the\n * block properly.\n * Assumes szone has been locked\n */\nstatic free_list_t\nsmall_free_list_add_ptr(rack_t *rack, magazine_t *small_mag_ptr, void *ptr, msize_t msize)\n{\n\tgrain_t slot = SMALL_FREE_SLOT_FOR_MSIZE(rack, msize);\n\tfree_list_t free_head = small_mag_ptr->mag_free_list[slot];\n\n\t// This will either return the free_list_t for the current pointer, or attempt\n\t// to reserve an OOB entry for us.\n\tfree_list_t free_ptr = small_free_list_from_ptr(rack, ptr, msize);\n\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"in %s, ptr=%p, msize=%d\\n\", __FUNCTION__, ptr, msize);\n\t}\n\tif (((uintptr_t)ptr) & (SMALL_QUANTUM - 1)) {\n\t\tmalloc_zone_error(rack->debug_flags, true, \"small_free_list_add_ptr: Unaligned ptr %p\\n\", ptr);\n\t}\n#endif\n\n\tsmall_free_list_set_previous(rack, free_ptr, (free_list_t){ .p = NULL });\n\tsmall_free_list_set_next(rack, free_ptr, free_head);\n\n\t// Set the start and end blocks of the meta header as \"free\". Marking the last block\n\t// allows coalescing the regions when we free adjacent regions.\n\tsmall_free_mark_free(rack, free_ptr, msize);\n\n\tif (small_free_list_get_ptr(rack, free_head)) {\n#if DEBUG_MALLOC\n\t\tif (small_free_list_get_previous(szone, free_head)) {\n\t\t\tmalloc_zone_error(rack->debug_flags, true, \"small_free_list_add_ptr: Internal invariant broken (free_head->previous != NULL)\\n\"\n\t\t\t\t\t\t\"ptr=%p slot=%d free_head=%p previous=%p\\n\", ptr, slot, (void *)free_head, free_head->previous.p);\n\t\t}\n\t\tif (!SMALL_PTR_IS_FREE(small_free_list_get_ptr(szone, free_head))) {\n\t\t\tmalloc_zone_error(rack->debug_flags, true, \"small_free_list_add_ptr: Internal invariant broken (free_head is not a free pointer)\\n\"\n\t\t\t\t\t\t\"ptr=%p slot=%d free_head=%p\\n\", ptr, slot, (void *)small_free_list_get_ptr(szone, free_head));\n\t\t}\n#endif\n\t\tsmall_free_list_set_previous(rack, free_head, free_ptr);\n\t} else {\n\t\tBITMAPN_SET(small_mag_ptr->mag_bitmap, slot);\n\t}\n\n\tsmall_mag_ptr->mag_free_list[slot] = free_ptr;\n\treturn free_ptr;\n}\n\n/*\n * Removes the item pointed to by ptr in the proper free list.\n * Assumes szone has been locked\n */\nstatic void\nsmall_free_list_remove_ptr_no_clear(rack_t *rack, magazine_t *small_mag_ptr, free_list_t entry, msize_t msize)\n{\n\tgrain_t slot = SMALL_FREE_SLOT_FOR_MSIZE(rack, msize);\n\tfree_list_t next, previous;\n\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"In %s, ptr=%p, msize=%d\\n\", __FUNCTION__, ptr, msize);\n\t}\n#endif\n\n\tprevious = small_free_list_get_previous(rack, entry);\n\tnext = small_free_list_get_next(rack, entry);\n\n\tif (!small_free_list_get_ptr(rack, previous)) {\n\t\t// The block to remove is the head of the free list\n#if DEBUG_MALLOC\n\t\tif (small_mag_ptr->mag_free_list[slot] != ptr) {\n\t\t\tmalloc_zone_error(rack->debug_flags, true,\n\t\t\t\t\t\"small_free_list_remove_ptr_no_clear: Internal invariant broken (small_mag_ptr->mag_free_list[slot])\\n\"\n\t\t\t\t\t\"ptr=%p slot=%d msize=%d small_mag_ptr->mag_free_list[slot]=%p\\n\", ptr, slot, msize,\n\t\t\t\t\t(void *)small_mag_ptr->mag_free_list[slot]);\n\t\t\treturn;\n\t\t}\n#endif\n\t\tsmall_mag_ptr->mag_free_list[slot] = next;\n\t\tif (!small_free_list_get_ptr(rack, next)) {\n\t\t\tBITMAPN_CLR(small_mag_ptr->mag_bitmap, slot);\n\t\t}\n\t} else {\n\t\t// Check that the next pointer of \"previous\" points to \"entry\".\n\t\tfree_list_t prev_next = small_free_list_get_next(rack, previous);\n\t\tif (small_free_list_get_ptr(rack, prev_next) != small_free_list_get_ptr(rack, entry)) {\n\t\t\tmalloc_zone_error(rack->debug_flags, true,\n\t\t\t\t\t\"small_free_list_remove_ptr_no_clear: Internal invariant broken (next ptr of prev) for %p, prev_next=%p\\n\",\n\t\t\t\t\tsmall_free_list_get_ptr(rack, entry), small_free_list_get_ptr(rack, prev_next));\n\t\t\t__builtin_unreachable(); // Always crashes in malloc_zone_error().\n\t\t}\n\t\tsmall_free_list_set_next(rack, previous, next);\n\t}\n\n\tif (small_free_list_get_ptr(rack, next)) {\n\t\t// Check that the previous pointer of \"next\" points to \"entry\".\n\t\tfree_list_t next_prev = small_free_list_get_previous(rack, next);\n\t\tif (small_free_list_get_ptr(rack, next_prev) != small_free_list_get_ptr(rack, entry)) {\n\t\t\tmalloc_zone_error(rack->debug_flags, true,\n\t\t\t\t\t\"small_free_list_remove_ptr_no_clear: Internal invariant broken (prev ptr of next) for %p, next_prev=%p\\n\",\n\t\t\t\t\tsmall_free_list_get_ptr(rack, entry), small_free_list_get_ptr(rack, next_prev));\n\t\t\t__builtin_unreachable(); // Always crashes in malloc_zone_error().\n\t\t}\n\t\tsmall_free_list_set_previous(rack, next, previous);\n\t}\n\n\tif (small_is_oob_free_entry(entry)) {\n\t\tsmall_oob_free_entry_set_free(entry.oob);\n\t}\n}\n\nstatic void\nsmall_free_list_remove_ptr(rack_t *rack, magazine_t *small_mag_ptr, free_list_t entry, msize_t msize)\n{\n\t// In the general case we want to ensure we marked these entries as \"middle\"\n\t// while we are in this function. However, when we're moving free list entries\n\t// from/to the recirc depot we rely on the metadata bits being intact to\n\t// reconstruct the free list. In that case we have to be able to skip this\n\t// metadata manipulation.\n\tsmall_free_mark_middle(rack, entry, msize);\n\tsmall_free_list_remove_ptr_no_clear(rack, small_mag_ptr, entry, msize);\n}\n\n// Find a free list entry by its pointer address. This should only really be used\n// by small_finalize_region, or similar, where the free_list_t entry of a known\n// pointer is desired. Otherwise it is cheaper to always pull off the free lists.\nstatic free_list_t\nsmall_free_list_find_by_ptr(rack_t *rack, magazine_t *small_mag_ptr, void *ptr, msize_t msize)\n{\n\tif (*SMALL_METADATA_FOR_PTR(ptr) == (SMALL_IS_FREE | msize)) {\n\t\t// If the block is marked free, and of size `msize`, then we first must check\n\t\t// if the alignment+size is such that we could have use an OOB-entry.\n\t\tif (small_needs_oob_free_entry(ptr, msize)) {\n\t\t\t// Scan the OOB entries looking for this address.\n\t\t\tsmall_region_t region = SMALL_REGION_FOR_PTR(ptr);\n\t\t\tfor (int i=0; i<SMALL_OOB_COUNT; i++) {\n\t\t\t\tif (!region->small_oob_free_entries[i].ptr) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (small_oob_free_entry_get_ptr(&region->small_oob_free_entries[i]) == ptr) {\n\t\t\t\t\treturn (free_list_t){ .oob = &region->small_oob_free_entries[i] };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Otherwise, the freed pointer will be in place.\n\t\treturn (free_list_t){ .p = ptr };\n\t}\n\n\tmalloc_zone_error(rack->debug_flags, true,\n\t\t\t\"small_free_list_find_by_ptr: ptr is not free (ptr metadata !SMALL_IS_FREE), \"\n\t\t\t\"ptr=%p msize=%d metadata=0x%x\\n\", ptr, msize, *SMALL_METADATA_FOR_PTR(ptr));\n\t__builtin_trap();\n}\n\nvoid\nsmall_finalize_region(rack_t *rack, magazine_t *small_mag_ptr)\n{\n\tvoid *last_block, *previous_block;\n\tmsize_t last_msize, previous_msize, last_index;\n\tfree_list_t previous;\n\n\t// It is possible that the block prior to the last block in the region has\n\t// been free'd, but was not coalesced with the free bytes at the end of the\n\t// block, since we treat the bytes at the end of the region as \"in use\" in\n\t// the meta headers. Attempt to coalesce the last block with the previous\n\t// block, so we don't violate the \"no consecutive free blocks\" invariant.\n\t//\n\t// FIXME: If we could calculate the previous small free size in the same\n\t//        manner as tiny_previous_preceding_free, it would eliminate the\n\t//        index & previous msize checks, which are a guard against reading\n\t//        bogus data out of in-use or written-on-freed memory.\n\t//\n\t// FIXME: Need to investigate how much work would be required to increase\n\t//        'mag_bytes_free_at_end' when freeing the preceding block, rather\n\t//        than performing this workaround.\n\t//\n\tif (small_mag_ptr->mag_bytes_free_at_end) {\n\t\tlast_block = SMALL_REGION_END(small_mag_ptr->mag_last_region) - small_mag_ptr->mag_bytes_free_at_end;\n\t\tlast_msize = SMALL_MSIZE_FOR_BYTES(small_mag_ptr->mag_bytes_free_at_end);\n\n\t\tlast_index = SMALL_META_INDEX_FOR_PTR(last_block);\n\t\tprevious_msize = SMALL_PREVIOUS_MSIZE(last_block);\n\n\t\tif (last_index && (previous_msize <= last_index)) {\n\t\t\tprevious_block = (void *)((uintptr_t)last_block - SMALL_BYTES_FOR_MSIZE(previous_msize));\n\n\t\t\tif (SMALL_PTR_IS_FREE(previous_block)) {\n\t\t\t\tprevious = small_free_list_find_by_ptr(rack, small_mag_ptr, previous_block, previous_msize);\n\t\t\t\tsmall_free_list_remove_ptr(rack, small_mag_ptr, previous, previous_msize);\n\t\t\t\tlast_block = previous_block;\n\t\t\t\tlast_msize += previous_msize;\n\t\t\t}\n\t\t}\n\n\t\t// splice last_block into the free list\n\t\tsmall_free_list_add_ptr(rack, small_mag_ptr, last_block, last_msize);\n\t\tsmall_mag_ptr->mag_bytes_free_at_end = 0;\n\t}\n\n#if CONFIG_ASLR_INTERNAL\n\tfree_list_t next;\n\n\tif (small_mag_ptr->mag_bytes_free_at_start) {\n\t\tlast_block = SMALL_REGION_ADDRESS(small_mag_ptr->mag_last_region);\n\t\tlast_msize = SMALL_MSIZE_FOR_BYTES(small_mag_ptr->mag_bytes_free_at_start);\n\n\t\tvoid *next_block = (void *)((uintptr_t)last_block + small_mag_ptr->mag_bytes_free_at_start);\n\t\tif (SMALL_PTR_IS_FREE(next_block)) {\n\t\t\tmsize_t next_msize = SMALL_PTR_SIZE(next_block);\n\t\t\tnext = small_free_list_find_by_ptr(rack, small_mag_ptr, next_block, next_msize);\n\t\t\tsmall_free_list_remove_ptr(rack, small_mag_ptr, next, next_msize);\n\t\t\tlast_msize += next_msize;\n\t\t}\n\n\t\t// splice last_block into the free list\n\t\tsmall_free_list_add_ptr(rack, small_mag_ptr, last_block, last_msize);\n\t\tsmall_mag_ptr->mag_bytes_free_at_start = 0;\n\t}\n#endif\n\n\t// TODO: Will we ever need to coalesce the blocks at the beginning and end when we finalize?\n\tsmall_mag_ptr->mag_last_region = NULL;\n}\n\nint\nsmall_free_detach_region(rack_t *rack, magazine_t *small_mag_ptr, region_t r)\n{\n\tunsigned char *ptr = SMALL_REGION_ADDRESS(r);\n\tmsize_t *meta_headers = SMALL_META_HEADER_FOR_PTR(ptr);\n\tuintptr_t start = (uintptr_t)SMALL_REGION_ADDRESS(r);\n\tuintptr_t current = start;\n\tuintptr_t limit = (uintptr_t)SMALL_REGION_END(r);\n\tint total_alloc = 0;\n\n\twhile (current < limit) {\n\t\tunsigned index = SMALL_META_INDEX_FOR_PTR(current);\n\t\tmsize_t msize_and_free = meta_headers[index];\n\t\tboolean_t is_free = msize_and_free & SMALL_IS_FREE;\n\t\tmsize_t msize = msize_and_free & ~SMALL_IS_FREE;\n\n\t\tif (!msize) {\n#if DEBUG_MALLOC\n\t\t\tboolean_t is_free = msize_and_free & SMALL_IS_FREE;\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** small_free_detach_region error with %p: msize=%d is_free=%d\\n\", (void *)current, msize, is_free);\n#endif\n\t\t\tbreak;\n\t\t}\n\n\t\tif (is_free) {\n\t\t\tfree_list_t entry = small_free_list_find_by_ptr(rack, small_mag_ptr, (void *)current, msize);\n\t\t\tsmall_free_list_remove_ptr_no_clear(rack, small_mag_ptr, entry, msize);\n\t\t} else {\n\t\t\ttotal_alloc++;\n\t\t}\n\t\tcurrent += SMALL_BYTES_FOR_MSIZE(msize);\n\t}\n\treturn total_alloc;\n}\n\nsize_t\nsmall_free_reattach_region(rack_t *rack, magazine_t *small_mag_ptr, region_t r)\n{\n\tunsigned char *ptr = SMALL_REGION_ADDRESS(r);\n\tmsize_t *meta_headers = SMALL_META_HEADER_FOR_PTR(ptr);\n\tuintptr_t start = (uintptr_t)SMALL_REGION_ADDRESS(r);\n\tuintptr_t current = start;\n\tuintptr_t limit = (uintptr_t)SMALL_REGION_END(r);\n\tsize_t total_alloc = 0;\n\n\twhile (current < limit) {\n\t\tunsigned index = SMALL_META_INDEX_FOR_PTR(current);\n\t\tmsize_t msize_and_free = meta_headers[index];\n\t\tboolean_t is_free = msize_and_free & SMALL_IS_FREE;\n\t\tmsize_t msize = msize_and_free & ~SMALL_IS_FREE;\n\n\t\tif (!msize) {\n#if DEBUG_MALLOC\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** small_free_reattach_region error with %p: msize=%d is_free=%d\\n\", (void *)current, msize, is_free);\n#endif\n\t\t\tbreak;\n\t\t}\n\t\tif (is_free) {\n\t\t\tsmall_free_list_add_ptr(rack, small_mag_ptr, (void *)current, msize);\n\t\t} else {\n\t\t\ttotal_alloc += SMALL_BYTES_FOR_MSIZE(msize);\n\t\t}\n\t\tcurrent += SMALL_BYTES_FOR_MSIZE(msize);\n\t}\n\treturn total_alloc;\n}\n\ntypedef struct {\n\tuint16_t pnum, size;\n} small_pg_pair_t;\n\nvoid\nsmall_free_scan_madvise_free(rack_t *rack, magazine_t *depot_ptr, region_t r)\n{\n\tuintptr_t start = (uintptr_t)SMALL_REGION_ADDRESS(r);\n\tuintptr_t current = start;\n\tuintptr_t limit = (uintptr_t)SMALL_REGION_END(r);\n\tmsize_t *meta_headers = SMALL_META_HEADER_FOR_PTR(start);\n\tsmall_pg_pair_t advisory[((SMALL_REGION_PAYLOAD_BYTES + vm_kernel_page_size - 1) >> vm_kernel_page_shift) >>\n\t\t\t\t\t\t\t 1]; // 4096bytes stack allocated\n\tint advisories = 0;\n\n\t// Scan the metadata identifying blocks which span one or more pages. Mark the pages MADV_FREE taking care to preserve free list\n\t// management data.\n\twhile (current < limit) {\n\t\tunsigned index = SMALL_META_INDEX_FOR_PTR(current);\n\t\tmsize_t msize_and_free = meta_headers[index];\n\t\tboolean_t is_free = msize_and_free & SMALL_IS_FREE;\n\t\tmsize_t msize = msize_and_free & ~SMALL_IS_FREE;\n\n\t\tif (is_free && !msize && (current == start)) {\n#if DEBUG_MALLOC\n\t\t\t// first block is all free\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** small_free_scan_madvise_free first block is all free! %p: msize=%d is_free=%d\\n\", (void *)current,\n\t\t\t\t\t\t  msize, is_free);\n#endif\n\t\t\tuintptr_t pgLo = round_page_kernel(start + sizeof(free_list_t) + sizeof(msize_t));\n\t\t\tuintptr_t pgHi = trunc_page_kernel(start + SMALL_REGION_SIZE - sizeof(msize_t));\n\n\t\t\tif (pgLo < pgHi) {\n\t\t\t\tadvisory[advisories].pnum = (pgLo - start) >> vm_kernel_page_shift;\n\t\t\t\tadvisory[advisories].size = (pgHi - pgLo) >> vm_kernel_page_shift;\n\t\t\t\tadvisories++;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tif (!msize) {\n#if DEBUG_MALLOC\n\t\t\tmalloc_report(ASL_LEVEL_ERR,\n\t\t\t\t\t\t  \"*** small_free_scan_madvise_free error with %p: msize=%d is_free=%d\\n\", (void *)current, msize, is_free);\n#endif\n\t\t\tbreak;\n\t\t}\n\t\tif (is_free) {\n\t\t\tuintptr_t pgLo = round_page_kernel(current + sizeof(free_list_t) + sizeof(msize_t));\n\t\t\tuintptr_t pgHi = trunc_page_kernel(current + SMALL_BYTES_FOR_MSIZE(msize) - sizeof(msize_t));\n\n\t\t\tif (pgLo < pgHi) {\n\t\t\t\tadvisory[advisories].pnum = (pgLo - start) >> vm_kernel_page_shift;\n\t\t\t\tadvisory[advisories].size = (pgHi - pgLo) >> vm_kernel_page_shift;\n\t\t\t\tadvisories++;\n\t\t\t}\n\t\t}\n\t\tcurrent += SMALL_BYTES_FOR_MSIZE(msize);\n\t}\n\n\tif (advisories > 0) {\n\t\tint i;\n\n\t\tOSAtomicIncrement32Barrier(&(REGION_TRAILER_FOR_SMALL_REGION(r)->pinned_to_depot));\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(depot_ptr);\n\t\tfor (i = 0; i < advisories; ++i) {\n\t\t\tuintptr_t addr = (advisory[i].pnum << vm_page_quanta_shift) + start;\n\t\t\tsize_t size = advisory[i].size << vm_page_quanta_shift;\n\n\t\t\tmvm_madvise_free(rack, r, addr, addr + size, NULL, rack->debug_flags & MALLOC_DO_SCRIBBLE);\n\t\t}\n\t\tSZONE_MAGAZINE_PTR_LOCK(depot_ptr);\n\t\tOSAtomicDecrement32Barrier(&(REGION_TRAILER_FOR_SMALL_REGION(r)->pinned_to_depot));\n\t}\n}\n\nstatic region_t\nsmall_find_msize_region(rack_t *rack, magazine_t *small_mag_ptr, mag_index_t mag_index, msize_t msize)\n{\n\tvoid *ptr;\n\tgrain_t slot = SMALL_FREE_SLOT_FOR_MSIZE(rack, msize);\n\tfree_list_t *free_list = small_mag_ptr->mag_free_list;\n\tfree_list_t *the_slot = free_list + slot;\n\tfree_list_t *limit;\n\tunsigned bitmap;\n\n\t// Assumes we've locked the magazine\n\tCHECK_MAGAZINE_PTR_LOCKED(szone, small_mag_ptr, __PRETTY_FUNCTION__);\n\n\t// Look for an exact match by checking the freelist for this msize.\n\tptr = small_free_list_get_ptr(rack, *the_slot);\n\tif (ptr) {\n\t\treturn SMALL_REGION_FOR_PTR(ptr);\n\t}\n\n\t// Mask off the bits representing slots holding free blocks smaller than\n\t// the size we need.\n\tif (SMALL_FREELIST_BITMAP_WORDS(rack) > 1) {\n\t\t// BITMAPN_CTZ implementation\n\t\tunsigned idx = slot >> 5;\n\t\tbitmap = 0;\n\t\tunsigned mask = ~((1 << (slot & 31)) - 1);\n\t\tfor (; idx < SMALL_FREELIST_BITMAP_WORDS(rack); ++idx) {\n\t\t\tbitmap = small_mag_ptr->mag_bitmap[idx] & mask;\n\t\t\tif (bitmap != 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmask = ~0U;\n\t\t}\n\t\t// Check for fallthrough: No bits set in bitmap\n\t\tif ((bitmap == 0) && (idx == SMALL_FREELIST_BITMAP_WORDS(rack))) {\n\t\t\treturn NULL;\n\t\t}\n\n\t\t// Start looking at the first set bit, plus 32 bits for every word of\n\t\t// zeroes or entries that were too small.\n\t\tslot = BITMAP32_CTZ((&bitmap)) + (idx * 32);\n\t} else {\n\t\tbitmap = small_mag_ptr->mag_bitmap[0] & ~((1 << slot) - 1);\n\t\tif (!bitmap) {\n\t\t\treturn NULL;\n\t\t}\n\n\t\tslot = BITMAP32_CTZ((&bitmap));\n\t}\n\tlimit = free_list + SMALL_FREE_SLOT_COUNT(rack) - 1;\n\tfree_list += slot;\n\n\tif (free_list < limit) {\n\t\tptr = small_free_list_get_ptr(rack, *free_list);\n\t\tif (ptr) {\n\t\t\treturn SMALL_REGION_FOR_PTR(ptr);\n\t\t} else {\n\t\t\t/* Shouldn't happen. Fall through to look at last slot. */\n#if DEBUG_MALLOC\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"in small_malloc_from_free_list(), mag_bitmap out of sync, slot=%d\\n\", slot);\n#endif\n\t\t}\n\t}\n\n\t// We are now looking at the last slot, which contains blocks equal to, or\n\t// due to coalescing of free blocks, larger than (num_small_slots - 1) * (small quantum size).\n\tptr = small_free_list_get_ptr(rack, *limit);\n\tif (ptr) {\n\t\treturn SMALL_REGION_FOR_PTR(ptr);\n\t}\n\n\treturn NULL;\n}\n\nstatic boolean_t\nsmall_get_region_from_depot(rack_t *rack, magazine_t *small_mag_ptr, mag_index_t mag_index, msize_t msize)\n{\n\tmagazine_t *depot_ptr = &(rack->magazines[DEPOT_MAGAZINE_INDEX]);\n\n\t/* FIXME: Would Uniprocessor benefit from recirc and MADV_FREE? */\n\tif (rack->num_magazines == 1) { // Uniprocessor, single magazine, so no recirculation necessary\n\t\treturn 0;\n\t}\n\n#if DEBUG_MALLOC\n\tif (DEPOT_MAGAZINE_INDEX == mag_index) {\n\t\tmalloc_zone_error(rack->debug_flags, true, \"small_get_region_from_depot called for magazine index -1\\n\", NULL, NULL);\n\t\treturn 0;\n\t}\n#endif\n\n\tSZONE_MAGAZINE_PTR_LOCK(depot_ptr);\n\n\t// Appropriate a Depot'd region that can satisfy requested msize.\n\tregion_trailer_t *node;\n\tregion_t sparse_region;\n\n\twhile (1) {\n\t\tsparse_region = small_find_msize_region(rack, depot_ptr, DEPOT_MAGAZINE_INDEX, msize);\n\t\tif (NULL == sparse_region) { // Depot empty?\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(depot_ptr);\n\t\t\treturn 0;\n\t\t}\n\n\t\tnode = REGION_TRAILER_FOR_SMALL_REGION(sparse_region);\n\t\tif (0 >= node->pinned_to_depot) {\n\t\t\tbreak;\n\t\t}\n\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(depot_ptr);\n\t\tyield();\n\t\tSZONE_MAGAZINE_PTR_LOCK(depot_ptr);\n\t}\n\n\t// disconnect node from Depot\n\trecirc_list_extract(rack, depot_ptr, node);\n\n\t// Iterate the region pulling its free entries off the (locked) Depot's free list\n\tint objects_in_use = small_free_detach_region(rack, depot_ptr, sparse_region);\n\n\t// Transfer ownership of the region\n\tMAGAZINE_INDEX_FOR_SMALL_REGION(sparse_region) = mag_index;\n\tnode->pinned_to_depot = 0;\n\n\t// Iterate the region putting its free entries on its new (locked) magazine's free list\n\tsize_t bytes_inplay = small_free_reattach_region(rack, small_mag_ptr, sparse_region);\n\n\tdepot_ptr->mag_num_bytes_in_objects -= bytes_inplay;\n\tdepot_ptr->num_bytes_in_magazine -= SMALL_REGION_PAYLOAD_BYTES;\n\tdepot_ptr->mag_num_objects -= objects_in_use;\n\n\tsmall_mag_ptr->mag_num_bytes_in_objects += bytes_inplay;\n\tsmall_mag_ptr->num_bytes_in_magazine += SMALL_REGION_PAYLOAD_BYTES;\n\tsmall_mag_ptr->mag_num_objects += objects_in_use;\n\n\t// connect to magazine as first node\n\trecirc_list_splice_first(rack, small_mag_ptr, node);\n\n\tSZONE_MAGAZINE_PTR_UNLOCK(depot_ptr);\n\n\tMAGMALLOC_DEPOTREGION(SMALL_SZONE_FROM_RACK(rack), (int)mag_index, (void *)sparse_region, SMALL_REGION_SIZE,\n\t\t\t\t\t\t  (int)BYTES_USED_FOR_SMALL_REGION(sparse_region)); // DTrace USDT Probe\n\n\treturn 1;\n}\n\n#if CONFIG_AGGRESSIVE_MADVISE || CONFIG_RECIRC_DEPOT\nstatic MALLOC_INLINE void\nsmall_madvise_free_range_no_lock(rack_t *rack,\n\t\t\t\t\t\t\t\t magazine_t *small_mag_ptr,\n\t\t\t\t\t\t\t\t region_t region,\n\t\t\t\t\t\t\t\t free_list_t freee,\n\t\t\t\t\t\t\t\t msize_t fmsize,\n\t\t\t\t\t\t\t\t void *headptr,\n\t\t\t\t\t\t\t\t size_t headsize)\n{\n\tvoid *ptr = small_free_list_get_ptr(rack, freee);\n\tregion_trailer_t *node = REGION_TRAILER_FOR_SMALL_REGION(region);\n\n\t// Lock on small_magazines[mag_index] is already held here.\n\t// Calculate the first page in the coalesced block that would be safe to mark MADV_FREE\n\tsize_t free_header_size = sizeof(free_list_t) + sizeof(msize_t);\n\n\t// If the free_list_t entry is out-of-line then we don't need to reserve any space\n\t// at the start of the region.\n\tif (small_is_oob_free_entry(freee)) {\n\t\tfree_header_size = 0;\n\t}\n\n\tuintptr_t safe_ptr = (uintptr_t)ptr + free_header_size;\n\tuintptr_t round_safe = round_page_kernel(safe_ptr);\n\n\t// Calculate the last page in the coalesced block that would be safe to mark MADV_FREE\n\tuintptr_t safe_extent = (uintptr_t)ptr + SMALL_BYTES_FOR_MSIZE(fmsize);\n\tuintptr_t trunc_extent = trunc_page_kernel(safe_extent);\n\n\t// The newly freed block may complete a span of bytes that cover one or more pages. Mark the span with MADV_FREE.\n\tif (round_safe < trunc_extent) { // Coalesced area covers a page (perhaps many)\n\t\t// Extend the freed block by the free region header and tail sizes to include pages\n\t\t// we may have coalesced that no longer host free region tails and headers.\n\t\t// This may extend over in-use ranges, but the MIN/MAX clamping below will fix that up.\n\t\tuintptr_t lo = trunc_page_kernel((uintptr_t)headptr);\n\t\tuintptr_t hi = round_page_kernel((uintptr_t)headptr + headsize + free_header_size);\n\n\t\tuintptr_t free_lo = MAX(round_safe, lo);\n\t\tuintptr_t free_hi = MIN(trunc_extent, hi);\n\n\t\tif (free_lo < free_hi) {\n\t\t\t// Before unlocking, ensure that the metadata for the freed region\n\t\t\t// makes it look not free but includes the length. This ensures that\n\t\t\t// any code that inspects the metadata while we are unlocked sees\n\t\t\t// a valid state and will not try to use or coalesce freed memory\n\t\t\t// into it.\n\t\t\tsmall_free_mark_unfree(rack, freee, fmsize);\n\t\t\tsmall_free_list_remove_ptr_no_clear(rack, small_mag_ptr, freee, fmsize);\n\t\t\tOSAtomicIncrement32Barrier(&(node->pinned_to_depot));\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\tmvm_madvise_free(rack, region, free_lo, free_hi, &rack->last_madvise, rack->debug_flags & MALLOC_DO_SCRIBBLE);\n\t\t\tSZONE_MAGAZINE_PTR_LOCK(small_mag_ptr);\n\t\t\tOSAtomicDecrement32Barrier(&(node->pinned_to_depot));\n\t\t\tsmall_free_list_add_ptr(rack, small_mag_ptr, ptr, fmsize);\n\t\t}\n\t}\n}\n#endif // CONFIG_AGGRESSIVE_MADVISE || CONFIG_RECIRC_DEPOT\n\n#if CONFIG_RECIRC_DEPOT\nstatic region_t\nsmall_free_try_depot_unmap_no_lock(rack_t *rack, magazine_t *depot_ptr, region_trailer_t *node)\n{\n\tif (0 < node->bytes_used || 0 < node->pinned_to_depot || depot_ptr->recirculation_entries < recirc_retained_regions) {\n\t\treturn NULL;\n\t}\n\n\t// disconnect first node from Depot\n\trecirc_list_extract(rack, depot_ptr, node);\n\n\t// Iterate the region pulling its free entries off the (locked) Depot's free list\n\tregion_t sparse_region = SMALL_REGION_FOR_PTR(node);\n\tint objects_in_use = small_free_detach_region(rack, depot_ptr, sparse_region);\n\n\tif (0 == objects_in_use) {\n\t\t// Invalidate the hash table entry for this region with HASHRING_REGION_DEALLOCATED.\n\t\t// Using HASHRING_REGION_DEALLOCATED preserves the collision chain, using HASHRING_OPEN_ENTRY (0) would not.\n\t\trgnhdl_t pSlot = hash_lookup_region_no_lock(rack->region_generation->hashed_regions,\n\t\t\t\t\t\t\t\t\t\t\t\t\track->region_generation->num_regions_allocated,\n\t\t\t\t\t\t\t\t\t\t\t\t\track->region_generation->num_regions_allocated_shift,\n\t\t\t\t\t\t\t\t\t\t\t\t\tsparse_region);\n\t\tif (NULL == pSlot) {\n\t\t\tmalloc_zone_error(rack->debug_flags, true, \"small_free_try_depot_unmap_no_lock hash lookup failed: %p\\n\", sparse_region);\n\t\t\treturn NULL;\n\t\t}\n\t\t*pSlot = HASHRING_REGION_DEALLOCATED;\n\t\tdepot_ptr->num_bytes_in_magazine -= SMALL_REGION_PAYLOAD_BYTES;\n\t\t// Atomically increment num_regions_dealloc\n#ifdef __LP64___\n\t\tOSAtomicIncrement64(&rack->num_regions_dealloc);\n#else\n\t\tOSAtomicIncrement32((int32_t *)&rack->num_regions_dealloc);\n#endif\n\n\t\t// Caller will transfer ownership of the region back to the OS with no locks held\n\t\tMAGMALLOC_DEALLOCREGION(SMALL_SZONE_FROM_RACK(rack), (void *)sparse_region, (int)SMALL_REGION_SIZE); // DTrace USDT Probe\n\t\treturn sparse_region;\n\n\t} else {\n\t\tmalloc_zone_error(rack->debug_flags, true, \"small_free_try_depot_unmap_no_lock objects_in_use not zero: %d\\n\", objects_in_use);\n\t\treturn NULL;\n\t}\n}\n\nstatic boolean_t\nsmall_free_do_recirc_to_depot(rack_t *rack, magazine_t *small_mag_ptr, mag_index_t mag_index)\n{\n\t// The entire magazine crossed the \"emptiness threshold\". Transfer a region\n\t// from this magazine to the Depot. Choose a region that itself has crossed the emptiness threshold (i.e\n\t// is at least fraction \"f\" empty.) Such a region will be marked \"suitable\" on the recirculation list.\n\tregion_trailer_t *node = small_mag_ptr->firstNode;\n\n\twhile (node && (!node->recirc_suitable || node->pinned_to_depot)) {\n\t\tnode = node->next;\n\t}\n\n\tif (NULL == node) {\n#if DEBUG_MALLOC\n\t\tmalloc_report(ASL_LEVEL_ERR, \"*** small_free_do_recirc_to_depot end of list\\n\");\n#endif\n\t\treturn TRUE; // Caller must SZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t}\n\n\tregion_t sparse_region = SMALL_REGION_FOR_PTR(node);\n\n\t// Deal with unclaimed memory -- mag_bytes_free_at_end or mag_bytes_free_at start\n\tif (sparse_region == small_mag_ptr->mag_last_region &&\n\t\t(small_mag_ptr->mag_bytes_free_at_end || small_mag_ptr->mag_bytes_free_at_start)) {\n\t\tsmall_finalize_region(rack, small_mag_ptr);\n\t}\n\n\t// disconnect \"suitable\" node from magazine\n\trecirc_list_extract(rack, small_mag_ptr, node);\n\n\t// Iterate the region pulling its free entries off its (locked) magazine's free list\n\tint objects_in_use = small_free_detach_region(rack, small_mag_ptr, sparse_region);\n\tmagazine_t *depot_ptr = &(rack->magazines[DEPOT_MAGAZINE_INDEX]);\n\n\t// hand over the region to the (locked) Depot\n\tSZONE_MAGAZINE_PTR_LOCK(depot_ptr);\n\t// this will cause small_free_list_add_ptr called by small_free_reattach_region to use\n\t// the depot as its target magazine, rather than magazine formerly associated with sparse_region\n\tMAGAZINE_INDEX_FOR_SMALL_REGION(sparse_region) = DEPOT_MAGAZINE_INDEX;\n\tnode->pinned_to_depot = 0;\n\n\t// Iterate the region putting its free entries on Depot's free list\n\tsize_t bytes_inplay = small_free_reattach_region(rack, depot_ptr, sparse_region);\n\n\tsmall_mag_ptr->mag_num_bytes_in_objects -= bytes_inplay;\n\tsmall_mag_ptr->num_bytes_in_magazine -= SMALL_REGION_PAYLOAD_BYTES;\n\tsmall_mag_ptr->mag_num_objects -= objects_in_use;\n\n\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr); // Unlock the originating magazine\n\n\tdepot_ptr->mag_num_bytes_in_objects += bytes_inplay;\n\tdepot_ptr->num_bytes_in_magazine += SMALL_REGION_PAYLOAD_BYTES;\n\tdepot_ptr->mag_num_objects += objects_in_use;\n\n\t// connect to Depot as last node\n\trecirc_list_splice_last(rack, depot_ptr, node);\n\n\tMAGMALLOC_RECIRCREGION(SMALL_SZONE_FROM_RACK(rack), (int)mag_index, (void *)sparse_region, SMALL_REGION_SIZE,\n\t\t\t\t\t\t   (int)BYTES_USED_FOR_SMALL_REGION(sparse_region)); // DTrace USDT Probe\n\n#if !CONFIG_AGGRESSIVE_MADVISE\n\t// Mark free'd dirty pages with MADV_FREE to reduce memory pressure\n\tsmall_free_scan_madvise_free(rack, depot_ptr, sparse_region);\n#endif\n\n\t// If the region is entirely empty vm_deallocate() it outside the depot lock\n\tregion_t r_dealloc = small_free_try_depot_unmap_no_lock(rack, depot_ptr, node);\n\tSZONE_MAGAZINE_PTR_UNLOCK(depot_ptr);\n\tif (r_dealloc) {\n\t\tmvm_deallocate_pages(r_dealloc, SMALL_REGION_SIZE, 0);\n\t}\n\treturn FALSE; // Caller need not unlock the originating magazine\n}\n\nstatic MALLOC_INLINE boolean_t\nsmall_free_try_recirc_to_depot(rack_t *rack,\n\t\t\t\t\t\t\t   magazine_t *small_mag_ptr,\n\t\t\t\t\t\t\t   mag_index_t mag_index,\n\t\t\t\t\t\t\t   region_t region,\n\t\t\t\t\t\t\t   free_list_t freee,\n\t\t\t\t\t\t\t   msize_t msize,\n\t\t\t\t\t\t\t   void *headptr,\n\t\t\t\t\t\t\t   size_t headsize)\n{\n\tregion_trailer_t *node = REGION_TRAILER_FOR_SMALL_REGION(region);\n\tsize_t bytes_used = node->bytes_used;\n\n\t/* FIXME: Would Uniprocessor benefit from recirc and MADV_FREE? */\n\tif (rack->num_magazines == 1) { // Uniprocessor, single magazine, so no recirculation necessary\n\t\t/* NOTHING */\n\t\treturn TRUE; // Caller must do SZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr)\n\t} else if (DEPOT_MAGAZINE_INDEX != mag_index) {\n\t\t// Emptiness discriminant\n\t\tif (bytes_used < DENSITY_THRESHOLD(SMALL_REGION_PAYLOAD_BYTES)) {\n\t\t\t/* Region has crossed threshold from density to sparsity. Mark it \"suitable\" on the\n\t\t\t * recirculation candidates list. */\n\t\t\tnode->recirc_suitable = TRUE;\n\t\t} else {\n\t\t\t/* After this free, we've found the region is still dense, so it must have been even more so before\n\t\t\t * the free. That implies the region is already correctly marked. Do nothing. */\n\t\t}\n\n\t\t// Has the entire magazine crossed the \"emptiness threshold\"? If so, transfer a region\n\t\t// from this magazine to the Depot. Choose a region that itself has crossed the emptiness threshold (i.e\n\t\t// is at least fraction \"f\" empty.) Such a region will be marked \"suitable\" on the recirculation list.\n\n\t\tsize_t a = small_mag_ptr->num_bytes_in_magazine;\t// Total bytes allocated to this magazine\n\t\tsize_t u = small_mag_ptr->mag_num_bytes_in_objects; // In use (malloc'd) from this magaqzine\n\n\t\tif (a - u > ((3 * SMALL_REGION_PAYLOAD_BYTES) / 2) && u < DENSITY_THRESHOLD(a)) {\n\t\t\treturn small_free_do_recirc_to_depot(rack, small_mag_ptr, mag_index);\n\t\t}\n\n\t} else {\n#if !CONFIG_AGGRESSIVE_MADVISE\n\t\t// We are free'ing into the depot, so madvise as we do so unless we were madvising every incoming\n\t\t// allocation anyway.\n\t\tsmall_madvise_free_range_no_lock(rack, small_mag_ptr, region, freee, msize, headptr, headsize);\n#endif\n\n\t\tif (0 < bytes_used || 0 < node->pinned_to_depot) {\n\t\t\t/* Depot'd region is still live. Leave it in place on the Depot's recirculation list\n\t\t\t * so as to avoid thrashing between the Depot's free list and a magazines's free list\n\t\t\t * with detach_region/reattach_region */\n\t\t} else {\n\t\t\t/* Depot'd region is just now empty. Consider return to OS. */\n\t\t\tregion_t r_dealloc = small_free_try_depot_unmap_no_lock(rack, small_mag_ptr, node);\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\tif (r_dealloc) {\n\t\t\t\tmvm_deallocate_pages(r_dealloc, SMALL_REGION_SIZE, 0);\n\t\t\t}\n\t\t\treturn FALSE; // Caller need not unlock\n\t\t}\n\t}\n\treturn TRUE; // Caller must do SZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr)\n}\n#endif // CONFIG_RECIRC_DEPOT\n\nstatic MALLOC_INLINE boolean_t\nsmall_free_no_lock(rack_t *rack, magazine_t *small_mag_ptr, mag_index_t mag_index, region_t region, void *ptr, msize_t msize)\n{\n\tmsize_t *meta_headers = SMALL_META_HEADER_FOR_PTR(ptr);\n\tunsigned index = SMALL_META_INDEX_FOR_PTR(ptr);\n\tsize_t original_size = SMALL_BYTES_FOR_MSIZE(msize);\n\tunsigned char *next_block = ((unsigned char *)ptr + original_size);\n\tmsize_t next_index = index + msize;\n\n\tMALLOC_TRACE(TRACE_small_free, (uintptr_t)rack, (uintptr_t)small_mag_ptr, (uintptr_t)ptr, SMALL_BYTES_FOR_MSIZE(msize));\n\n#if CONFIG_AGGRESSIVE_MADVISE || CONFIG_RECIRC_DEPOT\n\tvoid *original_ptr = ptr;\n#endif\n\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"in small_free_no_lock(), ptr=%p, msize=%d\\n\", ptr, msize);\n\t}\n\tif (!msize) {\n\t\tmalloc_zone_error(rack->debug_flags, true, \"trying to free small block that is too small in small_free_no_lock(), ptr=%p, msize=%d\\n\",\n\t\t\t\tptr, msize);\n\t}\n#endif\n\n\t// We try to coalesce this block with the preceeding one\n\tif (index > 0 && (meta_headers[index - 1] & SMALL_IS_FREE)) {\n\t\tmsize_t previous_msize = meta_headers[index - 1] & ~SMALL_IS_FREE;\n\t\tgrain_t previous_index = index - previous_msize;\n\n\t\t// Check if the metadata for the start of the block is also free.\n\t\tif (meta_headers[previous_index] == (previous_msize | SMALL_IS_FREE)) {\n\t\t\tvoid *previous_ptr = (void *)((uintptr_t)ptr - SMALL_BYTES_FOR_MSIZE(previous_msize));\n\t\t\tfree_list_t previous = small_free_list_find_by_ptr(rack, small_mag_ptr, previous_ptr, previous_msize);\n\t\t\tsmall_free_list_remove_ptr(rack, small_mag_ptr, previous, previous_msize);\n\t\t\tptr = previous_ptr;\n\t\t\tsmall_meta_header_set_middle(meta_headers, index); // This block is now a middle block.\n\t\t\tmsize += previous_msize;\n\t\t\tindex -= previous_msize;\n\t\t} else {\n\t\t\t_os_set_crash_log_message(\"small free list metadata inconsistency (headers[previous] != previous size)\");\n\t\t\t__builtin_trap();\n\t\t}\n\t}\n\n\t// Try to coalesce with this block with the next block\n\tif ((next_block < SMALL_REGION_END(region)) && (meta_headers[next_index] & SMALL_IS_FREE)) {\n\t\tmsize_t next_msize = meta_headers[next_index] & ~SMALL_IS_FREE;\n\t\tfree_list_t next = small_free_list_find_by_ptr(rack, small_mag_ptr, next_block, next_msize);\n\t\tsmall_free_list_remove_ptr(rack, small_mag_ptr, next, next_msize);\n\t\tmsize += next_msize;\n\t}\n\n\tif (rack->debug_flags & MALLOC_DO_SCRIBBLE) {\n\t\tif (!msize) {\n\t\t\tmalloc_zone_error(rack->debug_flags, true, \"incorrect size information for %p - block header was damaged\\n\", ptr);\n\t\t} else {\n\t\t\tmemset(ptr, SCRABBLE_BYTE, SMALL_BYTES_FOR_MSIZE(msize));\n\t\t}\n\t}\n\n\tfree_list_t freee = small_free_list_add_ptr(rack, small_mag_ptr, ptr, msize);\n\n\t// use original_size and not msize to avoid double counting the coalesced blocks\n\tsmall_mag_ptr->mag_num_bytes_in_objects -= original_size;\n\tsmall_mag_ptr->mag_num_objects--;\n\n\t// Update this region's bytes in use count\n\tregion_trailer_t *node = REGION_TRAILER_FOR_SMALL_REGION(region);\n\tsize_t bytes_used = node->bytes_used - original_size;\n\tnode->bytes_used = (unsigned int)bytes_used;\n\n#if CONFIG_AGGRESSIVE_MADVISE\n\tsmall_madvise_free_range_no_lock(rack, small_mag_ptr, region, freee, msize, original_ptr, original_size);\n#endif\n\n\t// Caller must do SZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr) if this function\n\t// returns TRUE.\n\tboolean_t needs_unlock = TRUE;\n\n#if CONFIG_RECIRC_DEPOT\n\tneeds_unlock = small_free_try_recirc_to_depot(rack, small_mag_ptr, mag_index, region, freee, msize, original_ptr, original_size);\n#endif\n\treturn needs_unlock;\n}\n\n// Allocates from the last region or a freshly allocated region\nstatic void *\nsmall_malloc_from_region_no_lock(rack_t *rack,\n\t\t\t\t\t\t\t\t magazine_t *small_mag_ptr,\n\t\t\t\t\t\t\t\t mag_index_t mag_index,\n\t\t\t\t\t\t\t\t msize_t msize,\n\t\t\t\t\t\t\t\t void *aligned_address)\n{\n\tvoid *ptr;\n\n\t// Before anything we transform the mag_bytes_free_at_end or mag_bytes_free_at_start - if any - to a regular free block\n\t/* FIXME: last_block needs to be coalesced with previous entry if free, <rdar://5462322> */\n\tif (small_mag_ptr->mag_bytes_free_at_end || small_mag_ptr->mag_bytes_free_at_start) {\n\t\tsmall_finalize_region(rack, small_mag_ptr);\n\t}\n\n\t// Tag the region at \"aligned_address\" as belonging to us,\n\t// and so put it under the protection of the magazine lock we are holding.\n\t// Do this before advertising \"aligned_address\" on the hash ring(!)\n\tMAGAZINE_INDEX_FOR_SMALL_REGION(aligned_address) = mag_index;\n\n\t// Insert the new region into the hash ring\n\track_region_insert(rack, (region_t)aligned_address);\n\n\tsmall_mag_ptr->mag_last_region = aligned_address;\n\tBYTES_USED_FOR_SMALL_REGION(aligned_address) = SMALL_BYTES_FOR_MSIZE(msize);\n\n#if CONFIG_ASLR_INTERNAL\n\tint offset_msize = malloc_entropy[1] & SMALL_ENTROPY_MASK;\n#if DEBUG_MALLOC\n\tif (getenv(\"MallocASLRForce\")) {\n\t\toffset_msize = strtol(getenv(\"MallocASLRForce\"), NULL, 0) & SMALL_ENTROPY_MASK;\n\t}\n\tif (getenv(\"MallocASLRPrint\")) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"Region: %p offset: %d\\n\", aligned_address, offset_msize);\n\t}\n#endif\n#else\n\tint offset_msize = 0;\n#endif\n\tptr = (void *)((uintptr_t)aligned_address + SMALL_BYTES_FOR_MSIZE(offset_msize));\n\tsmall_meta_header_set_in_use(SMALL_META_HEADER_FOR_PTR(ptr), offset_msize, msize);\n\tsmall_mag_ptr->mag_num_objects++;\n\tsmall_mag_ptr->mag_num_bytes_in_objects += SMALL_BYTES_FOR_MSIZE(msize);\n\tsmall_mag_ptr->num_bytes_in_magazine += SMALL_REGION_PAYLOAD_BYTES;\n\n\t// add a big free block at the end\n\tsmall_meta_header_set_in_use(SMALL_META_HEADER_FOR_PTR(ptr), offset_msize + msize, NUM_SMALL_BLOCKS - msize - offset_msize);\n\tsmall_mag_ptr->mag_bytes_free_at_end = SMALL_BYTES_FOR_MSIZE(NUM_SMALL_BLOCKS - msize - offset_msize);\n\n#if CONFIG_ASLR_INTERNAL\n\t// add a big free block at the start\n\tsmall_mag_ptr->mag_bytes_free_at_start = SMALL_BYTES_FOR_MSIZE(offset_msize);\n\tif (offset_msize) {\n\t\tsmall_meta_header_set_in_use(SMALL_META_HEADER_FOR_PTR(ptr), 0, offset_msize);\n\t}\n#else\n\tsmall_mag_ptr->mag_bytes_free_at_start = 0;\n#endif\n\n\t// connect to magazine as last node\n\trecirc_list_splice_last(rack, small_mag_ptr, REGION_TRAILER_FOR_SMALL_REGION(aligned_address));\n\n\treturn ptr;\n}\n\nvoid *\nsmall_memalign(szone_t *szone, size_t alignment, size_t size, size_t span)\n{\n\tmsize_t mspan = SMALL_MSIZE_FOR_BYTES(span + SMALL_QUANTUM - 1);\n\tvoid *p = small_malloc_should_clear(&szone->small_rack, mspan, 0);\n\n\tif (NULL == p) {\n\t\treturn NULL;\n\t}\n\n\tsize_t offset = ((uintptr_t)p) & (alignment - 1);\t// p % alignment\n\tsize_t pad = (0 == offset) ? 0 : alignment - offset; // p + pad achieves desired alignment\n\n\tmsize_t msize = SMALL_MSIZE_FOR_BYTES(size + SMALL_QUANTUM - 1);\n\tmsize_t mpad = SMALL_MSIZE_FOR_BYTES(pad + SMALL_QUANTUM - 1);\n\tmsize_t mwaste = mspan - msize - mpad; // excess blocks\n\n\tif (mpad > 0) {\n\t\tvoid *q = (void *)(((uintptr_t)p) + pad);\n\n\t\t// Mark q as block header and in-use, thus creating two blocks.\n\t\tmagazine_t *small_mag_ptr = mag_lock_zine_for_region_trailer(szone->small_rack.magazines,\n\t\t\t\tREGION_TRAILER_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(p)),\n\t\t\t\tMAGAZINE_INDEX_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(p)));\n\t\tsmall_meta_header_set_in_use(SMALL_META_HEADER_FOR_PTR(p), SMALL_META_INDEX_FOR_PTR(p), mpad);\n\t\tsmall_meta_header_set_in_use(SMALL_META_HEADER_FOR_PTR(q), SMALL_META_INDEX_FOR_PTR(q), msize + mwaste);\n\t\tsmall_mag_ptr->mag_num_objects++;\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\n\t\t// Give up mpad blocks beginning at p to the small free list\n\t\tfree_small(&szone->small_rack, p, SMALL_REGION_FOR_PTR(p), SMALL_BYTES_FOR_MSIZE(mpad));\n\n\t\tp = q; // advance p to the desired alignment\n\t}\n\tif (mwaste > 0) {\n\t\tvoid *q = (void *)(((uintptr_t)p) + SMALL_BYTES_FOR_MSIZE(msize));\n\t\t// Mark q as block header and in-use, thus creating two blocks.\n\t\tmagazine_t *small_mag_ptr = mag_lock_zine_for_region_trailer(szone->small_rack.magazines,\n\t\t\t\tREGION_TRAILER_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(p)),\n\t\t\t\tMAGAZINE_INDEX_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(p)));\n\t\tsmall_meta_header_set_in_use(SMALL_META_HEADER_FOR_PTR(p), SMALL_META_INDEX_FOR_PTR(p), msize);\n\t\tsmall_meta_header_set_in_use(SMALL_META_HEADER_FOR_PTR(q), SMALL_META_INDEX_FOR_PTR(q), mwaste);\n\t\tsmall_mag_ptr->mag_num_objects++;\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\n\t\t// Give up mwaste blocks beginning at q to the small free list\n\t\tfree_small(&szone->small_rack, q, SMALL_REGION_FOR_PTR(q), SMALL_BYTES_FOR_MSIZE(mwaste));\n\t}\n\n\treturn p; // p has the desired size and alignment, and can later be free()'d\n}\n\nboolean_t\nsmall_claimed_address(rack_t *rack, void *ptr)\n{\n\tregion_t r = small_region_for_ptr_no_lock(rack, ptr);\n\treturn r && ptr < (void *)SMALL_REGION_END(r);\n}\n\nvoid *\nsmall_try_shrink_in_place(rack_t *rack, void *ptr, size_t old_size, size_t new_good_size)\n{\n\tmsize_t new_msize = SMALL_MSIZE_FOR_BYTES(new_good_size);\n\tmsize_t mshrinkage = SMALL_MSIZE_FOR_BYTES(old_size) - new_msize;\n\n\tif (mshrinkage) {\n\t\tvoid *q = (void *)((uintptr_t)ptr + SMALL_BYTES_FOR_MSIZE(new_msize));\n\t\tmagazine_t *small_mag_ptr = mag_lock_zine_for_region_trailer(rack->magazines,\n\t\t\t\tREGION_TRAILER_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(ptr)),\n\t\t\t\tMAGAZINE_INDEX_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(ptr)));\n\n\t\t// Mark q as block header and in-use, thus creating two blocks.\n\t\tsmall_meta_header_set_in_use(SMALL_META_HEADER_FOR_PTR(ptr), SMALL_META_INDEX_FOR_PTR(ptr), new_msize);\n\t\tsmall_meta_header_set_in_use(SMALL_META_HEADER_FOR_PTR(q), SMALL_META_INDEX_FOR_PTR(q), mshrinkage);\n\t\tsmall_mag_ptr->mag_num_objects++;\n\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\tfree_small(rack, q, SMALL_REGION_FOR_PTR(q), 0);\n\t}\n\n\treturn ptr;\n}\n\nboolean_t\nsmall_try_realloc_in_place(rack_t *rack, void *ptr, size_t old_size, size_t new_size)\n{\n\t// returns 1 on success\n\tmsize_t *meta_headers = SMALL_META_HEADER_FOR_PTR(ptr);\n\tunsigned index;\n\tmsize_t old_msize, new_msize;\n\tunsigned next_index;\n\tvoid *next_block;\n\tmsize_t next_msize_and_free;\n\tboolean_t is_free;\n\tmsize_t next_msize, leftover_msize;\n\tvoid *leftover;\n\n\tindex = SMALL_META_INDEX_FOR_PTR(ptr);\n\told_msize = SMALL_MSIZE_FOR_BYTES(old_size);\n\tnew_msize = SMALL_MSIZE_FOR_BYTES(new_size + SMALL_QUANTUM - 1);\n\tnext_index = index + old_msize;\n\n\tif (next_index >= NUM_SMALL_BLOCKS) {\n\t\treturn 0;\n\t}\n\tnext_block = (char *)ptr + old_size;\n\n#if DEBUG_MALLOC\n\tif ((uintptr_t)next_block & (SMALL_QUANTUM - 1)) {\n\t\tmalloc_zone_error(rack->debug_flags, true, \"internal invariant broken in realloc(next_block) for %p\\n\", next_block);\n\t}\n\tif (meta_headers[index] != old_msize) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"*** small_try_realloc_in_place incorrect old %d %d\\n\", meta_headers[index], old_msize);\n\t}\n#endif\n\n\tmagazine_t *small_mag_ptr = mag_lock_zine_for_region_trailer(rack->magazines,\n\t\t\tREGION_TRAILER_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(ptr)),\n\t\t\tMAGAZINE_INDEX_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(ptr)));\n\tif (DEPOT_MAGAZINE_INDEX == MAGAZINE_INDEX_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(ptr))) {\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\treturn 0;\n\t}\n\n\tmsize_t coalesced_msize = new_msize - old_msize;\n#if CONFIG_SMALL_CACHE\n\tvoid *last_free_ptr = small_mag_ptr->mag_last_free;\n\tmsize_t last_free_msize = small_mag_ptr->mag_last_free_msize;\n\tif (last_free_ptr == next_block && old_msize + last_free_msize >= new_msize) {\n\t\t/*\n\t\t * There is a block in mag_last_free and it's immediately after\n\t\t * this block and it's large enough. We can use some or all of it.\n\t\t */\n\t\tleftover_msize = last_free_msize - coalesced_msize;\n\t\tif (leftover_msize) {\n\t\t\tsmall_mag_ptr->mag_last_free_msize -= coalesced_msize;\n\t\t\tsmall_mag_ptr->mag_last_free += new_size - old_size;\n\t\t\t// The block in mag_last_free is still marked as header and in-use, so copy that\n\t\t\t// state to the block that remains. The state for the block that we're going to\n\t\t\t// use is adjusted by the small_meta_header_set_middle() call below.\n\t\t\tsmall_meta_header_set_in_use(meta_headers, index + new_msize, leftover_msize);\n\t\t} else {\n\t\t\t// Using the whole block.\n\t\t\tsmall_mag_ptr->mag_last_free = NULL;\n\t\t\tsmall_mag_ptr->mag_last_free_msize = 0;\n\t\t\tsmall_mag_ptr->mag_last_free_rgn = NULL;\n\t\t}\n\t\tsmall_meta_header_set_in_use(meta_headers, index, new_msize);\n\t\tsmall_meta_header_set_middle(meta_headers, next_index);\n\t} else {\n#endif // CONFIG_SMALL_CACHE\n\t\t/*\n\t\t * Try to expand into unused space immediately after this block.\n\t\t */\n\t\tmsize_t unused_msize = SMALL_MSIZE_FOR_BYTES(small_mag_ptr->mag_bytes_free_at_end);\n\t\tvoid *unused_start = SMALL_REGION_END(SMALL_REGION_FOR_PTR(ptr)) - small_mag_ptr->mag_bytes_free_at_end;\n\t\tif (small_mag_ptr->mag_last_region == SMALL_REGION_FOR_PTR(ptr)\n\t\t\t\t&& coalesced_msize < unused_msize && unused_start == ptr + old_size) {\n\t\t\t// Extend the in-use for this block to the new size\n\t\t\tsmall_meta_header_set_in_use(meta_headers, index, new_msize);\n\n\t\t\t// Clear the in-use size for the start of the area we extended into\n\t\t\tsmall_meta_header_set_middle(meta_headers, next_index);\n\n\t\t\t// Reduce mag_bytes_free_at_end and update its in-use size.\n\t\t\tsmall_mag_ptr->mag_bytes_free_at_end -= SMALL_BYTES_FOR_MSIZE(coalesced_msize);\n\t\t\tsmall_meta_header_set_in_use(meta_headers, index + new_msize, SMALL_MSIZE_FOR_BYTES(small_mag_ptr->mag_bytes_free_at_end));\n\t\t} else {\n\t\t\t/*\n\t\t\t * Look for a free block immediately afterwards.  If it's large enough, we can consume (part of)\n\t\t\t * it.\n\t\t\t */\n\t\t\tnext_msize_and_free = meta_headers[next_index];\n\t\t\tis_free = next_msize_and_free & SMALL_IS_FREE;\n\t\t\tif (!is_free) {\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\t\treturn 0; // next_block is in use;\n\t\t\t}\n\n\t\t\tnext_msize = next_msize_and_free & ~SMALL_IS_FREE;\n\t\t\tif (old_msize + next_msize < new_msize) {\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\t\treturn 0; // even with next block, not enough\n\t\t\t}\n\n\t\t\t// The following block is big enough; pull it from its freelist and chop off enough to satisfy\n\t\t\t// our needs.\n\t\t\tfree_list_t freee = small_free_list_find_by_ptr(rack, small_mag_ptr, next_block, next_msize);\n\t\t\tsmall_free_list_remove_ptr(rack, small_mag_ptr, freee, next_msize);\n\t\t\tsmall_meta_header_set_middle(meta_headers, next_index);\n\t\t\tleftover_msize = old_msize + next_msize - new_msize;\n\t\t\tif (leftover_msize) {\n\t\t\t\t/* there's some left, so put the remainder back */\n\t\t\t\tleftover = (unsigned char *)ptr + SMALL_BYTES_FOR_MSIZE(new_msize);\n\t\t\t\tsmall_free_list_add_ptr(rack, small_mag_ptr, leftover, leftover_msize);\n\t\t\t}\n\t\t\tsmall_meta_header_set_in_use(meta_headers, index, new_msize);\n\t\t}\n#if CONFIG_SMALL_CACHE\n\t}\n#endif // CONFIG_SMALL_CACHE\n#if DEBUG_MALLOC\n\tif (SMALL_BYTES_FOR_MSIZE(new_msize) > szone->large_threshold) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"*** realloc in place for %p exceeded msize=%d\\n\", new_msize);\n\t}\n\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"in small_try_realloc_in_place(), ptr=%p, msize=%d\\n\", ptr, *SMALL_METADATA_FOR_PTR(ptr));\n\t}\n#endif\n\tsmall_mag_ptr->mag_num_bytes_in_objects += SMALL_BYTES_FOR_MSIZE(new_msize - old_msize);\n\n\t// Update this region's bytes in use count\n\tregion_trailer_t *node = REGION_TRAILER_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(ptr));\n\tsize_t bytes_used = node->bytes_used + SMALL_BYTES_FOR_MSIZE(new_msize - old_msize);\n\tnode->bytes_used = (unsigned int)bytes_used;\n\n\t// Emptiness discriminant\n\tif (bytes_used < DENSITY_THRESHOLD(SMALL_REGION_PAYLOAD_BYTES)) {\n\t\t/* After this reallocation the region is still sparse, so it must have been even more so before\n\t\t * the reallocation. That implies the region is already correctly marked. Do nothing. */\n\t} else {\n\t\t/* Region has crossed threshold from sparsity to density. Mark it not \"suitable\" on the\n\t\t * recirculation candidates list. */\n\t\tnode->recirc_suitable = FALSE;\n\t}\n\n\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\tCHECK(szone, __PRETTY_FUNCTION__);\n\treturn 1;\n}\n\nstatic char *small_check_fail_msg = \"check: incorrect small region \";\n\n#define SMALL_CHECK_FAIL(fmt, ...) \\\n\tmalloc_zone_check_fail(small_check_fail_msg, \\\n\t\t\t\"%ld, counter=%d\\n\" fmt,  region_index, counter, __VA_ARGS__);\n\nboolean_t\nsmall_check_region(rack_t *rack, region_t region, size_t region_index,\n\t\tunsigned counter)\n{\n\tunsigned char *ptr = SMALL_REGION_ADDRESS(region);\n\tmsize_t *meta_headers = SMALL_META_HEADER_FOR_PTR(ptr);\n\tunsigned char *region_end = SMALL_REGION_END(region);\n\tmsize_t prev_free = 0;\n\tunsigned index;\n\tmsize_t msize_and_free;\n\tmsize_t msize;\n\tfree_list_t free_head, previous, next;\n\tmsize_t *follower;\n\tmag_index_t mag_index = MAGAZINE_INDEX_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(ptr));\n\tmagazine_t *small_mag_ptr = &(rack->magazines[mag_index]);\n\n\t// Assumes locked\n\tCHECK_MAGAZINE_PTR_LOCKED(szone, small_mag_ptr, __PRETTY_FUNCTION__);\n\n\tif (region == small_mag_ptr->mag_last_region) {\n\t\tptr += small_mag_ptr->mag_bytes_free_at_start;\n\t\tregion_end -= small_mag_ptr->mag_bytes_free_at_end;\n\t}\n\n\twhile (ptr < region_end) {\n\t\tindex = SMALL_META_INDEX_FOR_PTR(ptr);\n\t\tmsize_and_free = meta_headers[index];\n\t\tif (!(msize_and_free & SMALL_IS_FREE)) {\n\t\t\t// block is in use\n\t\t\tmsize = msize_and_free;\n\t\t\tif (!msize) {\n\t\t\t\tSMALL_CHECK_FAIL(\"*** invariant broken: null msize ptr=%p num_small_regions=%d end=%p\\n\", ptr,\n\t\t\t\t\t\t\t  (int)rack->num_regions, region_end);\n\t\t\t\treturn 0;\n\t\t\t}\n#if !CONFIG_RELAXED_INVARIANT_CHECKS\n\t\t\tif (SMALL_BYTES_FOR_MSIZE(msize) > szone->large_threshold) {\n\t\t\t\tSMALL_CHECK_FAIL(\"*** invariant broken for %p this small msize=%d - size is too large\\n\", ptr, msize_and_free);\n\t\t\t\treturn 0;\n\t\t\t}\n#endif // CONFIG_RELAXED_INVARIANT_CHECKS\n\t\t\tptr += SMALL_BYTES_FOR_MSIZE(msize);\n\t\t\tprev_free = 0;\n\t\t} else {\n\t\t\t// free pointer\n\t\t\tmsize = msize_and_free & ~SMALL_IS_FREE;\n\t\t\tfree_head = (free_list_t){ .p = ptr };\n\t\t\tfollower = (msize_t *)FOLLOWING_SMALL_PTR(ptr, msize);\n\t\t\tif (!msize) {\n\t\t\t\tSMALL_CHECK_FAIL(\"*** invariant broken for free block %p this msize=%d\\n\", ptr, msize);\n\t\t\t\treturn 0;\n\t\t\t}\n#if !CONFIG_RELAXED_INVARIANT_CHECKS\n\t\t\tif (prev_free) {\n\t\t\t\tSMALL_CHECK_FAIL(\"*** invariant broken for %p (2 free in a row)\\n\", ptr);\n\t\t\t\treturn 0;\n\t\t\t}\n#endif\n\n\t\t\t// <rdar://problem/24680189> check for possible OOB entry if needed\n\t\t\tif (small_needs_oob_free_entry(ptr, msize)) {\n\t\t\t\toob_free_entry_t oob = small_oob_free_find_ptr(ptr, msize);\n\t\t\t\tif (oob) {\n\t\t\t\t\tfree_head.oob = oob;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprevious = small_free_list_get_previous(rack, free_head);\n\t\t\tnext = small_free_list_get_next(rack, free_head);\n\t\t\tif (previous.p && !SMALL_PTR_IS_FREE(small_free_list_get_ptr(rack, previous))) {\n\t\t\t\tSMALL_CHECK_FAIL(\"*** invariant broken for %p (previous %p is not a free pointer)\\n\", ptr, small_free_list_get_ptr(rack, previous));\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (next.p && !SMALL_PTR_IS_FREE(small_free_list_get_ptr(rack, next))) {\n\t\t\t\tSMALL_CHECK_FAIL(\"*** invariant broken for %p (next %p is not a free pointer)\\n\", ptr, small_free_list_get_ptr(rack, next));\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (SMALL_PREVIOUS_MSIZE(follower) != msize) {\n\t\t\t\tSMALL_CHECK_FAIL(\"*** invariant broken for small free %p followed by %p in region [%p-%p] \"\n\t\t\t\t\t\t\"(end marker incorrect) should be %d; in fact %d\\n\",\n\t\t\t\t\t\tptr, follower, SMALL_REGION_ADDRESS(region), region_end, msize, SMALL_PREVIOUS_MSIZE(follower));\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tptr = (unsigned char *)follower;\n\t\t\tprev_free = SMALL_IS_FREE;\n\t\t}\n\t}\n\treturn 1;\n}\n\nkern_return_t\nsmall_in_use_enumerator(task_t task,\n\t\t\t\t\t\tvoid *context,\n\t\t\t\t\t\tunsigned type_mask,\n\t\t\t\t\t\tszone_t *szone,\n\t\t\t\t\t\tmemory_reader_t reader,\n\t\t\t\t\t\tvm_range_recorder_t recorder)\n{\n\tsize_t num_regions;\n\tsize_t index;\n\tregion_t *regions;\n\tvm_range_t buffer[MAX_RECORDER_BUFFER];\n\tunsigned count = 0;\n\tkern_return_t err;\n\tregion_t region;\n\tvm_range_t range;\n\tvm_range_t admin_range;\n\tvm_range_t ptr_range;\n\tunsigned char *mapped_region;\n\tmsize_t *block_header;\n\tunsigned block_index;\n\tunsigned block_limit;\n\tmsize_t msize_and_free;\n\tmsize_t msize;\n\tmagazine_t *small_mag_base = NULL;\n\n\tregion_hash_generation_t *srg_ptr;\n\terr = reader(task, (vm_address_t)szone->small_rack.region_generation, sizeof(region_hash_generation_t), (void **)&srg_ptr);\n\tif (err) {\n\t\treturn err;\n\t}\n\n\tnum_regions = srg_ptr->num_regions_allocated;\n\terr = reader(task, (vm_address_t)srg_ptr->hashed_regions, sizeof(region_t) * num_regions, (void **)&regions);\n\tif (err) {\n\t\treturn err;\n\t}\n\n\tif (type_mask & MALLOC_PTR_IN_USE_RANGE_TYPE) {\n\t\t// Map in all active magazines. Do this outside the iteration over regions.\n\t\terr = reader(task, (vm_address_t)(szone->small_rack.magazines), szone->small_rack.num_magazines * sizeof(magazine_t),\n\t\t\t\t\t (void **)&small_mag_base);\n\t\tif (err) {\n\t\t\treturn err;\n\t\t}\n\t}\n\n\tfor (index = 0; index < num_regions; ++index) {\n\t\tregion = regions[index];\n\t\tif (HASHRING_OPEN_ENTRY != region && HASHRING_REGION_DEALLOCATED != region) {\n\t\t\trange.address = (vm_address_t)SMALL_REGION_ADDRESS(region);\n\t\t\trange.size = SMALL_REGION_SIZE;\n\t\t\tif (type_mask & MALLOC_ADMIN_REGION_RANGE_TYPE) {\n\t\t\t\tadmin_range.address = range.address + SMALL_METADATA_START;\n\t\t\t\tadmin_range.size = SMALL_METADATA_SIZE;\n\t\t\t\trecorder(task, context, MALLOC_ADMIN_REGION_RANGE_TYPE, &admin_range, 1);\n\t\t\t}\n\t\t\tif (type_mask & (MALLOC_PTR_REGION_RANGE_TYPE | MALLOC_ADMIN_REGION_RANGE_TYPE)) {\n\t\t\t\tptr_range.address = range.address;\n\t\t\t\tptr_range.size = NUM_SMALL_BLOCKS * SMALL_QUANTUM;\n\t\t\t\trecorder(task, context, MALLOC_PTR_REGION_RANGE_TYPE, &ptr_range, 1);\n\t\t\t}\n\t\t\tif (type_mask & MALLOC_PTR_IN_USE_RANGE_TYPE) {\n\t\t\t\tvm_address_t mag_last_free = 0;\n\t\t\t\tmsize_t mag_last_free_msize = 0;\n\n\t\t\t\terr = reader(task, range.address, range.size, (void **)&mapped_region);\n\t\t\t\tif (err) {\n\t\t\t\t\treturn err;\n\t\t\t\t}\n\n\t\t\t\tmag_index_t mag_index = MAGAZINE_INDEX_FOR_SMALL_REGION(mapped_region);\n\t\t\t\tmagazine_t *small_mag_ptr = small_mag_base + mag_index;\n\n\t\t\t\tif (DEPOT_MAGAZINE_INDEX != mag_index) {\n\t\t\t\t\tmag_last_free = (uintptr_t)small_mag_ptr->mag_last_free;\n\t\t\t\t\tmag_last_free_msize = small_mag_ptr->mag_last_free_msize;\n\t\t\t\t} else {\n\t\t\t\t\tfor (mag_index = 0; mag_index < szone->small_rack.num_magazines; mag_index++) {\n\t\t\t\t\t\tif ((void *)range.address == (small_mag_base + mag_index)->mag_last_free_rgn) {\n\t\t\t\t\t\t\tmag_last_free = (uintptr_t)(small_mag_base + mag_index)->mag_last_free;\n\t\t\t\t\t\t\tmag_last_free_msize = (small_mag_base + mag_index)->mag_last_free_msize;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tblock_header = (msize_t *)(mapped_region + SMALL_METADATA_START + sizeof(region_trailer_t));\n\t\t\t\tblock_index = 0;\n\t\t\t\tblock_limit = NUM_SMALL_BLOCKS;\n\t\t\t\tif (region == small_mag_ptr->mag_last_region) {\n\t\t\t\t\tblock_index += SMALL_MSIZE_FOR_BYTES(small_mag_ptr->mag_bytes_free_at_start);\n\t\t\t\t\tblock_limit -= SMALL_MSIZE_FOR_BYTES(small_mag_ptr->mag_bytes_free_at_end);\n\t\t\t\t}\n\t\t\t\twhile (block_index < block_limit) {\n\t\t\t\t\tmsize_and_free = block_header[block_index];\n\t\t\t\t\tmsize = msize_and_free & ~SMALL_IS_FREE;\n\t\t\t\t\tif (!(msize_and_free & SMALL_IS_FREE) &&\n\t\t\t\t\t\trange.address + SMALL_BYTES_FOR_MSIZE(block_index) != mag_last_free) {\n\t\t\t\t\t\t// Block in use\n\t\t\t\t\t\tbuffer[count].address = range.address + SMALL_BYTES_FOR_MSIZE(block_index);\n\t\t\t\t\t\tbuffer[count].size = SMALL_BYTES_FOR_MSIZE(msize);\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t\tif (count >= MAX_RECORDER_BUFFER) {\n\t\t\t\t\t\t\trecorder(task, context, MALLOC_PTR_IN_USE_RANGE_TYPE, buffer, count);\n\t\t\t\t\t\t\tcount = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!msize) {\n\t\t\t\t\t\treturn KERN_FAILURE; // Somethings amiss. Avoid looping at this block_index.\n\t\t\t\t\t}\n\t\t\t\t\tblock_index += msize;\n\t\t\t\t}\n\t\t\t\tif (count) {\n\t\t\t\t\trecorder(task, context, MALLOC_PTR_IN_USE_RANGE_TYPE, buffer, count);\n\t\t\t\t\tcount = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn 0;\n}\n\nstatic void *\nsmall_malloc_from_free_list(rack_t *rack, magazine_t *small_mag_ptr, mag_index_t mag_index, msize_t msize)\n{\n\tmsize_t this_msize;\n\tgrain_t slot = SMALL_FREE_SLOT_FOR_MSIZE(rack, msize);\n\tfree_list_t *free_list = small_mag_ptr->mag_free_list;\n\tfree_list_t *the_slot = free_list + slot;\n\tfree_list_t *limit;\n\tunsigned bitmap;\n\tmsize_t leftover_msize;\n\tvoid *leftover_ptr;\n\tvoid *ptr;\n\n\t// Assumes we've locked the region\n\tCHECK_MAGAZINE_PTR_LOCKED(szone, small_mag_ptr, __PRETTY_FUNCTION__);\n\n\t// Look for an exact match by checking the freelist for this msize.\n\tif (small_free_list_get_ptr(rack, *the_slot)) {\n\t\tptr = small_free_list_get_ptr(rack, *the_slot);\n\t\tthis_msize = msize;\n\t\tsmall_free_list_remove_ptr(rack, small_mag_ptr, *the_slot, msize);\n\t\tgoto return_small_alloc;\n\t}\n\n\t// Mask off the bits representing slots holding free blocks smaller than\n\t// the size we need.  If there are no larger free blocks, try allocating\n\t// from the free space at the end of the small region.\n\tif (SMALL_FREELIST_BITMAP_WORDS(rack) > 1) {\n\t\t// BITMAPN_CTZ implementation\n\t\tunsigned idx = slot >> 5;\n\t\tbitmap = 0;\n\t\tunsigned mask = ~((1 << (slot & 31)) - 1);\n\t\tfor (; idx < SMALL_FREELIST_BITMAP_WORDS(rack); ++idx) {\n\t\t\tbitmap = small_mag_ptr->mag_bitmap[idx] & mask;\n\t\t\tif (bitmap != 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmask = ~0U;\n\t\t}\n\t\t// Check for fallthrough: No bits set in bitmap\n\t\tif ((bitmap == 0) && (idx == SMALL_FREELIST_BITMAP_WORDS(rack))) {\n\t\t\tgoto try_small_from_end;\n\t\t}\n\n\t\t// Start looking at the first set bit, plus 32 bits for every word of\n\t\t// zeroes or entries that were too small.\n\t\tslot = BITMAP32_CTZ((&bitmap)) + (idx * 32);\n\t} else {\n\t\tbitmap = small_mag_ptr->mag_bitmap[0] & ~((1 << slot) - 1);\n\t\tif (!bitmap) {\n\t\t\tgoto try_small_from_end;\n\t\t}\n\n\t\tslot = BITMAP32_CTZ((&bitmap));\n\t}\n\t// FIXME: Explain use of - 1 here, last slot has special meaning\n\tlimit = free_list + SMALL_FREE_SLOT_COUNT(rack) - 1;\n\tfree_list += slot;\n\n\t// Attempt to pull off the free_list slot that we now think is full.\n\tif ((ptr = small_free_list_get_ptr(rack, *free_list))) {\n\t\tthis_msize = SMALL_PTR_SIZE(ptr);\n\t\tsmall_free_list_remove_ptr(rack, small_mag_ptr, *free_list, this_msize);\n\t\tgoto add_leftover_and_proceed;\n\t}\n\n#if DEBUG_MALLOC\n\tmalloc_report(ASL_LEVEL_ERR, \"in small_malloc_from_free_list(), mag_bitmap out of sync, slot=%d\\n\", slot);\n#endif\n\ntry_small_from_end:\n\t// Let's see if we can use small_mag_ptr->mag_bytes_free_at_end\n\tif (small_mag_ptr->mag_bytes_free_at_end >= SMALL_BYTES_FOR_MSIZE(msize)) {\n\t\tptr = SMALL_REGION_END(small_mag_ptr->mag_last_region) - small_mag_ptr->mag_bytes_free_at_end;\n\t\tsmall_mag_ptr->mag_bytes_free_at_end -= SMALL_BYTES_FOR_MSIZE(msize);\n\t\tif (small_mag_ptr->mag_bytes_free_at_end) {\n\t\t\t// let's mark this block as in use to serve as boundary\n\t\t\tsmall_meta_header_set_in_use(SMALL_META_HEADER_FOR_PTR(ptr),\n\t\t\t\t\t\t\t\t\t\t SMALL_META_INDEX_FOR_PTR((unsigned char *)ptr + SMALL_BYTES_FOR_MSIZE(msize)),\n\t\t\t\t\t\t\t\t\t\t SMALL_MSIZE_FOR_BYTES(small_mag_ptr->mag_bytes_free_at_end));\n\t\t}\n\t\tthis_msize = msize;\n\t\tgoto return_small_alloc;\n\t}\n#if CONFIG_ASLR_INTERNAL\n\t// Try from start if nothing left at end\n\tif (small_mag_ptr->mag_bytes_free_at_start >= SMALL_BYTES_FOR_MSIZE(msize)) {\n\t\tptr = SMALL_REGION_ADDRESS(small_mag_ptr->mag_last_region) + small_mag_ptr->mag_bytes_free_at_start -\n\t\t\t\tSMALL_BYTES_FOR_MSIZE(msize);\n\t\tsmall_mag_ptr->mag_bytes_free_at_start -= SMALL_BYTES_FOR_MSIZE(msize);\n\t\tif (small_mag_ptr->mag_bytes_free_at_start) {\n\t\t\t// let's mark this block as in use to serve as boundary\n\t\t\tsmall_meta_header_set_in_use(\n\t\t\t\t\t\t\t\t\t\t SMALL_META_HEADER_FOR_PTR(ptr), 0, SMALL_MSIZE_FOR_BYTES(small_mag_ptr->mag_bytes_free_at_start));\n\t\t}\n\t\tthis_msize = msize;\n\t\tgoto return_small_alloc;\n\t}\n#endif\n\treturn NULL;\n\nadd_leftover_and_proceed:\n\tif (this_msize > msize) {\n\t\tleftover_msize = this_msize - msize;\n\t\tleftover_ptr = (unsigned char *)ptr + SMALL_BYTES_FOR_MSIZE(msize);\n#if DEBUG_MALLOC\n\t\tif (LOG(szone, ptr)) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"in small_malloc_from_free_list(), adding leftover ptr=%p, this_msize=%d\\n\", ptr, this_msize);\n\t\t}\n#endif\n\t\tsmall_free_list_add_ptr(rack, small_mag_ptr, leftover_ptr, leftover_msize);\n\t\tthis_msize = msize;\n\t}\n\nreturn_small_alloc:\n\tsmall_mag_ptr->mag_num_objects++;\n\tsmall_mag_ptr->mag_num_bytes_in_objects += SMALL_BYTES_FOR_MSIZE(this_msize);\n\n\t// Update this region's bytes in use count\n\tregion_trailer_t *node = REGION_TRAILER_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(ptr));\n\tsize_t bytes_used = node->bytes_used + SMALL_BYTES_FOR_MSIZE(this_msize);\n\tnode->bytes_used = (unsigned int)bytes_used;\n\n\t// Emptiness discriminant\n\tif (bytes_used < DENSITY_THRESHOLD(SMALL_REGION_PAYLOAD_BYTES)) {\n\t\t/* After this allocation the region is still sparse, so it must have been even more so before\n\t\t * the allocation. That implies the region is already correctly marked. Do nothing. */\n\t} else {\n\t\t/* Region has crossed threshold from sparsity to density. Mark in not \"suitable\" on the\n\t\t * recirculation candidates list. */\n\t\tnode->recirc_suitable = FALSE;\n\t}\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"in small_malloc_from_free_list(), ptr=%p, this_msize=%d, msize=%d\\n\", ptr, this_msize, msize);\n\t}\n#endif\n\tsmall_meta_header_set_in_use(SMALL_META_HEADER_FOR_PTR(ptr), SMALL_META_INDEX_FOR_PTR(ptr), this_msize);\n\treturn ptr;\n}\n\nvoid *\nsmall_malloc_should_clear(rack_t *rack, msize_t msize, boolean_t cleared_requested)\n{\n\tvoid *ptr;\n\tmag_index_t mag_index = small_mag_get_thread_index() % rack->num_magazines;\n\tmagazine_t *small_mag_ptr = &(rack->magazines[mag_index]);\n\n\tMALLOC_TRACE(TRACE_small_malloc, (uintptr_t)rack, SMALL_BYTES_FOR_MSIZE(msize), (uintptr_t)small_mag_ptr, cleared_requested);\n\n\tSZONE_MAGAZINE_PTR_LOCK(small_mag_ptr);\n\n#if CONFIG_SMALL_CACHE\n\tptr = small_mag_ptr->mag_last_free;\n\n\tif (small_mag_ptr->mag_last_free_msize == msize) {\n\t\t// we have a winner\n\t\tsmall_mag_ptr->mag_last_free = NULL;\n\t\tsmall_mag_ptr->mag_last_free_msize = 0;\n\t\tsmall_mag_ptr->mag_last_free_rgn = NULL;\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\tCHECK(szone, __PRETTY_FUNCTION__);\n\t\tif (cleared_requested) {\n\t\t\tmemset(ptr, 0, SMALL_BYTES_FOR_MSIZE(msize));\n\t\t}\n\t\treturn ptr;\n\t}\n#endif /* CONFIG_SMALL_CACHE */\n\n\twhile (1) {\n\t\tptr = small_malloc_from_free_list(rack, small_mag_ptr, mag_index, msize);\n\t\tif (ptr) {\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\tCHECK(szone, __PRETTY_FUNCTION__);\n\t\t\tif (cleared_requested) {\n\t\t\t\tmemset(ptr, 0, SMALL_BYTES_FOR_MSIZE(msize));\n\t\t\t}\n\t\t\treturn ptr;\n\t\t}\n\n\t\tif (small_get_region_from_depot(rack, small_mag_ptr, mag_index, msize)) {\n\t\t\tptr = small_malloc_from_free_list(rack, small_mag_ptr, mag_index, msize);\n\t\t\tif (ptr) {\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\t\tCHECK(szone, __PRETTY_FUNCTION__);\n\t\t\t\tif (cleared_requested) {\n\t\t\t\t\tmemset(ptr, 0, SMALL_BYTES_FOR_MSIZE(msize));\n\t\t\t\t}\n\t\t\t\treturn ptr;\n\t\t\t}\n\t\t}\n\n\t\t// The magazine is exhausted. A new region (heap) must be allocated to satisfy this call to malloc().\n\t\t// The allocation, an mmap() system call, will be performed outside the magazine spin locks by the first\n\t\t// thread that suffers the exhaustion. That thread sets \"alloc_underway\" and enters a critical section.\n\t\t// Threads arriving here later are excluded from the critical section, yield the CPU, and then retry the\n\t\t// allocation. After some time the magazine is resupplied, the original thread leaves with its allocation,\n\t\t// and retry-ing threads succeed in the code just above.\n\t\tif (!small_mag_ptr->alloc_underway) {\n\t\t\tvoid *fresh_region;\n\n\t\t\t// time to create a new region (do this outside the magazine lock)\n\t\t\tsmall_mag_ptr->alloc_underway = TRUE;\n\t\t\tOSMemoryBarrier();\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\tfresh_region = mvm_allocate_pages_securely(SMALL_REGION_SIZE, SMALL_BLOCKS_ALIGN, VM_MEMORY_MALLOC_SMALL, rack->debug_flags);\n\t\t\tSZONE_MAGAZINE_PTR_LOCK(small_mag_ptr);\n\n\t\t\t// DTrace USDT Probe\n\t\t\tMAGMALLOC_ALLOCREGION(SMALL_SZONE_FROM_RACK(rack), (int)mag_index, fresh_region, SMALL_REGION_SIZE);\n\n\t\t\tif (!fresh_region) { // out of memory!\n\t\t\t\tsmall_mag_ptr->alloc_underway = FALSE;\n\t\t\t\tOSMemoryBarrier();\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\t\treturn NULL;\n\t\t\t}\n\n\t\t\tptr = small_malloc_from_region_no_lock(rack, small_mag_ptr, mag_index, msize, fresh_region);\n\n\t\t\t// we don't clear because this freshly allocated space is pristine\n\t\t\tsmall_mag_ptr->alloc_underway = FALSE;\n\t\t\tOSMemoryBarrier();\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\tCHECK(szone, __PRETTY_FUNCTION__);\n\t\t\treturn ptr;\n\t\t} else {\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\tyield();\n\t\t\tSZONE_MAGAZINE_PTR_LOCK(small_mag_ptr);\n\t\t}\n\t}\n\t/* NOTREACHED */\n}\n\nsize_t\nsmall_size(rack_t *rack, const void *ptr)\n{\n\tif (small_region_for_ptr_no_lock(rack, ptr)) {\n\t\tif (SMALL_META_INDEX_FOR_PTR(ptr) >= NUM_SMALL_BLOCKS) {\n\t\t\treturn 0;\n\t\t}\n\t\tmsize_t msize_and_free = *SMALL_METADATA_FOR_PTR(ptr);\n\t\tif (msize_and_free & SMALL_IS_FREE) {\n\t\t\treturn 0;\n\t\t}\n#if CONFIG_SMALL_CACHE\n\t\t{\n\t\t\tmag_index_t mag_index = MAGAZINE_INDEX_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(ptr));\n\t\t\tif (DEPOT_MAGAZINE_INDEX != mag_index) {\n\t\t\t\tmagazine_t *small_mag_ptr = &(rack->magazines[mag_index]);\n\n\t\t\t\tif (ptr == small_mag_ptr->mag_last_free) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (mag_index = 0; mag_index < rack->num_magazines; mag_index++) {\n\t\t\t\t\tmagazine_t *small_mag_ptr = &(rack->magazines[mag_index]);\n\n\t\t\t\t\tif (ptr == small_mag_ptr->mag_last_free) {\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n#endif\n\t\treturn SMALL_BYTES_FOR_MSIZE(msize_and_free);\n\t}\n\n\treturn 0;\n}\n\nstatic MALLOC_NOINLINE void\nfree_small_botch(rack_t *rack, void *ptr)\n{\n\tmag_index_t mag_index = MAGAZINE_INDEX_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(ptr));\n\tmagazine_t *small_mag_ptr = &(rack->magazines[mag_index]);\n\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\tmalloc_zone_error(rack->debug_flags, true, \"double free for ptr %p\\n\", ptr);\n}\n\nvoid\nfree_small(rack_t *rack, void *ptr, region_t small_region, size_t known_size)\n{\n\tmsize_t msize;\n\tmag_index_t mag_index = MAGAZINE_INDEX_FOR_SMALL_REGION(SMALL_REGION_FOR_PTR(ptr));\n\tmagazine_t *small_mag_ptr = &(rack->magazines[mag_index]);\n\n\t// ptr is known to be in small_region\n\tif (known_size) {\n\t\tmsize = SMALL_MSIZE_FOR_BYTES(known_size + SMALL_QUANTUM - 1);\n\t} else {\n\t\tmsize = SMALL_PTR_SIZE(ptr);\n\t\tif (SMALL_PTR_IS_FREE(ptr)) {\n\t\t\tfree_small_botch(rack, ptr);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tSZONE_MAGAZINE_PTR_LOCK(small_mag_ptr);\n\n#if CONFIG_SMALL_CACHE\n\t// Depot does not participate in CONFIG_SMALL_CACHE since it can't be directly malloc()'d\n\tif (DEPOT_MAGAZINE_INDEX != mag_index) {\n\t\tvoid *ptr2 = small_mag_ptr->mag_last_free; // Might be NULL\n\t\tmsize_t msize2 = small_mag_ptr->mag_last_free_msize;\n\t\tregion_t rgn2 = small_mag_ptr->mag_last_free_rgn;\n\n\t\t/* check that we don't already have this pointer in the cache */\n\t\tif (ptr == ptr2) {\n\t\t\tfree_small_botch(rack, ptr);\n\t\t\treturn;\n\t\t}\n\n\t\tif ((rack->debug_flags & MALLOC_DO_SCRIBBLE) && msize) {\n\t\t\tmemset(ptr, SCRABBLE_BYTE, SMALL_BYTES_FOR_MSIZE(msize));\n\t\t}\n\n\t\tsmall_mag_ptr->mag_last_free = ptr;\n\t\tsmall_mag_ptr->mag_last_free_msize = msize;\n\t\tsmall_mag_ptr->mag_last_free_rgn = small_region;\n\n\t\tif (!ptr2) {\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\tCHECK(szone, __PRETTY_FUNCTION__);\n\t\t\treturn;\n\t\t}\n\n\t\tmsize = msize2;\n\t\tptr = ptr2;\n\t\tsmall_region = rgn2;\n\t}\n#endif /* CONFIG_SMALL_CACHE */\n\n\t// Now in the time it took to acquire the lock, the region may have migrated\n\t// from one magazine to another. I.e. trailer->mag_index is volatile.\n\t// In which case the magazine lock we obtained (namely magazines[mag_index].mag_lock)\n\t// is stale. If so, keep on tryin' ...\n\tregion_trailer_t *trailer = REGION_TRAILER_FOR_SMALL_REGION(small_region);\n\tmag_index_t refreshed_index;\n\n\twhile (mag_index != (refreshed_index = trailer->mag_index)) { // Note assignment\n\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\n\t\tmag_index = refreshed_index;\n\t\tsmall_mag_ptr = &(rack->magazines[mag_index]);\n\t\tSZONE_MAGAZINE_PTR_LOCK(small_mag_ptr);\n\t}\n\n\tif (small_free_no_lock(rack, small_mag_ptr, mag_index, small_region, ptr, msize)) {\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t}\n\n\tCHECK(szone, __PRETTY_FUNCTION__);\n}\n\nvoid\nprint_small_free_list(rack_t *rack)\n{\n\tfree_list_t ptr;\n\t_SIMPLE_STRING b = _simple_salloc();\n\tmag_index_t mag_index;\n\n\tif (b) {\n\t\t_simple_sappend(b, \"small free sizes:\\n\");\n\t\tfor (mag_index = -1; mag_index < rack->num_magazines; mag_index++) {\n\t\t\tgrain_t slot = 0;\n\t\t\t_simple_sprintf(b, \"\\tMagazine %d: \", mag_index);\n\t\t\twhile (slot < SMALL_FREE_SLOT_COUNT(rack)) {\n\t\t\t\tptr = rack->magazines[mag_index].mag_free_list[slot];\n\t\t\t\tif (small_free_list_get_ptr(rack, ptr)) {\n\t\t\t\t\t_simple_sprintf(b, \"%s%y[%d]; \", (slot == SMALL_FREE_SLOT_COUNT(rack) - 1) ? \">=\" : \"\", (slot + 1) * SMALL_QUANTUM,\n\t\t\t\t\t\t\t\t\tsmall_free_list_count(rack, ptr));\n\t\t\t\t}\n\t\t\t\tslot++;\n\t\t\t}\n\t\t\t_simple_sappend(b, \"\\n\");\n\t\t}\n\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"%s\\n\", _simple_string(b));\n\t\t_simple_sfree(b);\n\t}\n}\n\nvoid\nprint_small_region(szone_t *szone, boolean_t verbose, region_t region, size_t bytes_at_start, size_t bytes_at_end)\n{\n\tunsigned counts[1024];\n\tunsigned in_use = 0;\n\tuintptr_t start = (uintptr_t)SMALL_REGION_ADDRESS(region);\n\tuintptr_t current = start + bytes_at_start;\n\tuintptr_t limit = (uintptr_t)SMALL_REGION_END(region) - bytes_at_end;\n\tmsize_t msize_and_free;\n\tmsize_t msize;\n\tunsigned ci;\n\t_SIMPLE_STRING b;\n\tuintptr_t pgTot = 0;\n\n\tif (region == HASHRING_REGION_DEALLOCATED) {\n\t\tif ((b = _simple_salloc()) != NULL) {\n\t\t\t_simple_sprintf(b, \"Small region [unknown address] was returned to the OS\\n\");\n\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"%s\\n\", _simple_string(b));\n\t\t\t_simple_sfree(b);\n\t\t}\n\t\treturn;\n\t}\n\n\tmemset(counts, 0, sizeof(counts));\n\twhile (current < limit) {\n\t\tmsize_and_free = *SMALL_METADATA_FOR_PTR(current);\n\t\tmsize = msize_and_free & ~SMALL_IS_FREE;\n\t\tif (!msize) {\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** error with %p: msize=%d\\n\", (void *)current, (unsigned)msize);\n\t\t\tbreak;\n\t\t}\n\t\tif (!(msize_and_free & SMALL_IS_FREE)) {\n\t\t\t// block in use\n\t\t\tif (msize < 1024) {\n\t\t\t\tcounts[msize]++;\n\t\t\t}\n\t\t\tin_use++;\n\t\t} else {\n\t\t\tuintptr_t pgLo = round_page_quanta(current + sizeof(free_list_t) + sizeof(msize_t));\n\t\t\tuintptr_t pgHi = trunc_page_quanta(current + SMALL_BYTES_FOR_MSIZE(msize) - sizeof(msize_t));\n\n\t\t\tif (pgLo < pgHi) {\n\t\t\t\tpgTot += (pgHi - pgLo);\n\t\t\t}\n\t\t}\n\t\tcurrent += SMALL_BYTES_FOR_MSIZE(msize);\n\t}\n\tif ((b = _simple_salloc()) != NULL) {\n\t\t_simple_sprintf(b, \"Small region [%p-%p, %y] \\t\", (void *)start, SMALL_REGION_END(region), (int)SMALL_REGION_SIZE);\n\t\t_simple_sprintf(b, \"Magazine=%d \\t\", MAGAZINE_INDEX_FOR_SMALL_REGION(region));\n\t\t_simple_sprintf(b, \"Allocations in use=%d \\t Bytes in use=%ly \\t\", in_use, BYTES_USED_FOR_SMALL_REGION(region));\n\t\tif (bytes_at_end || bytes_at_start) {\n\t\t\t_simple_sprintf(b, \"Untouched=%ly \", bytes_at_end + bytes_at_start);\n\t\t}\n\t\tif (DEPOT_MAGAZINE_INDEX == MAGAZINE_INDEX_FOR_SMALL_REGION(region)) {\n\t\t\t_simple_sprintf(b, \"Advised MADV_FREE=%ly\", pgTot);\n\t\t} else {\n\t\t\t_simple_sprintf(b, \"Fragments subject to reclamation=%ly\", pgTot);\n\t\t}\n\t\tif (verbose && in_use) {\n\t\t\t_simple_sappend(b, \"\\n\\tSizes in use: \");\n\t\t\tfor (ci = 0; ci < 1024; ci++) {\n\t\t\t\tif (counts[ci]) {\n\t\t\t\t\t_simple_sprintf(b, \"%d[%d] \", SMALL_BYTES_FOR_MSIZE(ci), counts[ci]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"%s\\n\", _simple_string(b));\n\t\t_simple_sfree(b);\n\t}\n}\n\nstatic char *small_freelist_fail_msg = \"check: small free list incorrect\";\n\n#define SMALL_FREELIST_FAIL(fmt, ...) \\\n\tmalloc_zone_check_fail(small_freelist_fail_msg, \\\n\t\t\t\" (slot=%u), counter=%d\\n\" fmt,  slot, counter, __VA_ARGS__);\n\nboolean_t\nsmall_free_list_check(rack_t *rack, grain_t slot, unsigned counter)\n{\n\tmag_index_t mag_index;\n\n\tfor (mag_index = -1; mag_index < rack->num_magazines; mag_index++) {\n\t\tmagazine_t *small_mag_ptr = &(rack->magazines[mag_index]);\n\t\tSZONE_MAGAZINE_PTR_LOCK(small_mag_ptr);\n\n\t\tunsigned count = 0;\n\t\tfree_list_t current = rack->magazines[mag_index].mag_free_list[slot];\n\t\tfree_list_t previous = (free_list_t){ .p = NULL };\n\t\tmsize_t msize_and_free;\n\t\tvoid *ptr = NULL;\n\n\t\twhile ((ptr = small_free_list_get_ptr(rack, current))) {\n\t\t\tmsize_and_free = *SMALL_METADATA_FOR_PTR(ptr);\n\t\t\tif (!(msize_and_free & SMALL_IS_FREE)) {\n\t\t\t\tSMALL_FREELIST_FAIL(\"*** in-use ptr in free list slot=%u count=%d ptr=%p\\n\", slot, count, ptr);\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (((uintptr_t)ptr) & (SMALL_QUANTUM - 1)) {\n\t\t\t\tSMALL_FREELIST_FAIL(\"*** unaligned ptr in free list slot=%u count=%d ptr=%p\\n\", slot, count, ptr);\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (!small_region_for_ptr_no_lock(rack, ptr)) {\n\t\t\t\tSMALL_FREELIST_FAIL(\"*** ptr not in szone slot=%d count=%d ptr=%p\\n\", slot, count, ptr);\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (small_free_list_get_previous(rack, current).p != previous.p) {\n\t\t\t\tSMALL_FREELIST_FAIL(\"*** previous incorrectly set slot=%u count=%d ptr=%p\\n\", slot, count, ptr);\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tprevious = current;\n\t\t\tcurrent = small_free_list_get_next(rack, current);\n\t\t\tcount++;\n\t\t}\n\t\t\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(small_mag_ptr);\n\t}\n\treturn 1;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/magazine_tiny.c",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"internal.h\"\n\n// The address and size of the block in mag_last_free are combined. These\n// macros abstract construction of the combined value and extraction of the\n// size and pointer.\n#define TINY_MAG_LAST_FREE_FROM_PTR_AND_MSIZE(ptr, msize) (void *)(((uintptr_t)(ptr))|((msize_t)msize))\n#define TINY_PTR_FROM_MAG_LAST_FREE(x) (void *)(((uintptr_t)(x)) & ~(TINY_QUANTUM - 1))\n#define TINY_MSIZE_FROM_MAG_LAST_FREE(x) (msize_t)(((uintptr_t)(x)) & (TINY_QUANTUM - 1))\n\n// Adjusts the pointer part of mag_last_free by a given amount in bytes. Must be\n// a multiple of the quantum size (not checked).\n#define TINY_MAG_LAST_FREE_PTR_ADJUST_PTR(x, size) (x) = ((void *)(x) + (size))\n\n// Decrements the size part of mag_last_free by a given msize value. Must not\n// reduce the msize part below zero (not checked).\n#define TINY_MAG_LAST_FREE_PTR_DEC_MSIZE(x, msize_delta) (x) = ((void *)(x) - (msize_delta))\n\nstatic MALLOC_INLINE MALLOC_ALWAYS_INLINE\nmag_index_t\ntiny_mag_get_thread_index(void)\n{\n#if CONFIG_TINY_USES_HYPER_SHIFT\n\tif (os_likely(_os_cpu_number_override == -1)) {\n\t\treturn _os_cpu_number() >> hyper_shift;\n\t} else {\n\t\treturn _os_cpu_number_override >> hyper_shift;\n\t}\n#else // CONFIG_SMALL_USES_HYPER_SHIFT\n\tif (os_likely(_os_cpu_number_override == -1)) {\n\t\treturn _os_cpu_number();\n\t} else {\n\t\treturn _os_cpu_number_override;\n\t}\n#endif // CONFIG_SMALL_USES_HYPER_SHIFT\n}\n\n/*\n * Get the size of the previous free block, which is stored in the last two\n * bytes of the block.  If the previous block is not free, then the result is\n * undefined.\n */\nstatic msize_t\nget_tiny_previous_free_msize(const void *ptr)\n{\n\t// check whether the previous block is in the tiny region and a block header\n\t// if so, then the size of the previous block is one, and there is no stored\n\t// size.\n\tif (ptr != TINY_REGION_FOR_PTR(ptr)) {\n\t\tvoid *prev_block = (void *)((uintptr_t)ptr - TINY_QUANTUM);\n\t\tuint32_t *prev_header = TINY_BLOCK_HEADER_FOR_PTR(prev_block);\n\t\tmsize_t prev_index = TINY_INDEX_FOR_PTR(prev_block);\n\t\tif (BITARRAY_BIT(prev_header, prev_index)) {\n\t\t\treturn 1;\n\t\t}\n\t\treturn TINY_PREVIOUS_MSIZE(ptr);\n\t}\n\t// don't read possibly unmapped memory before the beginning of the region\n\treturn 0;\n}\n\nstatic MALLOC_INLINE void\nset_tiny_meta_header_in_use(const void *ptr, msize_t msize)\n{\n\tuint32_t *block_header = TINY_BLOCK_HEADER_FOR_PTR(ptr);\n\tmsize_t index = TINY_INDEX_FOR_PTR(ptr);\n\tmsize_t clr_msize = msize - 1;\n\tmsize_t midx = (index >> 5) << 1;\n\tuint32_t val = (1 << (index & 31));\n\n#if DEBUG_MALLOC\n\tif (msize >= NUM_TINY_SLOTS) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"set_tiny_meta_header_in_use() invariant broken %p %d\\n\", ptr, msize);\n\t}\n\tif ((unsigned)index + (unsigned)msize > 0x10000) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"set_tiny_meta_header_in_use() invariant broken (2) %p %d\\n\", ptr, msize);\n\t}\n#endif\n\n\tblock_header[midx] |= val;\t // BITARRAY_SET(block_header, index);\n\tblock_header[midx + 1] |= val; // BITARRAY_SET(in_use, index);\n\n\t// bitarray_mclr(block_header, index, end_bit);\n\t// bitarray_mclr(in_use, index, end_bit);\n\n\tindex++;\n\tmidx = (index >> 5) << 1;\n\n\tunsigned start = index & 31;\n\tunsigned end = start + clr_msize;\n\n#if defined(__LP64__)\n\tif (end > 63) {\n\t\tunsigned mask0 = (0xFFFFFFFFU >> (31 - start)) >> 1;\n\t\tunsigned mask1 = (0xFFFFFFFFU << (end - 64));\n\t\tblock_header[midx + 0] &= mask0; // clear header\n\t\tblock_header[midx + 1] &= mask0; // clear in_use\n\t\tblock_header[midx + 2] = 0;\t\t // clear header\n\t\tblock_header[midx + 3] = 0;\t\t // clear in_use\n\t\tblock_header[midx + 4] &= mask1; // clear header\n\t\tblock_header[midx + 5] &= mask1; // clear in_use\n\t} else\n#endif\n\t\tif (end > 31) {\n\t\t\tunsigned mask0 = (0xFFFFFFFFU >> (31 - start)) >> 1;\n\t\t\tunsigned mask1 = (0xFFFFFFFFU << (end - 32));\n\t\t\tblock_header[midx + 0] &= mask0;\n\t\t\tblock_header[midx + 1] &= mask0;\n\t\t\tblock_header[midx + 2] &= mask1;\n\t\t\tblock_header[midx + 3] &= mask1;\n\t\t} else {\n\t\t\tunsigned mask = (0xFFFFFFFFU >> (31 - start)) >> 1;\n\t\t\tmask |= (0xFFFFFFFFU << end);\n\t\t\tblock_header[midx + 0] &= mask;\n\t\t\tblock_header[midx + 1] &= mask;\n\t\t}\n\n\t// we set the block_header bit for the following block to reaffirm next block is a block\n\tindex += clr_msize;\n\tmidx = (index >> 5) << 1;\n\tval = (1 << (index & 31));\n\tblock_header[midx] |= val; // BITARRAY_SET(block_header, (index+clr_msize));\n#if DEBUG_MALLOC\n\t{\n\t\tboolean_t ff;\n\t\tmsize_t mf;\n\n\t\tmf = get_tiny_meta_header(ptr, &ff);\n\t\tif (msize != mf) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"setting header for tiny in_use %p : %d\\n\", ptr, msize);\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"reading header for tiny %p : %d %d\\n\", ptr, mf, ff);\n\t\t}\n\t}\n#endif\n}\n\nstatic MALLOC_INLINE void set_tiny_meta_header_in_use_1(const void *ptr) // As above with msize == 1\n{\n\tuint32_t *block_header = TINY_BLOCK_HEADER_FOR_PTR(ptr);\n\tmsize_t index = TINY_INDEX_FOR_PTR(ptr);\n\tmsize_t midx = (index >> 5) << 1;\n\tuint32_t val = (1 << (index & 31));\n\n\tblock_header[midx] |= val;\t // BITARRAY_SET(block_header, index);\n\tblock_header[midx + 1] |= val; // BITARRAY_SET(in_use, index);\n\n\tindex++;\n\tmidx = (index >> 5) << 1;\n\tval = (1 << (index & 31));\n\n\tblock_header[midx] |= val; // BITARRAY_SET(block_header, (index+clr_msize))\n}\n\nstatic MALLOC_INLINE void\nset_tiny_meta_header_middle(const void *ptr)\n{\n\t// indicates this block is in the middle of an in use block\n\tuint32_t *block_header;\n\tuint32_t *in_use;\n\tmsize_t index;\n\n\tblock_header = TINY_BLOCK_HEADER_FOR_PTR(ptr);\n\tin_use = TINY_INUSE_FOR_HEADER(block_header);\n\tindex = TINY_INDEX_FOR_PTR(ptr);\n\n\tBITARRAY_CLR(block_header, index);\n\tBITARRAY_CLR(in_use, index);\n}\n\nstatic MALLOC_INLINE void\nset_tiny_meta_header_free(const void *ptr, msize_t msize)\n{\n\t// !msize is acceptable and means 65536\n\tuint32_t *block_header = TINY_BLOCK_HEADER_FOR_PTR(ptr);\n\tmsize_t index = TINY_INDEX_FOR_PTR(ptr);\n\tmsize_t midx = (index >> 5) << 1;\n\tuint32_t val = (1 << (index & 31));\n\n#if DEBUG_MALLOC\n\tif ((unsigned)index + (unsigned)msize > 0x10000) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"setting header for tiny free %p msize too large: %d\\n\", ptr, msize);\n\t}\n#endif\n\n\tblock_header[midx] |= val;\t\t// BITARRAY_SET(block_header, index);\n\tblock_header[midx + 1] &= ~val; // BITARRAY_CLR(in_use, index);\n\n\t// mark the end of this block if msize is > 1.  For msize == 0, the whole\n\t// region is free, so there is no following block. For msize == 1, there is\n\t// no space to write the size on 64 bit systems.  The size for 1 quantum\n\t// blocks is computed from the metadata bitmaps.\n\tif (msize > 1) {\n\t\tvoid *follower = FOLLOWING_TINY_PTR(ptr, msize);\n\t\tTINY_PREVIOUS_MSIZE(follower) = msize;\n\t\tTINY_FREE_SIZE(ptr) = msize;\n\t}\n\tif (msize == 0) {\n\t\tTINY_FREE_SIZE(ptr) = msize;\n\t}\n#if DEBUG_MALLOC\n\tboolean_t ff;\n\tmsize_t mf = get_tiny_meta_header(ptr, &ff);\n\tif ((msize != mf) || !ff) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"setting header for tiny free %p : %u\\n\", ptr, msize);\n\t\tmalloc_report(ASL_LEVEL_INFO, \"reading header for tiny %p : %u %u\\n\", ptr, mf, ff);\n\t}\n#endif\n}\n\nstatic MALLOC_INLINE boolean_t\ntiny_meta_header_is_free(const void *ptr)\n{\n\tuint32_t *block_header;\n\tuint32_t *in_use;\n\tmsize_t index;\n\n\tblock_header = TINY_BLOCK_HEADER_FOR_PTR(ptr);\n\tin_use = TINY_INUSE_FOR_HEADER(block_header);\n\tindex = TINY_INDEX_FOR_PTR(ptr);\n\tif (!BITARRAY_BIT(block_header, index)) {\n\t\treturn 0;\n\t}\n\treturn !BITARRAY_BIT(in_use, index);\n}\n\nstatic MALLOC_INLINE void *\ntiny_previous_preceding_free(void *ptr, msize_t *prev_msize)\n{\n\t// returns the previous block, assuming and verifying it's free\n\tuint32_t *block_header;\n\tuint32_t *in_use;\n\tmsize_t index;\n\tmsize_t previous_msize;\n\tmsize_t previous_index;\n\tvoid *previous_ptr;\n\n\tblock_header = TINY_BLOCK_HEADER_FOR_PTR(ptr);\n\tin_use = TINY_INUSE_FOR_HEADER(block_header);\n\tindex = TINY_INDEX_FOR_PTR(ptr);\n\n\tif (!index) {\n\t\treturn NULL;\n\t}\n\tif ((previous_msize = get_tiny_previous_free_msize(ptr)) > index) {\n\t\treturn NULL;\n\t}\n\n\tprevious_index = index - previous_msize;\n\tprevious_ptr = (void *)((uintptr_t)TINY_REGION_FOR_PTR(ptr) + TINY_BYTES_FOR_MSIZE(previous_index));\n\tif (!BITARRAY_BIT(block_header, previous_index)) {\n\t\treturn NULL;\n\t}\n\tif (BITARRAY_BIT(in_use, previous_index)) {\n\t\treturn NULL;\n\t}\n\tif (get_tiny_free_size(previous_ptr) != previous_msize) {\n\t\treturn NULL;\n\t}\n\n\t// conservative check did match true check\n\t*prev_msize = previous_msize;\n\treturn previous_ptr;\n}\n\n/*\n * Adds an item to the proper free list, and also marks the meta-header of the\n * block properly.\n * Assumes szone has been locked\n */\nstatic void\ntiny_free_list_add_ptr(rack_t *rack, magazine_t *tiny_mag_ptr, void *ptr, msize_t msize)\n{\n\tgrain_t slot = (!msize || (msize >= NUM_TINY_SLOTS)) ? NUM_TINY_SLOTS - 1 : msize - 1;\n\ttiny_free_list_t *free_ptr = ptr;\n\ttiny_free_list_t *free_head = tiny_mag_ptr->mag_free_list[slot].p;\n\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"in %s, ptr=%p, msize=%d\\n\", __FUNCTION__, ptr, msize);\n\t}\n\tif (((uintptr_t)ptr) & (TINY_QUANTUM - 1)) {\n\t\tmalloc_zone_error(rack->debug_flags, true, \"tiny_free_list_add_ptr: Unaligned ptr: %p\\n\", ptr);\n\t}\n#endif\n\tset_tiny_meta_header_free(ptr, msize);\n\tif (free_head) {\n#if DEBUG_MALLOC\n\t\tif (free_list_unchecksum_ptr(szone, &free_head->previous)) {\n\t\t\tmalloc_zone_error(rack->debug_flags, true,\n\t\t\t\t\t\"tiny_free_list_add_ptr: Internal invariant broken (free_head->previous): \"\n\t\t\t\t\t\"ptr=%p slot=%d free_head=%p previous=%p\\n\", ptr, slot, (void *)free_head, free_head->previous.p);\n\t\t}\n\t\tif (!tiny_meta_header_is_free(free_head)) {\n\t\t\tmalloc_zone_error(rack->debug_flags, true,\n\t\t\t\t\t\"tiny_free_list_add_ptr: Internal invariant broken (free_head is not a free pointer): \"\n\t\t\t\t\t\"ptr=%p slot=%d free_head=%p\\n\", ptr, slot, (void *)free_head);\n\t\t}\n#endif\n\t\tfree_head->previous.u = free_list_checksum_ptr(rack, free_ptr);\n\t} else {\n\t\tBITMAPV_SET(tiny_mag_ptr->mag_bitmap, slot);\n\t}\n\tfree_ptr->previous.u = free_list_checksum_ptr(rack, NULL);\n\tfree_ptr->next.u = free_list_checksum_ptr(rack, free_head);\n\n\ttiny_mag_ptr->mag_free_list[slot].p = free_ptr;\n}\n\n/*\n * Removes the item pointed to by ptr in the proper free list.\n * Assumes szone has been locked\n */\nstatic void\ntiny_free_list_remove_ptr(rack_t *rack, magazine_t *tiny_mag_ptr, void *ptr, msize_t msize)\n{\n\tgrain_t slot = (!msize || (msize >= NUM_TINY_SLOTS)) ? NUM_TINY_SLOTS - 1 : msize - 1;\n\ttiny_free_list_t *free_ptr = ptr, *next, *previous;\n\n\tnext = free_list_unchecksum_ptr(rack, &free_ptr->next);\n\tprevious = free_list_unchecksum_ptr(rack, &free_ptr->previous);\n\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"In %s, ptr=%p, msize=%d\\n\", __FUNCTION__, ptr, msize);\n\t}\n#endif\n\tif (!previous) {\n\t\t// The block to remove is the head of the free list\n#if DEBUG_MALLOC\n\t\tif (tiny_mag_ptr->mag_free_list[slot] != ptr) {\n\t\t\tmalloc_zone_error(rack->debug_flags, true,\n\t\t\t\t\t\"tiny_free_list_remove_ptr: Internal invariant broken (tiny_mag_ptr->mag_free_list[slot]): \"\n\t\t\t\t\t\"ptr=%p slot=%d msize=%d tiny_mag_ptr->mag_free_list[slot]=%p\\n\", ptr, slot, msize,\n\t\t\t\t\t(void *)tiny_mag_ptr->mag_free_list[slot]);\n\t\t\treturn;\n\t\t}\n#endif\n\t\ttiny_mag_ptr->mag_free_list[slot].p = next;\n\t\tif (!next) {\n\t\t\tBITMAPV_CLR(tiny_mag_ptr->mag_bitmap, slot);\n\t\t}\n\t} else {\n\t\t// Check that the next pointer of \"previous\" points to free_ptr.\n\t\ttiny_free_list_t *prev_next = free_list_unchecksum_ptr(rack, &previous->next);\n\t\tif (prev_next != free_ptr) {\n\t\t\tmalloc_zone_error(rack->debug_flags, true,\n\t\t\t\t\t\"tiny_free_list_remove_ptr: Internal invariant broken (next ptr of prev): \"\n\t\t\t\t\t\"ptr=%p, prev_next=%p\\n\", ptr, prev_next);\n\t\t\t__builtin_unreachable(); // Always crashes in malloc_zone_error().\n\t\t}\n\n\t\t// We know free_ptr is already checksummed, so we don't need to do it\n\t\t// again.\n\t\tprevious->next = free_ptr->next;\n\t}\n\tif (next) {\n\t\t// Check that the previous pointer of \"next\" points to free_ptr.\n\t\ttiny_free_list_t *next_prev = free_list_unchecksum_ptr(rack, &next->previous);\n\t\tif (next_prev != free_ptr) {\n\t\t\tmalloc_zone_error(rack->debug_flags, true,\n\t\t\t\t\t\"tiny_free_list_remove_ptr: Internal invariant broken (prev ptr of next): \"\n\t\t\t\t\t\"ptr=%p, next_prev=%p\\n\", ptr, next_prev);\n\t\t\t__builtin_unreachable(); // Always crashes in malloc_zone_error().\n\t\t}\n\n\t\t// We know free_ptr is already checksummed, so we don't need to do it\n\t\t// again.\n\t\tnext->previous = free_ptr->previous;\n\t}\n}\n\nvoid\ntiny_finalize_region(rack_t *rack, magazine_t *tiny_mag_ptr)\n{\n\tvoid *last_block, *previous_block;\n\tuint32_t *last_header;\n\tmsize_t last_msize, previous_msize, last_index;\n\n\t// It is possible that the block prior to the last block in the region has\n\t// been free'd, but was not coalesced with the free bytes at the end of the\n\t// block, since we treat the bytes at the end of the region as \"in use\" in\n\t// the meta headers. Attempt to coalesce the last block with the previous\n\t// block, so we don't violate the \"no consecutive free blocks\" invariant.\n\t//\n\t// FIXME: Need to investigate how much work would be required to increase\n\t//        'mag_bytes_free_at_end' when freeing the preceding block, rather\n\t//        than performing this workaround.\n\t//\n\n\tif (tiny_mag_ptr->mag_bytes_free_at_end) {\n\t\tlast_block = (void *)((uintptr_t)TINY_REGION_END(tiny_mag_ptr->mag_last_region) - tiny_mag_ptr->mag_bytes_free_at_end);\n\t\tlast_msize = TINY_MSIZE_FOR_BYTES(tiny_mag_ptr->mag_bytes_free_at_end);\n\t\tlast_header = TINY_BLOCK_HEADER_FOR_PTR(last_block);\n\t\tlast_index = TINY_INDEX_FOR_PTR(last_block);\n\n\t\t// Before anything we transform any remaining mag_bytes_free_at_end into a\n\t\t// regular free block.  We take special care here to update the bitfield\n\t\t// information, since we are bypassing the normal free codepath.  If there\n\t\t// is more than one quanta worth of memory in mag_bytes_free_at_end, then\n\t\t// there will be two block headers:\n\t\t// 1) header for the free space at end, msize = 1\n\t\t// 2) header inserted by set_tiny_meta_header_in_use after block\n\t\t// We must clear the second one so that when the free block's size is\n\t\t// queried, we do not think the block is only 1 quantum in size because\n\t\t// of the second set header bit.\n\t\tif (last_index != (NUM_TINY_BLOCKS - 1)) {\n\t\t\tBITARRAY_CLR(last_header, (last_index + 1));\n\t\t}\n\n\t\tprevious_block = tiny_previous_preceding_free(last_block, &previous_msize);\n\t\tif (previous_block) {\n\t\t\tset_tiny_meta_header_middle(last_block);\n\t\t\ttiny_free_list_remove_ptr(rack, tiny_mag_ptr, previous_block, previous_msize);\n\t\t\tlast_block = previous_block;\n\t\t\tlast_msize += previous_msize;\n\t\t}\n\n\t\t// splice last_block into the free list\n\t\ttiny_free_list_add_ptr(rack, tiny_mag_ptr, last_block, last_msize);\n\t\ttiny_mag_ptr->mag_bytes_free_at_end = 0;\n\t}\n\n#if CONFIG_ASLR_INTERNAL\n\t// Coalesce the big free block at start with any following free blocks\n\tif (tiny_mag_ptr->mag_bytes_free_at_start) {\n\t\tlast_block = TINY_REGION_ADDRESS(tiny_mag_ptr->mag_last_region);\n\t\tlast_msize = TINY_MSIZE_FOR_BYTES(tiny_mag_ptr->mag_bytes_free_at_start);\n\n\t\tvoid *next_block = (void *)((uintptr_t)last_block + tiny_mag_ptr->mag_bytes_free_at_start);\n\n\t\t// clear the in use bit we were using to mark the end of the big start block\n\t\tset_tiny_meta_header_middle((void *)((uintptr_t)next_block - TINY_QUANTUM));\n\n\t\t// Coalesce the big start block with any following free blocks\n\t\tif (tiny_meta_header_is_free(next_block)) {\n\t\t\tmsize_t next_msize = get_tiny_free_size(next_block);\n\t\t\tset_tiny_meta_header_middle(next_block);\n\t\t\ttiny_free_list_remove_ptr(rack, tiny_mag_ptr, next_block, next_msize);\n\t\t\tlast_msize += next_msize;\n\t\t}\n\n\t\t// splice last_block into the free list\n\t\ttiny_free_list_add_ptr(rack, tiny_mag_ptr, last_block, last_msize);\n\t\ttiny_mag_ptr->mag_bytes_free_at_start = 0;\n\t}\n#endif\n\n\ttiny_mag_ptr->mag_last_region = NULL;\n}\n\nint\ntiny_free_detach_region(rack_t *rack, magazine_t *tiny_mag_ptr, region_t r)\n{\n\tuintptr_t start = (uintptr_t)TINY_REGION_ADDRESS(r);\n\tuintptr_t current = start;\n\tuintptr_t limit = (uintptr_t)TINY_REGION_END(r);\n\tboolean_t is_free;\n\tmsize_t msize;\n\tint total_alloc = 0;\n\n\twhile (current < limit) {\n\t\tmsize = get_tiny_meta_header((void *)current, &is_free);\n\t\tif (is_free && !msize && (current == start)) {\n\t\t\t// first block is all free\n\t\t\tbreak;\n\t\t}\n\t\tif (!msize) {\n#if DEBUG_MALLOC\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** tiny_free_detach_region error with %p: msize=%d is_free=%d\\n\", (void *)current, msize, is_free);\n#endif\n\t\t\tbreak;\n\t\t}\n\t\tif (is_free) {\n\t\t\ttiny_free_list_remove_ptr(rack, tiny_mag_ptr, (void *)current, msize);\n\t\t} else {\n\t\t\ttotal_alloc++;\n\t\t}\n\t\tcurrent += TINY_BYTES_FOR_MSIZE(msize);\n\t}\n\treturn total_alloc;\n}\n\nsize_t\ntiny_free_reattach_region(rack_t *rack, magazine_t *tiny_mag_ptr, region_t r)\n{\n\tuintptr_t start = (uintptr_t)TINY_REGION_ADDRESS(r);\n\tuintptr_t current = start;\n\tuintptr_t limit = (uintptr_t)TINY_REGION_END(r);\n\tboolean_t is_free;\n\tmsize_t msize;\n\tsize_t total_alloc = 0;\n\n\twhile (current < limit) {\n\t\tmsize = get_tiny_meta_header((void *)current, &is_free);\n\t\tif (is_free && !msize && (current == start)) {\n\t\t\t// first block is all free\n\t\t\tbreak;\n\t\t}\n\t\tif (!msize) {\n#if DEBUG_MALLOC\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** tiny_free_reattach_region error with %p: msize=%d is_free=%d\\n\", (void *)current, msize, is_free);\n#endif\n\t\t\tbreak;\n\t\t}\n\t\tif (is_free) {\n\t\t\ttiny_free_list_add_ptr(rack, tiny_mag_ptr, (void *)current, msize);\n\t\t} else {\n\t\t\ttotal_alloc += TINY_BYTES_FOR_MSIZE(msize);\n\t\t}\n\t\tcurrent += TINY_BYTES_FOR_MSIZE(msize);\n\t}\n\treturn total_alloc;\n}\n\ntypedef struct {\n\tuint8_t pnum, size;\n} tiny_pg_pair_t;\n\nvoid\ntiny_free_scan_madvise_free(rack_t *rack, magazine_t *depot_ptr, region_t r)\n{\n\tuintptr_t start = (uintptr_t)TINY_REGION_ADDRESS(r);\n\tuintptr_t current = start;\n\tuintptr_t limit = (uintptr_t)TINY_REGION_END(r);\n\tboolean_t is_free;\n\tmsize_t msize;\n\ttiny_pg_pair_t advisory[((TINY_REGION_PAYLOAD_BYTES + vm_page_quanta_size - 1) >> vm_page_quanta_shift) >>\n\t\t\t\t\t\t\t1]; // 256bytes stack allocated\n\tint advisories = 0;\n\n\t// Scan the metadata identifying blocks which span one or more pages. Mark the pages MADV_FREE taking care to preserve free list\n\t// management data.\n\twhile (current < limit) {\n\t\tmsize = get_tiny_meta_header((void *)current, &is_free);\n\t\tif (is_free && !msize && (current == start)) {\n\t\t\t// first block is all free\n#if DEBUG_MALLOC\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"*** tiny_free_scan_madvise_free first block is all free! %p: msize=%d is_free=%d\\n\", (void *)current,\n\t\t\t\t\t\t  msize, is_free);\n#endif\n\t\t\tuintptr_t pgLo = round_page_kernel(start + sizeof(tiny_free_list_t) + sizeof(msize_t));\n\t\t\tuintptr_t pgHi = trunc_page_kernel(start + TINY_REGION_SIZE - sizeof(msize_t));\n\n\t\t\tif (pgLo < pgHi) {\n\t\t\t\tadvisory[advisories].pnum = (pgLo - start) >> vm_kernel_page_shift;\n\t\t\t\tadvisory[advisories].size = (pgHi - pgLo) >> vm_kernel_page_shift;\n\t\t\t\tadvisories++;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tif (!msize) {\n#if DEBUG_MALLOC\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** tiny_free_scan_madvise_free error with %p: msize=%d is_free=%d\\n\", (void *)current, msize, is_free);\n#endif\n\t\t\tbreak;\n\t\t}\n\t\tif (is_free) {\n\t\t\tuintptr_t pgLo = round_page_kernel(current + sizeof(tiny_free_list_t) + sizeof(msize_t));\n\t\t\tuintptr_t pgHi = trunc_page_kernel(current + TINY_BYTES_FOR_MSIZE(msize) - sizeof(msize_t));\n\n\t\t\tif (pgLo < pgHi) {\n\t\t\t\tadvisory[advisories].pnum = (pgLo - start) >> vm_kernel_page_shift;\n\t\t\t\tadvisory[advisories].size = (pgHi - pgLo) >> vm_kernel_page_shift;\n\t\t\t\tadvisories++;\n\t\t\t}\n\t\t}\n\t\tcurrent += TINY_BYTES_FOR_MSIZE(msize);\n\t}\n\n\tif (advisories > 0) {\n\t\tint i;\n\n\t\t// So long as the following hold for this region:\n\t\t// (1) No malloc()'s are ever performed from the depot (hence free pages remain free,)\n\t\t// (2) The region is not handed over to a per-CPU magazine (where malloc()'s could be performed),\n\t\t// (3) The entire region is not mumap()'d (so the madvise's are applied to the intended addresses),\n\t\t// then the madvise opportunities collected just above can be applied outside all locks.\n\t\t// (1) is ensured by design, (2) and (3) are ensured by bumping the globally visible counter node->pinned_to_depot.\n\n\t\tOSAtomicIncrement32Barrier(&(REGION_TRAILER_FOR_TINY_REGION(r)->pinned_to_depot));\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(depot_ptr);\n\t\tfor (i = 0; i < advisories; ++i) {\n\t\t\tuintptr_t addr = (advisory[i].pnum << vm_kernel_page_shift) + start;\n\t\t\tsize_t size = advisory[i].size << vm_kernel_page_shift;\n\n\t\t\tmvm_madvise_free(rack, r, addr, addr + size, NULL, rack->debug_flags & MALLOC_DO_SCRIBBLE);\n\t\t}\n\t\tSZONE_MAGAZINE_PTR_LOCK(depot_ptr);\n\t\tOSAtomicDecrement32Barrier(&(REGION_TRAILER_FOR_TINY_REGION(r)->pinned_to_depot));\n\t}\n}\n\nstatic region_t\ntiny_find_msize_region(rack_t *rack, magazine_t *tiny_mag_ptr, mag_index_t mag_index, msize_t msize)\n{\n\ttiny_free_list_t *ptr;\n\tgrain_t slot = msize - 1;\n\tfree_list_t *free_list = tiny_mag_ptr->mag_free_list;\n\tfree_list_t *the_slot = free_list + slot;\n\tfree_list_t *limit;\n#if defined(__LP64__)\n\tuint64_t bitmap;\n#else\n\tuint32_t bitmap;\n#endif\n\t// Assumes we've locked the magazine\n\tCHECK_MAGAZINE_PTR_LOCKED(szone, tiny_mag_ptr, __PRETTY_FUNCTION__);\n\n\t// Look for an exact match by checking the freelist for this msize.\n\tptr = the_slot->p;\n\tif (ptr) {\n\t\treturn TINY_REGION_FOR_PTR(ptr);\n\t}\n\n\t// Mask off the bits representing slots holding free blocks smaller than the\n\t// size we need.  If there are no larger free blocks, try allocating from\n\t// the free space at the end of the tiny region.\n#if defined(__LP64__)\n\tbitmap = ((uint64_t *)(tiny_mag_ptr->mag_bitmap))[0] & ~((1ULL << slot) - 1);\n#else\n\tbitmap = tiny_mag_ptr->mag_bitmap[0] & ~((1 << slot) - 1);\n#endif\n\tif (!bitmap) {\n\t\treturn NULL;\n\t}\n\n\tslot = BITMAPV_CTZ(bitmap);\n\tlimit = free_list + NUM_TINY_SLOTS - 1;\n\tfree_list += slot;\n\n\tif (free_list < limit) {\n\t\tptr = free_list->p;\n\t\tif (ptr) {\n\t\t\treturn TINY_REGION_FOR_PTR(ptr);\n\t\t} else {\n\t\t\t/* Shouldn't happen. Fall through to look at last slot. */\n#if DEBUG_MALLOC\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"in tiny_find_msize_region(), mag_bitmap out of sync, slot=%d\\n\", slot);\n#endif\n\t\t}\n\t}\n\n\t// We are now looking at the last slot, which contains blocks equal to, or\n\t// due to coalescing of free blocks, larger than (NUM_TINY_SLOTS - 1) * tiny quantum size.\n\tptr = limit->p;\n\tif (ptr) {\n\t\treturn TINY_REGION_FOR_PTR(ptr);\n\t}\n\n\treturn NULL;\n}\n\nstatic MALLOC_INLINE void\ntiny_madvise_free_range_no_lock(rack_t *rack,\n\t\t\t\t\t\t\t\tmagazine_t *tiny_mag_ptr,\n\t\t\t\t\t\t\t\tregion_t region,\n\t\t\t\t\t\t\t\tvoid *headptr,\n\t\t\t\t\t\t\t\tsize_t headsize,\n\t\t\t\t\t\t\t\tvoid *ptr,\n\t\t\t\t\t\t\t\tmsize_t msize)\n{\n\tregion_trailer_t *node = REGION_TRAILER_FOR_TINY_REGION(region);\n\n\t// Lock on tiny_magazines[mag_index] is already held here\n\t// Calculate the first page in the coalesced block that would be safe to mark MADV_FREE\n\tsize_t free_header_size = sizeof(tiny_free_list_t) + sizeof(msize_t);\n\tuintptr_t safe_ptr = (uintptr_t)ptr + free_header_size;\n\tuintptr_t round_safe = round_page_kernel(safe_ptr);\n\n\t// Calculate the last page in the coalesced block that would be safe to mark MADV_FREE\n\tsize_t free_tail_size = sizeof(msize_t);\n\tuintptr_t safe_extent = (uintptr_t)ptr + TINY_BYTES_FOR_MSIZE(msize) - free_tail_size;\n\tuintptr_t trunc_extent = trunc_page_kernel(safe_extent);\n\n\t// The newly freed block may complete a span of bytes that cover a page. Mark it with MADV_FREE.\n\tif (round_safe < trunc_extent) { // Coalesced area covers a page (perhaps many)\n\t\t// Extend the freed block by the free region header and tail sizes to include pages\n\t\t// we may have coalesced that no longer host free region tails and headers.\n\t\t// This may extend over in-use ranges, but the MIN/MAX clamping below will fix that up.\n\t\tuintptr_t lo = trunc_page_kernel((uintptr_t)headptr - free_tail_size);\n\t\tuintptr_t hi = round_page_kernel((uintptr_t)headptr + headsize + free_header_size);\n\n\t\tuintptr_t free_lo = MAX(round_safe, lo);\n\t\tuintptr_t free_hi = MIN(trunc_extent, hi);\n\n\t\tif (free_lo < free_hi) {\n\t\t\ttiny_free_list_remove_ptr(rack, tiny_mag_ptr, ptr, msize);\n\t\t\tset_tiny_meta_header_in_use(ptr, msize);\n\n\t\t\tOSAtomicIncrement32Barrier(&(node->pinned_to_depot));\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\tmvm_madvise_free(rack, region, free_lo, free_hi, &rack->last_madvise, rack->debug_flags & MALLOC_DO_SCRIBBLE);\n\t\t\tSZONE_MAGAZINE_PTR_LOCK(tiny_mag_ptr);\n\t\t\tOSAtomicDecrement32Barrier(&(node->pinned_to_depot));\n\n\t\t\tset_tiny_meta_header_free(ptr, msize);\n\t\t\ttiny_free_list_add_ptr(rack, tiny_mag_ptr, ptr, msize);\n\t\t}\n\t}\n}\n\nstatic boolean_t\ntiny_get_region_from_depot(rack_t *rack, magazine_t *tiny_mag_ptr, mag_index_t mag_index, msize_t msize)\n{\n\tmagazine_t *depot_ptr = &(rack->magazines[DEPOT_MAGAZINE_INDEX]);\n\n\t/* FIXME: Would Uniprocessor benefit from recirc and MADV_FREE? */\n\tif (rack->num_magazines == 1) { // Uniprocessor, single magazine, so no recirculation necessary\n\t\treturn 0;\n\t}\n\n#if DEBUG_MALLOC\n\tif (DEPOT_MAGAZINE_INDEX == mag_index) {\n\t\tmalloc_zone_error(rack->debug_flags, true, \"tiny_get_region_from_depot called for magazine index -1\\n\");\n\t\treturn 0;\n\t}\n#endif\n\n\tSZONE_MAGAZINE_PTR_LOCK(depot_ptr);\n\n\t// Appropriate a Depot'd region that can satisfy requested msize.\n\tregion_trailer_t *node;\n\tregion_t sparse_region;\n\n\twhile (1) {\n\t\tsparse_region = tiny_find_msize_region(rack, depot_ptr, DEPOT_MAGAZINE_INDEX, msize);\n\t\tif (NULL == sparse_region) { // Depot empty?\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(depot_ptr);\n\t\t\treturn 0;\n\t\t}\n\n\t\tnode = REGION_TRAILER_FOR_TINY_REGION(sparse_region);\n\t\tif (0 >= node->pinned_to_depot) {\n\t\t\tbreak;\n\t\t}\n\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(depot_ptr);\n\t\tyield();\n\t\tSZONE_MAGAZINE_PTR_LOCK(depot_ptr);\n\t}\n\n\t// disconnect node from Depot\n\trecirc_list_extract(rack, depot_ptr, node);\n\n\t// Iterate the region pulling its free entries off the (locked) Depot's free list\n\tint objects_in_use = tiny_free_detach_region(rack, depot_ptr, sparse_region);\n\n\t// Transfer ownership of the region\n\tMAGAZINE_INDEX_FOR_TINY_REGION(sparse_region) = mag_index;\n\tnode->pinned_to_depot = 0;\n\n\t// Iterate the region putting its free entries on its new (locked) magazine's free list\n\tsize_t bytes_inplay = tiny_free_reattach_region(rack, tiny_mag_ptr, sparse_region);\n\n\tdepot_ptr->mag_num_bytes_in_objects -= bytes_inplay;\n\tdepot_ptr->num_bytes_in_magazine -= TINY_REGION_PAYLOAD_BYTES;\n\tdepot_ptr->mag_num_objects -= objects_in_use;\n\n\ttiny_mag_ptr->mag_num_bytes_in_objects += bytes_inplay;\n\ttiny_mag_ptr->num_bytes_in_magazine += TINY_REGION_PAYLOAD_BYTES;\n\ttiny_mag_ptr->mag_num_objects += objects_in_use;\n\n\t// connect to magazine as first node\n\trecirc_list_splice_first(rack, tiny_mag_ptr, node);\n\n\tSZONE_MAGAZINE_PTR_UNLOCK(depot_ptr);\n\n\t// DTrace USDT Probe\n\tMAGMALLOC_DEPOTREGION(TINY_SZONE_FROM_RACK(rack), (int)mag_index, (void *)sparse_region,\n\t\t\tTINY_REGION_SIZE, (int)BYTES_USED_FOR_TINY_REGION(sparse_region));\n\n\treturn 1;\n}\n\n#if CONFIG_RECIRC_DEPOT\nstatic region_t\ntiny_free_try_depot_unmap_no_lock(rack_t *rack, magazine_t *depot_ptr, region_trailer_t *node)\n{\n\tif (0 < node->bytes_used || 0 < node->pinned_to_depot ||\n\t\tdepot_ptr->recirculation_entries < recirc_retained_regions)\n\t{\n\t\treturn NULL;\n\t}\n\n\t// disconnect node from Depot\n\trecirc_list_extract(rack, depot_ptr, node);\n\n\t// Iterate the region pulling its free entries off the (locked) Depot's free list\n\tregion_t sparse_region = TINY_REGION_FOR_PTR(node);\n\tint objects_in_use = tiny_free_detach_region(rack, depot_ptr, sparse_region);\n\n\tif (0 == objects_in_use) {\n\t\t// Invalidate the hash table entry for this region with HASHRING_REGION_DEALLOCATED.\n\t\t// Using HASHRING_REGION_DEALLOCATED preserves the collision chain, using HASHRING_OPEN_ENTRY (0) would not.\n\t\trgnhdl_t pSlot = hash_lookup_region_no_lock(rack->region_generation->hashed_regions,\n\t\t\t\track->region_generation->num_regions_allocated,\n\t\t\t\track->region_generation->num_regions_allocated_shift,\n\t\t\t\tsparse_region);\n\n\t\tif (NULL == pSlot) {\n\t\t\tmalloc_zone_error(rack->debug_flags, true, \"tiny_free_try_depot_unmap_no_lock hash lookup failed: %p\\n\", sparse_region);\n\t\t\treturn NULL;\n\t\t}\n\t\t*pSlot = HASHRING_REGION_DEALLOCATED;\n\t\tdepot_ptr->num_bytes_in_magazine -= TINY_REGION_PAYLOAD_BYTES;\n\n\t\t// Atomically increment num_regions_dealloc\n#ifdef __LP64___\n\t\tOSAtomicIncrement64(&rack->num_regions_dealloc);\n#else\n\t\tOSAtomicIncrement32((int32_t *)&rack->num_regions_dealloc);\n#endif\n\n\t\t// Caller will transfer ownership of the region back to the OS with no locks held\n\t\tMAGMALLOC_DEALLOCREGION(TINY_SZONE_FROM_RACK(rack), (void *)sparse_region, TINY_REGION_SIZE); // DTrace USDT Probe\n\t\treturn sparse_region;\n\t} else {\n\t\tmalloc_zone_error(rack->debug_flags, true, \"tiny_free_try_depot_unmap_no_lock objects_in_use not zero: %d\\n\", objects_in_use);\n\t\treturn NULL;\n\t}\n}\n\nstatic boolean_t\ntiny_free_do_recirc_to_depot(rack_t *rack, magazine_t *tiny_mag_ptr, mag_index_t mag_index)\n{\n\t// The entire magazine crossed the \"emptiness threshold\". Transfer a region\n\t// from this magazine to the Depot. Choose a region that itself has crossed the emptiness threshold (i.e\n\t// is at least fraction \"f\" empty.) Such a region will be marked \"suitable\" on the recirculation list.\n\tregion_trailer_t *node = tiny_mag_ptr->firstNode;\n\n\twhile (node && (!node->recirc_suitable || node->pinned_to_depot)) {\n\t\t// If we skip a node due to pinned_to_depot being non-zero, it must be\n\t\t// because another thread is madvising the same region in\n\t\t// tiny_madvise_free_range_no_lock(), called from tiny_free_no_lock().\n\t\t// When that's done, the same thread will enter tiny_free_try_recirc_to_depot()\n\t\t// for the same region, which will come back here. So this just defers\n\t\t// recirculation of the region.\n\t\tnode = node->next;\n\t}\n\n\tif (NULL == node) {\n#if DEBUG_MALLOC\n\t\tmalloc_report(ASL_LEVEL_INFO, \"*** tiny_free_do_recirc_to_depot end of list\\n\");\n#endif\n\t\treturn TRUE; // Caller must SZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t}\n\n\tregion_t sparse_region = TINY_REGION_FOR_PTR(node);\n\n\t// Deal with unclaimed memory -- mag_bytes_free_at_end or mag_bytes_free_at_start\n\tif (sparse_region == tiny_mag_ptr->mag_last_region &&\n\t\t(tiny_mag_ptr->mag_bytes_free_at_end || tiny_mag_ptr->mag_bytes_free_at_start)) {\n\t\ttiny_finalize_region(rack, tiny_mag_ptr);\n\t}\n\n\t// disconnect \"suitable\" node from magazine\n\trecirc_list_extract(rack, tiny_mag_ptr, node);\n\n\t// Iterate the region pulling its free entries off its (locked) magazine's free list\n\tint objects_in_use = tiny_free_detach_region(rack, tiny_mag_ptr, sparse_region);\n\tmagazine_t *depot_ptr = &(rack->magazines[DEPOT_MAGAZINE_INDEX]);\n\n\t// hand over the region to the (locked) Depot\n\tSZONE_MAGAZINE_PTR_LOCK(depot_ptr);\n\t// this will cause tiny_free_list_add_ptr called by tiny_free_reattach_region to use\n\t// the depot as its target magazine, rather than magazine formerly associated with sparse_region\n\tMAGAZINE_INDEX_FOR_TINY_REGION(sparse_region) = DEPOT_MAGAZINE_INDEX;\n\tnode->pinned_to_depot = 0;\n\n\t// Iterate the region putting its free entries on Depot's free list\n\tsize_t bytes_inplay = tiny_free_reattach_region(rack, depot_ptr, sparse_region);\n\n\ttiny_mag_ptr->mag_num_bytes_in_objects -= bytes_inplay;\n\ttiny_mag_ptr->num_bytes_in_magazine -= TINY_REGION_PAYLOAD_BYTES;\n\ttiny_mag_ptr->mag_num_objects -= objects_in_use;\n\n\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr); // Unlock the originating magazine\n\n\tdepot_ptr->mag_num_bytes_in_objects += bytes_inplay;\n\tdepot_ptr->num_bytes_in_magazine += TINY_REGION_PAYLOAD_BYTES;\n\tdepot_ptr->mag_num_objects += objects_in_use;\n\n\t// connect to Depot as last node\n\trecirc_list_splice_last(rack, depot_ptr, node);\n\n\tMAGMALLOC_RECIRCREGION(TINY_SZONE_FROM_RACK(rack), (int)mag_index, (void *)sparse_region, TINY_REGION_SIZE,\n\t\t\t\t\t\t   (int)BYTES_USED_FOR_TINY_REGION(sparse_region)); // DTrace USDT Probe\n\n#if !CONFIG_AGGRESSIVE_MADVISE\n\t// Mark free'd dirty pages with MADV_FREE to reduce memory pressure\n\ttiny_free_scan_madvise_free(rack, depot_ptr, sparse_region);\n#endif\n\n\t// If the region is entirely empty vm_deallocate() it outside the depot lock\n\tregion_t r_dealloc = tiny_free_try_depot_unmap_no_lock(rack, depot_ptr, node);\n\tSZONE_MAGAZINE_PTR_UNLOCK(depot_ptr);\n\tif (r_dealloc) {\n\t\tmvm_deallocate_pages(r_dealloc, TINY_REGION_SIZE, 0);\n\t}\n\treturn FALSE; // Caller need not unlock the originating magazine\n}\n\nstatic MALLOC_INLINE boolean_t\ntiny_free_try_recirc_to_depot(rack_t *rack,\n\t\t\t\t\t\t\t  magazine_t *tiny_mag_ptr,\n\t\t\t\t\t\t\t  mag_index_t mag_index,\n\t\t\t\t\t\t\t  region_t region,\n\t\t\t\t\t\t\t  void *headptr,\n\t\t\t\t\t\t\t  size_t headsize,\n\t\t\t\t\t\t\t  void *ptr,\n\t\t\t\t\t\t\t  msize_t msize)\n{\n\tregion_trailer_t *node = REGION_TRAILER_FOR_TINY_REGION(region);\n\tsize_t bytes_used = node->bytes_used;\n\n\t/* FIXME: Would Uniprocessor benefit from recirc and MADV_FREE? */\n\tif (rack->num_magazines == 1) { // Uniprocessor, single magazine, so no recirculation necessary\n\t\t/* NOTHING */\n\t\treturn TRUE; // Caller must do SZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr)\n\t} else if (DEPOT_MAGAZINE_INDEX != mag_index) {\n\t\t// Emptiness discriminant\n\t\tif (bytes_used < DENSITY_THRESHOLD(TINY_REGION_PAYLOAD_BYTES)) {\n\t\t\t/* Region has crossed threshold from density to sparsity. Mark it \"suitable\" on the\n\t\t\t * recirculation candidates list. */\n\t\t\tnode->recirc_suitable = TRUE;\n\t\t} else {\n\t\t\t/* After this free, we've found the region is still dense, so it must have been even more so before\n\t\t\t * the free. That implies the region is already correctly marked. Do nothing. */\n\t\t}\n\n\t\t// Has the entire magazine crossed the \"emptiness threshold\"? If so, transfer a region\n\t\t// from this magazine to the Depot. Choose a region that itself has crossed the emptiness threshold (i.e\n\t\t// is at least fraction \"f\" empty.) Such a region will be marked \"suitable\" on the recirculation list.\n\t\tsize_t a = tiny_mag_ptr->num_bytes_in_magazine;\t// Total bytes allocated to this magazine\n\t\tsize_t u = tiny_mag_ptr->mag_num_bytes_in_objects; // In use (malloc'd) from this magaqzine\n\n\t\tif (a - u > ((3 * TINY_REGION_PAYLOAD_BYTES) / 2) && u < DENSITY_THRESHOLD(a)) {\n\t\t\treturn tiny_free_do_recirc_to_depot(rack, tiny_mag_ptr, mag_index);\n\t\t}\n\t} else {\n#if !CONFIG_AGGRESSIVE_MADVISE\n\t\t// We are free'ing into the depot, so madvise as we do so unless we were madvising every incoming\n\t\t// allocation anyway.\n\t\ttiny_madvise_free_range_no_lock(rack, tiny_mag_ptr, region, headptr, headsize, ptr, msize);\n#endif\n\n\t\tif (0 < bytes_used || 0 < node->pinned_to_depot) {\n\t\t\t/* Depot'd region is still live. Leave it in place on the Depot's recirculation list\n\t\t\t * so as to avoid thrashing between the Depot's free list and a magazines's free list\n\t\t\t * with detach_region/reattach_region */\n\t\t} else {\n\t\t\t/* Depot'd region is just now empty. Consider return to OS. */\n\t\t\tregion_t r_dealloc = tiny_free_try_depot_unmap_no_lock(rack, tiny_mag_ptr, node);\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\tif (r_dealloc) {\n\t\t\t\tmvm_deallocate_pages(r_dealloc, TINY_REGION_SIZE, 0);\n\t\t\t}\n\t\t\treturn FALSE; // Caller need not unlock\n\t\t}\n\t}\n\treturn TRUE; // Caller must do SZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr)\n}\n#endif // CONFIG_RECIRC_DEPOT\n\nboolean_t\ntiny_free_no_lock(rack_t *rack, magazine_t *tiny_mag_ptr, mag_index_t mag_index, region_t region, void *ptr, msize_t msize)\n{\n\tvoid *original_ptr = ptr;\n\tsize_t original_size = TINY_BYTES_FOR_MSIZE(msize);\n\tvoid *next_block = ((unsigned char *)ptr + original_size);\n\tmsize_t previous_msize, next_msize;\n\tvoid *previous;\n\ttiny_free_list_t *big_free_block;\n\ttiny_free_list_t *after_next_block;\n\ttiny_free_list_t *before_next_block;\n\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"in tiny_free_no_lock(), ptr=%p, msize=%d\\n\", ptr, msize);\n\t}\n\tif (!msize) {\n\t\tmalloc_zone_error(rack->debug_flags, true,\n\t\t\t\t\"trying to free tiny block that is too small in tiny_free_no_lock(), ptr=%p, msize=%d\\n\",\n\t\t\t\tptr, msize);\n\t}\n#endif\n\n\t// We try to coalesce this block with the preceeding one\n\tprevious = tiny_previous_preceding_free(ptr, &previous_msize);\n\tif (previous) {\n#if DEBUG_MALLOC\n\t\tif (LOG(szone, ptr) || LOG(szone, previous)) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"in tiny_free_no_lock(), coalesced backwards for %p previous=%p\\n\", ptr, previous);\n\t\t}\n#endif\n\n\t\t// clear the meta_header since this is no longer the start of a block\n\t\tset_tiny_meta_header_middle(ptr);\n\t\ttiny_free_list_remove_ptr(rack, tiny_mag_ptr, previous, previous_msize);\n\t\tptr = previous;\n\t\tmsize += previous_msize;\n\t}\n\t// We try to coalesce with the next block\n\tif ((next_block < TINY_REGION_END(region)) && tiny_meta_header_is_free(next_block)) {\n\t\tnext_msize = get_tiny_free_size(next_block);\n#if DEBUG_MALLOC\n\t\tif (LOG(szone, ptr) || LOG(szone, next_block)) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"in tiny_free_no_lock(), for ptr=%p, msize=%d coalesced forward=%p next_msize=%d\\n\", ptr, msize,\n\t\t\t\t\t\t  next_block, next_msize);\n\t\t}\n#endif\n\t\t// If we are coalescing with the next block, and the next block is in\n\t\t// the last slot of the free list, then we optimize this case here to\n\t\t// avoid removing next_block from the slot (NUM_TINY_SLOTS - 1) and then adding ptr back\n\t\t// to slot (NUM_TINY_SLOTS - 1).\n\t\tif (next_msize >= NUM_TINY_SLOTS) {\n\t\t\tmsize += next_msize;\n\n\t\t\tbig_free_block = (tiny_free_list_t *)next_block;\n\t\t\tafter_next_block = free_list_unchecksum_ptr(rack, &big_free_block->next);\n\t\t\tbefore_next_block = free_list_unchecksum_ptr(rack, &big_free_block->previous);\n\n\t\t\tif (!before_next_block) {\n\t\t\t\ttiny_mag_ptr->mag_free_list[NUM_TINY_SLOTS - 1].p = ptr;\n\t\t\t} else {\n\t\t\t\tbefore_next_block->next.u = free_list_checksum_ptr(rack, ptr);\n\t\t\t}\n\n\t\t\tif (after_next_block) {\n\t\t\t\tafter_next_block->previous.u = free_list_checksum_ptr(rack, ptr);\n\t\t\t}\n\n\t\t\t// we don't need to checksum these since they are already checksummed\n\t\t\t((tiny_free_list_t *)ptr)->previous = big_free_block->previous;\n\t\t\t((tiny_free_list_t *)ptr)->next = big_free_block->next;\n\n\t\t\t// clear the meta_header to enable coalescing backwards\n\t\t\tset_tiny_meta_header_middle(big_free_block);\n\t\t\tset_tiny_meta_header_free(ptr, msize);\n\n\t\t\tgoto tiny_free_ending;\n\t\t}\n\t\ttiny_free_list_remove_ptr(rack, tiny_mag_ptr, next_block, next_msize);\n\t\tset_tiny_meta_header_middle(next_block); // clear the meta_header to enable coalescing backwards\n\t\tmsize += next_msize;\n\t}\n\n\t// The tiny cache already scribbles free blocks as they go through the\n\t// cache whenever msize < TINY_QUANTUM , so we do not need to do it here.\n\tif ((rack->debug_flags & MALLOC_DO_SCRIBBLE) && msize && (msize >= TINY_QUANTUM)) {\n\t\tmemset(ptr, SCRABBLE_BYTE, TINY_BYTES_FOR_MSIZE(msize));\n\t}\n\n\ttiny_free_list_add_ptr(rack, tiny_mag_ptr, ptr, msize);\n\ntiny_free_ending:\n\n\ttiny_mag_ptr->mag_num_objects--;\n\t// we use original_size and not msize to avoid double counting the coalesced blocks\n\ttiny_mag_ptr->mag_num_bytes_in_objects -= original_size;\n\n\t// Update this region's bytes in use count\n\tregion_trailer_t *node = REGION_TRAILER_FOR_TINY_REGION(region);\n\tsize_t bytes_used = node->bytes_used - original_size;\n\tnode->bytes_used = (unsigned int)bytes_used;\n\n#if CONFIG_AGGRESSIVE_MADVISE\n\t// Platforms that want to madvise every freed allocation do so here, even if we continue\n\t// on to use the recirc depot after.\n\ttiny_madvise_free_range_no_lock(rack, tiny_mag_ptr, region, original_ptr, original_size, ptr, msize);\n#endif\n\n\t// Caller must do SZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr) if this function\n\t// returns TRUE.\n\tboolean_t needs_unlock = TRUE;\n\n#if CONFIG_RECIRC_DEPOT\n\tneeds_unlock = tiny_free_try_recirc_to_depot(rack, tiny_mag_ptr, mag_index, region, original_ptr, original_size, ptr, msize);\n#endif\n\treturn needs_unlock;\n}\n\n// Allocates from the last region or a freshly allocated region\nstatic void *\ntiny_malloc_from_region_no_lock(rack_t *rack,\n\t\t\t\t\t\t\t\tmagazine_t *tiny_mag_ptr,\n\t\t\t\t\t\t\t\tmag_index_t mag_index,\n\t\t\t\t\t\t\t\tmsize_t msize,\n\t\t\t\t\t\t\t\tvoid *aligned_address)\n{\n\tvoid *ptr;\n\n\t// Deal with unclaimed memory -- mag_bytes_free_at_end or mag_bytes_free_at_start\n\tif (tiny_mag_ptr->mag_bytes_free_at_end || tiny_mag_ptr->mag_bytes_free_at_start) {\n\t\ttiny_finalize_region(rack, tiny_mag_ptr);\n\t}\n\n\t// We set the unused bits of the header in the last pair to be all ones, and those of the inuse to zeroes.\n#if NUM_TINY_BLOCKS & 31\n\tconst uint32_t header = 0xFFFFFFFFU << (NUM_TINY_BLOCKS & 31);\n#else\n\tconst uint32_t header = 0;\n#endif\n\t((tiny_region_t)aligned_address)->pairs[CEIL_NUM_TINY_BLOCKS_WORDS - 1].header = header;\n\t((tiny_region_t)aligned_address)->pairs[CEIL_NUM_TINY_BLOCKS_WORDS - 1].inuse = 0;\n\n\t// Tag the region at \"aligned_address\" as belonging to us,\n\t// and so put it under the protection of the magazine lock we are holding.\n\t// Do this before advertising \"aligned_address\" on the hash ring(!)\n\tMAGAZINE_INDEX_FOR_TINY_REGION(aligned_address) = mag_index;\n\n\t// Insert the new region into the hash ring\n\track_region_insert(rack, (region_t)aligned_address);\n\n\ttiny_mag_ptr->mag_last_region = aligned_address;\n\tBYTES_USED_FOR_TINY_REGION(aligned_address) = TINY_BYTES_FOR_MSIZE(msize);\n\n#if CONFIG_ASLR_INTERNAL\n\tint offset_msize = malloc_entropy[0] & TINY_ENTROPY_MASK;\n#if DEBUG_MALLOC\n\tif (getenv(\"MallocASLRForce\")) {\n\t\toffset_msize = strtol(getenv(\"MallocASLRForce\"), NULL, 0) & TINY_ENTROPY_MASK;\n\t}\n\tif (getenv(\"MallocASLRPrint\")) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"Region: %p offset: %d\\n\", aligned_address, offset_msize);\n\t}\n#endif\n#else\n\tint offset_msize = 0;\n#endif\n\tptr = (void *)((uintptr_t)aligned_address + TINY_BYTES_FOR_MSIZE(offset_msize));\n\tset_tiny_meta_header_in_use(ptr, msize);\n\ttiny_mag_ptr->mag_num_objects++;\n\ttiny_mag_ptr->mag_num_bytes_in_objects += TINY_BYTES_FOR_MSIZE(msize);\n\ttiny_mag_ptr->num_bytes_in_magazine += TINY_REGION_PAYLOAD_BYTES;\n\n\t// We put a header on the last block so that it appears in use (for coalescing, etc...)\n\tset_tiny_meta_header_in_use_1((void *)((uintptr_t)ptr + TINY_BYTES_FOR_MSIZE(msize)));\n\ttiny_mag_ptr->mag_bytes_free_at_end = TINY_BYTES_FOR_MSIZE(NUM_TINY_BLOCKS - msize - offset_msize);\n\n#if CONFIG_ASLR_INTERNAL\n\t// Put a header on the previous block for same reason\n\ttiny_mag_ptr->mag_bytes_free_at_start = TINY_BYTES_FOR_MSIZE(offset_msize);\n\tif (offset_msize) {\n\t\tset_tiny_meta_header_in_use_1((void *)((uintptr_t)ptr - TINY_QUANTUM));\n\t}\n#else\n\ttiny_mag_ptr->mag_bytes_free_at_start = 0;\n#endif\n\n\t// connect to magazine as last node\n\trecirc_list_splice_last(rack, tiny_mag_ptr, REGION_TRAILER_FOR_TINY_REGION(aligned_address));\n\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"in tiny_malloc_from_region_no_lock(), ptr=%p, msize=%d\\n\", ptr, msize);\n\t}\n#endif\n\treturn ptr;\n}\n\nvoid *\ntiny_memalign(szone_t *szone, size_t alignment, size_t size, size_t span)\n{\n\tmsize_t mspan = TINY_MSIZE_FOR_BYTES(span + TINY_QUANTUM - 1);\n\tvoid *p = tiny_malloc_should_clear(&szone->tiny_rack, mspan, 0);\n\n\tif (NULL == p) {\n\t\treturn NULL;\n\t}\n\n\tsize_t offset = ((uintptr_t)p) & (alignment - 1);\t// p % alignment\n\tsize_t pad = (0 == offset) ? 0 : alignment - offset; // p + pad achieves desired alignment\n\n\tmsize_t msize = TINY_MSIZE_FOR_BYTES(size + TINY_QUANTUM - 1);\n\tmsize_t mpad = TINY_MSIZE_FOR_BYTES(pad + TINY_QUANTUM - 1);\n\tmsize_t mwaste = mspan - msize - mpad; // excess blocks\n\n\tif (mpad > 0) {\n\t\tvoid *q = (void *)(((uintptr_t)p) + pad);\n\n\t\t// Mark q as a block header and in-use, thus creating two blocks.\n\t\tmagazine_t *tiny_mag_ptr = mag_lock_zine_for_region_trailer(szone->tiny_rack.magazines,\n\t\t\t\tREGION_TRAILER_FOR_TINY_REGION(TINY_REGION_FOR_PTR(p)),\n\t\t\t\tMAGAZINE_INDEX_FOR_TINY_REGION(TINY_REGION_FOR_PTR(p)));\n\t\tset_tiny_meta_header_in_use(q, msize);\n\t\ttiny_mag_ptr->mag_num_objects++;\n\n\t\t// set_tiny_meta_header_in_use() \"reaffirms\" the block_header on the *following* block, so\n\t\t// now set its in_use bit as well. But only if its within the original allocation made above.\n\t\tif (mwaste > 0) {\n\t\t\tBITARRAY_SET(TINY_INUSE_FOR_HEADER(TINY_BLOCK_HEADER_FOR_PTR(q)), TINY_INDEX_FOR_PTR(q) + msize);\n\t\t}\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\n\t\t// Give up mpad blocks beginning at p to the tiny free list\n\t\tfree_tiny(&szone->tiny_rack, p, TINY_REGION_FOR_PTR(p), TINY_BYTES_FOR_MSIZE(mpad));\n\n\t\tp = q; // advance p to the desired alignment\n\t}\n\n\tif (mwaste > 0) {\n\t\tvoid *q = (void *)(((uintptr_t)p) + TINY_BYTES_FOR_MSIZE(msize));\n\t\t// Mark q as block header and in-use, thus creating two blocks.\n\t\tmagazine_t *tiny_mag_ptr = mag_lock_zine_for_region_trailer(szone->tiny_rack.magazines,\n\t\t\t\tREGION_TRAILER_FOR_TINY_REGION(TINY_REGION_FOR_PTR(p)),\n\t\t\t\tMAGAZINE_INDEX_FOR_TINY_REGION(TINY_REGION_FOR_PTR(p)));\n\t\tset_tiny_meta_header_in_use(q, mwaste);\n\t\ttiny_mag_ptr->mag_num_objects++;\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\n\t\t// Give up mwaste blocks beginning at q to the tiny free list\n\t\tfree_tiny(&szone->tiny_rack, q, TINY_REGION_FOR_PTR(q), TINY_BYTES_FOR_MSIZE(mwaste));\n\t}\n\n\treturn p; // p has the desired size and alignment, and can later be free()'d\n}\n\nboolean_t\ntiny_claimed_address(rack_t *rack, void *ptr)\n{\n\tregion_t r = tiny_region_for_ptr_no_lock(rack, ptr);\n\treturn r && ptr < TINY_REGION_END(r);\n}\n\nvoid *\ntiny_try_shrink_in_place(rack_t *rack, void *ptr, size_t old_size, size_t new_good_size)\n{\n\tmsize_t new_msize = TINY_MSIZE_FOR_BYTES(new_good_size);\n\tmsize_t mshrinkage = TINY_MSIZE_FOR_BYTES(old_size) - new_msize;\n\n\tif (mshrinkage) {\n\t\tvoid *q = (void *)((uintptr_t)ptr + TINY_BYTES_FOR_MSIZE(new_msize));\n\t\tmagazine_t *tiny_mag_ptr = mag_lock_zine_for_region_trailer(rack->magazines,\n\t\t\t\tREGION_TRAILER_FOR_TINY_REGION(TINY_REGION_FOR_PTR(ptr)),\n\t\t\t\tMAGAZINE_INDEX_FOR_TINY_REGION(TINY_REGION_FOR_PTR(ptr)));\n\n\t\t// Mark q as block header and in-use, thus creating two blocks.\n\t\tset_tiny_meta_header_in_use(q, mshrinkage);\n\t\ttiny_mag_ptr->mag_num_objects++;\n\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\tfree_tiny(rack, q, TINY_REGION_FOR_PTR(q), 0);\n\t}\n\treturn ptr;\n}\n\nboolean_t\ntiny_try_realloc_in_place(rack_t *rack, void *ptr, size_t old_size, size_t new_size)\n{\n\t// returns 1 on success\n\tmsize_t index;\n\tmsize_t old_msize;\n\tunsigned next_index;\n\tvoid *next_block;\n\tboolean_t is_free;\n\tmsize_t next_msize, coalesced_msize, leftover_msize, new_msize;\n\tvoid *leftover;\n\n\tindex = TINY_INDEX_FOR_PTR(ptr);\n\told_msize = TINY_MSIZE_FOR_BYTES(old_size);\n\tnew_msize = TINY_MSIZE_FOR_BYTES(new_size + TINY_QUANTUM - 1);\n\tnext_index = index + old_msize;\n\n\tif (next_index >= NUM_TINY_BLOCKS) {\n\t\treturn 0;\n\t}\n\tnext_block = (char *)ptr + old_size;\n\n\tmagazine_t *tiny_mag_ptr = mag_lock_zine_for_region_trailer(rack->magazines,\n\t\t\tREGION_TRAILER_FOR_TINY_REGION(TINY_REGION_FOR_PTR(ptr)),\n\t\t\tMAGAZINE_INDEX_FOR_TINY_REGION(TINY_REGION_FOR_PTR(ptr)));\n\n\tif (DEPOT_MAGAZINE_INDEX == MAGAZINE_INDEX_FOR_TINY_REGION(TINY_REGION_FOR_PTR(ptr))) {\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\treturn 0;\n\t}\n\n\tcoalesced_msize = new_msize - old_msize;\n#if CONFIG_TINY_CACHE\n\tvoid *last_free_ptr = tiny_mag_ptr->mag_last_free;\n\tmsize_t last_free_msize = tiny_mag_ptr->mag_last_free_msize;\n\tif (last_free_ptr == next_block && old_msize + last_free_msize >= new_msize) {\n\t\t/*\n\t\t * There is a block in mag_last_free and it's immediately after\n\t\t * this block and it's large enough. We can use some or all of it.\n\t\t */\n\t\tleftover_msize = last_free_msize - coalesced_msize;\n\t\tif (leftover_msize) {\n\t\t\ttiny_mag_ptr->mag_last_free_msize -= coalesced_msize;\n\t\t\ttiny_mag_ptr->mag_last_free += new_size - old_size;\n\t\t\t// The block in mag_last_free is still marked as header and in-use, so copy that\n\t\t\t// state to the block that remains. The state for the block that we're going to\n\t\t\t// use is adjusted by the set_tiny_meta_header_middle() call below.\n\t\t\tset_tiny_meta_header_in_use(next_block + TINY_BYTES_FOR_MSIZE(coalesced_msize), leftover_msize);\n\t\t} else {\n\t\t\t// Using the whole block.\n\t\t\ttiny_mag_ptr->mag_last_free = NULL;\n\t\t\ttiny_mag_ptr->mag_last_free_msize = 0;\n\t\t\ttiny_mag_ptr->mag_last_free_rgn = NULL;\n\t\t}\n\t\tset_tiny_meta_header_middle(next_block);\n\t} else {\n#endif // CONFIG_TINY_CACHE\n\t\t/*\n\t\t * Try to expand into unused space immediately after this block.\n\t\t */\n\t\tmsize_t unused_msize = TINY_MSIZE_FOR_BYTES(tiny_mag_ptr->mag_bytes_free_at_end);\n\t\tvoid *unused_start = TINY_REGION_END(TINY_REGION_FOR_PTR(ptr)) - tiny_mag_ptr->mag_bytes_free_at_end;\n\t\tif (tiny_mag_ptr->mag_last_region == TINY_REGION_FOR_PTR(ptr)\n\t\t\t\t&& coalesced_msize < unused_msize && unused_start == ptr + old_size) {\n\t\t\t// The block at the start of mag_bytes_free_at_end is marked as\n\t\t\t// header/in-use and the next one has header/free. We need to\n\t\t\t// reset both the header and in-use bit in the first block and we\n\t\t\t// need to reset the header bit in the second block if it's part of\n\t\t\t// the new allocation.\n\t\t\tset_tiny_meta_header_middle(unused_start);\n\t\t\tif (coalesced_msize > 1) {\n\t\t\t\tset_tiny_meta_header_middle(unused_start + TINY_QUANTUM);\n\t\t\t}\n\t\t\ttiny_mag_ptr->mag_bytes_free_at_end -= TINY_BYTES_FOR_MSIZE(coalesced_msize);\n\t\t\tif (tiny_mag_ptr->mag_bytes_free_at_end) {\n\t\t\t\t// Mark the first block of the remaining free area as a header and in-use.\n\t\t\t\tset_tiny_meta_header_in_use_1(ptr + TINY_BYTES_FOR_MSIZE(new_msize));\n\t\t\t}\n\t\t} else {\n\t\t\t/*\n\t\t\t * Look for a free block immediately afterwards.  If it's large\n\t\t\t * enough, we can consume (part of) it.\n\t\t\t */\n\t\t\tis_free = tiny_meta_header_is_free(next_block);\n\t\t\tif (!is_free) {\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\t\treturn 0; // next_block is in use;\n\t\t\t}\n\t\t\tnext_msize = get_tiny_free_size(next_block);\n\t\t\tif (old_msize + next_msize < new_msize) {\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\t\treturn 0; // even with next block, not enough\n\t\t\t}\n\t\t\t/*\n\t\t \t * The following block is big enough; pull it from its freelist and chop off enough to satisfy\n\t\t \t * our needs.\n\t\t \t */\n\t\t\ttiny_free_list_remove_ptr(rack, tiny_mag_ptr, next_block, next_msize);\n\t\t\tset_tiny_meta_header_middle(next_block); // clear the meta_header to enable coalescing backwards\n\t\t\tleftover_msize = next_msize - coalesced_msize;\n\t\t\tif (leftover_msize) {\n\t\t\t\t/* there's some left, so put the remainder back */\n\t\t\t\tleftover = (void *)((uintptr_t)next_block + TINY_BYTES_FOR_MSIZE(coalesced_msize));\n\t\t\t\ttiny_free_list_add_ptr(rack, tiny_mag_ptr, leftover, leftover_msize);\n\t\t\t}\n\t\t\tset_tiny_meta_header_in_use(ptr, old_msize + coalesced_msize);\n\t\t}\n#if CONFIG_TINY_CACHE\n\t}\n#endif // CONFIG_TINY_CACHE\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"in tiny_try_realloc_in_place(), ptr=%p, msize=%d\\n\", ptr, old_msize + coalesced_msize);\n\t}\n#endif\n\ttiny_mag_ptr->mag_num_bytes_in_objects += TINY_BYTES_FOR_MSIZE(coalesced_msize);\n\n\t// Update this region's bytes in use count\n\tregion_trailer_t *node = REGION_TRAILER_FOR_TINY_REGION(TINY_REGION_FOR_PTR(ptr));\n\tsize_t bytes_used = node->bytes_used + TINY_BYTES_FOR_MSIZE(coalesced_msize);\n\tnode->bytes_used = (unsigned int)bytes_used;\n\n\t// Emptiness discriminant\n\tif (bytes_used < DENSITY_THRESHOLD(TINY_REGION_PAYLOAD_BYTES)) {\n\t\t/* After this reallocation the region is still sparse, so it must have been even more so before\n\t\t * the reallocation. That implies the region is already correctly marked. Do nothing. */\n\t} else {\n\t\t/* Region has crossed threshold from sparsity to density. Mark it not \"suitable\" on the\n\t\t * recirculation candidates list. */\n\t\tnode->recirc_suitable = FALSE;\n\t}\n\n\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\tCHECK(szone, __PRETTY_FUNCTION__);\n\treturn 1;\n}\n\nstatic char *tiny_check_fail_msg = \"*** check: incorrect tiny region \";\n\n#define TINY_CHECK_FAIL(fmt, ...) \\\n\tmalloc_zone_check_fail(tiny_check_fail_msg, \\\n\t\t\t\"%ld, counter=%d\\n\" fmt, region_index, counter, __VA_ARGS__);\n\nboolean_t\ntiny_check_region(rack_t *rack, region_t region, size_t region_index,\n\t\tunsigned counter)\n{\n\tuintptr_t start, ptr, region_end;\n\tboolean_t prev_free = 0;\n\tboolean_t is_free;\n\tmsize_t msize;\n\ttiny_free_list_t *free_head;\n\tvoid *follower, *previous, *next;\n\tmag_index_t mag_index = MAGAZINE_INDEX_FOR_TINY_REGION(region);\n\tmagazine_t *tiny_mag_ptr = &(rack->magazines[mag_index]);\n\n\t// Assumes locked\n\tCHECK_MAGAZINE_PTR_LOCKED(szone, tiny_mag_ptr, __PRETTY_FUNCTION__);\n\n\t// Do not check the region if pinned_to_depot is not zero because it\n\t// may not be in a consistent state (specifically, if may have a\n\t// block marked as in-use that's longer than any legal allocation,\n\t// which upsets get_tiny_meta_header() because it can't determine the\n\t// block's length).\n\tif (!REGION_TRAILER_FOR_TINY_REGION(region)->pinned_to_depot) {\n\t\treturn 1;\n\t}\n\n\t/* establish region limits */\n\tstart = (uintptr_t)TINY_REGION_ADDRESS(region);\n\tptr = start;\n\tif (region == tiny_mag_ptr->mag_last_region) {\n\t\tptr += tiny_mag_ptr->mag_bytes_free_at_start;\n\n\t\t/*\n\t\t * Check the leading block's integrity here also.\n\t\t */\n\t\tif (tiny_mag_ptr->mag_bytes_free_at_start) {\n\t\t\tmsize = get_tiny_meta_header((void *)(ptr - TINY_QUANTUM), &is_free);\n\t\t\tif (is_free || (msize != 1)) {\n\t\t\t\tTINY_CHECK_FAIL(\"*** invariant broken for leader block %p - %d %d\\n\",\n\t\t\t\t\t\t(void *)(ptr - TINY_QUANTUM), msize, is_free);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t}\n\tregion_end = (uintptr_t)TINY_REGION_END(region);\n\n\t/*\n\t * The last region may have a trailing chunk which has not been converted into inuse/freelist\n\t * blocks yet.\n\t */\n\tif (region == tiny_mag_ptr->mag_last_region) {\n\t\tregion_end -= tiny_mag_ptr->mag_bytes_free_at_end;\n\t}\n\n\t/*\n\t * Scan blocks within the region.\n\t */\n\twhile (ptr < region_end) {\n\t\t/*\n\t\t * If the first block is free, and its size is 65536 (msize = 0) then the entire region is\n\t\t * free.\n\t\t */\n\t\tmsize = get_tiny_meta_header((void *)ptr, &is_free);\n\t\tif (is_free && !msize && (ptr == start)) {\n\t\t\treturn 1;\n\t\t}\n\n\t\t/*\n\t\t * If the block's size is 65536 (msize = 0) then since we're not the first entry the size is\n\t\t * corrupt.\n\t\t */\n\t\tif (!msize) {\n\t\t\tTINY_CHECK_FAIL(\"*** invariant broken for tiny block %p this msize=%d - size is too small\\n\", (void *)ptr, msize);\n\t\t\treturn 0;\n\t\t}\n\n\t\tif (!is_free) {\n\t\t\t/*\n\t\t\t * In use blocks cannot be more than (NUM_TINY_SLOTS - 1) quanta large.\n\t\t\t */\n\t\t\tprev_free = 0;\n\t\t\tif (msize > (NUM_TINY_SLOTS - 1)) {\n\t\t\t\tTINY_CHECK_FAIL(\"*** invariant broken for %p this tiny msize=%d - size is too large\\n\", (void *)ptr, msize);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\t/* move to next block */\n\t\t\tptr += TINY_BYTES_FOR_MSIZE(msize);\n\t\t} else {\n#if !CONFIG_RELAXED_INVARIANT_CHECKS\n\t\t\t/*\n\t\t\t * Free blocks must have been coalesced, we cannot have a free block following another\n\t\t\t * free block.\n\t\t\t */\n\t\t\tif (prev_free) {\n\t\t\t\tTINY_CHECK_FAIL(\"*** invariant broken for free block %p this tiny msize=%d: two free blocks in a row\\n\", (void *)ptr, msize);\n\t\t\t\treturn 0;\n\t\t\t}\n#endif // CONFIG_RELAXED_INVARIANT_CHECKS\n\t\t\tprev_free = 1;\n\t\t\t/*\n\t\t\t * Check the integrity of this block's entry in its freelist.\n\t\t\t */\n\t\t\tfree_head = (tiny_free_list_t *)ptr;\n\t\t\tprevious = free_list_unchecksum_ptr(rack, &free_head->previous);\n\t\t\tnext = free_list_unchecksum_ptr(rack, &free_head->next);\n\t\t\tif (previous && !tiny_meta_header_is_free(previous)) {\n\t\t\t\tTINY_CHECK_FAIL(\"*** invariant broken for %p (previous %p is not a free pointer)\\n\", (void *)ptr, previous);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (next && !tiny_meta_header_is_free(next)) {\n\t\t\t\tTINY_CHECK_FAIL(\"*** invariant broken for %p (next in free list %p is not a free pointer)\\n\", (void *)ptr, next);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\t/*\n\t\t\t * Check the free block's trailing size value.\n\t\t\t */\n\t\t\tfollower = FOLLOWING_TINY_PTR(ptr, msize);\n\t\t\tif (((uintptr_t)follower != region_end) && (get_tiny_previous_free_msize(follower) != msize)) {\n\t\t\t\tTINY_CHECK_FAIL(\"*** invariant broken for tiny free %p followed by %p in region [%p-%p] \"\n\t\t\t\t\t\t\"(end marker incorrect) should be %d; in fact %d\\n\",\n\t\t\t\t\t\t(void *)ptr, follower, TINY_REGION_ADDRESS(region), (void *)region_end,\n\t\t\t\t\t\tmsize, get_tiny_previous_free_msize(follower));\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\t/* move to next block */\n\t\t\tptr = (uintptr_t)follower;\n\t\t}\n\t}\n\t/*\n\t * Ensure that we scanned the entire region\n\t */\n\tif (ptr != region_end) {\n\t\tTINY_CHECK_FAIL(\"*** invariant broken for region end %p - %p\\n\", (void *)ptr, (void *)region_end);\n\t\treturn 0;\n\t}\n\t/*\n\t * Check the trailing block's integrity.\n\t */\n\tif (region == tiny_mag_ptr->mag_last_region) {\n\t\tif (tiny_mag_ptr->mag_bytes_free_at_end) {\n\t\t\tmsize = get_tiny_meta_header((void *)ptr, &is_free);\n\t\t\tif (is_free || (msize != 1)) {\n\t\t\t\tTINY_CHECK_FAIL(\"*** invariant broken for blocker block %p - %d %d\\n\", (void *)ptr, msize, is_free);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t}\n\treturn 1;\n}\n\nkern_return_t\ntiny_in_use_enumerator(task_t task,\n\t\t\t\t\t   void *context,\n\t\t\t\t\t   unsigned type_mask,\n\t\t\t\t\t   szone_t *szone,\n\t\t\t\t\t   memory_reader_t reader,\n\t\t\t\t\t   vm_range_recorder_t recorder)\n{\n\tsize_t num_regions;\n\tsize_t index;\n\tregion_t *regions;\n\tvm_range_t buffer[MAX_RECORDER_BUFFER];\n\tunsigned count = 0;\n\tkern_return_t err;\n\tregion_t region;\n\tvm_range_t range;\n\tvm_range_t admin_range;\n\tvm_range_t ptr_range;\n\tunsigned char *mapped_region;\n\tuint32_t *block_header;\n\tuint32_t *in_use;\n\tunsigned block_index;\n\tunsigned block_limit;\n\tboolean_t is_free;\n\tmsize_t msize;\n\tvoid *mapped_ptr;\n\tunsigned bit;\n\tmagazine_t *tiny_mag_base = NULL;\n\n\tregion_hash_generation_t *trg_ptr;\n\terr = reader(task, (vm_address_t)szone->tiny_rack.region_generation, sizeof(region_hash_generation_t), (void **)&trg_ptr);\n\tif (err) {\n\t\treturn err;\n\t}\n\n\tnum_regions = trg_ptr->num_regions_allocated;\n\terr = reader(task, (vm_address_t)trg_ptr->hashed_regions, sizeof(region_t) * num_regions, (void **)&regions);\n\tif (err) {\n\t\treturn err;\n\t}\n\n\tif (type_mask & MALLOC_PTR_IN_USE_RANGE_TYPE) {\n\t\t// Map in all active magazines. Do this outside the iteration over regions.\n\t\terr = reader(task, (vm_address_t)(szone->tiny_rack.magazines), szone->tiny_rack.num_magazines * sizeof(magazine_t),\n\t\t\t\t\t (void **)&tiny_mag_base);\n\t\tif (err) {\n\t\t\treturn err;\n\t\t}\n\t}\n\n\tfor (index = 0; index < num_regions; ++index) {\n\t\tregion = regions[index];\n\t\tif (HASHRING_OPEN_ENTRY != region && HASHRING_REGION_DEALLOCATED != region) {\n\t\t\trange.address = (vm_address_t)TINY_REGION_ADDRESS(region);\n\t\t\trange.size = (vm_size_t)TINY_REGION_SIZE;\n\t\t\tif (type_mask & MALLOC_ADMIN_REGION_RANGE_TYPE) {\n\t\t\t\tadmin_range.address = range.address + TINY_METADATA_START;\n\t\t\t\tadmin_range.size = TINY_METADATA_SIZE;\n\t\t\t\trecorder(task, context, MALLOC_ADMIN_REGION_RANGE_TYPE, &admin_range, 1);\n\t\t\t}\n\t\t\tif (type_mask & (MALLOC_PTR_REGION_RANGE_TYPE | MALLOC_ADMIN_REGION_RANGE_TYPE)) {\n\t\t\t\tptr_range.address = range.address;\n\t\t\t\tptr_range.size = NUM_TINY_BLOCKS * TINY_QUANTUM;\n\t\t\t\trecorder(task, context, MALLOC_PTR_REGION_RANGE_TYPE, &ptr_range, 1);\n\t\t\t}\n\t\t\tif (type_mask & MALLOC_PTR_IN_USE_RANGE_TYPE) {\n\t\t\t\tvm_address_t mag_last_free;\n\t\t\t\tmsize_t mag_last_free_msize = 0;\n\n\t\t\t\terr = reader(task, range.address, range.size, (void **)&mapped_region);\n\t\t\t\tif (err) {\n\t\t\t\t\treturn err;\n\t\t\t\t}\n\n\t\t\t\tmag_index_t mag_index = MAGAZINE_INDEX_FOR_TINY_REGION(mapped_region);\n\t\t\t\tmagazine_t *tiny_mag_ptr = tiny_mag_base + mag_index;\n\n\t\t\t\tif (DEPOT_MAGAZINE_INDEX != mag_index) {\n\t\t\t\t\tmag_last_free = (uintptr_t)tiny_mag_ptr->mag_last_free;\n\t\t\t\t\tmag_last_free_msize = tiny_mag_ptr->mag_last_free_msize;\n\t\t\t\t} else {\n\t\t\t\t\tfor (mag_index = 0; mag_index < szone->tiny_rack.num_magazines; mag_index++) {\n\t\t\t\t\t\tif ((void *)range.address == (tiny_mag_base + mag_index)->mag_last_free_rgn) {\n\t\t\t\t\t\t\tmag_last_free = (uintptr_t)(tiny_mag_base + mag_index)->mag_last_free;\n\t\t\t\t\t\t\tmag_last_free_msize = (tiny_mag_base + mag_index)->mag_last_free_msize;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tblock_header = (uint32_t *)(mapped_region + TINY_METADATA_START + sizeof(region_trailer_t));\n\t\t\t\tin_use = TINY_INUSE_FOR_HEADER(block_header);\n\t\t\t\tblock_index = 0;\n\t\t\t\tblock_limit = NUM_TINY_BLOCKS;\n\t\t\t\tif (region == tiny_mag_ptr->mag_last_region) {\n\t\t\t\t\tblock_index += TINY_MSIZE_FOR_BYTES(tiny_mag_ptr->mag_bytes_free_at_start);\n\t\t\t\t\tblock_limit -= TINY_MSIZE_FOR_BYTES(tiny_mag_ptr->mag_bytes_free_at_end);\n\t\t\t\t}\n\n\t\t\t\twhile (block_index < block_limit) {\n\t\t\t\t\tvm_size_t block_offset = TINY_BYTES_FOR_MSIZE(block_index);\n\t\t\t\t\tis_free = !BITARRAY_BIT(in_use, block_index);\n\t\t\t\t\tif (is_free) {\n\t\t\t\t\t\tmapped_ptr = mapped_region + block_offset;\n\n\t\t\t\t\t\t// mapped_region, the address at which 'range' in 'task' has been\n\t\t\t\t\t\t// mapped into our process, is not necessarily aligned to\n\t\t\t\t\t\t// TINY_BLOCKS_ALIGN.\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// Since the code in get_tiny_free_size() assumes the pointer came\n\t\t\t\t\t\t// from a properly aligned tiny region, and mapped_region is not\n\t\t\t\t\t\t// necessarily aligned, then do the size calculation directly.\n\t\t\t\t\t\t// If the next bit is set in the header bitmap, then the size is one\n\t\t\t\t\t\t// quantum.  Otherwise, read the size field.\n\t\t\t\t\t\tif (!BITARRAY_BIT(block_header, (block_index + 1))) {\n\t\t\t\t\t\t\tmsize = TINY_FREE_SIZE(mapped_ptr);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmsize = 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else if (range.address + block_offset != mag_last_free) {\n\t\t\t\t\t\tmsize = 1;\n\t\t\t\t\t\tbit = block_index + 1;\n\t\t\t\t\t\twhile (!BITARRAY_BIT(block_header, bit)) {\n\t\t\t\t\t\t\tbit++;\n\t\t\t\t\t\t\tmsize++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbuffer[count].address = range.address + block_offset;\n\t\t\t\t\t\tbuffer[count].size = TINY_BYTES_FOR_MSIZE(msize);\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t\tif (count >= MAX_RECORDER_BUFFER) {\n\t\t\t\t\t\t\trecorder(task, context, MALLOC_PTR_IN_USE_RANGE_TYPE, buffer, count);\n\t\t\t\t\t\t\tcount = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Block is not free but it matches mag_last_free_ptr so even\n\t\t\t\t\t\t// though it is not marked free in the bitmap, we treat it as if\n\t\t\t\t\t\t// it is and move on\n\t\t\t\t\t\tmsize = mag_last_free_msize;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!msize) {\n\t\t\t\t\t\treturn KERN_FAILURE; // Somethings amiss. Avoid looping at this block_index.\n\t\t\t\t\t}\n\t\t\t\t\tblock_index += msize;\n\t\t\t\t}\n\t\t\t\tif (count) {\n\t\t\t\t\trecorder(task, context, MALLOC_PTR_IN_USE_RANGE_TYPE, buffer, count);\n\t\t\t\t\tcount = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn 0;\n}\n\nvoid *\ntiny_malloc_from_free_list(rack_t *rack, magazine_t *tiny_mag_ptr, mag_index_t mag_index, msize_t msize)\n{\n\ttiny_free_list_t *ptr;\n\tmsize_t this_msize;\n\tgrain_t slot = msize - 1;\n\tfree_list_t *free_list = tiny_mag_ptr->mag_free_list;\n\tfree_list_t *the_slot = free_list + slot;\n\ttiny_free_list_t *next;\n\tfree_list_t *limit;\n#if defined(__LP64__)\n\tuint64_t bitmap;\n#else\n\tuint32_t bitmap;\n#endif\n\tmsize_t leftover_msize;\n\ttiny_free_list_t *leftover_ptr;\n\n\t// Assumes we've locked the region\n\tCHECK_MAGAZINE_PTR_LOCKED(szone, tiny_mag_ptr, __PRETTY_FUNCTION__);\n\n\t// Look for an exact match by checking the freelist for this msize.\n\t//\n\tptr = the_slot->p;\n\tif (ptr) {\n\t\tnext = free_list_unchecksum_ptr(rack, &ptr->next);\n\t\tif (next) {\n\t\t\tnext->previous = ptr->previous;\n\t\t} else {\n\t\t\tBITMAPV_CLR(tiny_mag_ptr->mag_bitmap, slot);\n\t\t}\n\t\tthe_slot->p = next;\n\t\tthis_msize = msize;\n#if DEBUG_MALLOC\n\t\tif (LOG(szone, ptr)) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"in tiny_malloc_from_free_list(), exact match ptr=%p, this_msize=%d\\n\", ptr, this_msize);\n\t\t}\n#endif\n\t\tgoto return_tiny_alloc;\n\t}\n\n\t// Mask off the bits representing slots holding free blocks smaller than the\n\t// size we need.  If there are no larger free blocks, try allocating from\n\t// the free space at the end of the tiny region.\n#if defined(__LP64__)\n\tbitmap = ((uint64_t *)(tiny_mag_ptr->mag_bitmap))[0] & ~((1ULL << slot) - 1);\n#else\n\tbitmap = tiny_mag_ptr->mag_bitmap[0] & ~((1 << slot) - 1);\n#endif\n\tif (!bitmap) {\n\t\tgoto try_tiny_malloc_from_end;\n\t}\n\n\tslot = BITMAPV_CTZ(bitmap);\n\tlimit = free_list + NUM_TINY_SLOTS - 1;\n\tfree_list += slot;\n\n\tif (free_list < limit) {\n\t\tptr = free_list->p;\n\t\tif (ptr) {\n\t\t\tnext = free_list_unchecksum_ptr(rack, &ptr->next);\n\t\t\tfree_list->p = next;\n\t\t\tif (next) {\n\t\t\t\tnext->previous = ptr->previous;\n\t\t\t} else {\n\t\t\t\tBITMAPV_CLR(tiny_mag_ptr->mag_bitmap, slot);\n\t\t\t}\n\t\t\tthis_msize = get_tiny_free_size(ptr);\n\t\t\tgoto add_leftover_and_proceed;\n\t\t}\n#if DEBUG_MALLOC\n\t\tmalloc_report(ASL_LEVEL_ERR, \"in tiny_malloc_from_free_list(), mag_bitmap out of sync, slot=%d\\n\", slot);\n#endif\n\t}\n\n\t// We are now looking at the last slot, which contains blocks equal to, or\n\t// due to coalescing of free blocks, larger than (NUM_TINY_SLOTS - 1) * tiny quantum size.\n\t// If the last freelist is not empty, and the head contains a block that is\n\t// larger than our request, then the remainder is put back on the free list.\n\tptr = limit->p;\n\tif (ptr) {\n\t\tthis_msize = get_tiny_free_size(ptr);\n\t\tnext = free_list_unchecksum_ptr(rack, &ptr->next);\n\t\tif (this_msize - msize >= NUM_TINY_SLOTS) {\n\t\t\t// the leftover will go back to the free list, so we optimize by\n\t\t\t// modifying the free list rather than a pop and push of the head\n\t\t\tleftover_msize = this_msize - msize;\n\t\t\tleftover_ptr = (tiny_free_list_t *)((unsigned char *)ptr + TINY_BYTES_FOR_MSIZE(msize));\n\t\t\tlimit->p = leftover_ptr;\n\t\t\tif (next) {\n\t\t\t\tnext->previous.u = free_list_checksum_ptr(rack, leftover_ptr);\n\t\t\t}\n\t\t\tleftover_ptr->previous = ptr->previous;\n\t\t\tleftover_ptr->next = ptr->next;\n\t\t\tset_tiny_meta_header_free(leftover_ptr, leftover_msize);\n#if DEBUG_MALLOC\n\t\t\tif (LOG(szone, ptr)) {\n\t\t\t\tmalloc_report(ASL_LEVEL_INFO,\n\t\t\t\t\t\t\t  \"in tiny_malloc_from_free_list(), last slot ptr=%p, msize=%d this_msize=%d\\n\", ptr, msize, this_msize);\n\t\t\t}\n#endif\n\t\t\tthis_msize = msize;\n\t\t\tgoto return_tiny_alloc;\n\t\t}\n\t\tif (next) {\n\t\t\tnext->previous = ptr->previous;\n\t\t}\n\t\tlimit->p = next;\n\t\tgoto add_leftover_and_proceed;\n\t\t/* NOTREACHED */\n\t}\n\ntry_tiny_malloc_from_end:\n\t// Let's see if we can use tiny_mag_ptr->mag_bytes_free_at_end\n\tif (tiny_mag_ptr->mag_bytes_free_at_end >= TINY_BYTES_FOR_MSIZE(msize)) {\n\t\tptr = (tiny_free_list_t *)((uintptr_t)TINY_REGION_END(tiny_mag_ptr->mag_last_region) - tiny_mag_ptr->mag_bytes_free_at_end);\n\t\ttiny_mag_ptr->mag_bytes_free_at_end -= TINY_BYTES_FOR_MSIZE(msize);\n\t\tif (tiny_mag_ptr->mag_bytes_free_at_end) {\n\t\t\t// let's add an in use block after ptr to serve as boundary\n\t\t\tset_tiny_meta_header_in_use_1((unsigned char *)ptr + TINY_BYTES_FOR_MSIZE(msize));\n\t\t}\n\t\tthis_msize = msize;\n#if DEBUG_MALLOC\n\t\tif (LOG(szone, ptr)) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"in tiny_malloc_from_free_list(), from end ptr=%p, msize=%d\\n\", ptr, msize);\n\t\t}\n#endif\n\t\tgoto return_tiny_alloc;\n\t}\n#if CONFIG_ASLR_INTERNAL\n\t// Try from start if nothing left at end\n\tif (tiny_mag_ptr->mag_bytes_free_at_start >= TINY_BYTES_FOR_MSIZE(msize)) {\n\t\tptr = (tiny_free_list_t *)(TINY_REGION_ADDRESS(tiny_mag_ptr->mag_last_region) + tiny_mag_ptr->mag_bytes_free_at_start -\n\t\t\t\t\t\t\t  TINY_BYTES_FOR_MSIZE(msize));\n\t\ttiny_mag_ptr->mag_bytes_free_at_start -= TINY_BYTES_FOR_MSIZE(msize);\n\t\tif (tiny_mag_ptr->mag_bytes_free_at_start) {\n\t\t\t// let's add an in use block before ptr to serve as boundary\n\t\t\tset_tiny_meta_header_in_use_1((unsigned char *)ptr - TINY_QUANTUM);\n\t\t}\n\t\tthis_msize = msize;\n#if DEBUG_MALLOC\n\t\tif (LOG(szone, ptr)) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"in tiny_malloc_from_free_list(), from start ptr=%p, msize=%d\\n\", ptr, msize);\n\t\t}\n#endif\n\t\tgoto return_tiny_alloc;\n\t}\n#endif\n\treturn NULL;\n\nadd_leftover_and_proceed:\n\tif (!this_msize || (this_msize > msize)) {\n\t\tleftover_msize = this_msize - msize;\n\t\tleftover_ptr = (tiny_free_list_t *)((unsigned char *)ptr + TINY_BYTES_FOR_MSIZE(msize));\n#if DEBUG_MALLOC\n\t\tif (LOG(szone, ptr)) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"in tiny_malloc_from_free_list(), adding leftover ptr=%p, this_msize=%d\\n\", ptr, this_msize);\n\t\t}\n#endif\n\t\ttiny_free_list_add_ptr(rack, tiny_mag_ptr, leftover_ptr, leftover_msize);\n\t\tthis_msize = msize;\n\t}\n\nreturn_tiny_alloc:\n\ttiny_mag_ptr->mag_num_objects++;\n\ttiny_mag_ptr->mag_num_bytes_in_objects += TINY_BYTES_FOR_MSIZE(this_msize);\n\n\t// Update this region's bytes in use count\n\tregion_trailer_t *node = REGION_TRAILER_FOR_TINY_REGION(TINY_REGION_FOR_PTR(ptr));\n\tsize_t bytes_used = node->bytes_used + TINY_BYTES_FOR_MSIZE(this_msize);\n\tnode->bytes_used = (unsigned int)bytes_used;\n\n\t// Emptiness discriminant\n\tif (bytes_used < DENSITY_THRESHOLD(TINY_REGION_PAYLOAD_BYTES)) {\n\t\t/* After this allocation the region is still sparse, so it must have been even more so before\n\t\t * the allocation. That implies the region is already correctly marked. Do nothing. */\n\t} else {\n\t\t/* Region has crossed threshold from sparsity to density. Mark it not \"suitable\" on the\n\t\t * recirculation candidates list. */\n\t\tnode->recirc_suitable = FALSE;\n\t}\n#if DEBUG_MALLOC\n\tif (LOG(szone, ptr)) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"in tiny_malloc_from_free_list(), ptr=%p, this_msize=%d, msize=%d\\n\", ptr, this_msize, msize);\n\t}\n#endif\n\tif (this_msize > 1) {\n\t\tset_tiny_meta_header_in_use(ptr, this_msize);\n\t} else {\n\t\tset_tiny_meta_header_in_use_1(ptr);\n\t}\n\treturn ptr;\n}\n\nvoid *\ntiny_malloc_should_clear(rack_t *rack, msize_t msize, boolean_t cleared_requested)\n{\n\tvoid *ptr;\n\tmag_index_t mag_index = tiny_mag_get_thread_index() % rack->num_magazines;\n\tmagazine_t *tiny_mag_ptr = &(rack->magazines[mag_index]);\n\n\tMALLOC_TRACE(TRACE_tiny_malloc, (uintptr_t)rack, TINY_BYTES_FOR_MSIZE(msize), (uintptr_t)tiny_mag_ptr, cleared_requested);\n\n#if DEBUG_MALLOC\n\tif (DEPOT_MAGAZINE_INDEX == mag_index) {\n\t\tmalloc_zone_error(rack->debug_flags, true, \"malloc called for magazine index -1\\n\");\n\t\treturn (NULL);\n\t}\n\n\tif (!msize) {\n\t\tmalloc_zone_error(rack->debug_flags, true, \"invariant broken (!msize) in allocation (region)\\n\");\n\t\treturn (NULL);\n\t}\n#endif\n\n\tSZONE_MAGAZINE_PTR_LOCK(tiny_mag_ptr);\n\n#if CONFIG_TINY_CACHE\n\tptr = tiny_mag_ptr->mag_last_free;\n\n\tif (tiny_mag_ptr->mag_last_free_msize == msize) {\n\t\t// we have a winner\n\t\ttiny_mag_ptr->mag_last_free = NULL;\n\t\ttiny_mag_ptr->mag_last_free_msize = 0;\n\t\ttiny_mag_ptr->mag_last_free_rgn = NULL;\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\tCHECK(szone, __PRETTY_FUNCTION__);\n\t\tif (cleared_requested) {\n\t\t\tmemset(ptr, 0, TINY_BYTES_FOR_MSIZE(msize));\n\t\t}\n#if DEBUG_MALLOC\n\t\tif (LOG(szone, ptr)) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"in tiny_malloc_should_clear(), tiny cache ptr=%p, msize=%d\\n\", ptr, msize);\n\t\t}\n#endif\n\t\treturn ptr;\n\t}\n#endif /* CONFIG_TINY_CACHE */\n\n\twhile (1) {\n\t\tptr = tiny_malloc_from_free_list(rack, tiny_mag_ptr, mag_index, msize);\n\t\tif (ptr) {\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\tCHECK(szone, __PRETTY_FUNCTION__);\n\t\t\tif (cleared_requested) {\n\t\t\t\tmemset(ptr, 0, TINY_BYTES_FOR_MSIZE(msize));\n\t\t\t}\n\t\t\treturn ptr;\n\t\t}\n\n\t\tif (tiny_get_region_from_depot(rack, tiny_mag_ptr, mag_index, msize)) {\n\t\t\tptr = tiny_malloc_from_free_list(rack, tiny_mag_ptr, mag_index, msize);\n\t\t\tif (ptr) {\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\t\tCHECK(szone, __PRETTY_FUNCTION__);\n\t\t\t\tif (cleared_requested) {\n\t\t\t\t\tmemset(ptr, 0, TINY_BYTES_FOR_MSIZE(msize));\n\t\t\t\t}\n\t\t\t\treturn ptr;\n\t\t\t}\n\t\t}\n\n\t\t// The magazine is exhausted. A new region (heap) must be allocated to satisfy this call to malloc().\n\t\t// The allocation, an mmap() system call, will be performed outside the magazine spin locks by the first\n\t\t// thread that suffers the exhaustion. That thread sets \"alloc_underway\" and enters a critical section.\n\t\t// Threads arriving here later are excluded from the critical section, yield the CPU, and then retry the\n\t\t// allocation. After some time the magazine is resupplied, the original thread leaves with its allocation,\n\t\t// and retry-ing threads succeed in the code just above.\n\t\tif (!tiny_mag_ptr->alloc_underway) {\n\t\t\tvoid *fresh_region;\n\n\t\t\t// time to create a new region (do this outside the magazine lock)\n\t\t\ttiny_mag_ptr->alloc_underway = TRUE;\n\t\t\tOSMemoryBarrier();\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\tfresh_region = mvm_allocate_pages_securely(TINY_REGION_SIZE, TINY_BLOCKS_ALIGN, VM_MEMORY_MALLOC_TINY, rack->debug_flags);\n\t\t\tSZONE_MAGAZINE_PTR_LOCK(tiny_mag_ptr);\n\n\t\t\t// DTrace USDT Probe\n\t\t\tMAGMALLOC_ALLOCREGION(TINY_SZONE_FROM_RACK(rack), (int)mag_index, fresh_region, TINY_REGION_SIZE);\n\n\t\t\tif (!fresh_region) { // out of memory!\n\t\t\t\ttiny_mag_ptr->alloc_underway = FALSE;\n\t\t\t\tOSMemoryBarrier();\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\t\treturn NULL;\n\t\t\t}\n\n\t\t\tptr = tiny_malloc_from_region_no_lock(rack, tiny_mag_ptr, mag_index, msize, fresh_region);\n\n\t\t\t// we don't clear because this freshly allocated space is pristine\n\t\t\ttiny_mag_ptr->alloc_underway = FALSE;\n\t\t\tOSMemoryBarrier();\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\tCHECK(szone, __PRETTY_FUNCTION__);\n\t\t\treturn ptr;\n\t\t} else {\n\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\tyield();\n\t\t\tSZONE_MAGAZINE_PTR_LOCK(tiny_mag_ptr);\n\t\t}\n\t}\n\t/* NOTREACHED */\n}\n\nsize_t\ntiny_size(rack_t *rack, const void *ptr)\n{\n\tif (tiny_region_for_ptr_no_lock(rack, ptr)) {\n\t\tif (TINY_INDEX_FOR_PTR(ptr) >= NUM_TINY_BLOCKS) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tboolean_t is_free;\n\t\tmsize_t msize = get_tiny_meta_header(ptr, &is_free);\n\t\tif (is_free) {\n\t\t\treturn 0;\n\t\t}\n\n#if CONFIG_TINY_CACHE\n\t\t{\n\t\t\tmag_index_t mag_index = MAGAZINE_INDEX_FOR_TINY_REGION(TINY_REGION_FOR_PTR(ptr));\n\t\t\tif (DEPOT_MAGAZINE_INDEX != mag_index) {\n\t\t\t\tmagazine_t *tiny_mag_ptr = &rack->magazines[mag_index];\n\n\t\t\t\tif (msize < TINY_QUANTUM && ptr == tiny_mag_ptr->mag_last_free) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (mag_index = 0; mag_index < rack->num_magazines; mag_index++) {\n\t\t\t\t\tmagazine_t *tiny_mag_ptr = &(rack->magazines[mag_index]);\n\n\t\t\t\t\tif (msize < TINY_QUANTUM && ptr == tiny_mag_ptr->mag_last_free) {\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n#endif\n\t\treturn TINY_BYTES_FOR_MSIZE(msize);\n\t}\n\n\treturn 0;\n}\n\nstatic MALLOC_NOINLINE void\nfree_tiny_botch(rack_t *rack, tiny_free_list_t *ptr)\n{\n\tmag_index_t mag_index = MAGAZINE_INDEX_FOR_TINY_REGION(TINY_REGION_FOR_PTR(ptr));\n\tmagazine_t *tiny_mag_ptr = &(rack->magazines[mag_index]);\n\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\tmalloc_zone_error(rack->debug_flags, true, \"Double free of object %p\\n\", ptr);\n}\n\nvoid\nfree_tiny(rack_t *rack, void *ptr, region_t tiny_region, size_t known_size)\n{\n\tmsize_t msize;\n\tboolean_t is_free;\n\tmag_index_t mag_index = MAGAZINE_INDEX_FOR_TINY_REGION(tiny_region);\n\tmagazine_t *tiny_mag_ptr = &(rack->magazines[mag_index]);\n\n\tMALLOC_TRACE(TRACE_tiny_free, (uintptr_t)rack, (uintptr_t)ptr, (uintptr_t)tiny_mag_ptr, known_size);\n\n\t// ptr is known to be in tiny_region\n\tif (known_size) {\n\t\tmsize = TINY_MSIZE_FOR_BYTES(known_size + TINY_QUANTUM - 1);\n\t} else {\n\t\tmsize = get_tiny_meta_header(ptr, &is_free);\n\t\tif (is_free) {\n\t\t\tfree_tiny_botch(rack, ptr);\n\t\t\treturn;\n\t\t}\n\t}\n#if DEBUG_MALLOC\n\tif (!msize) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"*** free_tiny() block in use is too large: %p\\n\", ptr);\n\t\treturn;\n\t}\n#endif\n\n\tSZONE_MAGAZINE_PTR_LOCK(tiny_mag_ptr);\n\n#if CONFIG_TINY_CACHE\n\t// Depot does not participate in CONFIG_TINY_CACHE since it can't be directly malloc()'d\n\tif (DEPOT_MAGAZINE_INDEX != mag_index) {\n\t\tif (msize < TINY_QUANTUM) {\t\t\t\t\t  // to see if the bits fit in the last 4 bits\n\t\t\tvoid *ptr2 = tiny_mag_ptr->mag_last_free; // Might be NULL\n\t\t\tmsize_t msize2 = tiny_mag_ptr->mag_last_free_msize;\n\t\t\tregion_t rgn2 = tiny_mag_ptr->mag_last_free_rgn;\n\n\t\t\t/* check that we don't already have this pointer in the cache */\n\t\t\tif (ptr == ptr2) {\n\t\t\t\tfree_tiny_botch(rack, ptr);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ((rack->debug_flags & MALLOC_DO_SCRIBBLE) && msize) {\n\t\t\t\tmemset(ptr, SCRABBLE_BYTE, TINY_BYTES_FOR_MSIZE(msize));\n\t\t\t}\n\n\t\t\ttiny_mag_ptr->mag_last_free = ptr;\n\t\t\ttiny_mag_ptr->mag_last_free_msize = msize;\n\t\t\ttiny_mag_ptr->mag_last_free_rgn = tiny_region;\n\n\t\t\tif (!ptr2) {\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\t\tCHECK(szone, __PRETTY_FUNCTION__);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmsize = msize2;\n\t\t\tptr = ptr2;\n\t\t\ttiny_region = rgn2;\n\t\t}\n\t}\n#endif /* CONFIG_TINY_CACHE */\n\n\t// Now in the time it took to acquire the lock, the region may have migrated\n\t// from one magazine to another. I.e. trailer->mag_index is volatile.\n\t// In which case the magazine lock we obtained (namely magazines[mag_index].mag_lock)\n\t// is stale. If so, keep on tryin' ...\n\tregion_trailer_t *trailer = REGION_TRAILER_FOR_TINY_REGION(tiny_region);\n\tmag_index_t refreshed_index;\n\n\twhile (mag_index != (refreshed_index = trailer->mag_index)) { // Note assignment\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\tmag_index = refreshed_index;\n\t\ttiny_mag_ptr = &(rack->magazines[mag_index]);\n\t\tSZONE_MAGAZINE_PTR_LOCK(tiny_mag_ptr);\n\t}\n\n\tif (tiny_free_no_lock(rack, tiny_mag_ptr, mag_index, tiny_region, ptr, msize)) {\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t}\n\n\tCHECK(szone, __PRETTY_FUNCTION__);\n}\n\nunsigned\ntiny_batch_malloc(szone_t *szone, size_t size, void **results, unsigned count)\n{\n\tmsize_t msize = TINY_MSIZE_FOR_BYTES(size + TINY_QUANTUM - 1);\n\tunsigned found = 0;\n\tmag_index_t mag_index = tiny_mag_get_thread_index() % szone->tiny_rack.num_magazines;\n\tmagazine_t *tiny_mag_ptr = &(szone->tiny_rack.magazines[mag_index]);\n\n\t// make sure to return objects at least one quantum in size\n\tif (!msize) {\n\t\tmsize = 1;\n\t}\n\n\tCHECK(szone, __PRETTY_FUNCTION__);\n\n\t// We must lock the zone now, since tiny_malloc_from_free_list assumes that\n\t// the caller has done so.\n\tSZONE_MAGAZINE_PTR_LOCK(tiny_mag_ptr);\n\n\t// with the zone locked, allocate objects from the free list until all\n\t// sufficiently large objects have been exhausted, or we have met our quota\n\t// of objects to allocate.\n\twhile (found < count) {\n\t\tvoid *ptr = tiny_malloc_from_free_list(&szone->tiny_rack, tiny_mag_ptr, mag_index, msize);\n\t\tif (!ptr) {\n\t\t\tbreak;\n\t\t}\n\n\t\t*results++ = ptr;\n\t\tfound++;\n\t}\n\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\treturn found;\n}\n\nvoid\ntiny_batch_free(szone_t *szone, void **to_be_freed, unsigned count)\n{\n\tunsigned cc = 0;\n\tvoid *ptr;\n\tregion_t tiny_region = NULL;\n\tboolean_t is_free;\n\tmsize_t msize;\n\tmagazine_t *tiny_mag_ptr = NULL;\n\tmag_index_t mag_index = -1;\n\n\t// frees all the pointers in to_be_freed\n\t// note that to_be_freed may be overwritten during the process\n\tif (!count) {\n\t\treturn;\n\t}\n\n\tCHECK(szone, __PRETTY_FUNCTION__);\n\twhile (cc < count) {\n\t\tptr = to_be_freed[cc];\n\t\tif (ptr) {\n\t\t\tif (NULL == tiny_region || tiny_region != TINY_REGION_FOR_PTR(ptr)) { // region same as last iteration?\n\t\t\t\tif (tiny_mag_ptr) {\t\t\t\t\t\t\t\t\t\t\t\t  // non-NULL iff magazine lock taken\n\t\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\t\t\ttiny_mag_ptr = NULL;\n\t\t\t\t}\n\n\t\t\t\ttiny_region = tiny_region_for_ptr_no_lock(&szone->tiny_rack, ptr);\n\n\t\t\t\tif (tiny_region) {\n\t\t\t\t\ttiny_mag_ptr = mag_lock_zine_for_region_trailer(szone->tiny_rack.magazines,\n\t\t\t\t\t\t\tREGION_TRAILER_FOR_TINY_REGION(tiny_region),\n\t\t\t\t\t\t\tMAGAZINE_INDEX_FOR_TINY_REGION(tiny_region));\n\t\t\t\t\tmag_index = MAGAZINE_INDEX_FOR_TINY_REGION(tiny_region);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (tiny_region) {\n\t\t\t\t// this is a tiny pointer\n\t\t\t\tif (TINY_INDEX_FOR_PTR(ptr) >= NUM_TINY_BLOCKS) {\n\t\t\t\t\tbreak; // pointer to metadata; let the standard free deal with it\n\t\t\t\t}\n\t\t\t\tmsize = get_tiny_meta_header(ptr, &is_free);\n\t\t\t\tif (is_free) {\n\t\t\t\t\tbreak; // a double free; let the standard free deal with it\n\t\t\t\t}\n\t\t\t\tif (!tiny_free_no_lock(&szone->tiny_rack, tiny_mag_ptr, mag_index, tiny_region, ptr, msize)) {\n\t\t\t\t\t// Arrange to re-acquire magazine lock\n\t\t\t\t\ttiny_mag_ptr = NULL;\n\t\t\t\t\ttiny_region = NULL;\n\t\t\t\t}\n\t\t\t\tto_be_freed[cc] = NULL;\n\t\t\t} else {\n\t\t\t\t// No region in this zone claims ptr; let the standard free deal with it\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tcc++;\n\t}\n\n\tif (tiny_mag_ptr) {\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\ttiny_mag_ptr = NULL;\n\t}\n}\n\n\nvoid\nprint_tiny_free_list(rack_t *rack)\n{\n\ttiny_free_list_t *ptr;\n\t_SIMPLE_STRING b = _simple_salloc();\n\tmag_index_t mag_index;\n\n\tif (b) {\n\t\t_simple_sappend(b, \"tiny free sizes:\\n\");\n\t\tfor (mag_index = -1; mag_index < rack->num_magazines; mag_index++) {\n\t\t\tgrain_t slot = 0;\n\t\t\t_simple_sprintf(b, \"\\tMagazine %d: \", mag_index);\n\t\t\twhile (slot < NUM_TINY_SLOTS) {\n\t\t\t\tptr = rack->magazines[mag_index].mag_free_list[slot].p;\n\t\t\t\tif (ptr) {\n\t\t\t\t\t_simple_sprintf(b, \"%s%y[%d]; \", (slot == NUM_TINY_SLOTS - 1) ? \">=\" : \"\", (slot + 1) * TINY_QUANTUM,\n\t\t\t\t\t\t\t\t\tfree_list_count(rack, (free_list_t){ .p = ptr }));\n\t\t\t\t}\n\t\t\t\tslot++;\n\t\t\t}\n\t\t\t_simple_sappend(b, \"\\n\");\n\t\t}\n\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"%s\\n\", _simple_string(b));\n\t\t_simple_sfree(b);\n\t}\n}\n\nvoid\nprint_tiny_region(boolean_t verbose, region_t region, size_t bytes_at_start, size_t bytes_at_end)\n{\n\tunsigned counts[1024];\n\tunsigned in_use = 0;\n\tuintptr_t start = (uintptr_t)TINY_REGION_ADDRESS(region);\n\tuintptr_t current = start + bytes_at_start;\n\tuintptr_t limit = (uintptr_t)TINY_REGION_END(region) - bytes_at_end;\n\tboolean_t is_free;\n\tmsize_t msize;\n\tunsigned ci;\n\t_SIMPLE_STRING b;\n\tuintptr_t pgTot = 0;\n\n\tif (region == HASHRING_REGION_DEALLOCATED) {\n\t\tif ((b = _simple_salloc()) != NULL) {\n\t\t\t_simple_sprintf(b, \"Tiny region [unknown address] was returned to the OS\\n\");\n\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"%s\\n\", _simple_string(b));\n\t\t\t_simple_sfree(b);\n\t\t}\n\t\treturn;\n\t}\n\n\tmemset(counts, 0, sizeof(counts));\n\twhile (current < limit) {\n\t\tmsize = get_tiny_meta_header((void *)current, &is_free);\n\t\tif (is_free && !msize && (current == start)) {\n\t\t\t// first block is all free\n\t\t\tuintptr_t pgLo = round_page_quanta(start + sizeof(tiny_free_list_t) + sizeof(msize_t));\n\t\t\tuintptr_t pgHi = trunc_page_quanta(start + TINY_REGION_SIZE - sizeof(msize_t));\n\n\t\t\tif (pgLo < pgHi) {\n\t\t\t\tpgTot += (pgHi - pgLo);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tif (!msize) {\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** error with %p: msize=%d\\n\", (void *)current, (unsigned)msize);\n\t\t\tbreak;\n\t\t}\n\t\tif (!is_free) {\n\t\t\t// block in use\n\t\t\tif (msize > NUM_TINY_SLOTS) {\n\t\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** error at %p msize for in_use is %d\\n\", (void *)current, msize);\n\t\t\t}\n\t\t\tif (msize < 1024) {\n\t\t\t\tcounts[msize]++;\n\t\t\t}\n\t\t\tin_use++;\n\t\t} else {\n\t\t\tuintptr_t pgLo = round_page_quanta(current + sizeof(tiny_free_list_t) + sizeof(msize_t));\n\t\t\tuintptr_t pgHi = trunc_page_quanta(current + TINY_BYTES_FOR_MSIZE(msize) - sizeof(msize_t));\n\n\t\t\tif (pgLo < pgHi) {\n\t\t\t\tpgTot += (pgHi - pgLo);\n\t\t\t}\n\t\t}\n\t\tcurrent += TINY_BYTES_FOR_MSIZE(msize);\n\t}\n\tif ((b = _simple_salloc()) != NULL) {\n\t\t_simple_sprintf(b, \"Tiny region [%p-%p, %y] \\t\", (void *)start, TINY_REGION_END(region), (int)TINY_REGION_SIZE);\n\t\t_simple_sprintf(b, \"Magazine=%d \\t\", MAGAZINE_INDEX_FOR_TINY_REGION(region));\n\t\t_simple_sprintf(b, \"Allocations in use=%d \\t Bytes in use=%ly \\t\", in_use, BYTES_USED_FOR_TINY_REGION(region));\n\t\tif (bytes_at_end || bytes_at_start) {\n\t\t\t_simple_sprintf(b, \"Untouched=%ly \", bytes_at_end + bytes_at_start);\n\t\t}\n\t\tif (DEPOT_MAGAZINE_INDEX == MAGAZINE_INDEX_FOR_TINY_REGION(region)) {\n\t\t\t_simple_sprintf(b, \"Advised MADV_FREE=%ly\", pgTot);\n\t\t} else {\n\t\t\t_simple_sprintf(b, \"Fragments subject to reclamation=%ly\", pgTot);\n\t\t}\n\t\tif (verbose && in_use) {\n\t\t\t_simple_sappend(b, \"\\n\\tSizes in use: \");\n\t\t\tfor (ci = 0; ci < 1024; ci++) {\n\t\t\t\tif (counts[ci]) {\n\t\t\t\t\t_simple_sprintf(b, \"%d[%d] \", TINY_BYTES_FOR_MSIZE(ci), counts[ci]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"%s\\n\", _simple_string(b));\n\t\t_simple_sfree(b);\n\t}\n}\n\nstatic char *tiny_freelist_fail_msg = \"check: tiny free list incorrect \";\n\n#define TINY_FREELIST_FAIL(fmt, ...) \\\n\tmalloc_zone_check_fail(tiny_freelist_fail_msg, \\\n\t\t\t\" (slot=%u), counter=%d\\n\" fmt, slot, counter, __VA_ARGS__);\n\nboolean_t\ntiny_free_list_check(rack_t *rack, grain_t slot, unsigned counter)\n{\n\tmag_index_t mag_index;\n\n\tfor (mag_index = -1; mag_index < rack->num_magazines; mag_index++) {\n\t\tmagazine_t *tiny_mag_ptr = &(rack->magazines[mag_index]);\n\t\tSZONE_MAGAZINE_PTR_LOCK(tiny_mag_ptr);\n\n\t\tunsigned count = 0;\n\t\ttiny_free_list_t *ptr = rack->magazines[mag_index].mag_free_list[slot].p;\n\t\tboolean_t is_free;\n\t\ttiny_free_list_t *previous = NULL;\n\n\t\twhile (ptr) {\n\t\t\tis_free = tiny_meta_header_is_free(ptr);\n\t\t\tif (!is_free) {\n\t\t\t\tTINY_FREELIST_FAIL(\"*** in-use ptr in free list slot=%u count=%d ptr=%p\\n\", slot, count, ptr);\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (((uintptr_t)ptr) & (TINY_QUANTUM - 1)) {\n\t\t\t\tTINY_FREELIST_FAIL(\"*** unaligned ptr in free list slot=%u count=%d ptr=%p\\n\", slot, count, ptr);\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (!tiny_region_for_ptr_no_lock(rack, ptr)) {\n\t\t\t\tTINY_FREELIST_FAIL(\"*** ptr not in szone slot=%d  count=%u ptr=%p\\n\", slot, count, ptr);\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (free_list_unchecksum_ptr(rack, &ptr->previous) != previous) {\n\t\t\t\tTINY_FREELIST_FAIL(\"*** previous incorrectly set slot=%u count=%d ptr=%p\\n\", slot, count, ptr);\n\t\t\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tprevious = ptr;\n\t\t\tptr = free_list_unchecksum_ptr(rack, &ptr->next);\n\t\t\tcount++;\n\t\t}\n\t\t\n\t\tSZONE_MAGAZINE_PTR_UNLOCK(tiny_mag_ptr);\n\t}\n\treturn 1;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/magazine_zone.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __MAGAZINE_ZONE_H\n#define __MAGAZINE_ZONE_H\n\n/*********************\tDEFINITIONS\t************************/\n\n// Out-of-band free list entry. Out-of-band free list entries are used\n// in specific cases where a free-list entry is the *only* data on a given page,\n// and the presence of that entry causes the page to stay dirty.\n//\n// `ptr` is all 16-bit quantum-sized index and packed, as that references a\n// block address inside the current region. `next` and `prev` have to be pointer\n// sized references, as these values can point to entries outside the current\n// region, so it's not safe to compact them.\ntypedef struct {\n\tuintptr_t prev;\n\tuintptr_t next;\n\tuint16_t ptr;\n} MALLOC_PACKED oob_free_entry_s, *oob_free_entry_t;\n\n// In-place free list entry. Unlike the out-of-band entry, the in-place entries\n// are stored at the start of the range that has been freed.\ntypedef struct _inplace_free_entry_s *inplace_free_entry_t;\n\ntypedef struct {\n\tvoid *ptr;\n\tuint8_t checksum;\n} inplace_linkage_s;\n\ntypedef union {\n\tinplace_free_entry_t p;\n\tuintptr_t u;\n} inplace_union;\n\ntypedef struct _inplace_free_entry_s {\n\tinplace_union previous;\n\tinplace_union next;\n} inplace_free_entry_s, *inplace_free_entry_t;\n\n#ifdef __LP64__\nMALLOC_STATIC_ASSERT(sizeof(inplace_free_entry_s) == 16, \"inplace free list must be 16-bytes long\");\n#else\nMALLOC_STATIC_ASSERT(sizeof(inplace_free_entry_s) == 8, \"inplace free list must be 8-bytes long\");\n#endif\n\ntypedef struct _small_inplace_free_entry_s {\n\tinplace_linkage_s previous;\n\tinplace_linkage_s next;\n} small_inplace_free_entry_s, *small_inplace_free_entry_t;\n\ntypedef union {\n\tsmall_inplace_free_entry_t small_inplace;\n\tinplace_free_entry_t inplace;\n\toob_free_entry_t oob;\n\tvoid *p;\n} free_list_t;\n\ntypedef struct {\n\tinplace_union previous;\n\tinplace_union next;\n} tiny_free_list_t;\n\ntypedef unsigned int grain_t; // N.B. wide enough to index all free slots\n\ntypedef int mag_index_t;\n\n#define CHECK_REGIONS (1 << 31)\n#define DISABLE_ASLR (1 << 30)\n\n#define MAX_RECORDER_BUFFER 256\n\n/*********************\tDEFINITIONS for tiny\t************************/\n\n/*\n * Memory in the Tiny range is allocated from regions (heaps) pointed to by the\n * szone's hashed_regions pointer.\n *\n * Each region is laid out as a heap, followed by a header block, all within\n * a 1MB (2^20) block.  This means there are 64520 16-byte blocks and the header\n * is 16138 bytes, making the total 1048458 bytes, leaving 118 bytes unused.\n *\n * The header block is arranged as in struct tiny_region defined just below, and\n * consists of two bitfields (or bit arrays) interleaved 32 bits by 32 bits.\n *\n * Each bitfield comprises NUM_TINY_BLOCKS bits, and refers to the corresponding\n * TINY_QUANTUM block within the heap.\n *\n * The bitfields are used to encode the state of memory within the heap.  The header bit indicates\n * that the corresponding quantum is the first quantum in a block (either in use or free).  The\n * in-use bit is set for the header if the block has been handed out (allocated).  If the header\n * bit is not set, the in-use bit is invalid.\n *\n * The szone maintains an array of NUM_TINY_SLOTS freelists, each of which is used to hold\n * free objects of the corresponding quantum size.\n *\n * A free block is laid out depending on its size, in order to fit all free\n * blocks in 16 bytes, on both 32 and 64 bit platforms.  One quantum blocks do\n * not store their size in the block, instead relying on the header information\n * to determine their size.  Blocks of two or more quanta have room to store\n * their size in the block, and store it both after the 'next' pointer, and in\n * the last 2 bytes of the block.\n *\n * 1-quantum block\n * Offset (32-bit mode)\t(64-bit mode)\n * 0x0          0x0      : previous\n * 0x4          0x08     : next\n * end          end\n *\n * >1-quantum block\n * Offset (32-bit mode)\t(64-bit mode)\n * 0x0          0x0      : previous\n * 0x4          0x08     : next\n * 0x8          0x10     : size (in quantum counts)\n * end - 2      end - 2  : size (in quantum counts)\n * end          end\n *\n * All fields are pointer-sized, except for the size which is an unsigned short.\n *\n */\n\n#define FOLLOWING_TINY_PTR(ptr, msize) (((unsigned char *)(ptr)) + ((msize) << SHIFT_TINY_QUANTUM))\n\n#define TINY_BLOCKS_ALIGN (SHIFT_TINY_CEIL_BLOCKS + SHIFT_TINY_QUANTUM) // 20\n\n#define TINY_ENTROPY_BITS 15\n#define TINY_ENTROPY_MASK ((1 << TINY_ENTROPY_BITS) - 1)\n\n/*\n * Avoid having so much entropy that the end of a valid tiny allocation\n * might overrun the end of the tiny region.\n */\n#if TINY_ENTROPY_MASK + NUM_TINY_SLOTS > NUM_TINY_BLOCKS\n#error Too many entropy bits for tiny region requested\n#endif\n\n/*\n * Enough room for the data, followed by the bit arrays (2-bits per block)\n * plus rounding to the nearest page.\n */\n#define CEIL_NUM_TINY_BLOCKS_WORDS (((NUM_TINY_BLOCKS + 31) & ~31) >> 5)\n#define TINY_METADATA_SIZE (sizeof(region_trailer_t) + sizeof(tiny_header_inuse_pair_t) * CEIL_NUM_TINY_BLOCKS_WORDS)\n#define TINY_REGION_SIZE ((NUM_TINY_BLOCKS * TINY_QUANTUM + TINY_METADATA_SIZE + PAGE_MAX_SIZE - 1) & ~(PAGE_MAX_SIZE - 1))\n\n#define TINY_METADATA_START (NUM_TINY_BLOCKS * TINY_QUANTUM)\n\n/*\n * Beginning and end pointers for a region's heap.\n */\n#define TINY_REGION_ADDRESS(region) ((void *)(region))\n#define TINY_REGION_END(region) ((void *)(((uintptr_t)(region)) + (NUM_TINY_BLOCKS * TINY_QUANTUM)))\n\n/*\n * Locate the heap base for a pointer known to be within a tiny region.\n */\n#define TINY_REGION_FOR_PTR(_p) ((void *)((uintptr_t)(_p) & ~((1 << TINY_BLOCKS_ALIGN) - 1)))\n\n/*\n * Convert between byte and msize units.\n */\n#define TINY_BYTES_FOR_MSIZE(_m) ((_m) << SHIFT_TINY_QUANTUM)\n#define TINY_MSIZE_FOR_BYTES(_b) ((_b) >> SHIFT_TINY_QUANTUM)\n\n#if MALLOC_TARGET_64BIT\n#define TINY_FREE_SIZE(ptr) (((msize_t *)(ptr))[8])\n#else // MALLOC_TARGET_64BIT\n#define TINY_FREE_SIZE(ptr) (((msize_t *)(ptr))[4])\n#endif // MALLOC_TARGET_64BIT\n#define TINY_PREVIOUS_MSIZE(ptr) ((msize_t *)(ptr))[-1]\n\n/*\n * Layout of a tiny region\n */\ntypedef uint32_t tiny_block_t[4]; // assert(TINY_QUANTUM == sizeof(tiny_block_t))\n\ntypedef struct tiny_header_inuse_pair {\n\tuint32_t header;\n\tuint32_t inuse;\n} tiny_header_inuse_pair_t;\n\ntypedef struct region_trailer {\n\tstruct region_trailer *prev;\n\tstruct region_trailer *next;\n\tboolean_t recirc_suitable;\n\tvolatile int pinned_to_depot;\n\tunsigned bytes_used;\n\tmag_index_t mag_index;\n} region_trailer_t;\n\ntypedef struct tiny_region {\n\ttiny_block_t blocks[NUM_TINY_BLOCKS];\n\n\tregion_trailer_t trailer;\n\n\t// The interleaved bit arrays comprising the header and inuse bitfields.\n\t// The unused bits of each component in the last pair will be initialized to sentinel values.\n\ttiny_header_inuse_pair_t pairs[CEIL_NUM_TINY_BLOCKS_WORDS];\n\n\tuint8_t pad[TINY_REGION_SIZE - (NUM_TINY_BLOCKS * sizeof(tiny_block_t)) - TINY_METADATA_SIZE];\n} * tiny_region_t;\n\n/*\n * Per-region meta data for tiny allocator\n */\n#define REGION_TRAILER_FOR_TINY_REGION(r) (&(((tiny_region_t)(r))->trailer))\n#define MAGAZINE_INDEX_FOR_TINY_REGION(r) (REGION_TRAILER_FOR_TINY_REGION(r)->mag_index)\n#define BYTES_USED_FOR_TINY_REGION(r) (REGION_TRAILER_FOR_TINY_REGION(r)->bytes_used)\n\n/*\n * Locate the block header for a pointer known to be within a tiny region.\n */\n#define TINY_BLOCK_HEADER_FOR_PTR(_p) ((void *)&(((tiny_region_t)TINY_REGION_FOR_PTR(_p))->pairs))\n\n/*\n * Locate the inuse map for a given block header pointer.\n */\n#define TINY_INUSE_FOR_HEADER(_h) ((void *)&(((tiny_header_inuse_pair_t *)(_h))->inuse))\n\n/*\n * Compute the bitmap index for a pointer known to be within a tiny region.\n */\n#define TINY_INDEX_FOR_PTR(_p) (((uintptr_t)(_p) >> SHIFT_TINY_QUANTUM) & (NUM_TINY_CEIL_BLOCKS - 1))\n\n/*\n * Offset back to an szone_t given prior knowledge that this rack_t\n * is contained within an szone_t.\n *\n * Note: the only place this is used, the dtrace probes, only occurs\n *       when the rack has been set up inside a scalable zone. Should\n *       this ever be used somewhere that this does not hold true\n *       (say, the test cases) then the pointer returned will be junk.\n */\n#define TINY_SZONE_FROM_RACK(_r) \\\n\t\t(szone_t *)((uintptr_t)(_r) - offsetof(struct szone_s, tiny_rack))\n\n\n#if !CONFIG_TINY_CACHE\n#warning CONFIG_TINY_CACHE turned off\n#endif\n\n#define TINY_REGION_PAYLOAD_BYTES (NUM_TINY_BLOCKS * TINY_QUANTUM)\n\n/*********************\tDEFINITIONS for small\t************************/\n\n/*\n * Memory in the Small range is allocated from regions (heaps) pointed to by the szone's hashed_regions\n * pointer.\n *\n * Each region is laid out as a heap, followed by the metadata array, all within an 8MB (2^23) block.\n * The array is arranged as an array of shorts, one for each SMALL_QUANTUM in the heap. There are \n * 16319 512-blocks and the array is 16319*2 bytes, which totals 8387966, leaving 642 bytes unused. \n * Once the region trailer is accounted for, there is room for 61 out-of-band free list entries in \n * the remaining padding (or 6, if the region was split into 16320 blocks, not 16319).\n *\n * The 16-bit shorts in the region are used for allocation metadata. The MSB bit marks a block as\n * either free, or not. The remaining 15-bits give the size of the allocation, defined in \"msize\", the\n * quantum-shifted size of the allocation.\n *\n * The metadata table either:\n *\n *    1. Stores the allocation size in the first short for the block, with the MSB cleared to indicate\n *       that the block is allocated and in-use, or,\n *\n *    2. Stores the free-allocation size in the first and last shorts for the block, with the MSB set\n *       in both places to indicate that the block is freed. (Storing the range in last block allows\n *       for coalescing of adjacent free entries).\n *\n *    3. Zero, or \"middle\", meaning that this block in the region is not the start or end of an\n *       allocated block.\n *\n * The small zone represents the free list in one of two ways:\n *\n *    1. In-line free list entries. These are stored at the starting address of the just-freed memory\n *       and both the previous and next pointer are checksummed to attempt to detect use-after-free\n *       writes.\n *\n *       An in-line free list entry is laid out as:\n *           |prev (uintptr_t)|checksum (uint8_t)|next (uintptr_t)|checksum (uint8_t)\n *\n *    2. Out-of-band free list entries. These utilitise the remaining padding in the 8mb region that\n *       follows the blocks, metadata and region trailer. Out-of-band entries are used *iff* the\n *       freed address lies on a page boundary and the freed region spans more than a page. If we were\n *       to store the free list entry in-line in that memory, it would keep the entire page dirty, \n *       so an out-of-band entry is used.\n *\n *       An out-of-band free list entry is laid out as:\n *           |prev (uintptr_t)|next (uintptr_t)|ptr (uint16_t)|\n *\n * The szone maintains an array of 32 freelists, each of which is used to hold free objects\n * of the corresponding quantum size.\n */\n\n#define SMALL_IS_FREE (1 << 15)\n#define FOLLOWING_SMALL_PTR(ptr, msize) (((unsigned char *)(ptr)) + ((msize) << SHIFT_SMALL_QUANTUM))\n\n/*\n * SMALL_IS_OOB is used mark to the MSB of OOB free list entries to show that they are in use, and \n * distinguish them from their initial, empty, state.\n */\n#define SMALL_IS_OOB (1 << 15)\n\n#define SMALL_ENTROPY_BITS 13\n#define SMALL_ENTROPY_MASK ((1 << SMALL_ENTROPY_BITS) - 1)\n\n/*\n * Avoid having so much entropy that the end of a valid small allocation\n * might overrun the end of the small region.\n */\n#if SMALL_ENTROPY_MASK + NUM_SMALL_SLOTS > NUM_SMALL_BLOCKS\n#error Too many entropy bits for small region requested\n#endif\n\n#define SMALL_METADATA_SIZE (sizeof(region_trailer_t) + NUM_SMALL_BLOCKS * sizeof(msize_t))\n#define SMALL_REGION_SIZE ((NUM_SMALL_BLOCKS * SMALL_QUANTUM + SMALL_METADATA_SIZE + PAGE_MAX_SIZE - 1) & ~(PAGE_MAX_SIZE - 1))\n\n#define SMALL_METADATA_START (NUM_SMALL_BLOCKS * SMALL_QUANTUM)\n\n/*\n * Beginning and end pointers for a region's heap.\n */\n#define SMALL_REGION_ADDRESS(region) ((unsigned char *)region)\n#define SMALL_REGION_END(region) (SMALL_REGION_ADDRESS(region) + (NUM_SMALL_BLOCKS * SMALL_QUANTUM))\n\n/*\n * Locate the heap base for a pointer known to be within a small region.\n */\n#define SMALL_REGION_FOR_PTR(_p) ((void *)((uintptr_t)(_p) & ~((1 << SMALL_BLOCKS_ALIGN) - 1)))\n#define SMALL_OFFSET_FOR_PTR(_p) ((uintptr_t)(_p) & ((1 << SMALL_BLOCKS_ALIGN) - 1))\n\n/*\n * Convert between byte and msize units.\n */\n#define SMALL_BYTES_FOR_MSIZE(_m) ((uint32_t)(_m) << SHIFT_SMALL_QUANTUM)\n#define SMALL_MSIZE_FOR_BYTES(_b) ((_b) >> SHIFT_SMALL_QUANTUM)\n\n#define SMALL_PREVIOUS_MSIZE(ptr) (*SMALL_METADATA_FOR_PTR(ptr - 1) & ~SMALL_IS_FREE)\n\n/*\n * Convert from msize unit to free list slot.\n */\n#define SMALL_FREE_SLOT_COUNT(_r) \\\n\t\t(((_r)->debug_flags & MALLOC_EXTENDED_SMALL_SLOTS) ? \\\n\t\t\t\tNUM_SMALL_SLOTS_LARGEMEM + 1 : NUM_SMALL_SLOTS + 1)\n#define SMALL_FREE_SLOT_FOR_MSIZE(_r, _m) \\\n\t\t(((_m) <= SMALL_FREE_SLOT_COUNT(_r)) ? ((_m) - 1) : (SMALL_FREE_SLOT_COUNT(_r) - 1))\n/* compare with MAGAZINE_FREELIST_BITMAP_WORDS */\n#define SMALL_FREELIST_BITMAP_WORDS(_r) ((SMALL_FREE_SLOT_COUNT(_r) + 31) >> 5)\n\n/*\n * Offset back to an szone_t given prior knowledge that this rack_t\n * is contained within an szone_t.\n *\n * Note: the only place this is used, the dtrace probes, only occurs\n *       when the rack has been set up inside a scalable zone. Should\n *       this ever be used somewhere that this does not hold true\n *       (say, the test cases) then the pointer returned will be junk.\n */\n#define SMALL_SZONE_FROM_RACK(_r) \\\n\t\t(szone_t *)((uintptr_t)(_r) - offsetof(struct szone_s, small_rack))\n\n/*\n * Layout of a small region\n */\ntypedef uint32_t small_block_t[SMALL_QUANTUM / sizeof(uint32_t)];\n#define SMALL_HEAP_SIZE (NUM_SMALL_BLOCKS * sizeof(small_block_t))\n#define SMALL_OOB_COUNT ((SMALL_REGION_SIZE - SMALL_HEAP_SIZE - SMALL_METADATA_SIZE) / sizeof(oob_free_entry_s))\n#define SMALL_OOB_SIZE (SMALL_OOB_COUNT * sizeof(oob_free_entry_s))\n#define SMALL_REGION_PAD (SMALL_REGION_SIZE - SMALL_HEAP_SIZE - SMALL_METADATA_SIZE - SMALL_OOB_SIZE)\n\ntypedef struct small_region {\n\tsmall_block_t blocks[NUM_SMALL_BLOCKS];\n\tregion_trailer_t trailer;\n\tmsize_t small_meta_words[NUM_SMALL_BLOCKS];\n\toob_free_entry_s small_oob_free_entries[SMALL_OOB_COUNT];\n\tuint8_t pad[SMALL_REGION_PAD];\n} * small_region_t;\n\n// The layout described above should result in a small_region_t being 8MB.\nMALLOC_STATIC_ASSERT(sizeof(struct small_region) == 8388608, \"incorrect small_region_size\");\n\n/*\n * Per-region meta data for small allocator\n */\n#define REGION_TRAILER_FOR_SMALL_REGION(r) (&(((small_region_t)(r))->trailer))\n#define MAGAZINE_INDEX_FOR_SMALL_REGION(r) (REGION_TRAILER_FOR_SMALL_REGION(r)->mag_index)\n#define BYTES_USED_FOR_SMALL_REGION(r) (REGION_TRAILER_FOR_SMALL_REGION(r)->bytes_used)\n\n/*\n * Locate the metadata base for a pointer known to be within a small region.\n */\n#define SMALL_META_HEADER_FOR_PTR(_p) (((small_region_t)SMALL_REGION_FOR_PTR(_p))->small_meta_words)\n\n/*\n * Compute the metadata index for a pointer known to be within a small region.\n */\n#define SMALL_META_INDEX_FOR_PTR(_p) (((uintptr_t)(_p) >> SHIFT_SMALL_QUANTUM) & (NUM_SMALL_CEIL_BLOCKS - 1))\n\n/*\n * Find the metadata word for a pointer known to be within a small region.\n */\n#define SMALL_METADATA_FOR_PTR(_p) (SMALL_META_HEADER_FOR_PTR(_p) + SMALL_META_INDEX_FOR_PTR(_p))\n\n/*\n * Determine whether a pointer known to be within a small region points to memory which is free.\n */\n#define SMALL_PTR_IS_FREE(_p) (*SMALL_METADATA_FOR_PTR(_p) & SMALL_IS_FREE)\n\n/*\n * Extract the msize value for a pointer known to be within a small region.\n */\n#define SMALL_PTR_SIZE(_p) (*SMALL_METADATA_FOR_PTR(_p) & ~SMALL_IS_FREE)\n\n#if !CONFIG_SMALL_CACHE\n#warning CONFIG_SMALL_CACHE turned off\n#endif\n\n#define SMALL_REGION_PAYLOAD_BYTES (NUM_SMALL_BLOCKS * SMALL_QUANTUM)\n\n/*************************  DEFINITIONS for large  ****************************/\n\n\ntypedef struct large_entry_s {\n\tvm_address_t address;\n\tvm_size_t size;\n\tboolean_t did_madvise_reusable;\n} large_entry_t;\n\n#if !CONFIG_LARGE_CACHE && DEBUG_MALLOC\n#warning CONFIG_LARGE_CACHE turned off\n#endif\n\n/*******************************************************************************\n * Per-processor magazine for tiny and small allocators\n ******************************************************************************/\n\ntypedef struct magazine_s { // vm_allocate()'d, so the array of magazines is page-aligned to begin with.\n\t// Take magazine_lock first,  Depot lock when needed for recirc, then szone->{tiny,small}_regions_lock when needed for alloc\n\t_malloc_lock_s magazine_lock MALLOC_CACHE_ALIGN;\n\t// Protection for the crtical section that does allocate_pages outside the magazine_lock\n\tvolatile boolean_t alloc_underway;\n\n\t// One element deep \"death row\", optimizes malloc/free/malloc for identical size.\n\tvoid *mag_last_free;\n\tmsize_t mag_last_free_msize;\t// msize for mag_last_free\n#if MALLOC_TARGET_64BIT\n\tuint32_t _pad;\n#endif\n\tregion_t mag_last_free_rgn; // holds the region for mag_last_free\n\n\tfree_list_t mag_free_list[MAGAZINE_FREELIST_SLOTS];\n\tuint32_t mag_bitmap[MAGAZINE_FREELIST_BITMAP_WORDS];\n\n\t// the first and last free region in the last block are treated as big blocks in use that are not accounted for\n\tsize_t mag_bytes_free_at_end;\n\tsize_t mag_bytes_free_at_start;\n\tregion_t mag_last_region; // Valid iff mag_bytes_free_at_end || mag_bytes_free_at_start > 0\n\n\t// bean counting ...\n\tsize_t mag_num_bytes_in_objects;\n\tsize_t num_bytes_in_magazine;\n\tunsigned mag_num_objects;\n\n\t// recirculation list -- invariant: all regions owned by this magazine that meet the emptiness criteria\n\t// are located nearer to the head of the list than any region that doesn't satisfy that criteria.\n\t// Doubly linked list for efficient extraction.\n\tunsigned recirculation_entries;\n\tregion_trailer_t *firstNode;\n\tregion_trailer_t *lastNode;\n\n#if MALLOC_TARGET_64BIT\n\tuintptr_t pad[320 - 14 - MAGAZINE_FREELIST_SLOTS -\n\t\t\t(MAGAZINE_FREELIST_BITMAP_WORDS + 1) / 2];\n#else\n\tuintptr_t pad[320 - 16 - MAGAZINE_FREELIST_SLOTS -\n\t\t\tMAGAZINE_FREELIST_BITMAP_WORDS];\n#endif\n\n} magazine_t;\n\n#if MALLOC_TARGET_64BIT\nMALLOC_STATIC_ASSERT(sizeof(magazine_t) == 2560, \"Incorrect padding in magazine_t\");\n#else\nMALLOC_STATIC_ASSERT(sizeof(magazine_t) == 1280, \"Incorrect padding in magazine_t\");\n#endif\n\n#define TINY_MAX_MAGAZINES 64 /* MUST BE A POWER OF 2! */\n#define TINY_MAGAZINE_PAGED_SIZE                                                   \\\n\t(((sizeof(magazine_t) * (TINY_MAX_MAGAZINES + 1)) + vm_page_quanta_size - 1) & \\\n\t~(vm_page_quanta_size - 1)) /* + 1 for the Depot */\n\n#define SMALL_MAX_MAGAZINES 64 /* MUST BE A POWER OF 2! */\n#define SMALL_MAGAZINE_PAGED_SIZE                                                   \\\n\t(((sizeof(magazine_t) * (SMALL_MAX_MAGAZINES + 1)) + vm_page_quanta_size - 1) & \\\n\t~(vm_page_quanta_size - 1)) /* + 1 for the Depot */\n\n#define DEPOT_MAGAZINE_INDEX -1\n\n/****************************** zone itself ***********************************/\n\n/*\n * Note that objects whose adddress are held in pointers here must be pursued\n * individually in the {tiny,small}_in_use_enumeration() routines. See for\n * example the treatment of region_hash_generation and tiny_magazines below.\n */\n\ntypedef struct szone_s {\t  // vm_allocate()'d, so page-aligned to begin with.\n\tmalloc_zone_t basic_zone; // first page will be given read-only protection\n\tuint8_t pad[PAGE_MAX_SIZE - sizeof(malloc_zone_t)];\n\n\tunsigned long cpu_id_key; // unused\n\t// remainder of structure is R/W (contains no function pointers)\n\tunsigned debug_flags;\n\tvoid *log_address;\n\n\t/* Allocation racks per allocator type. */\n\tstruct rack_s tiny_rack;\n\tstruct rack_s small_rack;\n\n\t/* large objects: all the rest */\n\t_malloc_lock_s large_szone_lock MALLOC_CACHE_ALIGN; // One customer at a time for large\n\tunsigned num_large_objects_in_use;\n\tunsigned num_large_entries;\n\tlarge_entry_t *large_entries; // hashed by location; null entries don't count\n\tsize_t num_bytes_in_large_objects;\n\n#if CONFIG_LARGE_CACHE\n\tint large_entry_cache_oldest;\n\tint large_entry_cache_newest;\n\tlarge_entry_t large_entry_cache[LARGE_ENTRY_CACHE_SIZE]; // \"death row\" for large malloc/free\n\tboolean_t large_legacy_reset_mprotect;\n\tsize_t large_entry_cache_reserve_bytes;\n\tsize_t large_entry_cache_reserve_limit;\n\tsize_t large_entry_cache_bytes; // total size of death row, bytes\n#endif\n\n\t/* flag and limits pertaining to altered malloc behavior for systems with\n\t * large amounts of physical memory */\n\tunsigned is_largemem;\n\tunsigned large_threshold;\n\tunsigned vm_copy_threshold;\n\n\t/* security cookie */\n\tuintptr_t cookie;\n\n\t/* The purgeable zone constructed by create_purgeable_zone() would like to hand off tiny and small\n\t * allocations to the default scalable zone. Record the latter as the \"helper\" zone here. */\n\tstruct szone_s *helper_zone;\n\n\tboolean_t flotsam_enabled;\n} szone_t;\n\n#define SZONE_PAGED_SIZE round_page_quanta((sizeof(szone_t)))\n\n#endif // __MAGAZINE_ZONE_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/magmallocProvider.d",
    "content": "provider magmalloc {\n\t\tprobe refreshIndex(void *, int, int);\n\t\tprobe depotRegion(void *, int, void *, int, int);\n\t\tprobe recircRegion(void *, int, void *, int, int);\n\t\tprobe allocRegion(void *, int, void *, int);\n\t\tprobe deallocRegion(void *, void *, int);\n\t\tprobe madvfreeRegion(void *, void *, void *, int);\n\t\tprobe pressureReliefBegin(void *, char *, int);\n\t\tprobe pressureReliefEnd(void *, char *, int, int);\n\t\tprobe mallocErrorBreak();\n};\n\n#pragma D attributes Evolving/Evolving/ISA provider magmalloc provider\n#pragma D attributes Private/Private/Unknown provider magmalloc module\n#pragma D attributes Private/Private/Unknown provider magmalloc function\n#pragma D attributes Evolving/Evolving/ISA provider magmalloc name\n#pragma D attributes Evolving/Evolving/ISA provider magmalloc args\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/malloc.c",
    "content": "/*\n * Copyright (c) 1999, 2000, 2003, 2005, 2008, 2012 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"internal.h\"\n\n#if TARGET_OS_IPHONE\n// malloc_report(ASL_LEVEL_INFO...) on iOS doesn't show up in the Xcode Console log of the device,\n// but ASL_LEVEL_NOTICE does.  So raising the log level is helpful.\n#undef ASL_LEVEL_INFO\n#define ASL_LEVEL_INFO ASL_LEVEL_NOTICE\n#endif // TARGET_OS_IPHONE\n\n#define USE_SLEEP_RATHER_THAN_ABORT 0\n\n/*\n\tMAX_LITE_MALLOCS\n \n\tIf msl lite is turned on due to a memory resource exception use this value as the maximum\n\tnumber of allocations allowed before msl lite is turned off. This prevents msl lite from being\n\tenabled indefinitely if the process never reaches 100% of its jetsam limit.\n\tSee rdar://problem/25950426 for a discussion of how this number was determined.\n */\n\n#define MAX_LITE_MALLOCS 100000000\n\ntypedef void(malloc_logger_t)(uint32_t type,\n\t\tuintptr_t arg1,\n\t\tuintptr_t arg2,\n\t\tuintptr_t arg3,\n\t\tuintptr_t result,\n\t\tuint32_t num_hot_frames_to_skip);\n\nextern malloc_logger_t *__syscall_logger; // use this to set up syscall logging (e.g., vm_allocate, vm_deallocate, mmap, munmap)\n\nstatic _malloc_lock_s _malloc_lock = _MALLOC_LOCK_INIT;\n#define MALLOC_LOCK() _malloc_lock_lock(&_malloc_lock)\n#define MALLOC_TRY_LOCK() _malloc_lock_trylock(&_malloc_lock)\n#define MALLOC_UNLOCK() _malloc_lock_unlock(&_malloc_lock)\n#define MALLOC_REINIT_LOCK() _malloc_lock_init(&_malloc_lock)\n\n/* The following variables are exported for the benefit of performance tools\n *\n * It should always be safe to first read malloc_num_zones, then read\n * malloc_zones without taking the lock, if only iteration is required and\n * provided that when malloc_destroy_zone is called all prior operations on that\n * zone are complete and no further calls referencing that zone can be made.\n */\nint32_t malloc_num_zones = 0;\nint32_t malloc_num_zones_allocated = 0;\nmalloc_zone_t **malloc_zones = 0;\nmalloc_logger_t *malloc_logger = NULL;\nstatic malloc_zone_t *initial_default_zone = NULL;\n\nunsigned malloc_debug_flags = 0;\nboolean_t malloc_tracing_enabled = false;\n\nunsigned malloc_check_start = 0; // 0 means don't check\nunsigned malloc_check_counter = 0;\nunsigned malloc_check_each = 1000;\n\nstatic int malloc_check_sleep = 100; // default 100 second sleep\nstatic int malloc_check_abort = 0;   // default is to sleep, not abort\n\nstatic os_once_t _malloc_initialize_pred;\n\n// Used by memory resource exceptions and enabling/disabling malloc stack logging via malloc_memory_event_handler\nstatic boolean_t warn_mode_entered = false;\nstatic boolean_t warn_mode_disable_retries = false;\nstatic stack_logging_mode_type msl_type_enabled_at_runtime = stack_logging_mode_none;\n\n/*\n * Counters that coordinate zone destruction (in malloc_zone_unregister) with\n * find_registered_zone (here abbreviated as FRZ).\n */\nstatic int32_t volatile counterAlice = 0, counterBob = 0;\nstatic int32_t volatile * volatile pFRZCounterLive = &counterAlice;\nstatic int32_t volatile * volatile pFRZCounterDrain = &counterBob;\n\nunsigned int _os_cpu_number_override = -1;\n\nstatic inline malloc_zone_t *inline_malloc_default_zone(void) __attribute__((always_inline));\n\n#define MALLOC_LOG_TYPE_ALLOCATE stack_logging_type_alloc\n#define MALLOC_LOG_TYPE_DEALLOCATE stack_logging_type_dealloc\n#define MALLOC_LOG_TYPE_HAS_ZONE stack_logging_flag_zone\n#define MALLOC_LOG_TYPE_CLEARED stack_logging_flag_cleared\n\n#define DEFAULT_MALLOC_ZONE_STRING \"DefaultMallocZone\"\n#define DEFAULT_PUREGEABLE_ZONE_STRING \"DefaultPurgeableMallocZone\"\n#define MALLOC_HELPER_ZONE_STRING \"MallocHelperZone\"\n\nMALLOC_NOEXPORT\nunsigned int phys_ncpus;\n\nMALLOC_NOEXPORT\nunsigned int logical_ncpus;\n\nMALLOC_NOEXPORT\nunsigned int hyper_shift;\n\n// Boot argument for max magazine control\nstatic const char max_magazines_boot_arg[] = \"malloc_max_magazines\";\n\n/*********\tUtilities\t************/\nstatic bool _malloc_entropy_initialized;\n\nvoid __malloc_init(const char *apple[]);\n\nstatic int\n__entropy_from_kernel(const char *str)\n{\n\tunsigned long long val;\n\tchar tmp[20], *p;\n\tint idx = 0;\n\n\t/* Skip over key to the first value */\n\tstr = strchr(str, '=');\n\tif (str == NULL) {\n\t\treturn 0;\n\t}\n\tstr++;\n\n\twhile (str && idx < sizeof(malloc_entropy) / sizeof(malloc_entropy[0])) {\n\t\tstrlcpy(tmp, str, 20);\n\t\tp = strchr(tmp, ',');\n\t\tif (p) {\n\t\t\t*p = '\\0';\n\t\t}\n\t\tval = strtoull_l(tmp, NULL, 0, NULL);\n\t\tmalloc_entropy[idx] = (uint64_t)val;\n\t\tidx++;\n\t\tif ((str = strchr(str, ',')) != NULL) {\n\t\t\tstr++;\n\t\t}\n\t}\n\treturn idx;\n}\n\nstatic void\n__malloc_init_from_bootargs(const char *bootargs)\n{\n\t// The maximum number of magazines can be set either via a\n\t// boot argument or from the environment. Get the boot argument value\n\t// here and store it. We can't bounds check it until we have phys_ncpus,\n\t// which happens later in _malloc_initialize(), along with handling\n\t// of the environment value setting.\n\tchar value_buf[256];\n\tconst char *flag = malloc_common_value_for_key_copy(bootargs,\n\t\t\tmax_magazines_boot_arg, value_buf, sizeof(value_buf));\n\tif (flag) {\n\t\tconst char *endp;\n\t\tlong value = malloc_common_convert_to_long(flag, &endp);\n\t\tif (!*endp && value >= 0) {\n\t\t\tmax_magazines = (unsigned int)value;\n\t\t} else {\n\t\t\tmalloc_report(ASL_LEVEL_ERR,\n\t\t\t\t\t\t   \"malloc_max_magazines must be positive - ignored.\\n\");\n\t\t}\n\t}\n}\n\n/* TODO: Investigate adding _malloc_initialize() into this libSystem initializer */\nvoid\n__malloc_init(const char *apple[])\n{\n\t// We could try to be clever and cater for arbitrary length bootarg\n\t// strings, but it's probably not worth it, especially as we would need\n\t// to temporarily allocate at least a page of memory to read the bootargs\n\t// into.\n\tchar bootargs[1024] = { '\\0' };\n\tsize_t len = sizeof(bootargs) - 1;\n\tif (!sysctlbyname(\"kern.bootargs\", bootargs, &len, NULL, 0) && len > 0) {\n\t\tbootargs[len + 1] = '\\0';\n\t}\n\n#if CONFIG_NANOZONE\n\t// TODO: envp should be passed down from Libsystem\n\tconst char **envp = (const char **)*_NSGetEnviron();\n\tnano_common_init(envp, apple, bootargs);\n#endif\n\n\tconst char **p;\n\tfor (p = apple; p && *p; p++) {\n\t\tif (strstr(*p, \"malloc_entropy\") == *p) {\n\t\t\tint count = __entropy_from_kernel(*p);\n\t\t\tbzero((void *)*p, strlen(*p));\n\n\t\t\tif (sizeof(malloc_entropy) / sizeof(malloc_entropy[0]) == count) {\n\t\t\t\t_malloc_entropy_initialized = true;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (!_malloc_entropy_initialized) {\n\t\tgetentropy((void*)malloc_entropy, sizeof(malloc_entropy));\n\t\t_malloc_entropy_initialized = true;\n\t}\n\n\t__malloc_init_from_bootargs(bootargs);\n\tmvm_aslr_init();\n}\n\nstatic malloc_zone_t* lite_zone = NULL;\n\nMALLOC_ALWAYS_INLINE\nstatic inline malloc_zone_t *\nruntime_default_zone() {\n\treturn (lite_zone) ? lite_zone : inline_malloc_default_zone();\n}\n\nstatic size_t\ndefault_zone_size(malloc_zone_t *zone, const void *ptr)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->size(zone, ptr);\n}\n\nstatic void *\ndefault_zone_malloc(malloc_zone_t *zone, size_t size)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->malloc(zone, size);\n}\n\nstatic void *\ndefault_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->calloc(zone, num_items, size);\n}\n\nstatic void *\ndefault_zone_valloc(malloc_zone_t *zone, size_t size)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->valloc(zone, size);\n}\n\nstatic void\ndefault_zone_free(malloc_zone_t *zone, void *ptr)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->free(zone, ptr);\n}\n\nstatic void *\ndefault_zone_realloc(malloc_zone_t *zone, void *ptr, size_t new_size)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->realloc(zone, ptr, new_size);\n}\n\nstatic void\ndefault_zone_destroy(malloc_zone_t *zone)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->destroy(zone);\n}\n\nstatic unsigned\ndefault_zone_batch_malloc(malloc_zone_t *zone, size_t size, void **results, unsigned count)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->batch_malloc(zone, size, results, count);\n}\n\nstatic void\ndefault_zone_batch_free(malloc_zone_t *zone, void **to_be_freed, unsigned count)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->batch_free(zone, to_be_freed, count);\n}\n\nstatic void *\ndefault_zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->memalign(zone, alignment, size);\n}\n\nstatic void\ndefault_zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->free_definite_size(zone, ptr, size);\n}\n\nstatic size_t\ndefault_zone_pressure_relief(malloc_zone_t *zone, size_t goal)\n{\n\tzone = runtime_default_zone();\n\n\treturn zone->pressure_relief(zone, goal);\n}\n\nstatic boolean_t\ndefault_zone_malloc_claimed_address(malloc_zone_t *zone, void *ptr)\n{\n\tzone = runtime_default_zone();\n\n\treturn malloc_zone_claimed_address(zone, ptr);\n}\n\nstatic kern_return_t\ndefault_zone_ptr_in_use_enumerator(task_t task,\n\t\t\t\t\t\t\t\t   void *context,\n\t\t\t\t\t\t\t\t   unsigned type_mask,\n\t\t\t\t\t\t\t\t   vm_address_t zone_address,\n\t\t\t\t\t\t\t\t   memory_reader_t reader,\n\t\t\t\t\t\t\t\t   vm_range_recorder_t recorder)\n{\n\tmalloc_zone_t *zone = runtime_default_zone();\n\t\n\treturn zone->introspect->enumerator(task, context, type_mask, (vm_address_t) zone, reader, recorder);\n}\n\nstatic size_t\ndefault_zone_good_size(malloc_zone_t *zone, size_t size)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->introspect->good_size(zone, size);\n}\n\nstatic boolean_t\ndefault_zone_check(malloc_zone_t *zone)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->introspect->check(zone);\n}\n\nstatic void\ndefault_zone_print(malloc_zone_t *zone, boolean_t verbose)\n{\n\tzone = runtime_default_zone();\n\n\treturn (void)zone->introspect->print(zone, verbose);\n}\n\nstatic void\ndefault_zone_log(malloc_zone_t *zone, void *log_address)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->introspect->log(zone, log_address);\n}\n\nstatic void\ndefault_zone_force_lock(malloc_zone_t *zone)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->introspect->force_lock(zone);\n}\n\nstatic void\ndefault_zone_force_unlock(malloc_zone_t *zone)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->introspect->force_unlock(zone);\n}\n\nstatic void\ndefault_zone_statistics(malloc_zone_t *zone, malloc_statistics_t *stats)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->introspect->statistics(zone, stats);\n}\n\nstatic boolean_t\ndefault_zone_locked(malloc_zone_t *zone)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->introspect->zone_locked(zone);\n}\n\nstatic void\ndefault_zone_reinit_lock(malloc_zone_t *zone)\n{\n\tzone = runtime_default_zone();\n\t\n\treturn zone->introspect->reinit_lock(zone);\n}\n\nstatic struct malloc_introspection_t default_zone_introspect = {\n\tdefault_zone_ptr_in_use_enumerator,\n\tdefault_zone_good_size,\n\tdefault_zone_check,\n\tdefault_zone_print,\n\tdefault_zone_log,\n\tdefault_zone_force_lock,\n\tdefault_zone_force_unlock,\n\tdefault_zone_statistics,\n\tdefault_zone_locked,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tdefault_zone_reinit_lock\n};\n\ntypedef struct {\n\tmalloc_zone_t malloc_zone;\n\tuint8_t pad[PAGE_MAX_SIZE - sizeof(malloc_zone_t)];\n} virtual_default_zone_t;\n\nstatic virtual_default_zone_t virtual_default_zone\n__attribute__((section(\"__DATA,__v_zone\")))\n__attribute__((aligned(PAGE_MAX_SIZE))) = {\n\tNULL,\n\tNULL,\n\tdefault_zone_size,\n\tdefault_zone_malloc,\n\tdefault_zone_calloc,\n\tdefault_zone_valloc,\n\tdefault_zone_free,\n\tdefault_zone_realloc,\n\tdefault_zone_destroy,\n\tDEFAULT_MALLOC_ZONE_STRING,\n\tdefault_zone_batch_malloc,\n\tdefault_zone_batch_free,\n\t&default_zone_introspect,\n\t10,\n\tdefault_zone_memalign,\n\tdefault_zone_free_definite_size,\n\tdefault_zone_pressure_relief,\n\tdefault_zone_malloc_claimed_address,\n};\n\nstatic malloc_zone_t *default_zone = &virtual_default_zone.malloc_zone;\n\nstatic boolean_t\nhas_default_zone0(void)\n{\n\tif (!malloc_zones) {\n\t\treturn false;\n\t}\n\t\n\treturn initial_default_zone == malloc_zones[0];\n}\n\nstatic inline malloc_zone_t *find_registered_zone(const void *, size_t *) __attribute__((always_inline));\nstatic inline malloc_zone_t *\nfind_registered_zone(const void *ptr, size_t *returned_size)\n{\n\t// Returns a zone which contains ptr, else NULL\n\n\tif (0 == malloc_num_zones) {\n\t\tif (returned_size) {\n\t\t\t*returned_size = 0;\n\t\t}\n\t\treturn NULL;\n\t}\n\n\t// first look in the lite zone\n\tif (lite_zone) {\n\t\tmalloc_zone_t *zone = lite_zone;\n\t\tsize_t size = zone->size(zone, ptr);\n\t\tif (size) { // Claimed by this zone?\n\t\t\tif (returned_size) {\n\t\t\t\t*returned_size = size;\n\t\t\t}\n\t\t\t// Return the virtual default zone instead of the lite zone - see <rdar://problem/24994311>\n\t\t\treturn default_zone;\n\t\t}\n\t}\n\t\n\t// The default zone is registered in malloc_zones[0]. There's no danger that it will ever be unregistered.\n\t// So don't advance the FRZ counter yet.\n\tmalloc_zone_t *zone = malloc_zones[0];\n\tsize_t size = zone->size(zone, ptr);\n\tif (size) { // Claimed by this zone?\n\t\tif (returned_size) {\n\t\t\t*returned_size = size;\n\t\t}\n\n\t\t// Asan and others replace the zone at position 0 with their own zone.\n\t\t// In that case just return that zone as they need this information.\n\t\t// Otherwise return the virtual default zone, not the actual zone in position 0.\n\t\tif (!has_default_zone0()) {\n\t\t\treturn zone;\n\t\t} else {\n\t\t\treturn default_zone;\n\t\t}\n\t}\n\n\tint32_t volatile *pFRZCounter = pFRZCounterLive;   // Capture pointer to the counter of the moment\n\tOSAtomicIncrement32Barrier(pFRZCounter); // Advance this counter -- our thread is in FRZ\n\n\tunsigned index;\n\tint32_t limit = *(int32_t volatile *)&malloc_num_zones;\n\tmalloc_zone_t **zones = &malloc_zones[1];\n\n\t// From this point on, FRZ is accessing the malloc_zones[] array without locking\n\t// in order to avoid contention on common operations (such as non-default-zone free()).\n\t// In order to ensure that this is actually safe to do, register/unregister take care\n\t// to:\n\t//\n\t//   1. Register ensures that newly inserted pointers in malloc_zones[] are visible\n\t//      when malloc_num_zones is incremented. At the moment, we're relying on that store\n\t//      ordering to work without taking additional steps here to ensure load memory\n\t//      ordering.\n\t//\n\t//   2. Unregister waits for all readers in FRZ to complete their iteration before it\n\t//      returns from the unregister call (during which, even unregistered zone pointers\n\t//      are still valid). It also ensures that all the pointers in the zones array are\n\t//      valid until it returns, so that a stale value in limit is not dangerous.\n\n\tfor (index = 1; index < limit; ++index, ++zones) {\n\t\tzone = *zones;\n\t\tsize = zone->size(zone, ptr);\n\t\tif (size) { // Claimed by this zone?\n\t\t\tgoto out;\n\t\t}\n\t}\n\t// Unclaimed by any zone.\n\tzone = NULL;\n\tsize = 0;\nout:\n\tif (returned_size) {\n\t\t*returned_size = size;\n\t}\n\tOSAtomicDecrement32Barrier(pFRZCounter); // our thread is leaving FRZ\n\treturn zone;\n}\n\nvoid\nmalloc_error_break(void)\n{\n\t// Provides a non-inlined place for various malloc error procedures to call\n\t// that will be called after an error message appears.  It does not make\n\t// sense for developers to call this function, so it is marked\n\t// hidden to prevent it from becoming API.\n\tMAGMALLOC_MALLOCERRORBREAK(); // DTrace USDT probe\n}\n\nint\nmalloc_gdb_po_unsafe(void)\n{\n\t// In order to implement \"po\" other data formatters in gdb, the debugger\n\t// calls functions that call malloc.  The debugger will  only run one thread\n\t// of the program in this case, so if another thread is holding a zone lock,\n\t// gdb may deadlock in this case.\n\t//\n\t// Iterate over the zones in malloc_zones, and call \"trylock\" on the zone\n\t// lock.  If trylock succeeds, unlock it, otherwise return \"locked\".  Returns\n\t// 0 == safe, 1 == locked/unsafe.\n\n\tif (__stack_logging_locked()) {\n\t\treturn 1;\n\t}\n\n\tmalloc_zone_t **zones = malloc_zones;\n\tunsigned i, e = malloc_num_zones;\n\n\tfor (i = 0; i != e; ++i) {\n\t\tmalloc_zone_t *zone = zones[i];\n\n\t\t// Version must be >= 5 to look at the new introspection field.\n\t\tif (zone->version < 5) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (zone->introspect->zone_locked && zone->introspect->zone_locked(zone)) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\treturn 0;\n}\n\n/*********\tCreation and destruction\t************/\n\nstatic void set_flags_from_environment(void);\n\nstatic void\nmalloc_zone_register_while_locked(malloc_zone_t *zone)\n{\n\tsize_t protect_size;\n\tunsigned i;\n\n\t/* scan the list of zones, to see if this zone is already registered.  If\n\t * so, print an error message and return. */\n\tfor (i = 0; i != malloc_num_zones; ++i) {\n\t\tif (zone == malloc_zones[i]) {\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"Attempted to register zone more than once: %p\\n\", zone);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (malloc_num_zones == malloc_num_zones_allocated) {\n\t\tsize_t malloc_zones_size = malloc_num_zones * sizeof(malloc_zone_t *);\n\t\tmach_vm_size_t alloc_size = round_page(malloc_zones_size + vm_page_size);\n\t\tmach_vm_address_t vm_addr;\n\t\tint alloc_flags = VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_MALLOC);\n\n\t\tvm_addr = vm_page_size;\n\t\tkern_return_t kr = mach_vm_allocate(mach_task_self(), &vm_addr, alloc_size, alloc_flags);\n\t\tif (kr) {\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"malloc_zone_register allocation failed: %d\\n\", kr);\n\t\t\treturn;\n\t\t}\n\n\t\tmalloc_zone_t **new_zones = (malloc_zone_t **)vm_addr;\n\t\t/* If there were previously allocated malloc zones, we need to copy them\n\t\t * out of the previous array and into the new zones array */\n\t\tif (malloc_zones) {\n\t\t\tmemcpy(new_zones, malloc_zones, malloc_zones_size);\n\t\t\tvm_addr = (mach_vm_address_t)malloc_zones;\n\t\t\tmach_vm_size_t dealloc_size = round_page(malloc_zones_size);\n\t\t\tmach_vm_deallocate(mach_task_self(), vm_addr, dealloc_size);\n\t\t}\n\n\t\t/* Update the malloc_zones pointer, which we leak if it was previously\n\t\t * allocated, and the number of zones allocated */\n\t\tprotect_size = (size_t)alloc_size;\n\t\tmalloc_zones = new_zones;\n\t\tmalloc_num_zones_allocated = (int32_t)(alloc_size / sizeof(malloc_zone_t *));\n\t} else {\n\t\t/* If we don't need to reallocate zones, we need to briefly change the\n\t\t * page protection the malloc zones to allow writes */\n\t\tprotect_size = malloc_num_zones_allocated * sizeof(malloc_zone_t *);\n\t\tmprotect(malloc_zones, protect_size, PROT_READ | PROT_WRITE);\n\t}\n\n\t/* <rdar://problem/12871662> This store-increment needs to be visible in the correct\n\t * order to any threads in find_registered_zone, such that if the incremented value\n\t * in malloc_num_zones is visible then the pointer write before it must also be visible.\n\t *\n\t * While we could be slightly more efficent here with atomic ops the cleanest way to\n\t * ensure the proper store-release operation is performed is to use OSAtomic*Barrier\n\t * to update malloc_num_zones.\n\t */\n\tmalloc_zones[malloc_num_zones] = zone;\n\tOSAtomicIncrement32Barrier(&malloc_num_zones);\n\n\t/* Finally, now that the zone is registered, disallow write access to the\n\t * malloc_zones array */\n\tmprotect(malloc_zones, protect_size, PROT_READ);\n\t//malloc_report(ASL_LEVEL_INFO, \"Registered malloc_zone %p in malloc_zones %p [%u zones, %u bytes]\\n\", zone, malloc_zones,\n\t// malloc_num_zones, protect_size);\n}\n\nstatic void\ncreate_and_insert_lite_zone_while_locked()\n{\n\tmalloc_zone_t *zone0 = malloc_zones[0];\n\t\n\tmalloc_zone_t *stack_logging_lite_zone = create_stack_logging_lite_zone(0, zone0, malloc_debug_flags);\n\tmalloc_zone_register_while_locked(stack_logging_lite_zone);\n\tmalloc_set_zone_name(stack_logging_lite_zone, MALLOC_STOCK_LOGGING_LITE_ZONE_NAME);\n\tlite_zone = stack_logging_lite_zone;\n}\n\nboolean_t\nturn_on_stack_logging(stack_logging_mode_type mode)\n{\n\tboolean_t ret = false;\n\t\n\tMALLOC_LOCK();\n\t\n\tif (!stack_logging_enable_logging) {\n\t\tif (__uniquing_table_memory_was_deleted()) {\n\t\t\t// It would great to be able re-enable even if the uniquing table has been deleted\n\t\t\t// <rdar://problem/25014005> malloc stack logging should be able to recreate the uniquing table if needed\n\t\t} else {\n\t\t\tswitch (mode) {\n\t\t\t\tcase stack_logging_mode_all:\n\t\t\t\t\t__prepare_to_log_stacks(false);\n\t\t\t\t\tmalloc_logger = __disk_stack_logging_log_stack;\n\t\t\t\t\t__syscall_logger = __disk_stack_logging_log_stack;\n\t\t\t\t\tstack_logging_mode = mode;\n\t\t\t\t\tstack_logging_enable_logging = 1;\n\t\t\t\t\tret = true;\n\t\t\t\t\t\n\t\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"recording malloc and VM allocation stacks to disk using standard recorder\\n\");\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase stack_logging_mode_malloc:\n\t\t\t\t\t__prepare_to_log_stacks(false);\n\t\t\t\t\tmalloc_logger = __disk_stack_logging_log_stack;\n\t\t\t\t\tstack_logging_mode = mode;\n\t\t\t\t\tstack_logging_enable_logging = 1;\n\t\t\t\t\tret = true;\n\t\t\t\t\t\n\t\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"recording malloc (but not VM allocation) stacks to disk using standard recorder\\n\");\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase stack_logging_mode_vm:\n\t\t\t\t\t__prepare_to_log_stacks(false);\n\t\t\t\t\t__syscall_logger = __disk_stack_logging_log_stack;\n\t\t\t\t\tstack_logging_mode = mode;\n\t\t\t\t\tstack_logging_enable_logging = 1;\n\t\t\t\t\tret = true;\n\t\t\t\t\t\n\t\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"recording VM allocation (but not malloc) stacks to disk using standard recorder\\n\");\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase stack_logging_mode_lite:\n\t\t\t\t\tif (!has_default_zone0()) {\n\t\t\t\t\t\tmalloc_report(ASL_LEVEL_ERR, \"zone[0] is not the normal default zone so can't turn on lite mode.\\n\", mode);\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"recording malloc (and VM allocation) stacks using lite mode\\n\");\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (lite_zone) {\n\t\t\t\t\t\t\tenable_stack_logging_lite();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif (__prepare_to_log_stacks(true)) {\n\t\t\t\t\t\t\t\t__syscall_logger = __disk_stack_logging_log_stack;\n\t\t\t\t\t\t\t\tstack_logging_mode = stack_logging_mode_lite;\n\t\t\t\t\t\t\t\tstack_logging_enable_logging = 1;\n\t\t\t\t\t\t\t\t__prepare_to_log_stacks_stage2();\n\t\t\t\t\t\t\t\tcreate_and_insert_lite_zone_while_locked();\n\t\t\t\t\t\t\t\tenable_stack_logging_lite();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tret = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase stack_logging_mode_vmlite:\n\t\t\t\t\tif (__prepare_to_log_stacks(true)) {\n\t\t\t\t\t\t__syscall_logger = __disk_stack_logging_log_stack;\n\t\t\t\t\t\tstack_logging_mode = mode;\n\t\t\t\t\t\tstack_logging_enable_logging = 1;\n\t\t\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"recording VM allocation (but not malloc) stacks using lite mode\\n\");\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tdefault:\n\t\t\t\t\tmalloc_report(ASL_LEVEL_ERR, \"invalid mode %d passed to turn_on_stack_logging\\n\", mode);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"malloc stack logging already enabled.\\n\");\n\t}\n\t\n\tMALLOC_UNLOCK();\n\t\n\treturn ret;\n}\n\nvoid\nturn_off_stack_logging()\n{\n\tMALLOC_LOCK();\n\t\n\tif (stack_logging_enable_logging) {\n\t\tswitch (stack_logging_mode) {\n\t\t\tcase stack_logging_mode_all:\n\t\t\t\tmalloc_logger = NULL;\n\t\t\t\t__syscall_logger = NULL;\n\t\t\t\tstack_logging_enable_logging = 0;\n\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"turning off recording malloc and VM allocation stacks to disk using standard recorder\\n\");\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\tcase stack_logging_mode_malloc:\n\t\t\t\tmalloc_logger = NULL;\n\t\t\t\tstack_logging_enable_logging = 0;\n\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"turnning off recording malloc (but not VM allocation) stacks to disk using standard recorder\\n\");\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\tcase stack_logging_mode_vm:\n\t\t\t\t__syscall_logger = NULL;\n\t\t\t\tstack_logging_enable_logging = 0;\n\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"turning off recording VM allocation (but not malloc) stacks to disk using standard recorder\\n\");\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\tcase stack_logging_mode_lite:\n\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"turning off recording malloc (but not VM allocation) stacks using lite mode\\n\");\n\t\t\t\t\n\t\t\t\tdisable_stack_logging_lite();\n\t\t\t\tstack_logging_enable_logging = 0;\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\tcase stack_logging_mode_vmlite:\n\t\t\t\t__syscall_logger = NULL;\n\t\t\t\tstack_logging_enable_logging = 0;\n\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"turning off recording VM allocation stacks using lite mode\\n\");\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\tdefault:\n\t\t\t\tmalloc_report(ASL_LEVEL_ERR, \"invalid stack_logging_mode %d in turn_off_stack_logging\\n\", stack_logging_mode);\n\t\t\t\tbreak;\n\t\t}\n\t} else {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"malloc stack logging not enabled.\\n\");\n\t}\n\t\n\tMALLOC_UNLOCK();\n}\n\n// To be used in _malloc_initialize_once() only, call that function instead.\nstatic void\n_malloc_initialize(void *context __unused)\n{\n\tMALLOC_LOCK();\n\tunsigned n;\n\tmalloc_zone_t *zone = NULL;\n\n\tif (!_malloc_entropy_initialized) {\n\t\t// Lazy initialization may occur before __malloc_init (rdar://27075409)\n\t\t// TODO: make this a fatal error\n\t\tmalloc_report(ASL_LEVEL_ERR, \"*** malloc was initialized without entropy\\n\");\n\t}\n\n\tphys_ncpus = *(uint8_t *)(uintptr_t)_COMM_PAGE_PHYSICAL_CPUS;\n\tlogical_ncpus = *(uint8_t *)(uintptr_t)_COMM_PAGE_LOGICAL_CPUS;\n\n\tif (0 != (logical_ncpus % phys_ncpus)) {\n\t\tMALLOC_REPORT_FATAL_ERROR(logical_ncpus % phys_ncpus,\n\t\t\t\t\"logical_ncpus %% phys_ncpus != 0\\n\");\n\t}\n\n\tswitch (logical_ncpus / phys_ncpus) {\n\tcase 1:\n\t\thyper_shift = 0;\n\t\tbreak;\n\tcase 2:\n\t\thyper_shift = 1;\n\t\tbreak;\n\tcase 4:\n\t\thyper_shift = 2;\n\t\tbreak;\n\tdefault:\n\t\tMALLOC_REPORT_FATAL_ERROR(logical_ncpus / phys_ncpus, \"logical_ncpus / phys_ncpus not 1, 2, or 4\");\n\t}\n\n\t// max_magazines may already be set from a boot argument. Make sure that it\n\t// is bounded by the number of CPUs.\n\tif (max_magazines) {\n\t\tmax_magazines = MIN(max_magazines, logical_ncpus);\n\t} else {\n\t\tmax_magazines = logical_ncpus;\n\t}\n\n\tset_flags_from_environment(); // will only set flags up to two times\n\tn = malloc_num_zones;\n\n#if CONFIG_NANOZONE\n\tnano_common_configure();\n\t\n\tmalloc_zone_t *helper_zone = create_scalable_zone(0, malloc_debug_flags);\n\n\tif (_malloc_engaged_nano == NANO_V2) {\n\t\tzone = nanov2_create_zone(helper_zone, malloc_debug_flags);\n\t} else if (_malloc_engaged_nano == NANO_V1) {\n\t\tzone = nano_create_zone(helper_zone, malloc_debug_flags);\n\t}\n\n\tif (zone) {\n\t\tmalloc_zone_register_while_locked(zone);\n\t\tmalloc_zone_register_while_locked(helper_zone);\n\n\t\t// Must call malloc_set_zone_name() *after* helper and nano are hooked together.\n\t\tmalloc_set_zone_name(zone, DEFAULT_MALLOC_ZONE_STRING);\n\t\tmalloc_set_zone_name(helper_zone, MALLOC_HELPER_ZONE_STRING);\n\t} else {\n\t\tzone = helper_zone;\n\t\tmalloc_zone_register_while_locked(zone);\n\t\tmalloc_set_zone_name(zone, DEFAULT_MALLOC_ZONE_STRING);\n\t}\n#else\n\tzone = create_scalable_zone(0, malloc_debug_flags);\n\tmalloc_zone_register_while_locked(zone);\n\tmalloc_set_zone_name(zone, DEFAULT_MALLOC_ZONE_STRING);\n#endif\n\n\tinitial_default_zone = zone;\n\n\tif (n != 0) { // make the default first, for efficiency\n\t\tunsigned protect_size = malloc_num_zones_allocated * sizeof(malloc_zone_t *);\n\t\tmalloc_zone_t *hold = malloc_zones[0];\n\n\t\tif (hold->zone_name && strcmp(hold->zone_name, DEFAULT_MALLOC_ZONE_STRING) == 0) {\n\t\t\tmalloc_set_zone_name(hold, NULL);\n\t\t}\n\n\t\tmprotect(malloc_zones, protect_size, PROT_READ | PROT_WRITE);\n\t\tmalloc_zones[0] = malloc_zones[n];\n\t\tmalloc_zones[n] = hold;\n\t\tmprotect(malloc_zones, protect_size, PROT_READ);\n\t}\n\n\t// Only setup stack logging hooks once lazy initialization is complete, the\n\t// malloc_zone calls above would otherwise initialize malloc stack logging,\n\t// which calls into malloc re-entrantly from Libc upcalls and so deadlocks\n\t// in the lazy initialization os_once(). rdar://13046853\n\tif (stack_logging_enable_logging) {\n\t\tswitch (stack_logging_mode) {\n\t\tcase stack_logging_mode_malloc:\n\t\t\tmalloc_logger = __disk_stack_logging_log_stack;\n\t\t\tbreak;\n\t\tcase stack_logging_mode_vm:\n\t\t\t__syscall_logger = __disk_stack_logging_log_stack;\n\t\t\tbreak;\n\t\tcase stack_logging_mode_all:\n\t\t\tmalloc_logger = __disk_stack_logging_log_stack;\n\t\t\t__syscall_logger = __disk_stack_logging_log_stack;\n\t\t\tbreak;\n\t\tcase stack_logging_mode_lite:\n\t\t\t__syscall_logger = __disk_stack_logging_log_stack;\n\t\t\tcreate_and_insert_lite_zone_while_locked();\n\t\t\tenable_stack_logging_lite();\n\t\t\tbreak;\n\t\tcase stack_logging_mode_vmlite:\n\t\t\t__syscall_logger = __disk_stack_logging_log_stack;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// malloc_report(ASL_LEVEL_INFO, \"%d registered zones\\n\", malloc_num_zones);\n\t// malloc_report(ASL_LEVEL_INFO, \"malloc_zones is at %p; malloc_num_zones is at %p\\n\", (unsigned)&malloc_zones,\n\t// (unsigned)&malloc_num_zones);\n\tMALLOC_UNLOCK();\n}\n\nMALLOC_ALWAYS_INLINE\nstatic inline void\n_malloc_initialize_once(void)\n{\n\tos_once(&_malloc_initialize_pred, NULL, _malloc_initialize);\n}\n\nstatic inline malloc_zone_t *\ninline_malloc_default_zone(void)\n{\n\t_malloc_initialize_once();\n\t// malloc_report(ASL_LEVEL_INFO, \"In inline_malloc_default_zone with %d %d\\n\", malloc_num_zones, malloc_has_debug_zone);\n\treturn malloc_zones[0];\n}\n\nmalloc_zone_t *\nmalloc_default_zone(void)\n{\n\treturn default_zone;\n}\n\nstatic inline malloc_zone_t *inline_malloc_default_scalable_zone(void) __attribute__((always_inline));\nstatic inline malloc_zone_t *\ninline_malloc_default_scalable_zone(void)\n{\n\tunsigned index;\n\n\t_malloc_initialize_once();\n\t// malloc_report(ASL_LEVEL_INFO, \"In inline_malloc_default_scalable_zone with %d %d\\n\", malloc_num_zones,\n\t// malloc_has_debug_zone);\n\n\tMALLOC_LOCK();\n#if CONFIG_NANOZONE\n\tfor (index = 0; index < malloc_num_zones; ++index) {\n\t\tmalloc_zone_t *z = malloc_zones[index];\n\n\t\tif (z->zone_name && strcmp(z->zone_name, MALLOC_HELPER_ZONE_STRING) == 0) {\n\t\t\tMALLOC_UNLOCK();\n\t\t\treturn z;\n\t\t}\n\t}\n#endif\n\tfor (index = 0; index < malloc_num_zones; ++index) {\n\t\tmalloc_zone_t *z = malloc_zones[index];\n\n\t\tif (z->zone_name && strcmp(z->zone_name, DEFAULT_MALLOC_ZONE_STRING) == 0) {\n\t\t\tMALLOC_UNLOCK();\n\t\t\treturn z;\n\t\t}\n\t}\n\tMALLOC_UNLOCK();\n\n\tmalloc_report(ASL_LEVEL_ERR, \"*** malloc_default_scalable_zone() failed to find 'DefaultMallocZone'\\n\");\n\treturn NULL; // FIXME: abort() instead?\n}\n\nstatic void *\nlegacy_zeroing_large_malloc(malloc_zone_t *zone, size_t size)\n{\n\tif (size > LARGE_THRESHOLD) {\t\t\t // Leopard and earlier returned a ZFOD range, so ...\n\t\treturn default_zone_calloc(zone, 1, size); // Clear to zero always, ham-handedly touching in each page\n\t} else {\n\t\treturn default_zone_malloc(zone, size);\n\t}\n}\n\nstatic void *\nlegacy_zeroing_large_valloc(malloc_zone_t *zone, size_t size)\n{\n\tvoid *p = default_zone_valloc(zone, size);\n\n\t// Leopard and earlier returned a ZFOD range, so ...\n\tmemset(p, 0, size); // Clear to zero always, ham-handedly touching in each page\n\treturn p;\n}\n\nvoid\nzeroify_scalable_zone(malloc_zone_t *zone)\n{\n\t// <rdar://problem/27190324> this checkfix should replace the default zone's\n\t// allocation routines with the zeroing versions. Instead of getting in hot \n\t// water with the wrong zone, ensure that we're mutating the zone we expect.\n\t// \n\t// Additionally, the default_zone is no longer PROT_READ, so the two mprotect\n\t// calls that were here are no longer needed.\n\tif (zone == default_zone) {\n\t\tzone->malloc = (void *)legacy_zeroing_large_malloc;\n\t\tzone->valloc = (void *)legacy_zeroing_large_valloc;\n\t}\n}\n\n/*\n * Returns the version of the Nano allocator that's in use, or 0 if not.\n */\nint\nmalloc_engaged_nano(void)\n{\n#if CONFIG_NANOZONE\n\treturn _malloc_engaged_nano;\n#else\n\treturn 0;\n#endif\n}\n\nmalloc_zone_t *\nmalloc_default_purgeable_zone(void)\n{\n\tstatic malloc_zone_t *dpz;\n\n\tif (!dpz) {\n\t\t//\n\t\t// PR_7288598: Must pass a *scalable* zone (szone) as the helper for create_purgeable_zone().\n\t\t// Take care that the zone so obtained is not subject to interposing.\n\t\t//\n\t\tmalloc_zone_t *tmp = create_purgeable_zone(0, inline_malloc_default_scalable_zone(), malloc_debug_flags);\n\t\tmalloc_zone_register(tmp);\n\t\tmalloc_set_zone_name(tmp, DEFAULT_PUREGEABLE_ZONE_STRING);\n\t\tif (!OSAtomicCompareAndSwapPtrBarrier(NULL, tmp, (void**)&dpz)) {\n\t\t\tmalloc_destroy_zone(tmp);\n\t\t}\n\t}\n\treturn dpz;\n}\n\nstatic void\nset_flags_from_environment(void)\n{\n\tconst char *flag;\n\tchar **env = *_NSGetEnviron();\n\tchar **p;\n\tchar *c;\n\n#if __LP64__\n\tmalloc_debug_flags = MALLOC_ABORT_ON_CORRUPTION; // Set always on 64-bit processes\n#else\n\tint libSystemVersion = NSVersionOfLinkTimeLibrary(\"System\");\n\tif ((-1 != libSystemVersion) && ((libSystemVersion >> 16) < 126) /* Lion or greater */) {\n\t\tmalloc_debug_flags = 0;\n\t} else {\n\t\tmalloc_debug_flags = MALLOC_ABORT_ON_CORRUPTION;\n\t}\n#endif\n\tstack_logging_enable_logging = 0;\n\tstack_logging_dontcompact = 0;\n\tmalloc_logger = NULL;\n\tmalloc_check_start = 0;\n\tmalloc_check_each = 1000;\n\tmalloc_check_abort = 0;\n\tmalloc_check_sleep = 100;\n\t/*\n\t * Given that all environment variables start with \"Malloc\" we optimize by scanning quickly\n\t * first the environment, therefore avoiding repeated calls to getenv().\n\t * If we are setu/gid these flags are ignored to prevent a malicious invoker from changing\n\t * our behaviour.\n\t */\n\tfor (p = env; (c = *p) != NULL; ++p) {\n\t\tif (!strncmp(c, \"Malloc\", 6)) {\n\t\t\tif (issetugid()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t/*\n\t * Deny certain flags for entitled processes rdar://problem/13521742\n\t * MallocLogFile & MallocCorruptionAbort\n\t * as these provide the ability to turn *off* aborting in error cases.\n\t */\n\tbool restricted = dyld_process_is_restricted();\n\tmalloc_print_configure(restricted);\n\n\tif (c == NULL) {\n\t\treturn;\n\t}\n\n\tif (getenv(\"MallocGuardEdges\")) {\n\t\tmalloc_debug_flags |= MALLOC_ADD_GUARD_PAGES;\n\t\tmalloc_report(ASL_LEVEL_INFO, \"protecting edges\\n\");\n\t\tif (getenv(\"MallocDoNotProtectPrelude\")) {\n\t\t\tmalloc_debug_flags |= MALLOC_DONT_PROTECT_PRELUDE;\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"... but not protecting prelude guard page\\n\");\n\t\t}\n\t\tif (getenv(\"MallocDoNotProtectPostlude\")) {\n\t\t\tmalloc_debug_flags |= MALLOC_DONT_PROTECT_POSTLUDE;\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"... but not protecting postlude guard page\\n\");\n\t\t}\n\t}\n\tflag = getenv(\"MallocStackLogging\");\n\tif (!flag) {\n\t\tflag = getenv(\"MallocStackLoggingNoCompact\");\n\t\tstack_logging_dontcompact = 1;\n\t}\n\tif (flag) {\n\t\t// Set up stack logging as early as possible to catch all ensuing VM allocations,\n\t\t// including those from malloc_report and malloc zone setup.  Make sure to set\n\t\t// __syscall_logger after this, because prepare_to_log_stacks() itself makes VM\n\t\t// allocations that we aren't prepared to log yet.\n\t\tboolean_t lite_or_vmlite_mode = strcmp(flag, \"lite\") == 0 || strcmp(flag, \"vmlite\") == 0;\n\t\t\n\t\t__prepare_to_log_stacks(lite_or_vmlite_mode);\n\n\t\tif (strcmp(flag, \"lite\") == 0) {\n\t\t\tstack_logging_mode = stack_logging_mode_lite;\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"recording malloc and VM allocation stacks using lite mode\\n\");\n\t\t} else if (strcmp(flag,\"malloc\") == 0) {\n\t\t\tstack_logging_mode = stack_logging_mode_malloc;\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"recording malloc (but not VM allocation) stacks to disk using standard recorder\\n\");\n\t\t} else if (strcmp(flag, \"vm\") == 0) {\n\t\t\tstack_logging_mode = stack_logging_mode_vm;\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"recording VM allocation (but not malloc) stacks to disk using standard recorder\\n\");\n\t\t} else if (strcmp(flag, \"vmlite\") == 0) {\n\t\t\tstack_logging_mode = stack_logging_mode_vmlite;\n\t\t\tmalloc_report(ASL_LEVEL_NOTICE, \"recording VM allocation (but not malloc) stacks using lite mode\\n\");\n\t\t} else {\n\t\t\tstack_logging_mode = stack_logging_mode_all;\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"recording malloc and VM allocation stacks to disk using standard recorder\\n\");\n\t\t}\n\t\tstack_logging_enable_logging = 1;\n\t\tif (stack_logging_dontcompact) {\n\t\t\tif (stack_logging_mode == stack_logging_mode_all || stack_logging_mode == stack_logging_mode_malloc) {\n\t\t\t\tmalloc_report(\n\t\t\t\t\t\tASL_LEVEL_INFO, \"stack logging compaction turned off; size of log files on disk can increase rapidly\\n\");\n\t\t\t} else {\n\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"stack logging compaction turned off; VM can increase rapidly\\n\");\n\t\t\t}\n\t\t}\n\t}\n\tif (getenv(\"MallocScribble\")) {\n\t\tmalloc_debug_flags |= MALLOC_DO_SCRIBBLE;\n\t\tmalloc_report(ASL_LEVEL_INFO, \"enabling scribbling to detect mods to free blocks\\n\");\n\t}\n\tif (getenv(\"MallocErrorAbort\")) {\n\t\tmalloc_debug_flags |= MALLOC_ABORT_ON_ERROR;\n\t\tmalloc_report(ASL_LEVEL_INFO, \"enabling abort() on bad malloc or free\\n\");\n\t}\n\tif (getenv(\"MallocTracing\")) {\n\t\tmalloc_tracing_enabled = true;\n\t}\n\n#if __LP64__\n/* initialization above forces MALLOC_ABORT_ON_CORRUPTION of 64-bit processes */\n#else\n\tflag = getenv(\"MallocCorruptionAbort\");\n\tif (!restricted && flag && (flag[0] == '0')) { // Set from an environment variable in 32-bit processes\n\t\tmalloc_debug_flags &= ~MALLOC_ABORT_ON_CORRUPTION;\n\t} else if (flag) {\n\t\tmalloc_debug_flags |= MALLOC_ABORT_ON_CORRUPTION;\n\t}\n#endif\n\tflag = getenv(\"MallocCheckHeapStart\");\n\tif (flag) {\n\t\tmalloc_check_start = (unsigned)strtoul(flag, NULL, 0);\n\t\tif (malloc_check_start == 0) {\n\t\t\tmalloc_check_start = 1;\n\t\t}\n\t\tif (malloc_check_start == -1) {\n\t\t\tmalloc_check_start = 1;\n\t\t}\n\t\tflag = getenv(\"MallocCheckHeapEach\");\n\t\tif (flag) {\n\t\t\tmalloc_check_each = (unsigned)strtoul(flag, NULL, 0);\n\t\t\tif (malloc_check_each == 0) {\n\t\t\t\tmalloc_check_each = 1;\n\t\t\t}\n\t\t\tif (malloc_check_each == -1) {\n\t\t\t\tmalloc_check_each = 1;\n\t\t\t}\n\t\t}\n\t\tmalloc_report(ASL_LEVEL_INFO, \"checks heap after operation #%d and each %d operations\\n\", malloc_check_start, malloc_check_each);\n\t\tflag = getenv(\"MallocCheckHeapAbort\");\n\t\tif (flag) {\n\t\t\tmalloc_check_abort = (unsigned)strtol(flag, NULL, 0);\n\t\t}\n\t\tif (malloc_check_abort) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"will abort on heap corruption\\n\");\n\t\t} else {\n\t\t\tflag = getenv(\"MallocCheckHeapSleep\");\n\t\t\tif (flag) {\n\t\t\t\tmalloc_check_sleep = (unsigned)strtol(flag, NULL, 0);\n\t\t\t}\n\t\t\tif (malloc_check_sleep > 0) {\n\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"will sleep for %d seconds on heap corruption\\n\", malloc_check_sleep);\n\t\t\t} else if (malloc_check_sleep < 0) {\n\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"will sleep once for %d seconds on heap corruption\\n\", -malloc_check_sleep);\n\t\t\t} else {\n\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"no sleep on heap corruption\\n\");\n\t\t\t}\n\t\t}\n\t}\n\n\tflag = getenv(\"MallocMaxMagazines\");\n\tif (flag) {\n\t\tint value = (unsigned)strtol(flag, NULL, 0);\n\t\tif (value == 0) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"Maximum magazines defaulted to %d\\n\", max_magazines);\n\t\t} else if (value < 0) {\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"MallocMaxMagazines must be positive - ignored.\\n\");\n\t\t} else if (value > logical_ncpus) {\n\t\t\tmax_magazines = logical_ncpus;\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"Maximum magazines limited to number of logical CPUs (%d)\\n\", max_magazines);\n\t\t} else {\n\t\t\tmax_magazines = value;\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"Maximum magazines set to %d\\n\", max_magazines);\n\t\t}\n\t}\n#if CONFIG_RECIRC_DEPOT\n\tflag = getenv(\"MallocRecircRetainedRegions\");\n\tif (flag) {\n\t\tint value = (int)strtol(flag, NULL, 0);\n\t\tif (value > 0) {\n\t\t\trecirc_retained_regions = value;\n\t\t} else {\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"MallocRecircRetainedRegions must be positive - ignored.\\n\");\n\t\t}\n\t}\n#endif // CONFIG_RECIRC_DEPOT\n\tif (getenv(\"MallocHelp\")) {\n\t\tmalloc_report(ASL_LEVEL_INFO,\n\t\t\t\t\"environment variables that can be set for debug:\\n\"\n\t\t\t\t\"- MallocLogFile <f> to create/append messages to file <f> instead of stderr\\n\"\n\t\t\t\t\"- MallocGuardEdges to add 2 guard pages for each large block\\n\"\n\t\t\t\t\"- MallocDoNotProtectPrelude to disable protection (when previous flag set)\\n\"\n\t\t\t\t\"- MallocDoNotProtectPostlude to disable protection (when previous flag set)\\n\"\n\t\t\t\t\"- MallocStackLogging to record all stacks.  Tools like leaks can then be applied\\n\"\n\t\t\t\t\"- MallocStackLoggingNoCompact to record all stacks.  Needed for malloc_history\\n\"\n\t\t\t\t\"- MallocStackLoggingDirectory to set location of stack logs, which can grow large; default is /tmp\\n\"\n\t\t\t\t\"- MallocScribble to detect writing on free blocks and missing initializers:\\n\"\n\t\t\t\t\"  0x55 is written upon free and 0xaa is written on allocation\\n\"\n\t\t\t\t\"- MallocCheckHeapStart <n> to start checking the heap after <n> operations\\n\"\n\t\t\t\t\"- MallocCheckHeapEach <s> to repeat the checking of the heap after <s> operations\\n\"\n\t\t\t\t\"- MallocCheckHeapSleep <t> to sleep <t> seconds on heap corruption\\n\"\n\t\t\t\t\"- MallocCheckHeapAbort <b> to abort on heap corruption if <b> is non-zero\\n\"\n\t\t\t\t\"- MallocCorruptionAbort to abort on malloc errors, but not on out of memory for 32-bit processes\\n\"\n\t\t\t\t\"  MallocCorruptionAbort is always set on 64-bit processes\\n\"\n\t\t\t\t\"- MallocErrorAbort to abort on any malloc error, including out of memory\\n\"\\\n\t\t\t\t\"- MallocTracing to emit kdebug trace points on malloc entry points\\n\"\\\n\t\t\t\t\"- MallocHelp - this help!\\n\");\n\t}\n}\n\nmalloc_zone_t *\nmalloc_create_zone(vm_size_t start_size, unsigned flags)\n{\n\tmalloc_zone_t *zone;\n\n\t/* start_size doesn't actually appear to be used, but we test anyway. */\n\tif (start_size > MALLOC_ABSOLUTE_MAX_SIZE) {\n\t\treturn NULL;\n\t}\n\t_malloc_initialize_once();\n\tzone = create_scalable_zone(start_size, flags | malloc_debug_flags);\n\tmalloc_zone_register(zone);\n\treturn zone;\n}\n\n/*\n * For use by CheckFix: establish a new default zone whose behavior is, apart from\n * the use of death-row and per-CPU magazines, that of Leopard.\n */\nvoid\nmalloc_create_legacy_default_zone(void)\n{\n\tmalloc_zone_t *zone;\n\tint i;\n\n\t_malloc_initialize_once();\n\tzone = create_legacy_scalable_zone(0, malloc_debug_flags);\n\n\tMALLOC_LOCK();\n\tmalloc_zone_register_while_locked(zone);\n\n\t//\n\t// Establish the legacy scalable zone just created as the default zone.\n\t//\n\tmalloc_zone_t *hold = malloc_zones[0];\n\tif (hold->zone_name && strcmp(hold->zone_name, DEFAULT_MALLOC_ZONE_STRING) == 0) {\n\t\tmalloc_set_zone_name(hold, NULL);\n\t}\n\tmalloc_set_zone_name(zone, DEFAULT_MALLOC_ZONE_STRING);\n\n\tunsigned protect_size = malloc_num_zones_allocated * sizeof(malloc_zone_t *);\n\tmprotect(malloc_zones, protect_size, PROT_READ | PROT_WRITE);\n\n\t// assert(zone == malloc_zones[malloc_num_zones - 1];\n\tfor (i = malloc_num_zones - 1; i > 0; --i) {\n\t\tmalloc_zones[i] = malloc_zones[i - 1];\n\t}\n\tmalloc_zones[0] = zone;\n\n\tmprotect(malloc_zones, protect_size, PROT_READ);\n\tMALLOC_UNLOCK();\n}\n\nvoid\nmalloc_destroy_zone(malloc_zone_t *zone)\n{\n\tmalloc_set_zone_name(zone, NULL); // Deallocate zone name wherever it may reside PR_7701095\n\tmalloc_zone_unregister(zone);\n\tzone->destroy(zone);\n}\n\nstatic vm_address_t *frames = NULL;\nstatic unsigned num_frames;\n\nMALLOC_NOINLINE\nvoid\nmalloc_zone_check_fail(const char *msg, const char *fmt, ...)\n{\n\t_SIMPLE_STRING b = _simple_salloc();\n\tif (b) {\n\t\t_simple_sprintf(b, \"*** MallocCheckHeap: FAILED check at operation #%d\\n\", malloc_check_counter - 1);\n\t} else {\n\t\tmalloc_report(MALLOC_REPORT_NOLOG, \"*** MallocCheckHeap: FAILED check at operation #%d\\n\", malloc_check_counter - 1);\n\t}\n\tif (frames) {\n\t\tunsigned index = 1;\n\t\tif (b) {\n\t\t\t_simple_sappend(b, \"Stack for last operation where the malloc check succeeded: \");\n\t\t\twhile (index < num_frames)\n\t\t\t\t_simple_sprintf(b, \"%p \", (void*)frames[index++]);\n\t\t\tmalloc_report(MALLOC_REPORT_NOLOG, \"%s\\n(Use 'atos' for a symbolic stack)\\n\", _simple_string(b));\n\t\t} else {\n\t\t\t/*\n\t\t\t * Should only get here if vm_allocate() can't get a single page of\n\t\t\t * memory, implying _simple_asl_log() would also fail.  So we just\n\t\t\t * print to the file descriptor.\n\t\t\t */\n\t\t\tmalloc_report(MALLOC_REPORT_NOLOG, \"Stack for last operation where the malloc check succeeded: \");\n\t\t\twhile (index < num_frames) {\n\t\t\t\tmalloc_report(MALLOC_REPORT_NOLOG, \"%p \", (void *)frames[index++]);\n\t\t\t}\n\t\t\tmalloc_report(MALLOC_REPORT_NOLOG, \"\\n(Use 'atos' for a symbolic stack)\\n\");\n\t\t}\n\t}\n\tif (malloc_check_each > 1) {\n\t\tunsigned recomm_each = (malloc_check_each > 10) ? malloc_check_each / 10 : 1;\n\t\tunsigned recomm_start =\n\t\t\t\t(malloc_check_counter > malloc_check_each + 1) ? malloc_check_counter - 1 - malloc_check_each : 1;\n\t\tmalloc_report(MALLOC_REPORT_NOLOG,\n\t\t\t\t\"*** Recommend using 'setenv MallocCheckHeapStart %d; setenv MallocCheckHeapEach %d' to narrow down failure\\n\",\n\t\t\t\trecomm_start, recomm_each);\n\t}\n\n\tif (b) {\n\t\t_simple_sfree(b);\n\t}\n\n\t// Use malloc_vreport() to:\n\t// \t* report the error\n\t// \t* call malloc_error_break() for a breakpoint\n\t// \t* sleep or stop for debug\n\t// \t* set the crash message and crash if malloc_check_abort is set.\n\tunsigned sleep_time = 0;\n\tuint32_t report_flags = ASL_LEVEL_ERR | MALLOC_REPORT_DEBUG | MALLOC_REPORT_NOLOG;\n\tif (malloc_check_abort) {\n\t\treport_flags |= MALLOC_REPORT_CRASH;\n\t} else {\n\t\tif (malloc_check_sleep > 0) {\n\t\t\tmalloc_report(ASL_LEVEL_NOTICE, \"*** Will sleep for %d seconds to leave time to attach\\n\", malloc_check_sleep);\n\t\t\tsleep_time = malloc_check_sleep;\n\t\t} else if (malloc_check_sleep < 0) {\n\t\t\tmalloc_report(ASL_LEVEL_NOTICE, \"*** Will sleep once for %d seconds to leave time to attach\\n\", -malloc_check_sleep);\n\t\t\tsleep_time = -malloc_check_sleep;\n\t\t\tmalloc_check_sleep = 0;\n\t\t}\n\t}\n\tva_list ap;\n\tva_start(ap, fmt);\n\tmalloc_vreport(report_flags, sleep_time, msg, NULL, fmt, ap);\n\tva_end(ap);\n}\n\n/*********\tBlock creation and manipulation\t************/\n\nstatic void\ninternal_check(void)\n{\n\tif (malloc_zone_check(NULL)) {\n\t\tif (!frames) {\n\t\t\tvm_allocate(mach_task_self(), (void *)&frames, vm_page_size, 1);\n\t\t}\n\t\tthread_stack_pcs(frames, (unsigned)(vm_page_size / sizeof(vm_address_t) - 1), &num_frames);\n\t}\n\tmalloc_check_start += malloc_check_each;\n}\n\nvoid *\nmalloc_zone_malloc(malloc_zone_t *zone, size_t size)\n{\n\tMALLOC_TRACE(TRACE_malloc | DBG_FUNC_START, (uintptr_t)zone, size, 0, 0);\n\n\tvoid *ptr;\n\tif (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {\n\t\tinternal_check();\n\t}\n\tif (size > MALLOC_ABSOLUTE_MAX_SIZE) {\n\t\treturn NULL;\n\t}\n\n\tptr = zone->malloc(zone, size);\t\t// if lite zone is passed in then we still call the lite methods\n\n\t\n\tif (malloc_logger) {\n\t\tmalloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE, (uintptr_t)zone, (uintptr_t)size, 0, (uintptr_t)ptr, 0);\n\t}\n\n\tMALLOC_TRACE(TRACE_malloc | DBG_FUNC_END, (uintptr_t)zone, size, (uintptr_t)ptr, 0);\n\treturn ptr;\n}\n\nvoid *\nmalloc_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size)\n{\n\tMALLOC_TRACE(TRACE_calloc | DBG_FUNC_START, (uintptr_t)zone, num_items, size, 0);\n\n\tvoid *ptr;\n\tif (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {\n\t\tinternal_check();\n\t}\n\n\tptr = zone->calloc(zone, num_items, size);\n\t\n\tif (malloc_logger) {\n\t\tmalloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE | MALLOC_LOG_TYPE_CLEARED, (uintptr_t)zone,\n\t\t\t\t(uintptr_t)(num_items * size), 0, (uintptr_t)ptr, 0);\n\t}\n\n\tMALLOC_TRACE(TRACE_calloc | DBG_FUNC_END, (uintptr_t)zone, num_items, size, (uintptr_t)ptr);\n\treturn ptr;\n}\n\nvoid *\nmalloc_zone_valloc(malloc_zone_t *zone, size_t size)\n{\n\tMALLOC_TRACE(TRACE_valloc | DBG_FUNC_START, (uintptr_t)zone, size, 0, 0);\n\n\tvoid *ptr;\n\tif (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {\n\t\tinternal_check();\n\t}\n\tif (size > MALLOC_ABSOLUTE_MAX_SIZE) {\n\t\treturn NULL;\n\t}\n\n\tptr = zone->valloc(zone, size);\n\t\n\tif (malloc_logger) {\n\t\tmalloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE, (uintptr_t)zone, (uintptr_t)size, 0, (uintptr_t)ptr, 0);\n\t}\n\n\tMALLOC_TRACE(TRACE_valloc | DBG_FUNC_END, (uintptr_t)zone, size, (uintptr_t)ptr, 0);\n\treturn ptr;\n}\n\nvoid *\nmalloc_zone_realloc(malloc_zone_t *zone, void *ptr, size_t size)\n{\n\tMALLOC_TRACE(TRACE_realloc | DBG_FUNC_START, (uintptr_t)zone, (uintptr_t)ptr, size, 0);\n\n\tvoid *new_ptr;\n\tif (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {\n\t\tinternal_check();\n\t}\n\tif (size > MALLOC_ABSOLUTE_MAX_SIZE) {\n\t\treturn NULL;\n\t}\n\n\tnew_ptr = zone->realloc(zone, ptr, size);\n\t\n\tif (malloc_logger) {\n\t\tmalloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_DEALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE, (uintptr_t)zone,\n\t\t\t\t(uintptr_t)ptr, (uintptr_t)size, (uintptr_t)new_ptr, 0);\n\t}\n\tMALLOC_TRACE(TRACE_realloc | DBG_FUNC_END, (uintptr_t)zone, (uintptr_t)ptr, size, (uintptr_t)new_ptr);\n\treturn new_ptr;\n}\n\nvoid\nmalloc_zone_free(malloc_zone_t *zone, void *ptr)\n{\n\tMALLOC_TRACE(TRACE_free, (uintptr_t)zone, (uintptr_t)ptr, (ptr) ? *(uintptr_t*)ptr : 0, 0);\n\n\tif (malloc_logger) {\n\t\tmalloc_logger(MALLOC_LOG_TYPE_DEALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE, (uintptr_t)zone, (uintptr_t)ptr, 0, 0, 0);\n\t}\n\tif (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {\n\t\tinternal_check();\n\t}\n\n\tzone->free(zone, ptr);\n}\n\nstatic void\nmalloc_zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size)\n{\n\tMALLOC_TRACE(TRACE_free, (uintptr_t)zone, (uintptr_t)ptr, size, (ptr && size) ? *(uintptr_t*)ptr : 0);\n\n\tif (malloc_logger) {\n\t\tmalloc_logger(MALLOC_LOG_TYPE_DEALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE, (uintptr_t)zone, (uintptr_t)ptr, 0, 0, 0);\n\t}\n\tif (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {\n\t\tinternal_check();\n\t}\n\n\tzone->free_definite_size(zone, ptr, size);\n}\n\nmalloc_zone_t *\nmalloc_zone_from_ptr(const void *ptr)\n{\n\tif (!ptr) {\n\t\treturn NULL;\n\t} else {\n\t\treturn find_registered_zone(ptr, NULL);\n\t}\n}\n\nvoid *\nmalloc_zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size)\n{\n\tMALLOC_TRACE(TRACE_memalign | DBG_FUNC_START, (uintptr_t)zone, alignment, size, 0);\n\n\tvoid *ptr;\n\tif (zone->version < 5) { // Version must be >= 5 to look at the new memalign field.\n\t\treturn NULL;\n\t}\n\tif (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {\n\t\tinternal_check();\n\t}\n\tif (size > MALLOC_ABSOLUTE_MAX_SIZE) {\n\t\treturn NULL;\n\t}\n\tif (alignment < sizeof(void *) ||\t\t\t  // excludes 0 == alignment\n\t\t\t0 != (alignment & (alignment - 1))) { // relies on sizeof(void *) being a power of two.\n\t\treturn NULL;\n\t}\n\n\tif (!(zone->memalign)) {\n\t\treturn NULL;\n\t}\n\tptr = zone->memalign(zone, alignment, size);\n\n\tif (malloc_logger) {\n\t\tmalloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE, (uintptr_t)zone, (uintptr_t)size, 0, (uintptr_t)ptr, 0);\n\t}\n\n\tMALLOC_TRACE(TRACE_memalign | DBG_FUNC_END, (uintptr_t)zone, alignment, size, (uintptr_t)ptr);\n\treturn ptr;\n}\n\nboolean_t\nmalloc_zone_claimed_address(malloc_zone_t *zone, void *ptr)\n{\n\tif (!ptr) {\n\t\t// NULL is not a member of any zone.\n\t\treturn false;\n\t}\n\n\tif (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {\n\t\tinternal_check();\n\t}\n\n\tif (zone->version < 10 || !zone->claimed_address) {\n\t\t// For zones that have not implemented claimed_address, we always have\n\t\t// to return true to avoid a false negative.\n\t\treturn true;\n\t}\n\n\treturn zone->claimed_address(zone, ptr);\n}\n\n/*********\tFunctions for zone implementors\t************/\n\nvoid\nmalloc_zone_register(malloc_zone_t *zone)\n{\n\tMALLOC_LOCK();\n\tmalloc_zone_register_while_locked(zone);\n\tMALLOC_UNLOCK();\n}\n\nvoid\nmalloc_zone_unregister(malloc_zone_t *z)\n{\n\tunsigned index;\n\n\tif (malloc_num_zones == 0) {\n\t\treturn;\n\t}\n\n\tMALLOC_LOCK();\n\tfor (index = 0; index < malloc_num_zones; ++index) {\n\t\tif (z != malloc_zones[index]) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Modify the page to be allow write access, so that we can update the\n\t\t// malloc_zones array.\n\t\tsize_t protect_size = malloc_num_zones_allocated * sizeof(malloc_zone_t *);\n\t\tmprotect(malloc_zones, protect_size, PROT_READ | PROT_WRITE);\n\n\t\t// If we found a match, replace it with the entry at the end of the list, shrink the list,\n\t\t// and leave the end of the list intact to avoid racing with find_registered_zone().\n\n\t\tmalloc_zones[index] = malloc_zones[malloc_num_zones - 1];\n\t\t--malloc_num_zones;\n\n\t\tmprotect(malloc_zones, protect_size, PROT_READ);\n\n\t\t// Exchange the roles of the FRZ counters. The counter that has captured the number of threads presently\n\t\t// executing *inside* find_regiatered_zone is swapped with the counter drained to zero last time through.\n\t\t// The former is then allowed to drain to zero while this thread yields.\n\t\tint32_t volatile *p = pFRZCounterLive;\n\t\tpFRZCounterLive = pFRZCounterDrain;\n\t\tpFRZCounterDrain = p;\n\t\tOSMemoryBarrier(); // Full memory barrier\n\n\t\twhile (0 != *pFRZCounterDrain) {\n\t\t\tyield();\n\t\t}\n\n\t\tMALLOC_UNLOCK();\n\n\t\treturn;\n\t}\n\tMALLOC_UNLOCK();\n\tmalloc_report(ASL_LEVEL_ERR, \"*** malloc_zone_unregister() failed for %p\\n\", z);\n}\n\nvoid\nmalloc_set_zone_name(malloc_zone_t *z, const char *name)\n{\n\tchar *newName;\n\n\tmprotect(z, sizeof(malloc_zone_t), PROT_READ | PROT_WRITE);\n\tif (z->zone_name) {\n\t\tfree((char *)z->zone_name);\n\t\tz->zone_name = NULL;\n\t}\n\tif (name) {\n\t\tsize_t buflen = strlen(name) + 1;\n\t\tnewName = malloc_zone_malloc(z, buflen);\n\t\tif (newName) {\n\t\t\tstrlcpy(newName, name, buflen);\n\t\t\tz->zone_name = (const char *)newName;\n\t\t} else {\n\t\t\tz->zone_name = NULL;\n\t\t}\n\t}\n\tmprotect(z, sizeof(malloc_zone_t), PROT_READ);\n}\n\nconst char *\nmalloc_get_zone_name(malloc_zone_t *zone)\n{\n\treturn zone->zone_name;\n}\n\n\n/*********\tGeneric ANSI callouts\t************/\n\nvoid *\nmalloc(size_t size)\n{\n\tvoid *retval;\n\tretval = malloc_zone_malloc(default_zone, size);\n\tif (retval == NULL) {\n\t\terrno = ENOMEM;\n\t}\n\treturn retval;\n}\n\nvoid *\ncalloc(size_t num_items, size_t size)\n{\n\tvoid *retval;\n\tretval = malloc_zone_calloc(default_zone, num_items, size);\n\tif (retval == NULL) {\n\t\terrno = ENOMEM;\n\t}\n\treturn retval;\n}\n\nvoid\nfree(void *ptr)\n{\n\tmalloc_zone_t *zone;\n\tsize_t size;\n\tif (!ptr) {\n\t\treturn;\n\t}\n\n\tzone = find_registered_zone(ptr, &size);\n\tif (!zone) {\n\t\tint flags = MALLOC_REPORT_DEBUG | MALLOC_REPORT_NOLOG;\n\t\tif ((malloc_debug_flags & (MALLOC_ABORT_ON_CORRUPTION | MALLOC_ABORT_ON_ERROR))) {\n\t\t\tflags = MALLOC_REPORT_CRASH | MALLOC_REPORT_NOLOG;\n\t\t}\n\t\tmalloc_report(flags,\n\t\t\t\t\"*** error for object %p: pointer being freed was not allocated\\n\", ptr);\n\t} else if (zone->version >= 6 && zone->free_definite_size) {\n\t\tmalloc_zone_free_definite_size(zone, ptr, size);\n\t} else {\n\t\tmalloc_zone_free(zone, ptr);\n\t}\n}\n\nvoid *\nrealloc(void *in_ptr, size_t new_size)\n{\n\tvoid *retval = NULL;\n\tvoid *old_ptr;\n\tmalloc_zone_t *zone;\n\n\t// SUSv3: \"If size is 0 and ptr is not a null pointer, the object\n\t// pointed to is freed. If the space cannot be allocated, the object\n\t// shall remain unchanged.\"  Also \"If size is 0, either a null pointer\n\t// or a unique pointer that can be successfully passed to free() shall\n\t// be returned.\"  We choose to allocate a minimum size object by calling\n\t// malloc_zone_malloc with zero size, which matches \"If ptr is a null\n\t// pointer, realloc() shall be equivalent to malloc() for the specified\n\t// size.\"  So we only free the original memory if the allocation succeeds.\n\told_ptr = (new_size == 0) ? NULL : in_ptr;\n\tif (!old_ptr) {\n\t\tretval = malloc_zone_malloc(default_zone, new_size);\n\t} else {\n\t\tzone = find_registered_zone(old_ptr, NULL);\n\t\tif (!zone) {\n\t\t\tint flags = MALLOC_REPORT_DEBUG | MALLOC_REPORT_NOLOG;\n\t\t\tif (malloc_debug_flags & (MALLOC_ABORT_ON_CORRUPTION | MALLOC_ABORT_ON_ERROR)) {\n\t\t\t\tflags = MALLOC_REPORT_CRASH | MALLOC_REPORT_NOLOG;\n\t\t\t}\n\t\t\tmalloc_report(flags, \"*** error for object %p: pointer being realloc'd was not allocated\\n\", in_ptr);\n\t\t} else {\n\t\t\tretval = malloc_zone_realloc(zone, old_ptr, new_size);\n\t\t}\n\t}\n\n\tif (retval == NULL) {\n\t\terrno = ENOMEM;\n\t} else if (new_size == 0) {\n\t\tfree(in_ptr);\n\t}\n\treturn retval;\n}\n\nvoid *\nvalloc(size_t size)\n{\n\tvoid *retval;\n\tmalloc_zone_t *zone = default_zone;\n\tretval = malloc_zone_valloc(zone, size);\n\tif (retval == NULL) {\n\t\terrno = ENOMEM;\n\t}\n\treturn retval;\n}\n\nextern void\nvfree(void *ptr)\n{\n\tfree(ptr);\n}\n\nsize_t\nmalloc_size(const void *ptr)\n{\n\tsize_t size = 0;\n\n\tif (!ptr) {\n\t\treturn size;\n\t}\n\n\t(void)find_registered_zone(ptr, &size);\n\treturn size;\n}\n\nsize_t\nmalloc_good_size(size_t size)\n{\n\tmalloc_zone_t *zone = default_zone;\n\treturn zone->introspect->good_size(zone, size);\n}\n\n/*\n * The posix_memalign() function shall allocate size bytes aligned on a boundary specified by alignment,\n * and shall return a pointer to the allocated memory in memptr.\n * The value of alignment shall be a multiple of sizeof( void *), that is also a power of two.\n * Upon successful completion, the value pointed to by memptr shall be a multiple of alignment.\n *\n * Upon successful completion, posix_memalign() shall return zero; otherwise,\n * an error number shall be returned to indicate the error.\n *\n * The posix_memalign() function shall fail if:\n * EINVAL\n *\tThe value of the alignment parameter is not a power of two multiple of sizeof( void *).\n * ENOMEM\n *\tThere is insufficient memory available with the requested alignment.\n */\n\nint\nposix_memalign(void **memptr, size_t alignment, size_t size)\n{\n\tvoid *retval;\n\n\t/* POSIX is silent on NULL == memptr !?! */\n\n\tretval = malloc_zone_memalign(default_zone, alignment, size);\n\tif (retval == NULL) {\n\t\t// To avoid testing the alignment constraints redundantly, we'll rely on the\n\t\t// test made in malloc_zone_memalign to vet each request. Only if that test fails\n\t\t// and returns NULL, do we arrive here to detect the bogus alignment and give the\n\t\t// required EINVAL return.\n\t\tif (alignment < sizeof(void *) ||\t\t\t  // excludes 0 == alignment\n\t\t\t\t0 != (alignment & (alignment - 1))) { // relies on sizeof(void *) being a power of two.\n\t\t\treturn EINVAL;\n\t\t}\n\t\treturn ENOMEM;\n\t} else {\n\t\t*memptr = retval; // Set iff allocation succeeded\n\t\treturn 0;\n\t}\n}\n\nboolean_t\nmalloc_claimed_address(void *ptr)\n{\n\t// We need to check with each registered zone whether it claims \"ptr\".\n\t// Use logic similar to that in find_registered_zone().\n\tif (malloc_num_zones == 0) {\n\t\treturn false;\n\t}\n\n\t// Start with the lite zone, if it's in use.\n\tif (lite_zone && malloc_zone_claimed_address(lite_zone, ptr)) {\n\t\treturn true;\n\t}\n\n\t// Next, try the default zone, which is always present.\n\tif (malloc_zone_claimed_address(malloc_zones[0], ptr)) {\n\t\treturn true;\n\t}\n\n\t// Try all the other zones. Increment the FRZ barrier so that we can\n\t// walk the zones array without a lock (see find_registered_zone() for\n\t// the details).\n\tint32_t volatile *pFRZCounter = pFRZCounterLive;\n\tOSAtomicIncrement32Barrier(pFRZCounter);\n\n\tint32_t limit = *(int32_t volatile *)&malloc_num_zones;\n\tmalloc_zone_t **zones = &malloc_zones[1];\n\tboolean_t result = false;\n\tfor (unsigned index = 1; index < limit; ++index, ++zones) {\n\t\tmalloc_zone_t *zone = *zones;\n\t\tif (malloc_zone_claimed_address(zone, ptr)) {\n\t\t\tresult = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tOSAtomicDecrement32Barrier(pFRZCounter);\n\treturn result;\n}\n\nvoid *\nreallocarray(void * in_ptr, size_t nmemb, size_t size){\n\tsize_t alloc_size;\n\tif (os_mul_overflow(nmemb, size, &alloc_size)){\n\t\terrno = ENOMEM;\n\t\treturn NULL;\n\t}\n\treturn realloc(in_ptr, alloc_size);\n}\n\nvoid *\nreallocarrayf(void * in_ptr, size_t nmemb, size_t size){\n\tsize_t alloc_size;\n\tif (os_mul_overflow(nmemb, size, &alloc_size)){\n\t\terrno = ENOMEM;\n\t\treturn NULL;\n\t}\n\treturn reallocf(in_ptr, alloc_size);\n}\n\nstatic malloc_zone_t *\nfind_registered_purgeable_zone(void *ptr)\n{\n\tif (!ptr) {\n\t\treturn NULL;\n\t}\n\n\t/*\n\t * Look for a zone which contains ptr.  If that zone does not have the purgeable malloc flag\n\t * set, or the allocation is too small, do nothing.  Otherwise, set the allocation volatile.\n\t * FIXME: for performance reasons, we should probably keep a separate list of purgeable zones\n\t * and only search those.\n\t */\n\tsize_t size = 0;\n\tmalloc_zone_t *zone = find_registered_zone(ptr, &size);\n\n\t/* FIXME: would really like a zone->introspect->flags->purgeable check, but haven't determined\n\t * binary compatibility impact of changing the introspect struct yet. */\n\tif (!zone) {\n\t\treturn NULL;\n\t}\n\n\t/* Check to make sure pointer is page aligned and size is multiple of page size */\n\tif ((size < vm_page_size) || ((size % vm_page_size) != 0)) {\n\t\treturn NULL;\n\t}\n\n\treturn zone;\n}\n\nvoid\nmalloc_make_purgeable(void *ptr)\n{\n\tmalloc_zone_t *zone = find_registered_purgeable_zone(ptr);\n\tif (!zone) {\n\t\treturn;\n\t}\n\n\tint state = VM_PURGABLE_VOLATILE;\n\tvm_purgable_control(mach_task_self(), (vm_address_t)ptr, VM_PURGABLE_SET_STATE, &state);\n\treturn;\n}\n\n/* Returns true if ptr is valid.  Ignore the return value from vm_purgeable_control and only report\n * state. */\nint\nmalloc_make_nonpurgeable(void *ptr)\n{\n\tmalloc_zone_t *zone = find_registered_purgeable_zone(ptr);\n\tif (!zone) {\n\t\treturn 0;\n\t}\n\n\tint state = VM_PURGABLE_NONVOLATILE;\n\tvm_purgable_control(mach_task_self(), (vm_address_t)ptr, VM_PURGABLE_SET_STATE, &state);\n\n\tif (state == VM_PURGABLE_EMPTY) {\n\t\treturn EFAULT;\n\t}\n\n\treturn 0;\n}\n\nvoid\nmalloc_enter_process_memory_limit_warn_mode(void)\n{\n\t// <rdar://problem/25063714>\n}\n\n#if ENABLE_MEMORY_RESOURCE_EXCEPTION_HANDLING\n\n// Is the system elible to turn on/off MSL lite in response to memory resource exceptions\n//\n// Return true if\n// - The user has not explicitly opted out\n//     and\n// - Either the user has explicitly opted in or this is an Apple Internal enabled build\n\nstatic boolean_t\ncheck_is_eligible_for_lite_mode_mre_handling(void)\n{\n\tstruct stat stat_buf;\n\t\t\n\t// User opted out\n\tif (stat(\"/var/db/disableLiteModeMemoryResourceExceptionHandling\", &stat_buf) == 0) {\n\t\treturn false;\n\t}\n\t\n\t// User opted in\n\tif (stat(\"/var/db/enableLiteModeMemoryResourceExceptionHandling\", &stat_buf) == 0) {\n\t\treturn true;\n\t}\n\t\n\t\n\t// Not enabled for everything else\n\treturn false;\n}\n\n// Not thread-safe, but it's called from malloc_memory_event_handler which already assumes\n// single thread execution.\nstatic boolean_t\nis_eligible_for_lite_mode_mre_handling(void)\n{\n\tstatic boolean_t is_eligible = false;\n\tstatic boolean_t needs_check = true;\n\t\n\tif (needs_check) {\n\t\tis_eligible = check_is_eligible_for_lite_mode_mre_handling();\n\t\tneeds_check = false;\n\t}\n\t\n\treturn is_eligible;\n}\n\n#endif\n\nstatic void\nhandle_msl_memory_event(unsigned long event)\n{\n\t// don't mix and match enabling mechanisms\n\tif (warn_mode_entered) {\n\t\treturn;\n\t}\n\t\n\tevent &= NOTE_MEMORYSTATUS_MSL_STATUS;\n\t\n\t// sanity check\n\tif (event == 0) {\n\t\treturn;\n\t}\n\t\n\t// first check if the disable bit is set\n\tif (event & MEMORYSTATUS_DISABLE_MSL) {\n\t\tturn_off_stack_logging();\n\t\treturn;\n\t}\n\t\n\tboolean_t msl_malloc = (event & MEMORYSTATUS_ENABLE_MSL_MALLOC);\n\tboolean_t msl_vm = (event & MEMORYSTATUS_ENABLE_MSL_VM);\n\tboolean_t msl_lite = (event & MEMORYSTATUS_ENABLE_MSL_LITE);\n\t\n\t// The following ensures it's not possible to enable two different modes\n\t// For instance this would not be allowed:\n\t// Enable lite\n\t// Disable\n\t// Enable full\n\t\n\tif (msl_lite) {\n\t\tif (msl_vm && msl_malloc) {\n\t\t\tif (msl_type_enabled_at_runtime == stack_logging_mode_none || msl_type_enabled_at_runtime == stack_logging_mode_lite) {\n\t\t\t\tmsl_type_enabled_at_runtime = stack_logging_mode_lite;\n\t\t\t\tturn_on_stack_logging(stack_logging_mode_lite);\n\t\t\t}\n\t\t} else if (msl_vm) {\n\t\t\tif (msl_type_enabled_at_runtime == stack_logging_mode_none || msl_type_enabled_at_runtime == stack_logging_mode_vmlite) {\n\t\t\t\tmsl_type_enabled_at_runtime = stack_logging_mode_vmlite;\n\t\t\t\tturn_on_stack_logging(stack_logging_mode_vmlite);\n\t\t\t}\n\t\t}\n\t\treturn;\n\t} else if (msl_malloc && msl_vm) {\n\t\tif (msl_type_enabled_at_runtime == stack_logging_mode_none || msl_type_enabled_at_runtime == stack_logging_mode_all) {\n\t\t\tmsl_type_enabled_at_runtime = stack_logging_mode_all;\n\t\t\tturn_on_stack_logging(stack_logging_mode_all);\n\t\t}\n\t\treturn;\n\t} else if (msl_malloc) {\n\t\tif (msl_type_enabled_at_runtime == stack_logging_mode_none || msl_type_enabled_at_runtime == stack_logging_mode_malloc) {\n\t\t\tmsl_type_enabled_at_runtime = stack_logging_mode_malloc;\n\t\t\tturn_on_stack_logging(stack_logging_mode_malloc);\n\t\t}\n\t\treturn;\n\t} else if (msl_vm) {\n\t\tif (msl_type_enabled_at_runtime == stack_logging_mode_none || msl_type_enabled_at_runtime == stack_logging_mode_vm) {\n\t\t\tmsl_type_enabled_at_runtime = stack_logging_mode_vm;\n\t\t\tturn_on_stack_logging(stack_logging_mode_vm);\n\t\t}\n\t\treturn;\n\t}\n}\n\n// Note that malloc_memory_event_handler is not thread-safe, and we are relying on the callers of this for synchronization\nvoid\nmalloc_memory_event_handler(unsigned long event)\n{\n\tif (event & NOTE_MEMORYSTATUS_PRESSURE_WARN) {\n\t\tmalloc_zone_pressure_relief(0, 0);\n\t}\n\t\n\t// First check for enable/disable MSL - only recognize if all other bits are 0\n\t// Don't attempt this if we've either entered or exited MRE mode\n\tif ((event & NOTE_MEMORYSTATUS_MSL_STATUS) != 0 && (event & ~NOTE_MEMORYSTATUS_MSL_STATUS) == 0 && !warn_mode_entered && !warn_mode_disable_retries) {\n\t\thandle_msl_memory_event(event);\n\t\treturn;\n\t}\n\n#if ENABLE_MEMORY_RESOURCE_EXCEPTION_HANDLING\n\t// If we have reached EXC_RESOURCE, we no longer need stack log data.\n\t// If we are under system-wide memory pressure, we should jettison stack log data.\n\tif ((event & (NOTE_MEMORYSTATUS_PROC_LIMIT_CRITICAL | NOTE_MEMORYSTATUS_PRESSURE_CRITICAL)) &&\n\t\t!warn_mode_disable_retries) {\n\t\t// If we have crossed the EXC_RESOURCE limit once already, there is no point in\n\t\t// collecting stack logs in the future, even if we missed a previous chance to\n\t\t// collect data because nobody is going to ask us for it again.\n\t\twarn_mode_disable_retries = true;\n\n\t\t// Only try to clean up stack log data if it was enabled through a proc limit warning.\n\t\t// User initiated stack logging should proceed unimpeded.\n\t\tif (warn_mode_entered) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"malloc_memory_event_handler: stopping stack-logging\\n\");\n\t\t\tturn_off_stack_logging();\n\t\t\t__malloc_lock_stack_logging();\n\t\t\t__delete_uniquing_table_memory_while_locked();\n\t\t\t__malloc_unlock_stack_logging();\n\t\t\t\n\t\t\twarn_mode_entered = false;\n\t\t}\n\t}\n\n\t// Enable stack logging if we are approaching the process limit, provided\n\t// we aren't under system wide memory pressure and we're allowed to try again.\n\tif ((event & NOTE_MEMORYSTATUS_PROC_LIMIT_WARN) &&\n\t\t!(event & NOTE_MEMORYSTATUS_PRESSURE_CRITICAL) &&\n\t\t!warn_mode_entered && !warn_mode_disable_retries &&\n\t\tis_eligible_for_lite_mode_mre_handling()) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"malloc_memory_event_handler: approaching memory limit. Starting stack-logging.\\n\");\n\t\tif (turn_on_stack_logging(stack_logging_mode_lite)) {\n\t\t\twarn_mode_entered = true;\n\t\t\t\n\t\t\t// set the maximum allocation threshold\n\t\t\tmax_lite_mallocs = MAX_LITE_MALLOCS;\n\t\t}\n\t}\n#endif\n}\n\nsize_t\nmalloc_zone_pressure_relief(malloc_zone_t *zone, size_t goal)\n{\n\tif (!zone) {\n\t\tunsigned index = 0;\n\t\tsize_t total = 0;\n\n\t\t// Take lock to defend against malloc_destroy_zone()\n\t\tMALLOC_LOCK();\n\t\twhile (index < malloc_num_zones) {\n\t\t\tzone = malloc_zones[index++];\n\t\t\tif (zone->version < 8) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (NULL == zone->pressure_relief) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (0 == goal) { /* Greedy */\n\t\t\t\ttotal += zone->pressure_relief(zone, 0);\n\t\t\t} else if (goal > total) {\n\t\t\t\ttotal += zone->pressure_relief(zone, goal - total);\n\t\t\t} else { /* total >= goal */\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tMALLOC_UNLOCK();\n\t\treturn total;\n\t} else {\n\t\t// Assumes zone is not destroyed for the duration of this call\n\t\tif (zone->version < 8) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (NULL == zone->pressure_relief) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn zone->pressure_relief(zone, goal);\n\t}\n}\n\n/*********\tBatch methods\t************/\n\nunsigned\nmalloc_zone_batch_malloc(malloc_zone_t *zone, size_t size, void **results, unsigned num_requested)\n{\n\tif (!zone->batch_malloc) {\n\t\treturn 0;\n\t}\n\tif (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {\n\t\tinternal_check();\n\t}\n\tunsigned batched = zone->batch_malloc(zone, size, results, num_requested);\n\t\n\tif (malloc_logger) {\n\t\tunsigned index = 0;\n\t\twhile (index < batched) {\n\t\t\tmalloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE, (uintptr_t)zone, (uintptr_t)size, 0,\n\t\t\t\t\t(uintptr_t)results[index], 0);\n\t\t\tindex++;\n\t\t}\n\t}\n\treturn batched;\n}\n\nvoid\nmalloc_zone_batch_free(malloc_zone_t *zone, void **to_be_freed, unsigned num)\n{\n\tif (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {\n\t\tinternal_check();\n\t}\n\tif (malloc_logger) {\n\t\tunsigned index = 0;\n\t\twhile (index < num) {\n\t\t\tmalloc_logger(\n\t\t\t\t\tMALLOC_LOG_TYPE_DEALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE, (uintptr_t)zone, (uintptr_t)to_be_freed[index], 0, 0, 0);\n\t\t\tindex++;\n\t\t}\n\t}\n\t\n\tif (zone->batch_free) {\n\t\tzone->batch_free(zone, to_be_freed, num);\n\t} else {\n\t\tvoid (*free_fun)(malloc_zone_t *, void *) = zone->free;\n\t\t\n\t\twhile (num--) {\n\t\t\tvoid *ptr = *to_be_freed++;\n\t\t\tfree_fun(zone, ptr);\n\t\t}\n\t}\n}\n\n/*********\tFunctions for performance tools\t************/\n\nstatic kern_return_t\n_malloc_default_reader(task_t task, vm_address_t address, vm_size_t size, void **ptr)\n{\n\t*ptr = (void *)address;\n\treturn 0;\n}\n\nkern_return_t\nmalloc_get_all_zones(task_t task, memory_reader_t reader, vm_address_t **addresses, unsigned *count)\n{\n\t// Note that the 2 following addresses are not correct if the address of the target is different from your own.  This notably\n\t// occurs if the address of System.framework is slid (e.g. different than at B & I )\n\tvm_address_t remote_malloc_zones = (vm_address_t)&malloc_zones;\n\tvm_address_t remote_malloc_num_zones = (vm_address_t)&malloc_num_zones;\n\tkern_return_t err;\n\tvm_address_t zones_address;\n\tvm_address_t *zones_address_ref;\n\tunsigned num_zones;\n\tunsigned *num_zones_ref;\n\tif (!reader) {\n\t\treader = _malloc_default_reader;\n\t}\n\t// printf(\"Read malloc_zones at address %p should be %p\\n\", &malloc_zones, malloc_zones);\n\terr = reader(task, remote_malloc_zones, sizeof(void *), (void **)&zones_address_ref);\n\t// printf(\"Read malloc_zones[%p]=%p\\n\", remote_malloc_zones, *zones_address_ref);\n\tif (err) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"*** malloc_get_all_zones: error reading zones_address at %p\\n\", (void *)remote_malloc_zones);\n\t\treturn err;\n\t}\n\tzones_address = *zones_address_ref;\n\t// printf(\"Reading num_zones at address %p\\n\", remote_malloc_num_zones);\n\terr = reader(task, remote_malloc_num_zones, sizeof(unsigned), (void **)&num_zones_ref);\n\tif (err) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"*** malloc_get_all_zones: error reading num_zones at %p\\n\", (void *)remote_malloc_num_zones);\n\t\treturn err;\n\t}\n\tnum_zones = *num_zones_ref;\n\t// printf(\"Read malloc_num_zones[%p]=%d\\n\", remote_malloc_num_zones, num_zones);\n\t*count = num_zones;\n\t// printf(\"malloc_get_all_zones succesfully found %d zones\\n\", num_zones);\n\terr = reader(task, zones_address, sizeof(malloc_zone_t *) * num_zones, (void **)addresses);\n\tif (err) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"*** malloc_get_all_zones: error reading zones at %p\\n\", &zones_address);\n\t\treturn err;\n\t}\n\t// printf(\"malloc_get_all_zones succesfully read %d zones\\n\", num_zones);\n\treturn err;\n}\n\n/*********\tDebug helpers\t************/\n\nvoid\nmalloc_zone_print_ptr_info(void *ptr)\n{\n\tmalloc_zone_t *zone;\n\tif (!ptr) {\n\t\treturn;\n\t}\n\tzone = malloc_zone_from_ptr(ptr);\n\tif (zone) {\n\t\tprintf(\"ptr %p in registered zone %p\\n\", ptr, zone);\n\t} else {\n\t\tprintf(\"ptr %p not in heap\\n\", ptr);\n\t}\n}\n\nboolean_t\nmalloc_zone_check(malloc_zone_t *zone)\n{\n\tboolean_t ok = 1;\n\tif (!zone) {\n\t\tunsigned index = 0;\n\t\twhile (index < malloc_num_zones) {\n\t\t\tzone = malloc_zones[index++];\n\t\t\tif (!zone->introspect->check(zone)) {\n\t\t\t\tok = 0;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tok = zone->introspect->check(zone);\n\t}\n\treturn ok;\n}\n\nvoid\nmalloc_zone_print(malloc_zone_t *zone, boolean_t verbose)\n{\n\tif (!zone) {\n\t\tunsigned index = 0;\n\t\twhile (index < malloc_num_zones) {\n\t\t\tzone = malloc_zones[index++];\n\t\t\tzone->introspect->print(zone, verbose);\n\t\t}\n\t} else {\n\t\tzone->introspect->print(zone, verbose);\n\t}\n}\n\nvoid\nmalloc_zone_statistics(malloc_zone_t *zone, malloc_statistics_t *stats)\n{\n\tif (!zone) {\n\t\tmemset(stats, 0, sizeof(*stats));\n\t\tunsigned index = 0;\n\t\twhile (index < malloc_num_zones) {\n\t\t\tzone = malloc_zones[index++];\n\t\t\tmalloc_statistics_t this_stats;\n\t\t\tzone->introspect->statistics(zone, &this_stats);\n\t\t\tstats->blocks_in_use += this_stats.blocks_in_use;\n\t\t\tstats->size_in_use += this_stats.size_in_use;\n\t\t\tstats->max_size_in_use += this_stats.max_size_in_use;\n\t\t\tstats->size_allocated += this_stats.size_allocated;\n\t\t}\n\t} else {\n\t\tzone->introspect->statistics(zone, stats);\n\t}\n}\n\nvoid\nmalloc_zone_log(malloc_zone_t *zone, void *address)\n{\n\tif (!zone) {\n\t\tunsigned index = 0;\n\t\twhile (index < malloc_num_zones) {\n\t\t\tzone = malloc_zones[index++];\n\t\t\tzone->introspect->log(zone, address);\n\t\t}\n\t} else {\n\t\tzone->introspect->log(zone, address);\n\t}\n}\n\n/*********\tMisc other entry points\t************/\n\nvoid\nmag_set_thread_index(unsigned int index)\n{\n\t_os_cpu_number_override = index;\n#if CONFIG_NANOZONE\n\tnano_common_cpu_number_override_set();\n#endif // CONFIG_NANOZONE\n}\n\nstatic void\nDefaultMallocError(int x)\n{\n#if USE_SLEEP_RATHER_THAN_ABORT\n\tmalloc_report(ASL_LEVEL_ERR, \"*** error %d\\n\", x);\n\tsleep(3600);\n#else\n\t_SIMPLE_STRING b = _simple_salloc();\n\tif (b) {\n\t\t_simple_sprintf(b, \"*** error %d\", x);\n\t\tmalloc_report(MALLOC_REPORT_NOLOG, \"%s\\n\", _simple_string(b));\n\t\t_os_set_crash_log_message_dynamic(_simple_string(b));\n\t} else {\n\t\tmalloc_report(MALLOC_REPORT_NOLOG, \"*** error %d\\n\", x);\n\t\t_os_set_crash_log_message(\"*** DefaultMallocError called\");\n\t}\n\tabort();\n#endif\n}\n\nvoid (*malloc_error(void (*func)(int)))(int)\n{\n\treturn DefaultMallocError;\n}\n\nstatic void\n_malloc_lock_all(void (*callout)(void))\n{\n\tunsigned index = 0;\n\tMALLOC_LOCK();\n\twhile (index < malloc_num_zones) {\n\t\tmalloc_zone_t *zone = malloc_zones[index++];\n\t\tzone->introspect->force_lock(zone);\n\t}\n\tcallout();\n}\n\nstatic void\n_malloc_unlock_all(void (*callout)(void))\n{\n\tunsigned index = 0;\n\tcallout();\n\twhile (index < malloc_num_zones) {\n\t\tmalloc_zone_t *zone = malloc_zones[index++];\n\t\tzone->introspect->force_unlock(zone);\n\t}\n\tMALLOC_UNLOCK();\n}\n\nstatic void\n_malloc_reinit_lock_all(void (*callout)(void))\n{\n\tunsigned index = 0;\n\tcallout();\n\twhile (index < malloc_num_zones) {\n\t\tmalloc_zone_t *zone = malloc_zones[index++];\n\t\tif (zone->version < 9) { // Version must be >= 9 to look at reinit_lock\n\t\t\tzone->introspect->force_unlock(zone);\n\t\t} else {\n\t\t\tzone->introspect->reinit_lock(zone);\n\t\t}\n\t}\n\tMALLOC_REINIT_LOCK();\n}\n\n\n// Called prior to fork() to guarantee that malloc is not in any critical\n// sections during the fork(); prevent any locks from being held by non-\n// surviving threads after the fork.\nvoid\n_malloc_fork_prepare(void)\n{\n\treturn _malloc_lock_all(&__stack_logging_fork_prepare);\n}\n\n// Called in the parent process after fork() to resume normal operation.\nvoid\n_malloc_fork_parent(void)\n{\n\treturn _malloc_unlock_all(&__stack_logging_fork_parent);\n}\n\n// Called in the child process after fork() to resume normal operation.\nvoid\n_malloc_fork_child(void)\n{\n#if CONFIG_NANOZONE\n\tif (_malloc_initialize_pred) {\n\t\tif (_malloc_engaged_nano == NANO_V2) {\n\t\t\tnanov2_forked_zone((nanozonev2_t *)inline_malloc_default_zone());\n\t\t} else if (_malloc_engaged_nano == NANO_V1) {\n\t\t\tnano_forked_zone((nanozone_t *)inline_malloc_default_zone());\n\t\t}\n\t}\n#endif\n\treturn _malloc_reinit_lock_all(&__stack_logging_fork_child);\n}\n\n/*\n * A Glibc-like mstats() interface.\n *\n * Note that this interface really isn't very good, as it doesn't understand\n * that we may have multiple allocators running at once.  We just massage\n * the result from malloc_zone_statistics in any case.\n */\nstruct mstats\nmstats(void)\n{\n\tmalloc_statistics_t s;\n\tstruct mstats m;\n\n\tmalloc_zone_statistics(NULL, &s);\n\tm.bytes_total = s.size_allocated;\n\tm.chunks_used = s.blocks_in_use;\n\tm.bytes_used = s.size_in_use;\n\tm.chunks_free = 0;\n\tm.bytes_free = m.bytes_total - m.bytes_used; /* isn't this somewhat obvious? */\n\n\treturn (m);\n}\n\nboolean_t\nmalloc_zone_enable_discharge_checking(malloc_zone_t *zone)\n{\n\tif (zone->version < 7) { // Version must be >= 7 to look at the new discharge checking fields.\n\t\treturn FALSE;\n\t}\n\tif (NULL == zone->introspect->enable_discharge_checking) {\n\t\treturn FALSE;\n\t}\n\treturn zone->introspect->enable_discharge_checking(zone);\n}\n\nvoid\nmalloc_zone_disable_discharge_checking(malloc_zone_t *zone)\n{\n\tif (zone->version < 7) { // Version must be >= 7 to look at the new discharge checking fields.\n\t\treturn;\n\t}\n\tif (NULL == zone->introspect->disable_discharge_checking) {\n\t\treturn;\n\t}\n\tzone->introspect->disable_discharge_checking(zone);\n}\n\nvoid\nmalloc_zone_discharge(malloc_zone_t *zone, void *memory)\n{\n\tif (NULL == zone) {\n\t\tzone = malloc_zone_from_ptr(memory);\n\t}\n\tif (NULL == zone) {\n\t\treturn;\n\t}\n\tif (zone->version < 7) { // Version must be >= 7 to look at the new discharge checking fields.\n\t\treturn;\n\t}\n\tif (NULL == zone->introspect->discharge) {\n\t\treturn;\n\t}\n\tzone->introspect->discharge(zone, memory);\n}\n\nvoid\nmalloc_zone_enumerate_discharged_pointers(malloc_zone_t *zone, void (^report_discharged)(void *memory, void *info))\n{\n\tif (!zone) {\n\t\tunsigned index = 0;\n\t\twhile (index < malloc_num_zones) {\n\t\t\tzone = malloc_zones[index++];\n\t\t\tif (zone->version < 7) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (NULL == zone->introspect->enumerate_discharged_pointers) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tzone->introspect->enumerate_discharged_pointers(zone, report_discharged);\n\t\t}\n\t} else {\n\t\tif (zone->version < 7) {\n\t\t\treturn;\n\t\t}\n\t\tif (NULL == zone->introspect->enumerate_discharged_pointers) {\n\t\t\treturn;\n\t\t}\n\t\tzone->introspect->enumerate_discharged_pointers(zone, report_discharged);\n\t}\n}\n\n/*****************\tOBSOLETE ENTRY POINTS\t********************/\n\n#if PHASE_OUT_OLD_MALLOC\n#error PHASE OUT THE FOLLOWING FUNCTIONS\n#endif\n\nvoid\nset_malloc_singlethreaded(boolean_t single)\n{\n\tstatic boolean_t warned = 0;\n\tif (!warned) {\n#if PHASE_OUT_OLD_MALLOC\n\t\tmalloc_report(ASL_LEVEL_ERR, \"*** OBSOLETE: set_malloc_singlethreaded(%d)\\n\", single);\n#endif\n\t\twarned = 1;\n\t}\n}\n\nvoid\nmalloc_singlethreaded(void)\n{\n\tstatic boolean_t warned = 0;\n\tif (!warned) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"*** OBSOLETE: malloc_singlethreaded()\\n\");\n\t\twarned = 1;\n\t}\n}\n\nint\nmalloc_debug(int level)\n{\n\tmalloc_report(ASL_LEVEL_ERR, \"*** OBSOLETE: malloc_debug()\\n\");\n\treturn 0;\n}\n\n/* vim: set noet:ts=4:sw=4:cindent: */\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/malloc_common.c",
    "content": "/*\n * Copyright (c) 2018 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n#include \"internal.h\"\n\n#pragma mark -\n#pragma mark Utility Functions\n\n// libplatform does not have strstr() and we don't want to add any new\n// dependencies on libc, so we have to implement a version of strntr()\n// here. Fortunately, as it's only used to look for boot arguments, it does not\n// have to be efficient. We can also assume that the source string is\n// nul-terminated. Eventually, we will move the function to a more central\n// location and use it to replace other uses of strstr().\nconst char *\nmalloc_common_strstr(const char *src, const char *target, size_t target_len)\n{\n\tconst char *next = src;\n\twhile (*next) {\n\t\tif (!strncmp(next, target, target_len)) {\n\t\t\treturn next;\n\t\t}\n\t\tnext++;\n\t}\n\treturn NULL;\n}\n\n// Converts a string to a long. If a non-numeric value is found, the\n// return value is whatever has been accumulated so far. end_ptr always points\n// to the character that caused the conversion to stop. We can't use strtol()\n// etc because that would add a new dependency on libc. Eventually, this\n// function could be made generally available within the library and used to\n// replace the existing calls to strtol(). Currenly only handles non-negative\n// numbers and does not detect overflow.\nlong\nmalloc_common_convert_to_long(const char *ptr, const char **end_ptr)\n{\n\tlong value = 0;\n\twhile (*ptr) {\n\t\tchar c = *ptr;\n\t\tif (c < '0' || c > '9') {\n\t\t\tbreak;\n\t\t}\n\t\tvalue = value * 10 + (c - '0');\n\t\tptr++;\n\t}\n\t*end_ptr = ptr;\n\treturn value;\n}\n\n// Looks for a sequence of the form \"key=value\" in the string 'src' and\n// returns the location of the first character of 'value', or NULL if not\n// found. No spaces are permitted around the \"=\".\nconst char *\nmalloc_common_value_for_key(const char *src, const char *key)\n{\n\tconst char *ptr = src;\n\tsize_t keylen = strlen(key);\n\twhile ((ptr = malloc_common_strstr(ptr, key, keylen)) != NULL) {\n\t\tptr += keylen;\n\t\tif (*ptr == '=') {\n\t\t\treturn ptr + 1;\n\t\t}\n\t}\n\treturn NULL;\n}\n\n// Looks for a sequence of the form \"key=value\" in the string 'src' and\n// returns the location of the first character of 'value'. No spaces are\n// permitted around the \"=\". The value is copied to 'bufp', up to the first\n// whitespace or nul character and bounded by maxlen, and nul-terminated.\n// Returns bufp if the key was found, NULL if not.\nconst char *\nmalloc_common_value_for_key_copy(const char *src, const char *key,\n\t\t\t\t\t\t\t   char *bufp, size_t maxlen)\n{\n\tconst char *ptr = malloc_common_value_for_key(src, key);\n\tif (ptr) {\n\t\tchar *to = bufp;\n\t\twhile (maxlen > 1) { // Always leave room for a '\\0'\n\t\t\tchar c = *ptr++;\n\t\t\tif (c == '\\0' || c == ' ' || c == '\\t' || c == '\\n') {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t*to++ = c;\n\t\t\tmaxlen--;\n\t\t}\n\t\t*to = '\\0';\t// Always nul-terminate\n\t\treturn bufp;\n\t}\n\treturn NULL;\n}\n\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/malloc_common.h",
    "content": "/*\n * Copyright (c) 2018 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n#ifndef __MALLOC_COMMON_H\n#define __MALLOC_COMMON_H\n\nMALLOC_NOEXPORT\nconst char *\nmalloc_common_strstr(const char *src, const char *target, size_t target_len);\n\nMALLOC_NOEXPORT\nlong\nmalloc_common_convert_to_long(const char *ptr, const char **end_ptr);\n\nMALLOC_NOEXPORT\nconst char *\nmalloc_common_value_for_key(const char *src, const char *key);\n\nMALLOC_NOEXPORT\nconst char *\nmalloc_common_value_for_key_copy(const char *src, const char *key,\n\t\t char *bufp, size_t maxlen);\n\n#endif // __MALLOC_COMMON_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/malloc_printf.c",
    "content": "/*\n * Copyright (c) 2018 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n#include \"internal.h\"\n\n/* global flag to suppress ASL logging e.g. for syslogd */\nint _malloc_no_asl_log = 0;\n\ntypedef enum {\n\tDEBUG_WRITE_NONE,\n\tDEBUG_WRITE_ON_CRASH,\n\tDEBUG_WRITE_ALWAYS,\n} write_debug_mode_t;\n\nstatic const char Malloc_Facility[] = \"com.apple.Libsystem.malloc\";\nstatic int malloc_debug_file = STDERR_FILENO;\nstatic write_debug_mode_t debug_mode = DEBUG_WRITE_NONE;\nstatic boolean_t malloc_error_stop;\t\t// Stop when reporting error.\nstatic boolean_t malloc_error_sleep;\t// Sleep after reporting error.\nstatic const int default_sleep_time = 3600;\n\n// Gets the default time to sleep for when reporting an error. Returns 0\n// (meaning do not sleep) if malloc_error_sleep is 0 (that is, if sleeping on\n// error is not configured).\nMALLOC_INLINE MALLOC_ALWAYS_INLINE\nstatic unsigned _malloc_default_debug_sleep_time()\n{\n\treturn malloc_error_sleep ? default_sleep_time : 0;\n}\n\n#define WRITE_TO_DEBUG_FILE(flags) \\\n\t\t((debug_mode == DEBUG_WRITE_ALWAYS) || \\\n\t\t(debug_mode == DEBUG_WRITE_ON_CRASH && (flags & MALLOC_REPORT_CRASH)))\n#define\tMALLOC_REPORT_LEVEL_MASK\t0x0f\n\n#pragma mark -\n#pragma mark Configuration\n\nvoid\nmalloc_print_configure(bool restricted)\n{\n\tchar *flag = getenv(\"MallocDebugReport\");\n\tif (flag) {\n\t\tif (!strcmp(flag, \"stderr\")) {\n\t\t\tdebug_mode = DEBUG_WRITE_ALWAYS;\n\t\t} else if (!strcmp(flag, \"crash\")) {\n\t\t\tdebug_mode = DEBUG_WRITE_ON_CRASH;\n\t\t} else if (!strcmp(flag, \"none\")) {\n\t\t\tdebug_mode = DEBUG_WRITE_NONE;\n\t\t} else {\n\t\t\tdebug_mode = DEBUG_WRITE_ALWAYS;\n\t\t\tmalloc_printf(\"Unrecognized value for MallocDebugReport (%s) - using 'stderr'\\n\", flag);\n\t\t}\n\t} else {\n\t\t// Default is to write to stderr only if it's a tty.\n\t\tif (isatty(STDERR_FILENO)) {\n\t\t\tdebug_mode = DEBUG_WRITE_ALWAYS;\n\t\t}\n\t}\n\tif (getenv(\"MallocErrorStop\")) {\n\t\tmalloc_error_stop = TRUE;\n\t}\n\tif (getenv(\"MallocErrorSleep\")) {\n\t\tmalloc_error_sleep = TRUE;\n\t}\n}\n\n#pragma mark -\n#pragma mark Low level debug output\n\n/*\n * The functions that follow use _simple_*printf.  They deal with a\n * subset of printf format specifiers and do not call malloc internally.\n */\nstatic void\n_malloc_put(uint32_t flags, const char *msg)\n{\n\t_SIMPLE_STRING b;\n\tif ((b = _simple_salloc()) == NULL) {\n\t\tif (WRITE_TO_DEBUG_FILE(flags)) {\n\t\t\tif (!(flags & MALLOC_REPORT_NOPREFIX)) {\n\t\t\t\tvoid *self = _os_tsd_get_direct(__TSD_THREAD_SELF);\n\t\t\t\t_simple_dprintf(malloc_debug_file, \"%s(%d,%p) malloc: \", getprogname(), getpid(), self);\n\t\t\t}\n\t\t\twrite(malloc_debug_file, msg, strlen(msg));\n\t\t}\n\t\treturn;\n\t}\n\tif (!(flags & MALLOC_REPORT_NOPREFIX)) {\n\t\tvoid *self = _os_tsd_get_direct(__TSD_THREAD_SELF);\n\t\t_simple_sprintf(b, \"%s(%d,%p) malloc: \", getprogname(), getpid(), self);\n\t}\n\n\t_simple_sprintf(b, \"%s\", msg);\n\tif (WRITE_TO_DEBUG_FILE(flags)) {\n\t\t_simple_put(b, malloc_debug_file);\n\t}\n\tif (_malloc_no_asl_log & !(flags & MALLOC_REPORT_NOLOG)) {\n\t\t_simple_asl_log(flags & MALLOC_REPORT_LEVEL_MASK, Malloc_Facility, _simple_string(b));\n\t}\n\t_simple_sfree(b);\n}\n\n#pragma mark -\n#pragma mark High-Level Reporting Functions\n\nMALLOC_NOINLINE void\nmalloc_vreport(uint32_t flags, unsigned sleep_time, const char *prefix_msg,\n\t\tconst void *prefix_arg, const char *fmt, va_list ap)\n{\n\tconst char *crash_msg = NULL;\n\t_SIMPLE_STRING b = NULL;\n\tif ((b = _simple_salloc()) == NULL) {\n\t\tif (WRITE_TO_DEBUG_FILE(flags)) {\n\t\t\tif (!(flags & MALLOC_REPORT_NOPREFIX)) {\n\t\t\t\tvoid *self = _os_tsd_get_direct(__TSD_THREAD_SELF);\n\t\t\t\t_simple_dprintf(malloc_debug_file, \"%s(%d,%p) malloc: \", getprogname(), getpid(), self);\n\t\t\t}\n\t\t\tif (prefix_msg) {\n\t\t\t\t_simple_dprintf(malloc_debug_file, prefix_msg, prefix_arg);\n\t\t\t}\n\t\t\t_simple_vdprintf(malloc_debug_file, fmt, ap);\n\t\t}\n\t\tif (flags & MALLOC_REPORT_CRASH) {\n\t\t\tcrash_msg = fmt;\n\t\t}\n\t} else {\n\t\tif (!(flags & MALLOC_REPORT_NOPREFIX)) {\n\t\t\tvoid *self = _os_tsd_get_direct(__TSD_THREAD_SELF);\n\t\t\t_simple_sprintf(b, \"%s(%d,%p) malloc: \", getprogname(), getpid(), self);\n\t\t}\n\t\tif (prefix_msg) {\n\t\t\t_simple_sprintf(b, prefix_msg, prefix_arg);\n\t\t}\n\t\t_simple_vsprintf(b, fmt, ap);\n\t\tif (WRITE_TO_DEBUG_FILE(flags)) {\n\t\t\t_simple_put(b, malloc_debug_file);\n\t\t}\n\t\tif (!_malloc_no_asl_log && !(flags & MALLOC_REPORT_NOLOG)) {\n\t\t\t_simple_asl_log(flags & MALLOC_REPORT_LEVEL_MASK, Malloc_Facility, _simple_string(b));\n\t\t}\n\t\tif (flags & MALLOC_REPORT_CRASH) {\n\t\t\tcrash_msg = _simple_string(b);\n\t\t} else {\n\t\t\t_simple_sfree(b);\n\t\t}\n\t}\n\n\tif (flags & (MALLOC_REPORT_DEBUG | MALLOC_REPORT_CRASH)) {\n\t\t_malloc_put(flags, \"*** set a breakpoint in malloc_error_break to debug\\n\");\n\t\tmalloc_error_break();\n\n\t\tif (malloc_error_stop) {\n\t\t\t_malloc_put(ASL_LEVEL_NOTICE, \"*** sending SIGSTOP to help debug\\n\");\n\t\t\tkill(getpid(), SIGSTOP);\n\t\t} else if (sleep_time) {\n\t\t\t_malloc_put(ASL_LEVEL_NOTICE, \"*** sleeping to help debug\\n\");\n\t\t\tsleep(sleep_time);\n\t\t}\n\t}\n\n\tif (flags & MALLOC_REPORT_CRASH) {\n\t\t_os_set_crash_log_message_dynamic(crash_msg);\n\t\tabort();\n\t}\n}\n\nMALLOC_NOEXPORT void\nmalloc_report(uint32_t flags, const char *fmt, ...)\n{\n\tva_list ap;\n\tva_start(ap, fmt);\n\tmalloc_vreport(flags, _malloc_default_debug_sleep_time(), NULL, NULL, fmt, ap);\n\tva_end(ap);\n}\n\n#pragma mark -\n#pragma mark Zone Error Reporing\n\nvoid\nmalloc_zone_error(uint32_t flags, bool is_corruption, const char *fmt, ...)\n{\n\tva_list ap;\n\tva_start(ap, fmt);\n\tuint32_t report_flags = MALLOC_REPORT_DEBUG | MALLOC_REPORT_NOLOG;\n\tif ((is_corruption && (flags & MALLOC_ABORT_ON_CORRUPTION)) ||\n\t\t\t(flags & MALLOC_ABORT_ON_ERROR)) {\n\t\treport_flags = MALLOC_REPORT_CRASH;\n\t}\n\tmalloc_vreport(report_flags | ASL_LEVEL_ERR, _malloc_default_debug_sleep_time(),\n\t\t\tNULL, NULL, fmt, ap);\n\tva_end(ap);\n}\n\n#pragma mark -\n#pragma mark Malloc Output API.\n\n// malloc_printf() needs to be retained and exported because it's API (defined\n// in malloc/malloc.h). It's equivalent to calling malloc_report() with\n// a flags value of ASL_LEVEL_ERR, so does not result in a crash or any prompts\n// for diagnostics or breakpoints.\n// Do not use in malloc code.\nvoid\nmalloc_printf(const char *fmt, ...)\n{\n\tva_list ap;\n\tva_start(ap, fmt);\n\tmalloc_vreport(ASL_LEVEL_ERR, 0, NULL, NULL, fmt, ap);\n\tva_end(ap);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/nano_malloc.c",
    "content": "/*\n * Copyright (c) 1999, 2000, 2003, 2005, 2008, 2012 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"internal.h\"\n\n/* nano_malloc for 64bit ABI */\n#if CONFIG_NANOZONE\n\n/*********************             PROTOTYPES\t\t***********************/\n\nstatic void nano_statistics(nanozone_t *nanozone, malloc_statistics_t *stats);\n\n/*********************\t   VERY LOW LEVEL UTILITIES    ************************/\n// msg prints after fmt, ...\n\nstatic MALLOC_ALWAYS_INLINE unsigned int\nnano_mag_index(const nanozone_t *nanozone)\n{\n\tif (os_likely(_os_cpu_number_override == -1)) {\n\t\treturn (_os_cpu_number() >> hyper_shift) % nano_common_max_magazines;\n\t}\n\treturn (_os_cpu_number_override >> hyper_shift) % nano_common_max_magazines;\n}\n\n#if NANO_PREALLOCATE_BAND_VM\nstatic boolean_t\nnano_preallocate_band_vm(void)\n{\n\tnano_blk_addr_t u;\n\tuintptr_t s, e;\n\n\tu.fields.nano_signature = NANOZONE_SIGNATURE;\n\tu.fields.nano_mag_index = 0;\n\tu.fields.nano_band = 0;\n\tu.fields.nano_slot = 0;\n\tu.fields.nano_offset = 0;\n\ts = u.addr; // start of first possible band\n\n\tu.fields.nano_mag_index = (1 << NANO_MAG_BITS) - 1;\n\tu.fields.nano_band = (1 << NANO_BAND_BITS) - 1;\n\te = u.addr + BAND_SIZE; // end of last possible band\n\n\treturn nano_common_allocate_vm_space(s, e - s);\n}\n#endif\n\n/*\n * We maintain separate free lists for each (quantized) size. The literature\n * calls this the \"segregated policy\".\n */\n\nstatic boolean_t\nsegregated_band_grow(nanozone_t *nanozone, nano_meta_admin_t pMeta, size_t slot_bytes, unsigned int mag_index)\n{\n\tnano_blk_addr_t u; // the compiler holds this in a register\n\tuintptr_t p, s;\n\tsize_t watermark, hiwater;\n\n\tif (0 == pMeta->slot_current_base_addr) { // First encounter?\n\n\t\tu.fields.nano_signature = NANOZONE_SIGNATURE;\n\t\tu.fields.nano_mag_index = mag_index;\n\t\tu.fields.nano_band = 0;\n\t\tu.fields.nano_slot = (slot_bytes >> SHIFT_NANO_QUANTUM) - 1;\n\t\tu.fields.nano_offset = 0;\n\n\t\tp = u.addr;\n\t\tpMeta->slot_bytes = (unsigned int)slot_bytes;\n\t\tpMeta->slot_objects = SLOT_IN_BAND_SIZE / slot_bytes;\n\t} else {\n\t\tp = pMeta->slot_current_base_addr + BAND_SIZE; // Growing, so stride ahead by BAND_SIZE\n\n\t\tu.addr = (uint64_t)p;\n\t\tif (0 == u.fields.nano_band) { // Did the band index wrap?\n\t\t\treturn FALSE;\n\t\t}\n\n\t\tassert(slot_bytes == pMeta->slot_bytes);\n\t}\n\tpMeta->slot_current_base_addr = p;\n\n\tmach_vm_address_t vm_addr = p & ~((uintptr_t)(BAND_SIZE - 1)); // Address of the (2MB) band covering this (128KB) slot\n\tif (nanozone->band_max_mapped_baseaddr[mag_index] < vm_addr) {\n#if !NANO_PREALLOCATE_BAND_VM\n\t\t// Obtain the next band to cover this slot\n\t\tkern_return_t kr = mach_vm_map(mach_task_self(), &vm_addr, BAND_SIZE, 0, VM_MAKE_TAG(VM_MEMORY_MALLOC_NANO),\n\t\t\t\tMEMORY_OBJECT_NULL, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);\n\n\t\tvoid *q = (void *)vm_addr;\n\t\tif (kr || q != (void *)(p & ~((uintptr_t)(BAND_SIZE - 1)))) { // Must get exactly what we asked for\n\t\t\tif (!kr) {\n\t\t\t\tmach_vm_deallocate(mach_task_self(), vm_addr, BAND_SIZE);\n\t\t\t}\n\t\t\treturn FALSE;\n\t\t}\n#endif\n\t\tnanozone->band_max_mapped_baseaddr[mag_index] = vm_addr;\n\t}\n\n\t// Randomize the starting allocation from this slot (introduces 11 to 14 bits of entropy)\n\tif (0 == pMeta->slot_objects_mapped) { // First encounter?\n\t\tpMeta->slot_objects_skipped = (malloc_entropy[1] % (SLOT_IN_BAND_SIZE / slot_bytes));\n\t\tpMeta->slot_bump_addr = p + (pMeta->slot_objects_skipped * slot_bytes);\n\t} else {\n\t\tpMeta->slot_bump_addr = p;\n\t}\n\n\tpMeta->slot_limit_addr = p + (SLOT_IN_BAND_SIZE / slot_bytes) * slot_bytes;\n\tpMeta->slot_objects_mapped += (SLOT_IN_BAND_SIZE / slot_bytes);\n\n\tu.fields.nano_signature = NANOZONE_SIGNATURE;\n\tu.fields.nano_mag_index = mag_index;\n\tu.fields.nano_band = 0;\n\tu.fields.nano_slot = 0;\n\tu.fields.nano_offset = 0;\n\ts = u.addr; // Base for this core.\n\n\t// Set the high water mark for this CPU's entire magazine, if this resupply raised it.\n\twatermark = nanozone->core_mapped_size[mag_index];\n\thiwater = MAX(watermark, p - s + SLOT_IN_BAND_SIZE);\n\tnanozone->core_mapped_size[mag_index] = hiwater;\n\n\treturn TRUE;\n}\n\nstatic inline unsigned long\ndivrem(unsigned long a, unsigned int b, unsigned int *remainder)\n{\n\t// Encapsulating the modulo and division in an in-lined function convinces the compiler\n\t// to issue just a single divide instruction to obtain quotient and remainder. Go figure.\n\t*remainder = a % b;\n\treturn a / b;\n}\n\nstatic MALLOC_INLINE void *\nsegregated_next_block(nanozone_t *nanozone, nano_meta_admin_t pMeta, size_t slot_bytes, unsigned int mag_index)\n{\n\twhile (1) {\n\t\tuintptr_t theLimit = pMeta->slot_limit_addr; // Capture the slot limit that bounds slot_bump_addr right now\n\t\tuintptr_t b = OSAtomicAdd64Barrier(slot_bytes, (volatile int64_t *)&(pMeta->slot_bump_addr));\n\t\tb -= slot_bytes; // Atomic op returned addr of *next* free block. Subtract to get addr for *this* allocation.\n\n\t\tif (b < theLimit) {   // Did we stay within the bound of the present slot allocation?\n\t\t\treturn (void *)b; // Yep, so the slot_bump_addr this thread incremented is good to go\n\t\t} else {\n\t\t\tif (pMeta->slot_exhausted) { // exhausted all the bands availble for this slot?\n\t\t\t\tpMeta->slot_bump_addr = theLimit;\n\t\t\t\treturn 0;\t\t\t\t // We're toast\n\t\t\t} else {\n\t\t\t\t// One thread will grow the heap, others will see its been grown and retry allocation\n\t\t\t\t_malloc_lock_lock(&nanozone->band_resupply_lock[mag_index]);\n\t\t\t\t// re-check state now that we've taken the lock\n\t\t\t\tif (pMeta->slot_exhausted) {\n\t\t\t\t\t_malloc_lock_unlock(&nanozone->band_resupply_lock[mag_index]);\n\t\t\t\t\treturn 0; // Toast\n\t\t\t\t} else if (b < pMeta->slot_limit_addr) {\n\t\t\t\t\t_malloc_lock_unlock(&nanozone->band_resupply_lock[mag_index]);\n\t\t\t\t\tcontinue; // ... the slot was successfully grown by first-taker (not us). Now try again.\n\t\t\t\t} else if (segregated_band_grow(nanozone, pMeta, slot_bytes, mag_index)) {\n\t\t\t\t\t_malloc_lock_unlock(&nanozone->band_resupply_lock[mag_index]);\n\t\t\t\t\tcontinue; // ... the slot has been successfully grown by us. Now try again.\n\t\t\t\t} else {\n\t\t\t\t\tpMeta->slot_exhausted = TRUE;\n\t\t\t\t\tpMeta->slot_bump_addr = theLimit;\n\t\t\t\t\t_malloc_lock_unlock(&nanozone->band_resupply_lock[mag_index]);\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nstatic MALLOC_INLINE size_t\nsegregated_size_to_fit(nanozone_t *nanozone, size_t size, size_t *pKey)\n{\n\tsize_t k, slot_bytes;\n\n\tif (0 == size) {\n\t\tsize = NANO_REGIME_QUANTA_SIZE; // Historical behavior\n\t}\n\tk = (size + NANO_REGIME_QUANTA_SIZE - 1) >> SHIFT_NANO_QUANTUM; // round up and shift for number of quanta\n\tslot_bytes = k << SHIFT_NANO_QUANTUM;\t\t\t\t\t\t\t// multiply by power of two quanta size\n\t*pKey = k - 1;\t\t\t\t\t\t\t\t\t\t\t\t\t// Zero-based!\n\n\treturn slot_bytes;\n}\n\nstatic MALLOC_INLINE index_t\noffset_to_index(nanozone_t *nanozone, nano_meta_admin_t pMeta, uintptr_t offset)\n{\n\tunsigned int slot_bytes = pMeta->slot_bytes;\n\tunsigned int slot_objects = pMeta->slot_objects; // SLOT_IN_BAND_SIZE / slot_bytes;\n\tunsigned int rem;\n\tunsigned long quo = divrem(offset, BAND_SIZE, &rem);\n\n\tassert(0 == rem % slot_bytes || pMeta->slot_exhausted);\n\treturn (index_t)((quo * slot_objects) + (rem / slot_bytes));\n}\n\nstatic MALLOC_INLINE uintptr_t\nindex_to_offset(nanozone_t *nanozone, nano_meta_admin_t pMeta, index_t i)\n{\n\tunsigned int slot_bytes = pMeta->slot_bytes;\n\tunsigned int slot_objects = pMeta->slot_objects; // SLOT_IN_BAND_SIZE / slot_bytes;\n\tunsigned int rem;\n\tunsigned long quo = divrem(i, slot_objects, &rem);\n\n\treturn (quo * BAND_SIZE) + (rem * slot_bytes);\n}\n\nstatic kern_return_t\nsegregated_in_use_enumerator(task_t task,\n\t\tvoid *context,\n\t\tunsigned type_mask,\n\t\tnanozone_t *nanozone,\n\t\tmemory_reader_t reader,\n\t\tvm_range_recorder_t recorder)\n{\n\tunsigned int mag_index, slot_key;\n\tvm_range_t ptr_range;\n\tvm_range_t buffer[MAX_RECORDER_BUFFER];\n\tkern_return_t err;\n\tunsigned count = 0;\n\n\tfor (mag_index = 0; mag_index < nano_common_max_magazines; mag_index++) {\n\t\tuintptr_t clone_magazine;  // magazine base for ourselves\n\t\tnano_blk_addr_t p;\t\t   // slot base for remote\n\t\tuintptr_t clone_slot_base; // slot base for ourselves (tracks with \"p\")\n\n\t\t// Establish p as base address for slot 0 in remote\n\t\tp.fields.nano_signature = NANOZONE_SIGNATURE;\n\t\tp.fields.nano_mag_index = mag_index;\n\t\tp.fields.nano_band = 0;\n\t\tp.fields.nano_slot = 0;\n\t\tp.fields.nano_offset = 0;\n\n\t\tif (type_mask & MALLOC_PTR_IN_USE_RANGE_TYPE) {\n\t\t\tmach_vm_address_t vm_addr;\n\t\t\tmach_vm_size_t alloc_size = nanozone->core_mapped_size[mag_index];\n\t\t\tint alloc_flags = VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_MALLOC);\n\n\t\t\tvm_addr = vm_page_size;\n\t\t\tkern_return_t kr = mach_vm_allocate(mach_task_self(), &vm_addr, alloc_size, alloc_flags);\n\t\t\tif (kr) {\n\t\t\t\treturn kr;\n\t\t\t}\n\t\t\tclone_magazine = (uintptr_t)vm_addr;\n\t\t\tclone_slot_base = clone_magazine; // base for slot 0 in this local magazine\n\t\t} else {\n\t\t\tclone_slot_base = clone_magazine = 0; // and won't be used in this loop\n\t\t}\n\n\t\tfor (slot_key = 0; slot_key < SLOT_KEY_LIMIT; p.addr += SLOT_IN_BAND_SIZE, // Advance to next slot base for remote\n\t\t\t\tclone_slot_base += SLOT_IN_BAND_SIZE,\t\t\t\t\t\t\t   // Advance to next slot base for ourselves\n\t\t\t\tslot_key++) {\n\t\t\tnano_meta_admin_t pMeta = &(nanozone->meta_data[mag_index][slot_key]);\n\t\t\tsize_t slot_objects_mapped = pMeta->slot_objects_mapped; // capture this volatile count\n\n\t\t\tif (0 == slot_objects_mapped) { // Nothing allocated in this magazine for this slot?\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (type_mask & MALLOC_ADMIN_REGION_RANGE_TYPE) {\n\t\t\t\t/* do NOTHING as there is no distinct admin region */\n\t\t\t}\n\n\t\t\tif (type_mask & (MALLOC_PTR_REGION_RANGE_TYPE | MALLOC_ADMIN_REGION_RANGE_TYPE)) {\n\t\t\t\tnano_blk_addr_t q = p;\n\t\t\t\tuintptr_t skip_adj = index_to_offset(nanozone, pMeta, (index_t)pMeta->slot_objects_skipped);\n\n\t\t\t\twhile (q.addr < pMeta->slot_limit_addr) {\n\t\t\t\t\tptr_range.address = q.addr + skip_adj;\n\t\t\t\t\tptr_range.size = SLOT_IN_BAND_SIZE - skip_adj;\n\t\t\t\t\tskip_adj = 0;\n\t\t\t\t\trecorder(task, context, MALLOC_PTR_REGION_RANGE_TYPE, &ptr_range, 1);\n\t\t\t\t\tq.addr += BAND_SIZE;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (type_mask & MALLOC_PTR_IN_USE_RANGE_TYPE) {\n\t\t\t\tnano_blk_addr_t q = p;\n\t\t\t\tuintptr_t slot_band, clone_slot_band_base = clone_slot_base;\n\t\t\t\tuintptr_t skip_adj = index_to_offset(nanozone, pMeta, (index_t)pMeta->slot_objects_skipped);\n\n\t\t\t\t// Copy the bitarray_t denoting madvise()'d pages (if any) into *this* task's address space\n\t\t\t\tbitarray_t madv_page_bitarray;\n\t\t\t\tint log_page_count;\n\n\t\t\t\tif (pMeta->slot_madvised_pages) {\n\t\t\t\t\tlog_page_count = pMeta->slot_madvised_log_page_count;\n\t\t\t\t\terr = reader(task, (vm_address_t)(pMeta->slot_madvised_pages), bitarray_size(log_page_count),\n\t\t\t\t\t\t\t(void **)&madv_page_bitarray);\n\t\t\t\t\tif (err) {\n\t\t\t\t\t\treturn err;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tmadv_page_bitarray = NULL;\n\t\t\t\t\tlog_page_count = 0;\n\t\t\t\t}\n\n\t\t\t\twhile (q.addr < pMeta->slot_limit_addr) {\n\t\t\t\t\t// read slot in each remote band. Lands in some random location. Do not read\n\t\t\t\t\t// parts of the slot that are in madvised pages.\n\t\t\t\t\tif (!madv_page_bitarray) {\n\t\t\t\t\t\t// Nothing madvised yet - read everything in one go.\n\t\t\t\t\t\tsize_t len = MIN(pMeta->slot_bump_addr - q.addr, SLOT_IN_BAND_SIZE) - skip_adj;\n\t\t\t\t\t\terr = reader(task, (vm_address_t)(q.addr + skip_adj), len, (void **)&slot_band);\n\t\t\t\t\t\tif (err) {\n\t\t\t\t\t\t\treturn err;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Place the data just read in the correct position relative to the local magazine.\n\t\t\t\t\t\tmemcpy((void *)(clone_slot_band_base + skip_adj), (void *)slot_band, len);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// We madvised at least one page. Read only the pages that\n\t\t\t\t\t\t// have not been madvised. If bitarray_t had operations\n\t\t\t\t\t\t// like \"get next bit set after a given bit\" and \"find\n\t\t\t\t\t\t// next unset bit after a given bit\", we could do this more\n\t\t\t\t\t\t// efficiently but given that it doesn't, we have to walk\n\t\t\t\t\t\t// through each page individually. In practice this is not\n\t\t\t\t\t\t// much of an issue because this code is only used by\n\t\t\t\t\t\t// sampling tools and the additional time required is not\n\t\t\t\t\t\t// really noticeable.\n\t\t\t\t\t\tsize_t len = MIN(pMeta->slot_bump_addr - q.addr, SLOT_IN_BAND_SIZE) - skip_adj;\n\t\t\t\t\t\tvm_address_t start_addr = (vm_address_t)(q.addr + skip_adj);\n\t\t\t\t\t\tvm_address_t end_addr = (vm_address_t)(start_addr + len);\n\t\t\t\t\t\tvoid *target_addr = (void *)(clone_slot_band_base + skip_adj);\n\t\t\t\t\t\tfor (vm_address_t addr = start_addr; addr < end_addr;) {\n\t\t\t\t\t\t\tvm_address_t next_page_addr = trunc_page_kernel(addr + vm_kernel_page_size);\n\t\t\t\t\t\t\tsize_t read_size = MIN(len, next_page_addr - addr);\n\n\t\t\t\t\t\t\tboolean_t madvised = false;\n\t\t\t\t\t\t\tnano_blk_addr_t r;\n\t\t\t\t\t\t\tr.addr = addr;\n\t\t\t\t\t\t\tindex_t pgnum = ((((unsigned)r.fields.nano_band) << NANO_OFFSET_BITS) | ((unsigned)r.fields.nano_offset)) >>\n\t\t\t\t\t\t\t\tvm_kernel_page_shift;\n\t\t\t\t\t\t\tunsigned int log_page_count = pMeta->slot_madvised_log_page_count;\n\t\t\t\t\t\t\tmadvised = (pgnum < (1 << log_page_count)) &&\n\t\t\t\t\t\t\t\t\tbitarray_get(madv_page_bitarray, log_page_count, pgnum);\n\t\t\t\t\t\t\tif (!madvised) {\n\t\t\t\t\t\t\t\t// This is not an madvised page - grab the data.\n\t\t\t\t\t\t\t\terr = reader(task, addr, read_size, (void **)&slot_band);\n\t\t\t\t\t\t\t\tif (err) {\n\t\t\t\t\t\t\t\t\treturn err;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Place the data just read in the correct position relative to the local magazine.\n\t\t\t\t\t\t\t\tmemcpy(target_addr, (void *)slot_band, read_size);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// This is an madvised page - there should be nothing in here that's\n\t\t\t\t\t\t\t\t// on the freelist, so just write garbage to the target memory.\n\t\t\t\t\t\t\t\tmemset(target_addr, (char)0xee, read_size);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\taddr = next_page_addr;\n\t\t\t\t\t\t\ttarget_addr += read_size;\n\t\t\t\t\t\t\tlen -= read_size;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Simultaneously advance pointers in remote and ourselves to the next band.\n\t\t\t\t\tq.addr += BAND_SIZE;\n\t\t\t\t\tclone_slot_band_base += BAND_SIZE;\n\t\t\t\t\tskip_adj = 0;\n\t\t\t\t}\n\n\t\t\t\t// Walk the slot free list and populate a bitarray_t\n\t\t\t\tint log_size = 64 - __builtin_clzl(slot_objects_mapped);\n\t\t\t\tbitarray_t slot_bitarray = bitarray_create(log_size);\n\n\t\t\t\tif (!slot_bitarray) {\n\t\t\t\t\treturn errno;\n\t\t\t\t}\n\n\t\t\t\tchained_block_t t;\n\t\t\t\tunsigned stoploss = (unsigned)slot_objects_mapped;\n\t\t\t\twhile ((t = OSAtomicDequeue(\n\t\t\t\t\t\t\t\t&(pMeta->slot_LIFO), offsetof(struct chained_block_s, next) + (clone_slot_base - p.addr)))) {\n\t\t\t\t\tif (0 == stoploss) {\n\t\t\t\t\t\tmalloc_report(ASL_LEVEL_ERR, \"Free list walk in segregated_in_use_enumerator exceeded object count.\\n\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tstoploss--;\n\n\t\t\t\t\tuintptr_t offset = ((uintptr_t)t - p.addr); // offset from beginning of slot, task-independent\n\t\t\t\t\tindex_t block_index = offset_to_index(nanozone, pMeta, offset);\n\n\t\t\t\t\tif (block_index < slot_objects_mapped) {\n\t\t\t\t\t\tbitarray_set(slot_bitarray, log_size, block_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// N.B. pMeta->slot_LIFO in *this* task is now drained (remote free list has *not* been disturbed)\n\n\n\t\t\t\t// Enumerate all the block indices issued to date, and report those not on the free list\n\t\t\t\tindex_t i;\n\t\t\t\tfor (i = (index_t)pMeta->slot_objects_skipped; i < slot_objects_mapped; ++i) {\n\t\t\t\t\tuintptr_t block_offset = index_to_offset(nanozone, pMeta, i);\n\t\t\t\t\tif (p.addr + block_offset >= pMeta->slot_bump_addr) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// blocks falling on madvise()'d pages are free! So not enumerated.\n\t\t\t\t\tif (madv_page_bitarray) {\n\t\t\t\t\t\tnano_blk_addr_t q;\n\t\t\t\t\t\tindex_t pgnum, pgnum_end;\n\n\t\t\t\t\t\tq.addr = p.addr + block_offset;\n\t\t\t\t\t\tpgnum = ((((unsigned)q.fields.nano_band) << NANO_OFFSET_BITS) | ((unsigned)q.fields.nano_offset)) >>\n\t\t\t\t\t\t\t\tvm_kernel_page_shift;\n\t\t\t\t\t\tq.addr += pMeta->slot_bytes - 1;\n\t\t\t\t\t\tpgnum_end = ((((unsigned)q.fields.nano_band) << NANO_OFFSET_BITS) | ((unsigned)q.fields.nano_offset)) >>\n\t\t\t\t\t\t\t\t\tvm_kernel_page_shift;\n\n\t\t\t\t\t\tif (pgnum < (1 << log_page_count)) { // bounds check for bitarray_get()'s that follow\n\t\t\t\t\t\t\tif (bitarray_get(madv_page_bitarray, log_page_count, pgnum) ||\n\t\t\t\t\t\t\t\t\tbitarray_get(madv_page_bitarray, log_page_count, pgnum_end)) {\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!bitarray_get(slot_bitarray, log_size, i)) {\n\t\t\t\t\t\tbuffer[count].address = p.addr + block_offset;\n\t\t\t\t\t\tbuffer[count].size = (slot_key + 1) << SHIFT_NANO_QUANTUM;\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t\tif (count >= MAX_RECORDER_BUFFER) {\n\t\t\t\t\t\t\trecorder(task, context, MALLOC_PTR_IN_USE_RANGE_TYPE, buffer, count);\n\t\t\t\t\t\t\tcount = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (count) {\n\t\t\t\t\trecorder(task, context, MALLOC_PTR_IN_USE_RANGE_TYPE, buffer, count);\n\t\t\t\t\tcount = 0;\n\t\t\t\t}\n\n\t\t\t\tfree(slot_bitarray);\n\t\t\t}\n\t\t}\n\t\tif (clone_magazine) {\n\t\t\tmach_vm_address_t vm_addr = clone_magazine;\n\t\t\tmach_vm_size_t alloc_size = nanozone->core_mapped_size[mag_index];\n\t\t\tmach_vm_deallocate(mach_task_self(), vm_addr, alloc_size);\n\t\t}\n\t}\n\treturn 0;\n}\n\n/******************           nanozone methods           **********************/\n/*\n * These methods are called with \"ptr\" known to possess the nano signature (from\n * which we can additionally infer \"ptr\" is not NULL), and with \"size\" bounded to\n * the extent of the nano allocation regime -- (0, 256].\n */\n\nstatic MALLOC_INLINE MALLOC_UNUSED boolean_t\n_nano_block_inuse_p(nanozone_t *nanozone, const void *ptr)\n{\n\tnano_blk_addr_t p; // happily, the compiler holds this in a register\n\tnano_meta_admin_t pMeta;\n\tchained_block_t head = NULL, tail = NULL, t;\n\tboolean_t inuse = TRUE;\n\n\tp.addr = (uint64_t)ptr; // place ptr on the dissecting table\n\n\tpMeta = &(nanozone->meta_data[p.fields.nano_mag_index][p.fields.nano_slot]);\n\n\t// pop elements off the free list all the while looking for ptr.\n\tunsigned stoploss = (unsigned)pMeta->slot_objects_mapped;\n\twhile ((t = OSAtomicDequeue(&(pMeta->slot_LIFO), offsetof(struct chained_block_s, next)))) {\n\t\tif (0 == stoploss) {\n\t\t\tmalloc_zone_error(nanozone->debug_flags, true,\n\t\t\t\t\t\"Free list walk for slot %p in _nano_block_inuse_p exceeded object count.\\n\",\n\t\t\t\t\t(void *)&(pMeta->slot_LIFO));\n\t\t}\n\t\tstoploss--;\n\n\t\tif (NULL == head) {\n\t\t\thead = t;\n\t\t} else {\n\t\t\ttail->next = t;\n\t\t}\n\t\ttail = t;\n\n\t\tif (ptr == t) {\n\t\t\tinuse = FALSE;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (tail) {\n\t\ttail->next = NULL;\n\t}\n\n\t// push the free list extracted above back onto the LIFO, all at once\n\tif (head) {\n\t\tOSAtomicEnqueue(&(pMeta->slot_LIFO), head, (uintptr_t)tail - (uintptr_t)head + offsetof(struct chained_block_s, next));\n\t}\n\n\treturn inuse;\n}\n\nstatic MALLOC_INLINE size_t\n__nano_vet_and_size_inner(nanozone_t *nanozone, const void *ptr, boolean_t inner)\n{\n\t// Extracts the size of the block in bytes. Checks for a plausible ptr.\n\tnano_blk_addr_t p; // the compiler holds this in a register\n\tnano_meta_admin_t pMeta;\n\n\tp.addr = (uint64_t)ptr; // Begin the dissection of ptr\n\n\tif (NANOZONE_SIGNATURE != p.fields.nano_signature) {\n\t\treturn 0;\n\t}\n\n\tif (nano_common_max_magazines <= p.fields.nano_mag_index) {\n\t\treturn 0;\n\t}\n\n\tif (!inner && p.fields.nano_offset & NANO_QUANTA_MASK) { // stray low-order bits?\n\t\treturn 0;\n\t}\n\n\tpMeta = &(nanozone->meta_data[p.fields.nano_mag_index][p.fields.nano_slot]);\n\tif ((void *)(pMeta->slot_bump_addr) <= ptr) {\n\t\treturn 0; // Beyond what's ever been allocated!\n\t}\n\tif (!inner && ((p.fields.nano_offset % pMeta->slot_bytes) != 0)) {\n\t\treturn 0; // Not an exact multiple of the block size for this slot\n\t}\n\treturn pMeta->slot_bytes;\n}\n\n\nstatic MALLOC_INLINE size_t\n__nano_vet_and_size(nanozone_t *nanozone, const void *ptr)\n{\n\treturn __nano_vet_and_size_inner(nanozone, ptr, false);\n}\n\nstatic MALLOC_ALWAYS_INLINE boolean_t\n_nano_block_has_canary_value(nanozone_t *nanozone, const void *ptr)\n{\n\treturn (((chained_block_t)ptr)->double_free_guard ^ nanozone->cookie)\n\t\t\t== (uintptr_t)ptr;\n}\n\nstatic MALLOC_ALWAYS_INLINE void\n_nano_block_set_canary_value(nanozone_t *nanozone, const void *ptr)\n{\n\t((chained_block_t)ptr)->double_free_guard =\n\t\t\t((uintptr_t)ptr) ^ nanozone->cookie;\n}\n\nstatic MALLOC_INLINE size_t\n_nano_vet_and_size_of_live(nanozone_t *nanozone, const void *ptr)\n{\n\tsize_t size = __nano_vet_and_size(nanozone, ptr);\n\n\tif (0 == size) { // ptr fails sanity check?\n\t\treturn 0;\n\t}\n\t\n\t// We have the invariant: If ptr is on a free list, then ptr->double_free_guard is the canary.\n\t// So if ptr->double_free_guard is NOT the canary, then ptr is not on a free list, hence is live.\n\tif (!_nano_block_has_canary_value(nanozone, ptr)) {\n\t\treturn size; // Common case: not on a free list, hence live. Return its size.\n\t} else {\n\t\t// confirm that ptr is live despite ptr->double_free_guard having the canary value\n\t\tif (_nano_block_inuse_p(nanozone, ptr)) {\n\t\t\treturn size; // live block that exhibits canary\n\t\t} else {\n\t\t\treturn 0; // ptr wasn't live after all (likely a double free)\n\t\t}\n\t}\n}\n\nstatic MALLOC_INLINE size_t\n_nano_vet_and_size_of_free(nanozone_t *nanozone, const void *ptr)\n{\n\tsize_t size = __nano_vet_and_size(nanozone, ptr);\n\n\tif (0 == size) { // ptr fails sanity check?\n\t\treturn 0;\n\t}\n\t\n\t// ptr was just dequed from a free list, so ptr->double_free_guard must have the canary value.\n\tif (_nano_block_has_canary_value(nanozone, ptr)) {\n\t\treturn size; // return the size of this well formed free block.\n\t} else {\n\t\treturn 0; // Broken invariant: If ptr is on a free list, then ptr->double_free_guard is the canary. (likely use after free)\n\t}\n}\n\nstatic void *\n_nano_malloc_check_clear(nanozone_t *nanozone, size_t size, boolean_t cleared_requested)\n{\n\tMALLOC_TRACE(TRACE_nano_malloc, (uintptr_t)nanozone, size, cleared_requested, 0);\n\n\tvoid *ptr;\n\tsize_t slot_key;\n\tsize_t slot_bytes = segregated_size_to_fit(nanozone, size, &slot_key); // Note slot_key is set here\n\tmag_index_t mag_index = nano_mag_index(nanozone);\n\n\tnano_meta_admin_t pMeta = &(nanozone->meta_data[mag_index][slot_key]);\n\n\tptr = OSAtomicDequeue(&(pMeta->slot_LIFO), offsetof(struct chained_block_s, next));\n\tif (ptr) {\n\t\tunsigned debug_flags = nanozone->debug_flags;\n#if NANO_FREE_DEQUEUE_DILIGENCE\n\t\tsize_t gotSize;\n\t\tnano_blk_addr_t p; // the compiler holds this in a register\n\n\t\tp.addr = (uint64_t)ptr; // Begin the dissection of ptr\n\t\tif (NANOZONE_SIGNATURE != p.fields.nano_signature) {\n\t\t\tmalloc_zone_error(debug_flags, true,\n\t\t\t\t\t\"Invalid signature for pointer %p dequeued from free list\\n\",\n\t\t\t\t\tptr);\n\t\t}\n\n\t\tif (mag_index != p.fields.nano_mag_index) {\n\t\t\tmalloc_zone_error(debug_flags, true,\n\t\t\t\t\t\"Mismatched magazine for pointer %p dequeued from free list\\n\",\n\t\t\t\t\tptr);\n\t\t}\n\n\t\tgotSize = _nano_vet_and_size_of_free(nanozone, ptr);\n\t\tif (0 == gotSize) {\n\t\t\tmalloc_zone_error(debug_flags, true,\n\t\t\t\t\t\"Invalid pointer %p dequeued from free list\\n\", ptr);\n\t\t}\n\t\tif (gotSize != slot_bytes) {\n\t\t\tmalloc_zone_error(debug_flags, true,\n\t\t\t\t\t\"Mismatched size for pointer %p dequeued from free list\\n\",\n\t\t\t\t\tptr);\n\t\t}\n\n\t\tif (!_nano_block_has_canary_value(nanozone, ptr)) {\n\t\t\tmalloc_zone_error(debug_flags, true,\n\t\t\t\t\t\"Heap corruption detected, free list canary is damaged for %p\\n\"\n\t\t\t\t\t\"*** Incorrect guard value: %lu\\n\", ptr,\n\t\t\t\t\t((chained_block_t)ptr)->double_free_guard);\n\t\t}\n\n#if defined(DEBUG)\n\t\tvoid *next = (void *)(((chained_block_t)ptr)->next);\n\t\tif (next) {\n\t\t\tp.addr = (uint64_t)next; // Begin the dissection of next\n\t\t\tif (NANOZONE_SIGNATURE != p.fields.nano_signature) {\n\t\t\t\tmalloc_zone_error(debug_flags, true,\n\t\t\t\t\t\t\"Invalid next signature for pointer %p dequeued from free \"\n\t\t\t\t\t\t\"list, next = %p\\n\", ptr, \"next\");\n\t\t\t}\n\n\t\t\tif (mag_index != p.fields.nano_mag_index) {\n\t\t\t\tmalloc_zone_error(debug_flags, true,\n\t\t\t\t\t\t\"Mismatched next magazine for pointer %p dequeued from \"\n\t\t\t\t\t\t\"free list, next = %p\\n\", ptr, next);\n\t\t\t}\n\n\t\t\tgotSize = _nano_vet_and_size_of_free(nanozone, next);\n\t\t\tif (0 == gotSize) {\n\t\t\t\tmalloc_zone_error(debug_flags, true,\n\t\t\t\t\t\t\"Invalid next for pointer %p dequeued from free list, \"\n\t\t\t\t\t\t\"next = %p\\n\", ptr, next);\n\t\t\t}\n\t\t\tif (gotSize != slot_bytes) {\n\t\t\t\tmalloc_zone_error(debug_flags, true,\n\t\t\t\t\t\t\"Mismatched next size for pointer %p dequeued from free \"\n\t\t\t\t\t\t\"list, next = %p\\n\", ptr, next);\n\t\t\t}\n\t\t}\n#endif /* DEBUG */\n#endif /* NANO_FREE_DEQUEUE_DILIGENCE */\n\n\t\t((chained_block_t)ptr)->double_free_guard = 0;\n\t\t((chained_block_t)ptr)->next = NULL; // clear out next pointer to protect free list\n\t} else {\n\t\tptr = segregated_next_block(nanozone, pMeta, slot_bytes, mag_index);\n\t}\n\n\tif (cleared_requested && ptr) {\n\t\tmemset(ptr, 0, slot_bytes); // TODO: Needs a memory barrier after memset to ensure zeroes land first?\n\t}\n\treturn ptr;\n}\n\nstatic void *\n_nano_malloc_check_scribble(nanozone_t *nanozone, size_t size)\n{\n\tvoid *ptr = _nano_malloc_check_clear(nanozone, size, 0);\n\n\t/*\n\t * Scribble on allocated memory when requested.\n\t */\n\tif ((nanozone->debug_flags & MALLOC_DO_SCRIBBLE) && ptr && size) {\n\t\tmemset(ptr, SCRIBBLE_BYTE, _nano_vet_and_size_of_live(nanozone, ptr));\n\t}\n\n\treturn ptr;\n}\n\nstatic MALLOC_INLINE size_t\n_nano_size(nanozone_t *nanozone, const void *ptr)\n{\n\treturn _nano_vet_and_size_of_live(nanozone, ptr);\n}\n\nstatic MALLOC_INLINE size_t\n_nano_good_size(nanozone_t *nanozone, size_t size)\n{\n\treturn (size <= NANO_REGIME_QUANTA_SIZE) ? NANO_REGIME_QUANTA_SIZE\n\t\t\t\t\t\t\t\t\t\t\t : (((size + NANO_REGIME_QUANTA_SIZE - 1) >> SHIFT_NANO_QUANTUM) << SHIFT_NANO_QUANTUM);\n}\n\nstatic MALLOC_INLINE void _nano_free_trusted_size_check_scribble(nanozone_t *nanozone,\n\t\tvoid *ptr,\n\t\tsize_t trusted_size,\n\t\tboolean_t do_scribble) MALLOC_ALWAYS_INLINE;\n\nstatic MALLOC_INLINE void\n_nano_free_trusted_size_check_scribble(nanozone_t *nanozone, void *ptr, size_t trusted_size, boolean_t do_scribble)\n{\n\tif (trusted_size) {\n\t\tnano_blk_addr_t p; // happily, the compiler holds this in a register\n\t\tnano_meta_admin_t pMeta;\n\n\t\tif (do_scribble) {\n\t\t\t(void)memset(ptr, SCRABBLE_BYTE, trusted_size);\n\t\t}\n\t\t_nano_block_set_canary_value(nanozone, ptr);\n\n\t\tp.addr = (uint64_t)ptr; // place ptr on the dissecting table\n\t\tpMeta = &(nanozone->meta_data[p.fields.nano_mag_index][p.fields.nano_slot]);\n\t\tOSAtomicEnqueue(&(pMeta->slot_LIFO), ptr, offsetof(struct chained_block_s, next));\n\t} else {\n\t\tmalloc_zone_error(nanozone->debug_flags, true,\n\t\t\t\t\"Freeing unallocated pointer %p\\n\", ptr);\n\t}\n}\n\nstatic MALLOC_INLINE void _nano_free_check_scribble(nanozone_t *nanozone, void *ptr, boolean_t do_scribble) MALLOC_ALWAYS_INLINE;\n\nstatic MALLOC_INLINE void\n_nano_free_check_scribble(nanozone_t *nanozone, void *ptr, boolean_t do_scribble)\n{\n\t_nano_free_trusted_size_check_scribble(nanozone, ptr, _nano_vet_and_size_of_live(nanozone, ptr), do_scribble);\n}\n\nstatic MALLOC_INLINE void *\n_nano_realloc(nanozone_t *nanozone, void *ptr, size_t new_size)\n{\n\tsize_t old_size, new_good_size, valid_size;\n\tvoid *new_ptr;\n\n\tif (FALSE && NULL == ptr) { // ptr has our_signature so can't be NULL, but if it were Posix sez ...\n\t\t// If ptr is a null pointer, realloc() shall be equivalent to malloc() for the specified size.\n\t\treturn _nano_malloc_check_scribble(nanozone, new_size);\n\t} else if (0 == new_size) {\n\t\t// If size is 0 and ptr is not a null pointer, the object pointed to is freed.\n\t\t_nano_free_check_scribble(nanozone, ptr, (nanozone->debug_flags & MALLOC_DO_SCRIBBLE));\n\t\t// If size is 0, either a null pointer or a unique pointer that can be successfully passed\n\t\t// to free() shall be returned.\n\t\treturn _nano_malloc_check_scribble(nanozone, 1);\n\t}\n\n\told_size = _nano_vet_and_size_of_live(nanozone, ptr);\n\tif (!old_size) {\n\t\tmalloc_zone_error(nanozone->debug_flags, true,\n\t\t\t\t\"pointer %p being reallocated was not allocated\\n\", ptr);\n\t\treturn NULL;\n\t}\n\n\tnew_good_size = _nano_good_size(nanozone, new_size);\n\tif (new_good_size > old_size) {\n\t\t/* Must grow. FALL THROUGH to alloc/copy/free. */\n\t} else if (new_good_size <= (old_size >> 1)) {\n\t\t/* Serious shrinkage (more than half). FALL THROUGH to alloc/copy/free. */\n\t} else {\n\t\t/* Let's hang on to what we got. */\n\t\tif (nanozone->debug_flags & MALLOC_DO_SCRIBBLE) {\n\t\t\tmemset(ptr + new_size, SCRIBBLE_BYTE, old_size - new_size);\n\t\t}\n\t\treturn ptr;\n\t}\n\n\t/*\n\t * Allocate a new buffer and copy.\n\t */\n\tnew_ptr = _nano_malloc_check_scribble(nanozone, new_good_size);\n\tif (new_ptr == NULL) {\n\t\treturn NULL;\n\t}\n\n\tvalid_size = MIN(old_size, new_good_size);\n\tmemcpy(new_ptr, ptr, valid_size);\n\t_nano_free_check_scribble(nanozone, ptr, (nanozone->debug_flags & MALLOC_DO_SCRIBBLE));\n\n\treturn new_ptr;\n}\n\nstatic MALLOC_INLINE void\n_nano_destroy(nanozone_t *nanozone)\n{\n\t/* Now destroy the separate nanozone region */\n\tnano_common_deallocate_pages((void *)nanozone, NANOZONE_PAGED_SIZE,\n\t\t\tnanozone->debug_flags);\n}\n\n/******************           nanozone dispatch          **********************/\n\nstatic void *\nnano_malloc(nanozone_t *nanozone, size_t size)\n{\n\tif (size <= NANO_MAX_SIZE) {\n\t\tvoid *p = _nano_malloc_check_clear(nanozone, size, 0);\n\t\tif (p) {\n\t\t\treturn p;\n\t\t} else {\n\t\t\t/* FALLTHROUGH to helper zone */\n\t\t}\n\t}\n\n\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\treturn zone->malloc(zone, size);\n}\n\nstatic void *\nnano_forked_malloc(nanozone_t *nanozone, size_t size)\n{\n\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\treturn zone->malloc(zone, size);\n}\n\nstatic void *\nnano_malloc_scribble(nanozone_t *nanozone, size_t size)\n{\n\tif (size <= NANO_MAX_SIZE) {\n\t\tvoid *ptr = _nano_malloc_check_clear(nanozone, size, 0);\n\t\tif (ptr) {\n\t\t\t/*\n\t\t\t * Scribble on allocated memory.\n\t\t\t */\n\t\t\tif (size) {\n\t\t\t\tmemset(ptr, SCRIBBLE_BYTE, _nano_vet_and_size_of_live(nanozone, ptr));\n\t\t\t}\n\n\t\t\treturn ptr;\n\t\t} else {\n\t\t\t/* FALLTHROUGH to helper zone */\n\t\t}\n\t}\n\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\treturn zone->malloc(zone, size);\n}\n\nstatic void *\nnano_calloc(nanozone_t *nanozone, size_t num_items, size_t size)\n{\n\tsize_t total_bytes;\n\n\tif (calloc_get_size(num_items, size, 0, &total_bytes)) {\n\t\treturn NULL;\n\t}\n\n\tif (total_bytes <= NANO_MAX_SIZE) {\n\t\tvoid *p = _nano_malloc_check_clear(nanozone, total_bytes, 1);\n\t\tif (p) {\n\t\t\treturn p;\n\t\t} else {\n\t\t\t/* FALLTHROUGH to helper zone */\n\t\t}\n\t}\n\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\treturn zone->calloc(zone, 1, total_bytes);\n}\n\nstatic void *\nnano_forked_calloc(nanozone_t *nanozone, size_t num_items, size_t size)\n{\n\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\treturn zone->calloc(zone, num_items, size);\n}\n\nstatic void *\nnano_valloc(nanozone_t *nanozone, size_t size)\n{\n\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\treturn zone->valloc(zone, size);\n}\n\nstatic MALLOC_INLINE void\n__nano_free_definite_size(nanozone_t *nanozone, void *ptr, size_t size, boolean_t do_scribble) MALLOC_ALWAYS_INLINE;\n\nstatic MALLOC_INLINE void\n__nano_free_definite_size(nanozone_t *nanozone, void *ptr, size_t size, boolean_t do_scribble)\n{\n\tnano_blk_addr_t p; // happily, the compiler holds this in a register\n\n\tp.addr = (uint64_t)ptr; // place ptr on the dissecting table\n\tif (NANOZONE_SIGNATURE == p.fields.nano_signature) {\n\t\tif (size == ((p.fields.nano_slot + 1) << SHIFT_NANO_QUANTUM)) { // \"Trust but verify.\"\n\t\t\t_nano_free_trusted_size_check_scribble(nanozone, ptr, size, do_scribble);\n\t\t\treturn;\n\t\t} else {\n\t\t\tmalloc_zone_error(nanozone->debug_flags, true,\n\t\t\t\t\t\"Freeing pointer %p whose size was misdeclared\\n\", ptr);\n\t\t}\n\t} else {\n\t\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\t\tzone->free_definite_size(zone, ptr, size);\n\t\treturn;\n\t}\n\t/* NOTREACHED */\n}\n\nstatic void\nnano_free_definite_size(nanozone_t *nanozone, void *ptr, size_t size)\n{\n\t__nano_free_definite_size(nanozone, ptr, size, 0);\n}\n\nstatic void\nnano_free_definite_size_scribble(nanozone_t *nanozone, void *ptr, size_t size)\n{\n\t__nano_free_definite_size(nanozone, ptr, size, 1);\n}\n\nstatic MALLOC_INLINE void __nano_free(nanozone_t *nanozone, void *ptr, boolean_t do_scribble) MALLOC_ALWAYS_INLINE;\n\nstatic MALLOC_INLINE void\n__nano_free(nanozone_t *nanozone, void *ptr, boolean_t do_scribble)\n{\n\tMALLOC_TRACE(TRACE_nano_free, (uintptr_t)nanozone, (uintptr_t)ptr, do_scribble, 0);\n\n\tif (!ptr) {\n\t\treturn; // Protect against malloc_zone_free() passing NULL.\n\t}\n\n\t// <rdar://problem/26481467> exhausting a slot may result in a pointer with\n\t// the nanozone prefix being given to nano_free via malloc_zone_free. Calling\n\t// vet_and_size here, instead of in _nano_free_check_scribble means we can\n\t// early-out into the helper_zone if it turns out nano does not own this ptr.\n\tsize_t sz = _nano_vet_and_size_of_live(nanozone, ptr);\n\n\tif (sz) {\n\t\t_nano_free_trusted_size_check_scribble(nanozone, ptr, sz, do_scribble);\n\t\treturn;\n\t} else {\n\t\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\t\tzone->free(zone, ptr);\n\t\treturn;\n\t}\n\t/* NOTREACHED */\n}\n\nstatic void\nnano_free(nanozone_t *nanozone, void *ptr)\n{\n\t__nano_free(nanozone, ptr, 0);\n}\n\nstatic void\nnano_forked_free(nanozone_t *nanozone, void *ptr)\n{\n\tif (!ptr) {\n\t\treturn; // Protect against malloc_zone_free() passing NULL.\n\t}\n\n\t// <rdar://problem/26481467> exhausting a slot may result in a pointer with\n\t// the nanozone prefix being given to nano_free via malloc_zone_free. Calling\n\t// vet_and_size here, instead of in _nano_free_check_scribble means we can\n\t// early-out into the helper_zone if it turns out nano does not own this ptr.\n\tsize_t sz = _nano_vet_and_size_of_live(nanozone, ptr);\n\n\tif (sz) {\n\t\t/* NOTHING. Drop it on the floor as nanozone metadata could be fouled by fork. */\n\t\treturn;\n\t} else {\n\t\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\t\tzone->free(zone, ptr);\n\t\treturn;\n\t}\n\t/* NOTREACHED */\n}\n\nstatic void\nnano_forked_free_definite_size(nanozone_t *nanozone, void *ptr, size_t size)\n{\n\tnano_forked_free(nanozone, ptr);\n}\n\nstatic void\nnano_free_scribble(nanozone_t *nanozone, void *ptr)\n{\n\t__nano_free(nanozone, ptr, 1);\n}\n\nstatic size_t\nnano_size(nanozone_t *nanozone, const void *ptr)\n{\n\tnano_blk_addr_t p; // happily, the compiler holds this in a register\n\n\tp.addr = (uint64_t)ptr; // place ptr on the dissecting table\n\n\tif (NANOZONE_SIGNATURE == p.fields.nano_signature) { // Our signature?\n\t\treturn _nano_size(nanozone, ptr);\n\t} else {\n\t\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\t\treturn zone->size(zone, ptr); // Not nano. Try other sizes.\n\t}\n\t/* NOTREACHED */\n}\n\nstatic void *\nnano_realloc(nanozone_t *nanozone, void *ptr, size_t new_size)\n{\n\t// could occur through malloc_zone_realloc() path\n\tif (!ptr) {\n\t\t// If ptr is a null pointer, realloc() shall be equivalent to malloc() for the specified size.\n\t\treturn nano_malloc(nanozone, new_size);\n\t}\n\n\tsize_t old_size = _nano_vet_and_size_of_live(nanozone, ptr);\n\tif (!old_size) {\n\t\t// not-nano pointer, hand down to helper zone\n\t\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\t\treturn zone->realloc(zone, ptr, new_size);\n\t} else {\n\t\tif (new_size <= NANO_MAX_SIZE) {\n\t\t\t// nano to nano?\n\t\t\tvoid *q = _nano_realloc(nanozone, ptr, new_size);\n\t\t\tif (q) {\n\t\t\t\treturn q;\n\t\t\t} else { \n\t\t\t\t// nano exhausted\n\t\t\t\t/* FALLTHROUGH to helper zone copying case */\n\t\t\t}\n\t\t}\n\n\t\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\t\tvoid *new_ptr = zone->malloc(zone, new_size);\n\n\t\tif (new_ptr) {\n\t\t\tsize_t valid_size = MIN(old_size, new_size);\n\t\t\tmemcpy(new_ptr, ptr, valid_size);\n\t\t\t_nano_free_check_scribble(nanozone, ptr, (nanozone->debug_flags & MALLOC_DO_SCRIBBLE));\n\t\t\treturn new_ptr;\n\t\t} else {\n\t\t\t/* Original ptr is left intact */\n\t\t\treturn NULL;\n\t\t}\n\t\t/* NOTREACHED */\n\t}\n\t/* NOTREACHED */\n}\n\nstatic void *\nnano_forked_realloc(nanozone_t *nanozone, void *ptr, size_t new_size)\n{\n\t// could occur through malloc_zone_realloc() path\n\tif (!ptr) {\n\t\t// If ptr is a null pointer, realloc() shall be equivalent to malloc() for the specified size.\n\t\treturn nano_forked_malloc(nanozone, new_size);\n\t}\n\n\tsize_t old_size = _nano_vet_and_size_of_live(nanozone, ptr);\n\tif (!old_size) {\n\t\t// not-nano pointer, hand down to helper zone\n\t\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\t\treturn zone->realloc(zone, ptr, new_size);\n\t} else {\n\t\tif (0 == new_size) {\n\t\t\t// If size is 0 and ptr is not a null pointer, the object pointed to is freed.\n\t\t\t// However as nanozone metadata could be fouled by fork, we'll intentionally leak it.\n\n\t\t\t// If size is 0, either a null pointer or a unique pointer that can be successfully passed\n\t\t\t// to free() shall be returned.\n\t\t\treturn nano_forked_malloc(nanozone, 1);\n\t\t}\n\n\t\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\t\tvoid *new_ptr = zone->malloc(zone, new_size);\n\n\t\tif (new_ptr) {\n\t\t\tsize_t valid_size = MIN(old_size, new_size);\n\t\t\tmemcpy(new_ptr, ptr, valid_size);\n\t\t\t/* Original pointer is intentionally leaked as nanozone metadata could be fouled by fork. */\n\t\t\treturn new_ptr;\n\t\t} else {\n\t\t\t/* Original ptr is left intact */\n\t\t\treturn NULL;\n\t\t}\n\t\t/* NOTREACHED */\n\t}\n\t/* NOTREACHED */\n}\n\nstatic void\nnano_destroy(nanozone_t *nanozone)\n{\n\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\tzone->destroy(zone);\n\n\t_nano_destroy(nanozone);\n}\n\nstatic unsigned\nnano_batch_malloc(nanozone_t *nanozone, size_t size, void **results, unsigned count)\n{\n\tunsigned found = 0;\n\n\tif (size <= NANO_MAX_SIZE) {\n\t\twhile (found < count) {\n\t\t\tvoid *ptr = _nano_malloc_check_clear(nanozone, size, 0);\n\t\t\tif (!ptr) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t*results++ = ptr;\n\t\t\tfound++;\n\t\t}\n\t\tif (found == count) {\n\t\t\treturn found;\n\t\t} else {\n\t\t\t/* FALLTHROUGH to mop-up in the helper zone */\n\t\t}\n\t}\n\n\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\treturn found + zone->batch_malloc(zone, size, results, count - found);\n}\n\nstatic unsigned\nnano_forked_batch_malloc(nanozone_t *nanozone, size_t size, void **results, unsigned count)\n{\n\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\treturn zone->batch_malloc(zone, size, results, count);\n}\n\nstatic void\nnano_batch_free(nanozone_t *nanozone, void **to_be_freed, unsigned count)\n{\n\tvoid *ptr;\n\n\t// frees all the pointers in to_be_freed\n\t// note that to_be_freed may be overwritten during the process\n\tif (!count) {\n\t\treturn;\n\t}\n\n\twhile (count--) {\n\t\tptr = to_be_freed[count];\n\t\tif (ptr) {\n\t\t\tnano_free(nanozone, ptr);\n\t\t}\n\t}\n}\n\nstatic void\nnano_forked_batch_free(nanozone_t *nanozone, void **to_be_freed, unsigned count)\n{\n\tvoid *ptr;\n\n\t// frees all the pointers in to_be_freed\n\t// note that to_be_freed may be overwritten during the process\n\tif (!count) {\n\t\treturn;\n\t}\n\n\twhile (count--) {\n\t\tptr = to_be_freed[count];\n\t\tif (ptr) {\n\t\t\tnano_forked_free(nanozone, ptr);\n\t\t}\n\t}\n}\n\nstatic void *\nnano_memalign(nanozone_t *nanozone, size_t alignment, size_t size)\n{\n\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\treturn zone->memalign(zone, alignment, size);\n}\n\nstatic boolean_t\nnano_claimed_address(nanozone_t *nanozone, void *ptr)\n{\n\tnano_blk_addr_t p;\n\tp.addr = (uint64_t)ptr;\n\tif (NANOZONE_SIGNATURE != p.fields.nano_signature) {\n\t\t// Not a nano address - let the helper zone handle it.\n\t\tmalloc_zone_t *helper_zone = nanozone->helper_zone;\n\t\treturn malloc_zone_claimed_address(helper_zone, ptr);\n\t}\n\treturn __nano_vet_and_size_inner(nanozone, ptr, true) != 0;\n}\n\nstatic boolean_t\nnano_forked_claimed_address(struct _malloc_zone_t *zone, void *ptr)\n{\n\t// This does not operate after fork - default to true to avoid\n\t// false negatives.\n\treturn true;\n}\n\nstatic size_t\nnano_try_madvise(nanozone_t *nanozone, size_t goal)\n{\n\tunsigned int mag_index, slot_key;\n\tsize_t bytes_toward_goal = 0;\n\n\tfor (mag_index = 0; mag_index < nano_common_max_magazines; mag_index++) {\n\t\tnano_blk_addr_t p;\n\n\t\t// Establish p as base address for band 0, slot 0, offset 0\n\t\tp.fields.nano_signature = NANOZONE_SIGNATURE;\n\t\tp.fields.nano_mag_index = mag_index;\n\t\tp.fields.nano_band = 0;\n\t\tp.fields.nano_slot = 0;\n\t\tp.fields.nano_offset = 0;\n\n\t\tfor (slot_key = 0; slot_key < SLOT_KEY_LIMIT; p.addr += SLOT_IN_BAND_SIZE, // Advance to next slot base\n\t\t\t\tslot_key++) {\n\t\t\t// malloc_report(ASL_LEVEL_WARNING,\"nano_try_madvise examining slot base %p\\n\", p.addr);\n\t\t\tnano_meta_admin_t pMeta = &(nanozone->meta_data[mag_index][slot_key]);\n\t\t\tuintptr_t slot_bump_addr = pMeta->slot_bump_addr;\t\t // capture this volatile pointer\n\t\t\tsize_t slot_objects_mapped = pMeta->slot_objects_mapped; // capture this volatile count\n\n\t\t\tif (0 == slot_objects_mapped) { // Nothing allocated in this magazine for this slot?\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\t// Walk the slot free list and populate a bitarray_t\n\t\t\t\tint log_size = 64 - __builtin_clzl(slot_objects_mapped);\n\t\t\t\tbitarray_t slot_bitarray = bitarray_create(log_size);\n\n\t\t\t\tunsigned int slot_bytes = pMeta->slot_bytes;\n\t\t\t\tint log_page_count = 64 - __builtin_clzl((slot_objects_mapped * slot_bytes) / vm_kernel_page_size);\n\t\t\t\tlog_page_count = 1 + MAX(0, log_page_count);\n\t\t\t\tbitarray_t page_bitarray = bitarray_create(log_page_count);\n\n\t\t\t\t// malloc_report(ASL_LEVEL_WARNING,\"slot_bitarray: %db page_bitarray: %db\\n\", bitarray_size(log_size),\n\t\t\t\t// bitarray_size(log_page_count));\n\t\t\t\tif (!slot_bitarray) {\n\t\t\t\t\tmalloc_report(ASL_LEVEL_ERR, \"bitarray_create(%d) in nano_try_madvise returned errno=%d.\\n\", log_size, errno);\n\t\t\t\t\tfree(page_bitarray);\n\t\t\t\t\treturn bytes_toward_goal;\n\t\t\t\t}\n\n\t\t\t\tif (!page_bitarray) {\n\t\t\t\t\tmalloc_report(ASL_LEVEL_ERR, \"bitarray_create(%d) in nano_try_madvise returned errno=%d.\\n\", log_page_count, errno);\n\t\t\t\t\tfree(slot_bitarray);\n\t\t\t\t\treturn bytes_toward_goal;\n\t\t\t\t}\n\n\t\t\t\tchained_block_t head = NULL, tail = NULL, t;\n\t\t\t\tunsigned stoploss = (unsigned)slot_objects_mapped;\n\t\t\t\twhile ((t = OSAtomicDequeue(&(pMeta->slot_LIFO), offsetof(struct chained_block_s, next)))) {\n\t\t\t\t\tif (0 == stoploss) {\n\t\t\t\t\t\tmalloc_report(ASL_LEVEL_ERR, \"Free list walk in nano_try_madvise exceeded object count.\\n\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tstoploss--;\n\n\t\t\t\t\tuintptr_t offset = ((uintptr_t)t - p.addr); // offset from beginning of slot\n\t\t\t\t\tindex_t block_index = offset_to_index(nanozone, pMeta, offset);\n\n\t\t\t\t\t// build a simple linked list of the free blocks we're able to obtain\n\t\t\t\t\tif (NULL == head) {\n\t\t\t\t\t\thead = t;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttail->next = t;\n\t\t\t\t\t}\n\t\t\t\t\ttail = t;\n\n\t\t\t\t\t// take note in a bitarray_t of each free block we're able to obtain (allows fast lookup below)\n\t\t\t\t\tif (block_index < slot_objects_mapped) {\n\t\t\t\t\t\tbitarray_set(slot_bitarray, log_size, block_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (tail) {\n\t\t\t\t\ttail->next = NULL;\n\t\t\t\t}\n\n\t\t\t\tif (NULL == head) {\n\t\t\t\t\tfree(slot_bitarray);\n\t\t\t\t\tfree(page_bitarray);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tindex_t i;\n\t\t\t\tnano_blk_addr_t q;\n\t\t\t\tsize_t pgnum;\n\t\t\t\tfor (i = (index_t)pMeta->slot_objects_skipped; i < slot_objects_mapped; ++i) {\n\t\t\t\t\tuintptr_t block_offset = index_to_offset(nanozone, pMeta, i);\n\t\t\t\t\tif (p.addr + block_offset >= slot_bump_addr) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!bitarray_get(slot_bitarray, log_size, i)) { // is block i allocated or already on an madvise'd page?\n\n\t\t\t\t\t\t// Mark the page(s) it resides on as live\n\t\t\t\t\t\tq.addr = p.addr + block_offset;\n\t\t\t\t\t\tpgnum = ((((unsigned)q.fields.nano_band) << NANO_OFFSET_BITS) | ((unsigned)q.fields.nano_offset)) >>\n\t\t\t\t\t\t\t\tvm_kernel_page_shift;\n\t\t\t\t\t\tbitarray_set(page_bitarray, log_page_count, (index_t)pgnum);\n\n\t\t\t\t\t\tq.addr += slot_bytes - 1;\n\t\t\t\t\t\tpgnum = ((((unsigned)q.fields.nano_band) << NANO_OFFSET_BITS) | ((unsigned)q.fields.nano_offset)) >>\n\t\t\t\t\t\t\t\tvm_kernel_page_shift;\n\t\t\t\t\t\tbitarray_set(page_bitarray, log_page_count, (index_t)pgnum);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfree(slot_bitarray);\n\n\t\t\t\tq.addr = p.addr + index_to_offset(nanozone, pMeta, (index_t)pMeta->slot_objects_skipped);\n\t\t\t\tindex_t pgstart =\n\t\t\t\t\t\t((((unsigned)q.fields.nano_band) << NANO_OFFSET_BITS) | ((unsigned)q.fields.nano_offset)) >> vm_kernel_page_shift;\n\n\t\t\t\tq.addr = slot_bump_addr - slot_bytes;\n\t\t\t\tpgnum = ((((unsigned)q.fields.nano_band) << NANO_OFFSET_BITS) | ((unsigned)q.fields.nano_offset)) >> vm_kernel_page_shift;\n\n\t\t\t\t// malloc_report(ASL_LEVEL_WARNING,\"Examining %d pages. Slot base %p.\\n\", pgnum - pgstart + 1, p.addr);\n\n\t\t\t\tif (pMeta->slot_madvised_pages) {\n\t\t\t\t\tif (pMeta->slot_madvised_log_page_count < log_page_count) {\n\t\t\t\t\t\tbitarray_t new_madvised_pages = bitarray_create(log_page_count);\n\t\t\t\t\t\tindex_t index;\n\t\t\t\t\t\twhile (bitarray_zap_first_set(pMeta->slot_madvised_pages, pMeta->slot_madvised_log_page_count, &index)) {\n\t\t\t\t\t\t\tbitarray_set(new_madvised_pages, log_page_count, index);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfree(pMeta->slot_madvised_pages);\n\t\t\t\t\t\tpMeta->slot_madvised_pages = new_madvised_pages;\n\t\t\t\t\t\tpMeta->slot_madvised_log_page_count = log_page_count;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tpMeta->slot_madvised_pages = bitarray_create(log_page_count);\n\t\t\t\t\tpMeta->slot_madvised_log_page_count = log_page_count;\n\t\t\t\t}\n\n\t\t\t\tbitarray_t will_madvise_pages = bitarray_create(log_page_count);\n\t\t\t\tint num_advised = 0;\n\n\t\t\t\tfor (i = pgstart; i < pgnum; ++i) {\n\t\t\t\t\tif ((i < (1 << log_page_count)) && // bounds check for the bitarray_get()'s that follow.\n\t\t\t\t\t\t\t!bitarray_get(pMeta->slot_madvised_pages, log_page_count, i) && // already madvise'd?\n\t\t\t\t\t\t\t!bitarray_get(page_bitarray, log_page_count, i))\t\t\t\t// no live allocations?\n\t\t\t\t\t{\n\t\t\t\t\t\tnum_advised++;\n\t\t\t\t\t\tbitarray_set(will_madvise_pages, log_page_count, i);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfree(page_bitarray);\n\n\t\t\t\tif (num_advised) {\n\t\t\t\t\tchained_block_t new_head = NULL, new_tail = NULL;\n\t\t\t\t\t// malloc_report(ASL_LEVEL_WARNING,\"Constructing residual free list starting at %p num_advised %d\\n\", head,\n\t\t\t\t\t// num_advised);\n\t\t\t\t\tt = head;\n\t\t\t\t\twhile (t) {\n\t\t\t\t\t\tq.addr = (uintptr_t)t;\n\t\t\t\t\t\tindex_t pgnum_start =\n\t\t\t\t\t\t\t\t((((unsigned)q.fields.nano_band) << NANO_OFFSET_BITS) | ((unsigned)q.fields.nano_offset)) >>\n\t\t\t\t\t\t\t\tvm_kernel_page_shift;\n\t\t\t\t\t\tq.addr += slot_bytes - 1;\n\t\t\t\t\t\tindex_t pgnum_end =\n\t\t\t\t\t\t\t\t((((unsigned)q.fields.nano_band) << NANO_OFFSET_BITS) | ((unsigned)q.fields.nano_offset)) >>\n\t\t\t\t\t\t\t\tvm_kernel_page_shift;\n\n\t\t\t\t\t\t// bounds check for the bitarray_get()'s that follow. If the pgnum is beyond the\n\t\t\t\t\t\t// capacity of the will_madvise_pages just restore the block to the free list.\n\t\t\t\t\t\tif (pgnum_start >= (1 << log_page_count)) {\n\t\t\t\t\t\t\tif (NULL == new_head) {\n\t\t\t\t\t\t\t\tnew_head = t;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tnew_tail->next = t;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnew_tail = t;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// If the block nowhere lies on an madvise()'d page restore it to the slot free list.\n\t\t\t\t\t\telse if (!bitarray_get(will_madvise_pages, log_page_count, pgnum_start) &&\n\t\t\t\t\t\t\t\t !bitarray_get(will_madvise_pages, log_page_count, pgnum_end)) {\n\t\t\t\t\t\t\tif (NULL == new_head) {\n\t\t\t\t\t\t\t\tnew_head = t;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tnew_tail->next = t;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnew_tail = t;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tt = t->next;\n\t\t\t\t\t}\n\t\t\t\t\tif (new_tail) {\n\t\t\t\t\t\tnew_tail->next = NULL;\n\t\t\t\t\t}\n\n\t\t\t\t\t// push the free list extracted above back onto the LIFO, all at once\n\t\t\t\t\tif (new_head) {\n\t\t\t\t\t\tOSAtomicEnqueue(&(pMeta->slot_LIFO), new_head,\n\t\t\t\t\t\t\t\t(uintptr_t)new_tail - (uintptr_t)new_head + offsetof(struct chained_block_s, next));\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// malloc_report(ASL_LEVEL_WARNING,\"Reinstating free list since no pages were madvised (%d).\\n\", num_advised);\n\t\t\t\t\tif (head) {\n\t\t\t\t\t\tOSAtomicEnqueue(&(pMeta->slot_LIFO), head,\n\t\t\t\t\t\t\t\t(uintptr_t)tail - (uintptr_t)head + offsetof(struct chained_block_s, next));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (i = pgstart; i < pgnum; ++i) {\n\t\t\t\t\tif ((i < (1 << log_page_count)) && bitarray_get(will_madvise_pages, log_page_count, i)) {\n\t\t\t\t\t\tq = p;\n\t\t\t\t\t\tq.fields.nano_band = (i << vm_kernel_page_shift) >> NANO_OFFSET_BITS;\n\t\t\t\t\t\tq.fields.nano_offset = (i << vm_kernel_page_shift) & ((1 << NANO_OFFSET_BITS) - 1);\n\t\t\t\t\t\t// malloc_report(ASL_LEVEL_WARNING,\"Entire page non-live: %d. Slot base %p, madvising %p\\n\", i, p.addr,\n\t\t\t\t\t\t// q.addr);\n\n\t\t\t\t\t\tif (nanozone->debug_flags & MALLOC_DO_SCRIBBLE) {\n\t\t\t\t\t\t\tmemset((void *)q.addr, SCRUBBLE_BYTE, vm_kernel_page_size);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (-1 == madvise((void *)q.addr, vm_kernel_page_size, MADV_FREE_REUSABLE))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t/* -1 return: VM map entry change makes this unfit for reuse. Something evil lurks. */\n#if DEBUG_MADVISE\n\t\t\t\t\t\t\tnanozone_error(nanozone, 0, \"madvise(..., MADV_FREE_REUSABLE) failed\", (void *)cwq.addrpgLo,\n\t\t\t\t\t\t\t\t\t\"length=%d\\n\", vm_page_size);\n#endif\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbytes_toward_goal += vm_kernel_page_size;\n\t\t\t\t\t\t\tbitarray_set(pMeta->slot_madvised_pages, log_page_count, i);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfree(will_madvise_pages);\n\n\t\t\t\tif (!bitarray_first_set(pMeta->slot_madvised_pages, log_page_count)) {\n\t\t\t\t\tfree(pMeta->slot_madvised_pages);\n\t\t\t\t\tpMeta->slot_madvised_pages = NULL;\n\t\t\t\t\tpMeta->slot_madvised_log_page_count = 0;\n\t\t\t\t}\n\n\t\t\t\tif (goal && bytes_toward_goal >= goal) {\n\t\t\t\t\treturn bytes_toward_goal;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn bytes_toward_goal;\n}\n\nstatic size_t\nnano_pressure_relief(nanozone_t *nanozone, size_t goal)\n{\n\tMAGMALLOC_PRESSURERELIEFBEGIN((void *)nanozone, nanozone->basic_zone.zone_name, (int)goal);\n\tMALLOC_TRACE(TRACE_nano_memory_pressure | DBG_FUNC_START, (uint64_t)nanozone, goal, 0, 0);\n\n\tsize_t total = nano_try_madvise(nanozone, goal);\n\n\tMAGMALLOC_PRESSURERELIEFEND((void *)nanozone, nanozone->basic_zone.zone_name, (int)goal, (int)total);\n\tMALLOC_TRACE(TRACE_nano_memory_pressure | DBG_FUNC_END, (uint64_t)nanozone, goal, total, 0);\n\n\treturn total;\n}\n\n/****************           introspection methods         *********************/\n\nstatic kern_return_t\nnano_ptr_in_use_enumerator(task_t task,\n\t\tvoid *context,\n\t\tunsigned type_mask,\n\t\tvm_address_t zone_address,\n\t\tmemory_reader_t reader,\n\t\tvm_range_recorder_t recorder)\n{\n\tnanozone_t *nanozone;\n\tkern_return_t err;\n\tstruct nanozone_s zone_copy;\n\n\tif (!reader) {\n\t\treader = nano_common_default_reader;\n\t}\n\n\terr = reader(task, zone_address, sizeof(nanozone_t), (void **)&nanozone);\n\tif (err) {\n\t\treturn err;\n\t}\n\tmemcpy(&zone_copy, nanozone, sizeof(zone_copy));\n\n\terr = segregated_in_use_enumerator(task, context, type_mask, &zone_copy, reader, recorder);\n\treturn err;\n}\n\nstatic size_t\nnano_good_size(nanozone_t *nanozone, size_t size)\n{\n\tif (size <= NANO_MAX_SIZE) {\n\t\treturn _nano_common_good_size(size);\n\t} else {\n\t\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\t\treturn zone->introspect->good_size(zone, size);\n\t}\n}\n\n// TODO sanity checks\nunsigned nanozone_check_counter = 0;\nunsigned nanozone_check_start = 0;\nunsigned nanozone_check_modulo = 1;\n\nstatic boolean_t\nnano_check_all(nanozone_t *nanozone, const char *function)\n{\n\treturn 1;\n}\n\nstatic boolean_t\nnanozone_check(nanozone_t *nanozone)\n{\n\tif ((++nanozone_check_counter % 10000) == 0) {\n\t\tmalloc_report(ASL_LEVEL_NOTICE, \"at nanozone_check counter=%d\\n\", nanozone_check_counter);\n\t}\n\n\tif (nanozone_check_counter < nanozone_check_start) {\n\t\treturn 1;\n\t}\n\n\tif (nanozone_check_counter % nanozone_check_modulo) {\n\t\treturn 1;\n\t}\n\n\treturn nano_check_all(nanozone, \"\");\n}\n\nstatic unsigned\ncount_free(nanozone_t *nanozone, nano_meta_admin_t pMeta)\n{\n\tchained_block_t head = NULL, tail = NULL, t;\n\tunsigned count = 0;\n\n\tunsigned stoploss = (unsigned)pMeta->slot_objects_mapped;\n\twhile ((t = OSAtomicDequeue(&(pMeta->slot_LIFO), offsetof(struct chained_block_s, next)))) {\n\t\tif (0 == stoploss) {\n\t\t\tmalloc_zone_error(nanozone->debug_flags, true,\n\t\t\t\t\t\"Free list walk in count_free exceeded object count.\\n\",\n\t\t\t\t\t(void *)&(pMeta->slot_LIFO), NULL);\n\t\t}\n\t\tstoploss--;\n\n\t\tif (NULL == head) {\n\t\t\thead = t;\n\t\t} else {\n\t\t\ttail->next = t;\n\t\t}\n\t\ttail = t;\n\n\t\tcount++;\n\t}\n\tif (tail) {\n\t\ttail->next = NULL;\n\t}\n\n\t// push the free list extracted above back onto the LIFO, all at once\n\tif (head) {\n\t\tOSAtomicEnqueue(&(pMeta->slot_LIFO), head, (uintptr_t)tail - (uintptr_t)head + offsetof(struct chained_block_s, next));\n\t}\n\n\treturn count;\n}\n\nstatic void\nnano_print(nanozone_t *nanozone, boolean_t verbose)\n{\n\tunsigned int mag_index, slot_key;\n\tmalloc_statistics_t stats;\n\n\tnano_statistics(nanozone, &stats);\n\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\"Nanozone %p: inUse=%d(%lluKB) touched=%lluKB allocated=%lluMB\\n\",\n\t\t\tnanozone, stats.blocks_in_use, (uint64_t)stats.size_in_use >> 10,\n\t\t\t(uint64_t)stats.max_size_in_use >> 10, (uint64_t)stats.size_allocated >> 20);\n\n\tfor (mag_index = 0; mag_index < nano_common_max_magazines; mag_index++) {\n\t\tnano_blk_addr_t p;\n\n\t\t// Establish p as base address for band 0, slot 0, offset 0\n\t\tp.fields.nano_signature = NANOZONE_SIGNATURE;\n\t\tp.fields.nano_mag_index = mag_index;\n\t\tp.fields.nano_band = 0;\n\t\tp.fields.nano_slot = 0;\n\t\tp.fields.nano_offset = 0;\n\n\t\tfor (slot_key = 0; slot_key < SLOT_KEY_LIMIT; p.addr += SLOT_IN_BAND_SIZE, // Advance to next slot base\n\t\t\t\tslot_key++) {\n\t\t\tnano_meta_admin_t pMeta = &(nanozone->meta_data[mag_index][slot_key]);\n\t\t\tuintptr_t slot_bump_addr = pMeta->slot_bump_addr;\t\t // capture this volatile pointer\n\t\t\tsize_t slot_objects_mapped = pMeta->slot_objects_mapped; // capture this volatile count\n\n\t\t\tif (0 == slot_objects_mapped) { // Nothing allocated in this magazine for this slot?\n\t\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"Magazine %2d(%3d) Unrealized\\n\", mag_index,\n\t\t\t\t\t\t(slot_key + 1) << SHIFT_NANO_QUANTUM);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tuintptr_t offset = (0 == slot_bump_addr ? 0 : slot_bump_addr - p.addr);\n\t\t\tunsigned blocks_touched = offset_to_index(nanozone, pMeta, offset) - (unsigned)pMeta->slot_objects_skipped;\n\t\t\tunsigned blocks_now_free = count_free(nanozone, pMeta);\n\t\t\tunsigned blocks_in_use = blocks_touched - blocks_now_free;\n\n\t\t\tsize_t size_hiwater = ((slot_key + 1) << SHIFT_NANO_QUANTUM) * blocks_touched;\n\t\t\tsize_t size_in_use = ((slot_key + 1) << SHIFT_NANO_QUANTUM) * blocks_in_use;\n\t\t\tsize_t size_allocated = ((offset / BAND_SIZE) + 1) * SLOT_IN_BAND_SIZE;\n\n\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\t\t\"Magazine %2d(%3d) [%p, %3lluKB] \\t Allocations in use=%4d \\t Bytes in use=%llub \\t Untouched=%lluKB\\n\", mag_index,\n\t\t\t\t\t(slot_key + 1) << SHIFT_NANO_QUANTUM, (void *)p.addr, (uint64_t)(size_allocated >> 10), blocks_in_use, (uint64_t)size_in_use,\n\t\t\t\t\t(uint64_t)((size_allocated - size_hiwater) >> 10));\n\n\t\t\tif (!verbose) {\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\t// Walk the slot free list and populate a bitarray_t\n\t\t\t\tint log_size = 64 - __builtin_clzl(slot_objects_mapped);\n\t\t\t\tbitarray_t slot_bitarray = bitarray_create(log_size);\n\n\t\t\t\tif (!slot_bitarray) {\n\t\t\t\t\tmalloc_report(ASL_LEVEL_ERR, \"bitarray_create(%d) in nano_print returned errno=%d.\\n\", log_size, errno);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tchained_block_t head = NULL, tail = NULL, t;\n\t\t\t\tunsigned stoploss = (unsigned)slot_objects_mapped;\n\t\t\t\twhile ((t = OSAtomicDequeue(&(pMeta->slot_LIFO), offsetof(struct chained_block_s, next)))) {\n\t\t\t\t\tif (0 == stoploss) {\n\t\t\t\t\t\tmalloc_report(ASL_LEVEL_ERR, \"Free list walk in nano_print exceeded object count.\\n\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tstoploss--;\n\n\t\t\t\t\tuintptr_t offset = ((uintptr_t)t - p.addr); // offset from beginning of slot\n\t\t\t\t\tindex_t block_index = offset_to_index(nanozone, pMeta, offset);\n\n\t\t\t\t\tif (NULL == head) {\n\t\t\t\t\t\thead = t;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttail->next = t;\n\t\t\t\t\t}\n\t\t\t\t\ttail = t;\n\n\t\t\t\t\tif (block_index < slot_objects_mapped) {\n\t\t\t\t\t\tbitarray_set(slot_bitarray, log_size, block_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (tail) {\n\t\t\t\t\ttail->next = NULL;\n\t\t\t\t}\n\n\t\t\t\tindex_t i;\n\t\t\t\tfor (i = 0; i < slot_objects_mapped; ++i) {\n\t\t\t\t\tnano_blk_addr_t q;\n\t\t\t\t\tsize_t pgnum;\n\t\t\t\t\tuintptr_t block_offset = index_to_offset(nanozone, pMeta, i);\n\t\t\t\t\tif (p.addr + block_offset >= slot_bump_addr) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tq.addr = p.addr + block_offset;\n\t\t\t\t\tpgnum = ((((unsigned)q.fields.nano_band) << NANO_OFFSET_BITS) | ((unsigned)q.fields.nano_offset)) >>\n\t\t\t\t\t\t\tvm_kernel_page_shift;\n\n\t\t\t\t\tif (i < pMeta->slot_objects_skipped) {\n\t\t\t\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"_\");\n\t\t\t\t\t} else if (bitarray_get(slot_bitarray, log_size, i)) {\n\t\t\t\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"F\");\n\t\t\t\t\t} else if (pMeta->slot_madvised_pages && (pgnum < (1 << pMeta->slot_madvised_log_page_count)) &&\n\t\t\t\t\t\t\t   bitarray_get(pMeta->slot_madvised_pages, pMeta->slot_madvised_log_page_count, (index_t)pgnum)) {\n\t\t\t\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"M\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \".\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"\\n\");\n\n\t\t\t\tfree(slot_bitarray);\n\n\t\t\t\t// push the free list extracted above back onto the LIFO, all at once\n\t\t\t\tif (head) {\n\t\t\t\t\tOSAtomicEnqueue(\n\t\t\t\t\t\t\t&(pMeta->slot_LIFO), head, (uintptr_t)tail - (uintptr_t)head + offsetof(struct chained_block_s, next));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn;\n}\n\nstatic void\nnano_log(malloc_zone_t *zone, void *log_address)\n{\n}\n\nstatic void\nnano_force_lock(nanozone_t *nanozone)\n{\n\tint i;\n\n\tfor (i = 0; i < nano_common_max_magazines; ++i) {\n\t\t_malloc_lock_lock(&nanozone->band_resupply_lock[i]);\n\t}\n}\n\nstatic void\nnano_force_unlock(nanozone_t *nanozone)\n{\n\tint i;\n\n\tfor (i = 0; i < nano_common_max_magazines; ++i) {\n\t\t_malloc_lock_unlock(&nanozone->band_resupply_lock[i]);\n\t}\n}\n\nstatic void\nnano_reinit_lock(nanozone_t *nanozone)\n{\n\tint i;\n\n\tfor (i = 0; i < nano_common_max_magazines; ++i) {\n\t\t_malloc_lock_init(&nanozone->band_resupply_lock[i]);\n\t}\n}\n\nstatic void\nnano_statistics(nanozone_t *nanozone, malloc_statistics_t *stats)\n{\n\tint i, j;\n\n\tbzero(stats, sizeof(*stats));\n\n\tfor (i = 0; i < nano_common_max_magazines; ++i) {\n\t\tnano_blk_addr_t p;\n\n\t\t// Establish p as base address for slot 0 in this CPU magazine\n\t\tp.fields.nano_signature = NANOZONE_SIGNATURE;\n\t\tp.fields.nano_mag_index = i;\n\t\tp.fields.nano_band = 0;\n\t\tp.fields.nano_slot = 0;\n\t\tp.fields.nano_offset = 0;\n\n\t\tfor (j = 0; j < NANO_SLOT_SIZE; p.addr += SLOT_IN_BAND_SIZE, // Advance to next slot base\n\t\t\t\t++j) {\n\t\t\tnano_meta_admin_t pMeta = &nanozone->meta_data[i][j];\n\t\t\tuintptr_t offset = pMeta->slot_bump_addr - p.addr;\n\n\t\t\tif (0 == pMeta->slot_current_base_addr) { // Nothing allocated in this magazine for this slot?\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\tunsigned blocks_touched = offset_to_index(nanozone, pMeta, offset) - (unsigned)pMeta->slot_objects_skipped;\n\t\t\t\tunsigned blocks_now_free = count_free(nanozone, pMeta);\n\t\t\t\tunsigned blocks_in_use = blocks_touched - blocks_now_free;\n\n\t\t\t\tsize_t size_hiwater = ((j + 1) << SHIFT_NANO_QUANTUM) * blocks_touched;\n\t\t\t\tsize_t size_in_use = ((j + 1) << SHIFT_NANO_QUANTUM) * blocks_in_use;\n\t\t\t\tsize_t size_allocated = ((offset / BAND_SIZE) + 1) * SLOT_IN_BAND_SIZE;\n\n\t\t\t\tstats->blocks_in_use += blocks_in_use;\n\n\t\t\t\tstats->max_size_in_use += size_hiwater;\n\t\t\t\tstats->size_in_use += size_in_use;\n\t\t\t\tstats->size_allocated += size_allocated;\n\t\t\t}\n\t\t}\n\t}\n}\n\nstatic boolean_t\n_nano_locked(nanozone_t *nanozone)\n{\n\tint i;\n\n\tfor (i = 0; i < nano_common_max_magazines; ++i) {\n\t\tif (_malloc_lock_trylock(&nanozone->band_resupply_lock[i])) {\n\t\t\t_malloc_lock_unlock(&nanozone->band_resupply_lock[i]);\n\t\t\treturn TRUE;\n\t\t}\n\t}\n\treturn FALSE;\n}\n\nstatic boolean_t\nnano_locked(nanozone_t *nanozone)\n{\n\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\n\treturn _nano_locked(nanozone) || zone->introspect->zone_locked(zone);\n}\n\nstatic const struct malloc_introspection_t nano_introspect = {\n\t\t(void *)nano_ptr_in_use_enumerator, (void *)nano_good_size, (void *)nanozone_check, (void *)nano_print, nano_log,\n\t\t(void *)nano_force_lock, (void *)nano_force_unlock, (void *)nano_statistics, (void *)nano_locked, NULL, NULL, NULL,\n\t\tNULL, /* Zone enumeration version 7 and forward. */\n\t\t(void *)nano_reinit_lock, // reinit_lock version 9 and foward\n}; // marked as const to spare the DATA section\n\nvoid\nnano_forked_zone(nanozone_t *nanozone)\n{\n\t/*\n\t * Hobble the nano zone in the child of a fork prior to an exec since\n\t * the state of the zone can be made inconsistent by a parent thread while the\n\t * fork is underway.\n\t * All new allocations will be referred to the helper zone (which is more stable.)\n\t * All free()'s of existing nano objects will be leaked.\n\t */\n\n\tmprotect(nanozone, sizeof(nanozone->basic_zone), PROT_READ | PROT_WRITE);\n\n\tnanozone->basic_zone.size = (void *)nano_size; /* Unchanged. */\n\tnanozone->basic_zone.malloc = (void *)nano_forked_malloc;\n\tnanozone->basic_zone.calloc = (void *)nano_forked_calloc;\n\tnanozone->basic_zone.valloc = (void *)nano_valloc; /* Unchanged, already always obtained from helper zone. */\n\tnanozone->basic_zone.free = (void *)nano_forked_free;\n\tnanozone->basic_zone.realloc = (void *)nano_forked_realloc;\n\tnanozone->basic_zone.destroy = (void *)nano_destroy; /* Unchanged. */\n\tnanozone->basic_zone.batch_malloc = (void *)nano_forked_batch_malloc;\n\tnanozone->basic_zone.batch_free = (void *)nano_forked_batch_free;\n\tnanozone->basic_zone.introspect = (struct malloc_introspection_t *)&nano_introspect; /* Unchanged. */\n\tnanozone->basic_zone.memalign = (void *)nano_memalign;\t\t\t\t\t\t\t\t /* Unchanged. */\n\tnanozone->basic_zone.free_definite_size = (void *)nano_forked_free_definite_size;\n\tnanozone->basic_zone.claimed_address = nano_forked_claimed_address;\n\n\tmprotect(nanozone, sizeof(nanozone->basic_zone), PROT_READ);\n}\n\nmalloc_zone_t *\nnano_create_zone(malloc_zone_t *helper_zone, unsigned debug_flags)\n{\n\tnanozone_t *nanozone;\n\tint i, j;\n\n\t/* Note: It is important that nano_create_zone resets _malloc_engaged_nano\n\t * if it is unable to enable the nanozone (and chooses not to abort). As\n\t * several functions rely on _malloc_engaged_nano to determine if they\n\t * should manipulate the nanozone, and these should not run if we failed\n\t * to create the zone.\n\t */\n \tMALLOC_ASSERT(_malloc_engaged_nano == NANO_V1);\n\n\t/* get memory for the zone. */\n\tnanozone = nano_common_allocate_based_pages(NANOZONE_PAGED_SIZE, 0, 0, VM_MEMORY_MALLOC, 0);\n\tif (!nanozone) {\n\t\t_malloc_engaged_nano = NANO_NONE;\n\t\treturn NULL;\n\t}\n\n\t/* set up the basic_zone portion of the nanozone structure */\n\tnanozone->basic_zone.version = 10;\n\tnanozone->basic_zone.size = (void *)nano_size;\n\tnanozone->basic_zone.malloc = (debug_flags & MALLOC_DO_SCRIBBLE) ? (void *)nano_malloc_scribble : (void *)nano_malloc;\n\tnanozone->basic_zone.calloc = (void *)nano_calloc;\n\tnanozone->basic_zone.valloc = (void *)nano_valloc;\n\tnanozone->basic_zone.free = (debug_flags & MALLOC_DO_SCRIBBLE) ? (void *)nano_free_scribble : (void *)nano_free;\n\tnanozone->basic_zone.realloc = (void *)nano_realloc;\n\tnanozone->basic_zone.destroy = (void *)nano_destroy;\n\tnanozone->basic_zone.batch_malloc = (void *)nano_batch_malloc;\n\tnanozone->basic_zone.batch_free = (void *)nano_batch_free;\n\tnanozone->basic_zone.introspect = (struct malloc_introspection_t *)&nano_introspect;\n\tnanozone->basic_zone.memalign = (void *)nano_memalign;\n\tnanozone->basic_zone.free_definite_size = (debug_flags & MALLOC_DO_SCRIBBLE) ? (void *)nano_free_definite_size_scribble\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  : (void *)nano_free_definite_size;\n\n\tnanozone->basic_zone.pressure_relief = (void *)nano_pressure_relief;\n\tnanozone->basic_zone.claimed_address = (void *)nano_claimed_address;\n\n\tnanozone->basic_zone.reserved1 = 0; /* Set to zero once and for all as required by CFAllocator. */\n\tnanozone->basic_zone.reserved2 = 0; /* Set to zero once and for all as required by CFAllocator. */\n\n\tmprotect(nanozone, sizeof(nanozone->basic_zone), PROT_READ); /* Prevent overwriting the function pointers in basic_zone. */\n\n\t/* Nano zone does not support MALLOC_ADD_GUARD_PAGES. */\n\tif (debug_flags & MALLOC_ADD_GUARD_PAGES) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"nano zone does not support guard pages\\n\");\n\t\tdebug_flags &= ~MALLOC_ADD_GUARD_PAGES;\n\t}\n\n\t/* set up the remainder of the nanozone structure */\n\tnanozone->debug_flags = debug_flags;\n\n\tif (phys_ncpus > sizeof(nanozone->core_mapped_size) /\n\t\t\tsizeof(nanozone->core_mapped_size[0])) {\n\t\tMALLOC_REPORT_FATAL_ERROR(phys_ncpus,\n\t\t\t\t\"nanozone abandoned because NCPUS > max magazines.\\n\");\n\t}\n\n\t/* Initialize slot queue heads and resupply locks. */\n\tOSQueueHead q0 = OS_ATOMIC_QUEUE_INIT;\n\tfor (i = 0; i < nano_common_max_magazines; ++i) {\n\t\t_malloc_lock_init(&nanozone->band_resupply_lock[i]);\n\n\t\tfor (j = 0; j < NANO_SLOT_SIZE; ++j) {\n\t\t\tnanozone->meta_data[i][j].slot_LIFO = q0;\n\t\t}\n\t}\n\n\t/* Initialize the security token. */\n\tnanozone->cookie = (uintptr_t)malloc_entropy[0] & 0x0000ffffffff0000ULL; // scramble central 32bits with this cookie\n\n\tnanozone->helper_zone = helper_zone;\n\n\treturn (malloc_zone_t *)nanozone;\n}\n\nvoid\nnano_init(const char *envp[], const char *apple[],\n\t\tconst char *bootargs MALLOC_UNUSED)\n{\n#if NANO_PREALLOCATE_BAND_VM\n\t// Unconditionally preallocate the VA space set aside for nano malloc to\n\t// reserve it in all configurations. rdar://problem/33392283\n\tboolean_t preallocated = nano_preallocate_band_vm();\n\tif (!preallocated) {\n\t\tmalloc_report(ASL_LEVEL_NOTICE, \"nano zone abandoned due to inability to preallocate reserved vm space.\\n\");\n\t\t_malloc_engaged_nano = NANO_NONE;\n\t}\n#endif\n}\n\n// Second phase of initialization, called during _malloc_initialize(), after\n// environment variables have been read and processed.\nvoid\nnano_configure()\n{\n\t// Nothing to do.\n}\n\n#endif // CONFIG_NANOZONE\n\n/* vim: set noet:ts=4:sw=4:cindent: */\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/nano_malloc.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __NANO_MALLOC_H\n#define __NANO_MALLOC_H\n\n// Forward decl for the nanozone.\ntypedef struct nanozone_s nanozone_t;\n\nMALLOC_NOEXPORT\nmalloc_zone_t *\nnano_create_zone(malloc_zone_t *helper_zone, unsigned debug_flags);\n\nMALLOC_NOEXPORT\nvoid\nnano_forked_zone(nanozone_t *nanozone);\n\nMALLOC_NOEXPORT\nvoid\nnano_init(const char *envp[], const char *apple[], const char *bootargs);\n\nMALLOC_NOEXPORT\nvoid\nnano_configure(void);\n\n#endif // __NANO_MALLOC_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/nano_malloc_common.c",
    "content": "/*\n * Copyright (c) 2018 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"internal.h\"\n\n// Code that is common to Nano V1 and Nano V2. When Nano V1 is removed,\n// most of this file will move to nanov2_malloc.c.\n\n#if CONFIG_NANOZONE\n\n// Possible enablement modes for Nano V2\ntypedef enum {\n\tNANO_INACTIVE,\t// Inactive, but can be selected with MallocNanoZone=V2\n\tNANO_ENABLED,\t// Available and default if Nano is turned on.\n\tNANO_FORCED,\t// Force use of Nano V2 for all processes.\n} nanov2_mode_t;\n\n// Which version of Nano is engaged. By default, none.\nnano_version_t _malloc_engaged_nano = NANO_NONE;\n\n// Nano mode selection boot argument\nstatic const char mode_boot_arg[] = \"nanov2_mode\";\nstatic const char inactive_mode[] = \"inactive\"; // Use Nano V1 for Nano\nstatic const char enabled_mode[] = \"enabled\";\t// Use Nano V2 for Nano\nstatic const char forced_mode[] = \"forced\";\t\t// Force Nano V2 everywhere\n\n// The maximum number of per-CPU allocation regions to use for Nano.\nunsigned int nano_common_max_magazines;\nboolean_t nano_common_max_magazines_is_ncpu;\n\n// Boot argument for nano_common_max_magazines\nstatic const char nano_max_magazines_boot_arg[] = \"malloc_nano_max_magazines\";\n\n#pragma mark -\n#pragma mark Initialization\n\n// Shared initialization code. Determines which version of Nano should be used,\n// if any, and sets _malloc_engaged_nano. The Nano version is determined as\n// follows:\n// 1. If the nanov2_mode boot arg has value \"forced\", Nano V2 is used\n//\t\tunconditionally in every process, except in processes that have\n//\t\tthe MallocNanoZone variable set to V1.\n// 2. If the nanov2_mode boot arg has value \"enabled\", Nano V2 is used if\n//\t\tthe process wants to use Nano (i.e. the kernel opts the process in, or\n//\t\tthe environment variable MallocNanoZone is 1).\n// 3. If the nanov2_mode boot arg is not present or has any other value,\n//\t\tNano V1 is used if the process wants to use Nano (i.e. the kernel opts\n//\t\tthe process in, or the environment variable MallocNanoZone is 1).\n//\n// In cases (2) and (3), the selection can be explicitly overridden by setting\n// the environment variable MallocNanoZone to V1 or V2.\nvoid\nnano_common_init(const char *envp[], const char *apple[], const char *bootargs)\n{\n\t// Use the nanov2_mode boot argument and MallocNanoZone to determine\n\t// which version of Nano to use, if any.\n\tnanov2_mode_t nanov2_mode = NANO_ENABLED;\n\tconst char *p = malloc_common_value_for_key(bootargs, mode_boot_arg);\n\tif (p) {\n\t\tif (!strncmp(p, inactive_mode, sizeof(inactive_mode) - 1)) {\n\t\t\tnanov2_mode = NANO_INACTIVE;\n\t\t} else if (!strncmp(p, enabled_mode, sizeof(enabled_mode) - 1)) {\n\t\t\tnanov2_mode = NANO_ENABLED;\n\t\t} else if (!strncmp(p, forced_mode, sizeof(forced_mode) - 1)) {\n\t\t\tnanov2_mode = NANO_FORCED;\n\t\t}\n\t}\n\n\tif (nanov2_mode == NANO_FORCED) {\n\t\t// We will use Nano V2 unless MallocNanoZone is \"V1\".\n\t\tconst char *flag = _simple_getenv(envp, \"MallocNanoZone\");\n\t\tif (flag && (flag[0] == 'V' || flag[0] == 'v') && flag[1] == '1') {\n\t\t\t_malloc_engaged_nano = NANO_V1;\n\t\t} else {\n\t\t\t_malloc_engaged_nano = NANO_V2;\n\t\t}\n\t} else {\n\t\tconst char *flag = _simple_getenv(apple, \"MallocNanoZone\");\n\t\tif (flag && flag[0] == '1') {\n\t\t\t_malloc_engaged_nano = nanov2_mode == NANO_ENABLED ? NANO_V2 : NANO_V1;\n\t\t}\n\t\t/* Explicit overrides from the environment */\n\t\tflag = _simple_getenv(envp, \"MallocNanoZone\");\n\t\tif (flag) {\n\t\t\tif (flag[0] == '1') {\n\t\t\t\t_malloc_engaged_nano = nanov2_mode == NANO_ENABLED ? NANO_V2 : NANO_V1;\n\t\t\t} else if (flag[0] == '0') {\n\t\t\t\t_malloc_engaged_nano = NANO_NONE;\n\t\t\t} else if (flag[0] == 'V' || flag[0] == 'v') {\n\t\t\t\tif (flag[1] == '1') {\n\t\t\t\t\t_malloc_engaged_nano = NANO_V1;\n\t\t\t\t} else if (flag[1] == '2') {\n\t\t\t\t\t_malloc_engaged_nano = NANO_V2;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (_malloc_engaged_nano) {\n\t\t// The maximum number of nano magazines can be set either via a\n\t\t// boot argument or from the environment. Get the boot argument value\n\t\t// here and store it. We can't bounds check it until we have phys_ncpus,\n\t\t// which happens later in nano_common_configure(), along with handling\n\t\t// of the environment value setting.\n\t\tchar value_buf[256];\n\t\tconst char *flag = malloc_common_value_for_key_copy(bootargs,\n\t\t\t\tnano_max_magazines_boot_arg, value_buf, sizeof(value_buf));\n\t\tif (flag) {\n\t\t\tconst char *endp;\n\t\t\tlong value = malloc_common_convert_to_long(flag, &endp);\n\t\t\tif (!*endp && value >= 0) {\n\t\t\t\tnano_common_max_magazines = (unsigned int)value;\n\t\t\t} else {\n\t\t\t\tmalloc_report(ASL_LEVEL_ERR,\n\t\t\t\t\t\"malloc_nano_max_magazines must be positive - ignored.\\n\");\n\t\t\t}\n\t\t}\n\t}\n\n\tswitch (_malloc_engaged_nano) {\n\tcase NANO_V1:\n\t\tnano_init(envp, apple, bootargs);\n\t\tbreak;\n\tcase NANO_V2:\n\t\tnanov2_init(envp, apple, bootargs);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n// Second phase of initialization, called from _malloc_initialize(). Used for\n// code that depends on state set in _malloc_initialize(), such as the\n// number of physical CPUs.\nvoid\nnano_common_configure(void)\n{\n\t// Set nano_common_max_magazines. An initial (unvalidated) value may have\n\t// been set from the boot args.\n\tunsigned int magazines = nano_common_max_magazines > 0 ?\n\t\t\tnano_common_max_magazines : phys_ncpus;\n\n\t// Environment variable overrides boot arg, unless it's not valid.\n\tconst char *flag = getenv(\"MallocNanoMaxMagazines\");\n\tif (flag) {\n\t\tint value = (int)strtol(flag, NULL, 0);\n\t\tif (value < 0) {\n\t\t\tmalloc_report(ASL_LEVEL_ERR,\n\t\t\t\t\t\"MallocNanoMaxMagazines must be positive - ignored.\\n\");\n\t\t} else {\n\t\t\tmagazines = value;\n\t\t}\n\t}\n\n\tif (magazines == 0) {\n\t\tmagazines = phys_ncpus;\n\t} else if (magazines > phys_ncpus) {\n\t\tmagazines = phys_ncpus;\n\t\tmalloc_report(ASL_LEVEL_ERR,\n\t\t\t\t\"Nano maximum magazines limited to number of physical \"\n\t\t\t\t\"CPUs [%d]\\n\", phys_ncpus);\n\t}\n\tnano_common_max_magazines = magazines;\n\tif (flag) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"Nano maximum magazines set to %d\\n\",\n\t\t\t\t\t   nano_common_max_magazines);\n\t}\n\tnano_common_cpu_number_override_set();\n\n\tswitch (_malloc_engaged_nano) {\n\tcase NANO_V1:\n\t\tnano_configure();\n\t\tbreak;\n\tcase NANO_V2:\n\t\tnanov2_configure();\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n#pragma mark -\n#pragma mark VM Helper Functions\n\nvoid *\nnano_common_allocate_based_pages(size_t size, unsigned char align,\n\t\tunsigned debug_flags, int vm_page_label, void *base_addr)\n{\n\tmach_vm_address_t vm_addr;\n\tuintptr_t addr;\n\tmach_vm_size_t allocation_size = round_page(size);\n\tmach_vm_offset_t allocation_mask = ((mach_vm_offset_t)1 << align) - 1;\n\tint alloc_flags = VM_FLAGS_ANYWHERE | VM_MAKE_TAG(vm_page_label);\n\tkern_return_t kr;\n\n\tif (!allocation_size) {\n\t\tallocation_size = vm_page_size;\n\t}\n\tif (allocation_size < size) { // size_t arithmetic wrapped!\n\t\treturn NULL;\n\t}\n\n\tvm_addr = round_page((mach_vm_address_t)base_addr);\n\tif (!vm_addr) {\n\t\tvm_addr = vm_page_size;\n\t}\n\tkr = mach_vm_map(mach_task_self(), &vm_addr, allocation_size,\n\t\t\tallocation_mask, alloc_flags, MEMORY_OBJECT_NULL, 0, FALSE,\n\t\t\tVM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);\n\tif (kr) {\n\t\tmalloc_zone_error(debug_flags, false, \"*** can't allocate pages: \"\n\t\t\t\t\"mach_vm_map(size=%lu) failed (error code=%d)\\n\", size, kr);\n\t\treturn NULL;\n\t}\n\taddr = (uintptr_t)vm_addr;\n\n\treturn (void *)addr;\n}\n\n// Allocates virtual address from a given address for a given size. Succeeds\n// (and returns TRUE) only if we get exactly the range of addresses that we\n// asked for.\nboolean_t\nnano_common_allocate_vm_space(mach_vm_address_t base, mach_vm_size_t size)\n{\n\tmach_vm_address_t vm_addr = base;\n\tkern_return_t kr = mach_vm_map(mach_task_self(), &vm_addr, size, 0,\n\t\tVM_MAKE_TAG(VM_MEMORY_MALLOC_NANO), MEMORY_OBJECT_NULL, 0, FALSE,\n\t\tVM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);\n\t\n\tif (kr != KERN_SUCCESS || vm_addr != base) {\n\t\t// Failed or we got allocated somewhere else.\n\t\tif (!kr) {\n\t\t\tmach_vm_deallocate(mach_task_self(), vm_addr, size);\n\t\t}\n\t\treturn FALSE;\n\t}\n\treturn TRUE;\n}\n\nvoid\nnano_common_deallocate_pages(void *addr, size_t size, unsigned debug_flags)\n{\n\tmach_vm_address_t vm_addr = (mach_vm_address_t)addr;\n\tmach_vm_size_t allocation_size = size;\n\tkern_return_t kr;\n\n\tkr = mach_vm_deallocate(mach_task_self(), vm_addr, allocation_size);\n\tif (kr) {\n\t\tmalloc_zone_error(debug_flags, false, \"Can't deallocate_pages at %p\\n\",\n\t\t\t\taddr);\n\t}\n}\n\n#pragma mark -\n#pragma mark Introspection Helper Functions\n\nkern_return_t\nnano_common_default_reader(task_t task, vm_address_t address, vm_size_t size,\n\t\tvoid **ptr)\n{\n\t*ptr = (void *)address;\n\treturn 0;\n}\n\n#pragma mark -\n#pragma mark Utility functions\n\nvoid\nnano_common_cpu_number_override_set()\n{\n\t// This facilitates a shortcut in nanov2_get_allocation_block_index() --\n\t// if nano_common_max_magazines_is_ncpu is true, we can also assume that\n\t// _os_cpu_number_override == -1 (i.e. we are not in malloc_replay).\n\tnano_common_max_magazines_is_ncpu = _os_cpu_number_override == -1 &&\n\t\t\tnano_common_max_magazines == phys_ncpus;\n}\n\n#endif // CONFIG_NANOZONE\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/nano_malloc_common.h",
    "content": "/*\n * Copyright (c) 2018 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __NANO_MALLOC_COMMON_H\n#define __NANO_MALLOC_COMMON_H\n\n// Definitions that are common to Nano V1 and Nano V2.\n#if TARGET_OS_OSX || TARGET_OS_SIMULATOR\n#define NANO_PREALLOCATE_BAND_VM 0\n#else // TARGET_OS_OSX || TARGET_OS_SIMULATOR\n#define NANO_PREALLOCATE_BAND_VM 1 // pre-allocate reserved vm range\n#endif // TARGET_OS_OSX || TARGET_OS_SIMULATOR\n\ntypedef enum {\n\tNANO_NONE\t= 0,\n\tNANO_V1 \t= 1,\n\tNANO_V2\t\t= 2,\n} nano_version_t;\n\n// Nano malloc enabled flag\nMALLOC_NOEXPORT\nextern nano_version_t _malloc_engaged_nano;\n\n// The maximum number of per-CPU allocation regions to use for Nano.\nMALLOC_NOEXPORT\nextern unsigned int nano_common_max_magazines;\n\nMALLOC_NOEXPORT\nextern boolean_t nano_common_max_magazines_is_ncpu;\n\nMALLOC_NOEXPORT\nvoid\nnano_common_cpu_number_override_set(void);\n\nMALLOC_NOEXPORT\nvoid\nnano_common_init(const char *envp[], const char *apple[], const char *bootargs);\n\nMALLOC_NOEXPORT\nvoid\nnano_common_configure(void);\n\nMALLOC_NOEXPORT\nvoid *\nnano_common_allocate_based_pages(size_t size, unsigned char align,\n\t\tunsigned debug_flags, int vm_page_label, void *base_addr);\n\nMALLOC_NOEXPORT\nboolean_t\nnano_common_allocate_vm_space(mach_vm_address_t base, mach_vm_size_t size);\n\nMALLOC_NOEXPORT\nvoid\nnano_common_deallocate_pages(void *addr, size_t size, unsigned debug_flags);\n\nMALLOC_NOEXPORT\nkern_return_t\nnano_common_default_reader(task_t task, vm_address_t address, vm_size_t size,\n\t\tvoid **ptr);\n\n#endif // __NANO_MALLOC_COMMON_H\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/nano_zone.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n\n#ifndef __NANO_ZONE_H\n#define __NANO_ZONE_H\n\n#if CONFIG_NANOZONE\n\n/*********************\tDEFINITIONS\t************************/\n\n#define MAX_RECORDER_BUFFER\t\t256\n\n/*************          nanozone address field layout        ******************/\n\n#if defined(__x86_64)\n#define NANO_MAG_BITS\t\t\t6\n#define NANO_BAND_BITS\t\t\t17\n#define NANO_SLOT_BITS\t\t\t4\n#define NANO_OFFSET_BITS\t\t17\n\n#else\n#error Unknown Architecture\n#endif\n\n// clang-format really dislikes the bitfields here\n// clang-format off\n#if defined(__BIG_ENDIAN__)\nstruct nano_blk_addr_s {\n    uint64_t\n\tnano_signature:NANOZONE_SIGNATURE_BITS,\t// the address range devoted to us.\n\tnano_mag_index:NANO_MAG_BITS,\t\t// the core that allocated this block\n\tnano_band:NANO_BAND_BITS,\n\tnano_slot:NANO_SLOT_BITS,\t\t// bucket of homogenous quanta-multiple blocks\n\tnano_offset:NANO_OFFSET_BITS;\t\t// locates the block\n};\n#else\n// least significant bits declared first\nstruct nano_blk_addr_s {\n    uint64_t\n\tnano_offset:NANO_OFFSET_BITS,\t\t// locates the block\n\tnano_slot:NANO_SLOT_BITS,\t\t// bucket of homogenous quanta-multiple blocks\n\tnano_band:NANO_BAND_BITS,\n\tnano_mag_index:NANO_MAG_BITS,\t\t// the core that allocated this block\n\tnano_signature:NANOZONE_SIGNATURE_BITS;\t// the address range devoted to us.\n};\n#endif\n// clang-format on\n\ntypedef union  {\n    uint64_t\t\t\taddr;\n    struct nano_blk_addr_s\tfields;\n} nano_blk_addr_t;\n\n#define SLOT_IN_BAND_SIZE \t(1 << NANO_OFFSET_BITS)\n#define SLOT_KEY_LIMIT \t\t(1 << NANO_SLOT_BITS) /* Must track nano_slot width */\n#define BAND_SIZE \t\t(1 << (NANO_SLOT_BITS + NANO_OFFSET_BITS)) /*  == Number of bytes covered by a page table entry */\n#define NANO_MAG_SIZE \t\t(1 << NANO_MAG_BITS)\n#define NANO_SLOT_SIZE \t\t(1 << NANO_SLOT_BITS)\n\n#ifdef __INTERNAL_H\n\n/****************************** zone itself ***********************************/\n\n/*\n * Note that objects whose adddress are held in pointers here must be pursued\n * individually in the nano_in_use_enumeration() routines.\n */\n\ntypedef struct chained_block_s {\n    uintptr_t\t\t\tdouble_free_guard;\n    struct chained_block_s\t*next;\n} *chained_block_t;\n\ntypedef struct nano_meta_s {\n    OSQueueHead\t\t\tslot_LIFO MALLOC_NANO_CACHE_ALIGN;\n    unsigned int\t\tslot_madvised_log_page_count;\n    volatile uintptr_t\t\tslot_current_base_addr;\n    volatile uintptr_t\t\tslot_limit_addr;\n    volatile size_t\t\tslot_objects_mapped;\n    volatile size_t\t\tslot_objects_skipped;\n    bitarray_t\t\t\tslot_madvised_pages;\n    // position on cache line distinct from that of slot_LIFO\n    volatile uintptr_t\t\tslot_bump_addr MALLOC_NANO_CACHE_ALIGN;\n    volatile boolean_t\t\tslot_exhausted;\n    unsigned int\t\tslot_bytes;\n    unsigned int\t\tslot_objects;\n} *nano_meta_admin_t;\n\n// vm_allocate()'d, so page-aligned to begin with.\ntypedef struct nanozone_s {\n    // first page will be given read-only protection\n    malloc_zone_t\t\tbasic_zone;\n    uint8_t\t\t\tpad[PAGE_MAX_SIZE - sizeof(malloc_zone_t)];\n\n    // remainder of structure is R/W (contains no function pointers)\n    // page-aligned\n    // max: NANO_MAG_SIZE cores x NANO_SLOT_SIZE slots for nano blocks {16 .. 256}\n    struct nano_meta_s\t\tmeta_data[NANO_MAG_SIZE][NANO_SLOT_SIZE];\n    _malloc_lock_s\t\t\tband_resupply_lock[NANO_MAG_SIZE];\n    uintptr_t           band_max_mapped_baseaddr[NANO_MAG_SIZE];\n    size_t\t\t\tcore_mapped_size[NANO_MAG_SIZE];\n\n    unsigned\t\t\tdebug_flags;\n\n    /* security cookie */\n    uintptr_t\t\t\tcookie;\n\n    /*\n     * The nano zone constructed by create_nano_zone() would like to hand off tiny, small, and large\n     * allocations to the default scalable zone. Record the latter as the \"helper\" zone here.\n     */\n    malloc_zone_t\t\t*helper_zone;\n} nanozone_t;\n\n#define NANOZONE_PAGED_SIZE\t((sizeof(nanozone_t) + vm_page_size - 1) & ~ (vm_page_size - 1))\n\n#endif // __INTERNAL_H\n\n#endif // CONFIG_NANOZONE\n\n#endif // __NANO_ZONE_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/nano_zone_common.h",
    "content": "/*\n * Copyright (c) 2018 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n \n#ifndef __NANO_ZONE_COMMON_H\n#define __NANO_ZONE_COMMON_H\n\n#define NANO_MAX_SIZE\t\t\t256 /* Buckets sized {16, 32, 48, ..., 256} */\n#define SHIFT_NANO_QUANTUM\t\t4\n#define NANO_REGIME_QUANTA_SIZE\t(1 << SHIFT_NANO_QUANTUM)\t// 16\n#define NANO_QUANTA_MASK\t\t(NANO_REGIME_QUANTA_SIZE - 1)\n#define NANO_SIZE_CLASSES\t\t(NANO_MAX_SIZE/NANO_REGIME_QUANTA_SIZE)\n\n#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\n// Nanozone follows the shared region.\n#define SHIFT_NANO_SIGNATURE\t29\n#define NANOZONE_SIGNATURE_BITS\t35\n#define NANOZONE_BASE_REGION_ADDRESS (SHARED_REGION_BASE + SHARED_REGION_SIZE)\n#define NANOZONE_SIGNATURE (NANOZONE_BASE_REGION_ADDRESS >> SHIFT_NANO_SIGNATURE)\n\n#else // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\n#define SHIFT_NANO_SIGNATURE\t44\n#define NANOZONE_SIGNATURE_BITS\t20\n#define NANOZONE_SIGNATURE\t\t0x6ULL\n#define NANOZONE_BASE_REGION_ADDRESS (NANOZONE_SIGNATURE << SHIFT_NANO_SIGNATURE)\n\n#endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\nstatic MALLOC_INLINE size_t\n_nano_common_good_size(size_t size)\n{\n\treturn (size <= NANO_REGIME_QUANTA_SIZE) ? NANO_REGIME_QUANTA_SIZE\n\t\t: (((size + NANO_REGIME_QUANTA_SIZE - 1) >> SHIFT_NANO_QUANTUM) << SHIFT_NANO_QUANTUM);\n}\n\n#endif // __NANO_ZONE_COMMON_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/nanov2_malloc.c",
    "content": "/*\n * Copyright (c) 2018 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n#include \"resolver.h\"\n#include \"internal.h\"\n\n#if CONFIG_NANOZONE\n\n#pragma mark -\n#pragma mark Forward Declarations\n\n#if OS_VARIANT_NOTRESOLVED\nstatic void nanov2_statistics(nanozonev2_t *nanozone, malloc_statistics_t *stats);\n#endif // OS_VARIANT_NOTRESOLVED\n\n#pragma mark -\n#pragma mark Externals for resolved functions\n\nextern void *nanov2_allocate(nanozonev2_t *nanozone, size_t rounded_size,\n\t\tboolean_t clear);\nextern void nanov2_free_to_block(nanozonev2_t *nanozone, void *ptr,\n\t\tnanov2_size_class_t size_class);\nextern boolean_t nanov2_madvise_block(nanozonev2_t *nanozone,\n\t\tnanov2_block_meta_t *block_metap, nanov2_block_t *blockp,\n\t\tnanov2_size_class_t size_class);\nextern size_t nanov2_pointer_size(nanozonev2_t *nanozone, void *ptr,\n\t\tboolean_t allow_inner);\nextern size_t nanov2_pressure_relief(nanozonev2_t *nanozone, size_t goal);\n\n#if OS_VARIANT_RESOLVED\nextern boolean_t nanov2_allocate_new_region(nanozonev2_t *nanozone);\n#endif // OS_VARIANT_RESOLVED\n\n#pragma mark -\n#pragma mark Global Allocator State\n\n// -- Block scanning\ntypedef enum {\n\tNANO_SCAN_FIRST_FIT = 0,\n\tNANO_SCAN_CAPACITY_BASED,\n} nanov2_block_scan_policy_t;\n\n// Minimum occupancy percentage for an ideal block.\n#define DEFAULT_SCAN_MIN_CAPACITY 20\n\n// Maximum occupancy percentage for an ideal block.\n#define DEFAULT_SCAN_MAX_CAPACITY 80\n\n// Maximum number of blocks to scan while looking for a best fit once a\n// candidate block has been found. Value 0 means no limit.\n#define DEFAULT_SCAN_LIMIT 10\n\n// -- Madvise policy\ntypedef enum {\n\tNANO_MADVISE_IMMEDIATE = 0,\n\tNANO_MADVISE_WARNING_PRESSURE,\n\tNANO_MADVISE_CRITICAL_PRESSURE,\n} nanov2_madvise_policy_t;\n\ntypedef struct nanov2_policy_config_s {\n\t// Determines the algorithm for scanning for the next allocation block.\n\t// Used in conjunction with nanov2_block_scan_capacity_min,\n\t// nanov2_block_scan_capacity_max and nanov2_block_scan_limit. Set from the\n\t// MallocNanoScanPolicy environment variable.\n\tnanov2_block_scan_policy_t block_scan_policy;\n\n\t// Minimum occupancy percentage for an ideal block.\n\tint block_scan_min_capacity;\n\n\t// Maximum occupancy percentage for an ideal block.\n\tint block_scan_max_capacity;\n\n\t// Maximum number of blocks to scan while looking for a best fit once a\n\t// candidate block has been found. Value 0 means no limit.\n\tint block_scan_limit;\n\n\t// Bitmask for size classes that are only allowed a single arena. Set from\n\t// the MallocNanoSingleArena environment variable.\n\tuint16_t single_arena_size_classes;\n\n\t// Madvise policy. Set from the MallocNanoMadvisePolicy environment variable\n\tnanov2_madvise_policy_t madvise_policy;\n} nanov2_policy_config_t;\n\n#if OS_VARIANT_NOTRESOLVED\n\n// Madvise policy. Set from the MallocNanoMadvisePolicy environment variable.\nnanov2_madvise_policy_t nanov2_madvise_policy;\n\nnanov2_policy_config_t nanov2_policy_config = {\n\t.block_scan_policy = NANO_SCAN_CAPACITY_BASED,\n\t.block_scan_min_capacity = DEFAULT_SCAN_MIN_CAPACITY,\n\t.block_scan_max_capacity = DEFAULT_SCAN_MAX_CAPACITY,\n\t.block_scan_limit = DEFAULT_SCAN_LIMIT,\n\t.single_arena_size_classes = 0,\n\t.madvise_policy = NANO_MADVISE_IMMEDIATE,\n};\n\n#else  // OS_VARIANT_NOTRESOLVED\n\nextern nanov2_policy_config_t nanov2_policy_config;\nextern nanov2_madvise_policy_t nanov2_madvise_policy;\n\n#endif // OS_VARIANT_NOTRESOLVED\n\n// BLOCKS_PER_UNIT must be a power of two to make it possible to get the size\n// class from a pointer reasonably cheaply. Do not change the value without\n// fixing the code that depends on it.\n#define BLOCKS_PER_UNIT_SHIFT 6\n#define BLOCKS_PER_UNIT (1 << BLOCKS_PER_UNIT_SHIFT)\n\n#if OS_VARIANT_NOTRESOLVED\n// Number of units of each size class in an arena. The numbers here must add\n// up to 64. One unit corresponds to BLOCKS_PER_UNIT blocks in the corresponding\n// size class, so 64 units maps to a total of 64 * 64 = 4096 blocks and each\n// block is 16K, making a total of 64MB, which is the size of an arena.\nint block_units_by_size_class[] = {\n\t2,\t// 16-byte allocations (less 1 for the metadata block)\n\t10,\t// 32-byte allocations\n\t11,\t// 48-byte allocations\n\t10,\t// 64-byte allocations\n\t5,\t// 80-byte allocations\n\t3,\t// 96-byte allocations\n\t3,\t// 112-byte allocations\n\t4,\t// 128-byte allocations\n\t3,\t// 144-byte allocations\n\t2,\t// 160-byte allocations\n\t2,\t// 176-byte allocations\n\t2,\t// 192-byte allocations\n\t2,\t// 208-byte allocations\n\t2,\t// 224-byte allocations\n\t1,\t// 240-byte allocations\n\t2,\t// 256-byte allocations\n};\n\nMALLOC_STATIC_ASSERT(\n\t\tsizeof(block_units_by_size_class)/sizeof(block_units_by_size_class[0])\n\t\t\t\t== NANO_SIZE_CLASSES,\n\t\t\"Size of block_units_by_size_class is incorrect\");\n\n// Total of the number of blocks in all size classes. Currently this is 64.\n#define TOTAL_BLOCK_UNITS (NANOV2_BLOCKS_PER_ARENA/BLOCKS_PER_UNIT)\n\n// Offsets to the first and last blocks for each size class within an arena, in\n// the logical address space. These tables are constructed from the values in\n// the block_units_by_size_class table.\nint first_block_offset_by_size_class[NANO_SIZE_CLASSES];\nint last_block_offset_by_size_class[NANO_SIZE_CLASSES];\n\n// Table mapping the part of a logical address that depends on size class to\n// the size class. Also built from the block_units_by_size_class table.\nint ptr_offset_to_size_class[TOTAL_BLOCK_UNITS];\n\n// Number of slots in a block, indexed by size class. Note that there is a small\n// amount of wastage in some size classes because the block size is not always\n// exactly divisible by the allocation size. The number of wasted bytes is shown\n// in parentheses in the comments below.\nconst int slots_by_size_class[] = {\n\tNANOV2_BLOCK_SIZE/(1 * NANO_REGIME_QUANTA_SIZE),  \t// 16 bytes: 1024\t(0)\n\tNANOV2_BLOCK_SIZE/(2 * NANO_REGIME_QUANTA_SIZE),\t// 32 bytes: 512\t(0)\n\tNANOV2_BLOCK_SIZE/(3 * NANO_REGIME_QUANTA_SIZE),\t// 48 bytes: 341\t(16)\n\tNANOV2_BLOCK_SIZE/(4 * NANO_REGIME_QUANTA_SIZE),\t// 64 bytes: 256\t(0)\n\tNANOV2_BLOCK_SIZE/(5 * NANO_REGIME_QUANTA_SIZE),\t// 80 bytes: 204\t(64)\n\tNANOV2_BLOCK_SIZE/(6 * NANO_REGIME_QUANTA_SIZE),\t// 96 bytes: 170\t(64)\n\tNANOV2_BLOCK_SIZE/(7 * NANO_REGIME_QUANTA_SIZE),\t// 112 bytes: 146\t(32)\n\tNANOV2_BLOCK_SIZE/(8 * NANO_REGIME_QUANTA_SIZE),\t// 128 bytes: 128\t(0)\n\tNANOV2_BLOCK_SIZE/(9 * NANO_REGIME_QUANTA_SIZE),\t// 144 bytes: 113\t(112)\n\tNANOV2_BLOCK_SIZE/(10 * NANO_REGIME_QUANTA_SIZE),\t// 160 bytes: 102\t(64)\n\tNANOV2_BLOCK_SIZE/(11 * NANO_REGIME_QUANTA_SIZE),\t// 176 bytes: 93\t(16)\n\tNANOV2_BLOCK_SIZE/(12 * NANO_REGIME_QUANTA_SIZE),\t// 192 bytes: 85\t(64)\n\tNANOV2_BLOCK_SIZE/(13 * NANO_REGIME_QUANTA_SIZE),\t// 208 bytes: 78\t(160)\n\tNANOV2_BLOCK_SIZE/(14 * NANO_REGIME_QUANTA_SIZE),\t// 224 bytes: 73\t(32)\n\tNANOV2_BLOCK_SIZE/(15 * NANO_REGIME_QUANTA_SIZE),\t// 240 bytes: 68\t(64)\n\tNANOV2_BLOCK_SIZE/(16 * NANO_REGIME_QUANTA_SIZE),\t// 256 bytes: 64\t(0)\n};\n#else // OS_VARIANT_NOTRESOLVED\n\nextern int block_units_by_size_class[];\nextern int ptr_offset_to_size_class[];\nextern int first_block_offset_by_size_class[];\nextern int last_block_offset_by_size_class[];\nextern const int slots_by_size_class[];\n\n#endif // OS_VARIANT_NOTRESOLVED\n\n#pragma mark -\n#pragma mark Conversion and Mapping Inlines\n\n// nanov2_block_index_to_meta_index() and nanov2_meta_index_to_block_index()\n// map between the index of a block in its arena and the index of the meta data\n// header for that block in the metadata block. The mapping is not direct\n// to avoid false sharing caused by CPUs that are using adjacent blocks\n// writing to what would otherwise be adjacent meta data headers. The effect of\n// these functions is to separate the meta data headers for adjacent blocks by\n// at least the size of a cache line (assumed to be 64 bytes).\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_meta_index_t\nnanov2_block_index_to_meta_index(nanov2_block_index_t block_index)\n{\n\treturn ((block_index >> 6) | (block_index << 6)) & 0xFFF;\n}\n\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_block_index_t\nnanov2_meta_index_to_block_index(nanov2_meta_index_t block_meta_index)\n{\n\treturn ((block_meta_index >> 6) | (block_meta_index << 6)) & 0xFFF;\n}\n\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_meta_index_t\nnanov2_metablock_meta_index(nanozonev2_t *nanozone)\n{\n\treturn nanov2_block_index_to_meta_index((nanov2_block_index_t)\n\t\t\tnanozone->aslr_cookie);\n}\n\n// Given a block metadata pointer, returns whether the block is active (that is,\n// it is being used for allocations, it has allocations that have not been freed,\n// or is waiting to be madvised).\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE boolean_t\nnanov2_is_block_active(nanov2_block_meta_t block_meta)\n{\n\treturn block_meta.next_slot != SLOT_NULL\n\t\t\t&& block_meta.next_slot != SLOT_MADVISING\n\t\t\t&& block_meta.next_slot != SLOT_MADVISED;\n}\n\n#if OS_VARIANT_RESOLVED\n// Given a block metadata pointer, returns whether an allocation could be\n// attempted from it. Allocations are not allowed from blocks that have not yet\n// been used (since such a block has not been assigned), is full or has been\n// madvised.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE boolean_t\nnanov2_can_allocate_from_block(nanov2_block_meta_t block_meta)\n{\n\treturn block_meta.in_use && block_meta.next_slot != SLOT_FULL;\n}\n\n// Given a pointer, returns whether it has the correct signature to be a\n// Nano V2 address.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE boolean_t\nnanov2_has_valid_signature(void *ptr)\n{\n\treturn (((uintptr_t)ptr) >> SHIFT_NANO_SIGNATURE) == NANOZONE_SIGNATURE;\n}\n#endif // OS_VARIANT_RESOLVED\n\n// Converts a Nano V2 logical address to the corresponding real address.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE void *\nnanov2_logical_address_to_ptr(nanozonev2_t *nanozone, void *laddr)\n{\n\treturn (void *)(((uintptr_t)laddr) ^ nanozone->aslr_cookie_aligned);\n}\n\n// Gets the maximum allocation size for a given size class.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE int\nnanov2_size_from_size_class(nanov2_size_class_t size_class)\n{\n\treturn (size_class + 1) * NANO_REGIME_QUANTA_SIZE;\n}\n\n#if OS_VARIANT_RESOLVED\n// Given an allocation size, returns the corresponding size class. It is the\n// responsibility of the caller to ensure that the size is valid. Returned\n// value is zero-based.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_size_class_t\nnanov2_size_class_from_size(size_t size)\n{\n\treturn (nanov2_size_class_t)howmany(size, NANO_REGIME_QUANTA_SIZE) - 1;\n}\n#endif // OS_VARIANT_RESOLVED\n\n#if OS_VARIANT_RESOLVED\n// Given a pointer that is assumed to be in the Nano zone, returns the address\n// of its containing block. Works for both real and logical pointers and returns\n// a pointer of the same type.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_block_t *\nnanov2_block_address_for_ptr(void *ptr)\n{\n\treturn (void *)(((uintptr_t)ptr) & NANOV2_BLOCK_ADDRESS_MASK);\n}\n#endif // OS_VARIANT_RESOLVED\n\n// Given a pointer that is assumed to be in the Nano zone, returns the address\n// of its containing arena. Works for both real and logical pointers.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_arena_t *\nnanov2_arena_address_for_ptr(void *ptr)\n{\n\treturn (void *)(((uintptr_t)ptr) & NANOV2_ARENA_ADDRESS_MASK);\n}\n\n#if OS_VARIANT_RESOLVED\n// Given a pointer that is assumed to be in the Nano zone, returns the address\n// of its containing region. Works for both real and logical pointers.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_region_t *\nnanov2_region_address_for_ptr(void *ptr)\n{\n\treturn (nanov2_region_t *)(((uintptr_t)ptr) & NANOV2_REGION_ADDRESS_MASK);\n}\n#endif // OS_VARIANT_RESOLVED\n\n// Given a pointer that is assumed to be in the Nano zone, returns the real\n// address of its metadata block. Works for both real and logical pointers.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_arena_metablock_t *\nnanov2_metablock_address_for_ptr(nanozonev2_t *nanozone, void *ptr)\n{\n\t// The metadata block is the first logical block in the arena, so its\n\t// logical address is that of the arena. To get a real pointer, we map it\n\t// through nanov2_logical_address_to_ptr().\n\treturn (nanov2_arena_metablock_t *)nanov2_logical_address_to_ptr(nanozone,\n\t\t\tnanov2_arena_address_for_ptr(ptr));\n}\n\n#if OS_VARIANT_RESOLVED\n// Given a pointer to a block_metap_t for a block, returns a pointer to the\n// block itself.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_block_t *\nnanov2_block_address_from_meta_ptr(nanozonev2_t *nanozone,\n\t\tnanov2_block_meta_t *block_metap)\n{\n\tnanov2_block_t *meta_block = nanov2_block_address_for_ptr(block_metap);\n\tnanov2_arena_t *arena = nanov2_arena_address_for_ptr(block_metap);\n\n\t// Get the block's index and use that to get the address of the block.\n\tnanov2_meta_index_t meta_index =\n\t\t(nanov2_meta_index_t)(block_metap - (nanov2_block_meta_t *)meta_block);\n\tnanov2_block_index_t block_index = nanov2_meta_index_to_block_index(meta_index);\n\treturn &arena->blocks[block_index];\n}\n#endif // OS_VARIANT_RESOLVED\n\n// Given the index of a block_metap_t for a block, returns a pointer to the\n// block itself.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_block_t *\nnanov2_block_address_from_meta_index(nanozonev2_t *nanozone,\n\t\tnanov2_arena_t *arena, nanov2_meta_index_t meta_index)\n{\n\tnanov2_block_index_t block_index = nanov2_meta_index_to_block_index(meta_index);\n\treturn &arena->blocks[block_index];\n}\n\n// Given a pointer that is assumed to be in the nanozone, returns the index\n// of its containing block within its hosting arena. Works for both logical and\n// real pointers and returns an index in the corresponding address space.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_block_index_t\nnanov2_block_index_for_ptr(void *ptr)\n{\n\treturn (nanov2_block_index_t)(((uintptr_t)ptr) >> NANOV2_OFFSET_BITS)\n\t\t\t& ((1 << NANOV2_BLOCK_BITS) - 1);\n}\n\n#if OS_VARIANT_RESOLVED\n// Given a pointer that is assumed to be in the nanozone, returns a pointer to\n// the meta data for its containing block. Expects ptr be a real address.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_block_meta_t *\nnanov2_meta_ptr_for_ptr(nanozonev2_t *nanozone, void *ptr)\n{\n\tnanov2_arena_metablock_t *meta_block = nanov2_metablock_address_for_ptr(\n\t\t\tnanozone, ptr);\n\tnanov2_block_index_t block_index = nanov2_block_index_for_ptr(ptr);\n\tnanov2_meta_index_t meta_index = nanov2_block_index_to_meta_index(block_index);\n\treturn &meta_block->arena_block_meta[meta_index];\n}\n#endif // OS_VARIANT_RESOLVED\n\n// Given a region pointer, returns the address of the first arena in the region.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_arena_t *\nnanov2_first_arena_for_region(nanov2_region_t *region)\n{\n\t// The first arena is colocated with the region itself.\n\treturn (nanov2_arena_t *)region;\n}\n\n// Given a region pointer, returns a pointer to the arena after the last\n// active arena in the region.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_arena_t *\nnanov2_limit_arena_for_region(nanozonev2_t *nanozone, nanov2_region_t *region)\n{\n\t// The first arena is colocated with the region itself.\n\tnanov2_arena_t *limit_arena;\n\tif (region == nanozone->current_region_base) {\n\t\tlimit_arena = nanozone->current_region_next_arena;\n\t} else {\n\t\tlimit_arena = nanov2_first_arena_for_region(region + 1);\n\t}\n\treturn limit_arena;\n}\n\n// Given a region pointer, returns the address of the linkage structure for\n// that region. The linkage structure is stored in the first entry of the\n// metadata block of the first arena in the region.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_region_linkage_t *\nnanov2_region_linkage_for_region(nanozonev2_t *nanozone, nanov2_region_t *region)\n{\n\tnanov2_arena_metablock_t *first_metadata_block =\n\t\t\tnanov2_metablock_address_for_ptr(nanozone, region);\n\treturn (nanov2_region_linkage_t *)&first_metadata_block->arena_block_meta[\n\t\t\tnanov2_metablock_meta_index(nanozone)];\n}\n\n// Given a pointer to a region, returns a pointer to the region that follows it,\n// or NULL if there isn't one.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_region_t *\nnanov2_next_region_for_region(nanozonev2_t *nanozone, nanov2_region_t *region)\n{\n\tnanov2_region_linkage_t *linkage =\n\t\t\tnanov2_region_linkage_for_region(nanozone, region);\n\tint offset = linkage->next_region_offset;\n\treturn offset ? region + offset : NULL;\n}\n\n// Given the index of a slot in a block of a given size and the base address of\n// the block, returns a pointer to the start of the slot. This works for both\n// real and logical block pointers and returns a pointer of the same type.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE void *\nnanov2_slot_in_block_ptr(nanov2_block_t *block, nanov2_size_class_t size_class,\n\t\tint slot_index)\n{\n\treturn (void *)((uintptr_t)block +\n\t\t\tnanov2_size_from_size_class(size_class) * slot_index);\n}\n\n#if OS_VARIANT_RESOLVED\n// Given the base address of a block, the size class for the block and a pointer,\n// returns the index of the slot represented by the pointer. It is assumed that\n// the pointer is slot-aligned and is within the bounds of the block.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE int\nnanov2_slot_index_in_block(nanov2_block_t *block, nanov2_size_class_t size_class,\n\t\tvoid *ptr)\n{\n\treturn (int)((uintptr_t)ptr - (uintptr_t)block)/\n\t\t\t(nanov2_size_from_size_class(size_class));\n}\n#endif // OS_VARIANT_RESOLVED\n\n// Given a (real) pointer, gets the size class of its containing block. Assumes\n// that the pointer is in a valid region, arena and block.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_size_class_t\nnanov2_size_class_for_ptr(nanozonev2_t *nanozone, void *ptr)\n{\n\t// To get the size class, we need to convert the block number from\n\t// physical to logical, since the ptr_offset_to_size_class table is\n\t// indexed by logical block.\n\tnanov2_block_index_t block =\n\t\t\t(int)(nanov2_block_index_for_ptr(ptr) ^ nanozone->aslr_cookie);\n\treturn ptr_offset_to_size_class[block >> BLOCKS_PER_UNIT_SHIFT];\n}\n\n#if OS_VARIANT_NOTRESOLVED\n\n// Given a meta data index, gets the size class of the corresponding block.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_size_class_t\nnanov2_size_class_for_meta_index(nanozonev2_t *nanozone, nanov2_meta_index_t meta_index)\n{\n\t// To get the size class, we need to get the block index from meta index\n\t// and then convert it from real to logical, since the\n\t// ptr_offset_to_size_class table is indexed by logical block.\n\tnanov2_block_index_t block_index = nanov2_meta_index_to_block_index(meta_index);\n\tint logical_block_index = (int)(block_index ^ nanozone->aslr_cookie);\n\treturn ptr_offset_to_size_class[logical_block_index >> BLOCKS_PER_UNIT_SHIFT];\n}\n#endif // OS_VARIANT_NOTRESOLVED\n\n#if OS_VARIANT_RESOLVED\n// Given a size class and an arena, returns a pointer to the metadata for the\n// first block for that size class in the arena, ignoring the metadata block.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_block_meta_t *\nnanov2_first_block_for_size_class_in_arena(nanozonev2_t *nanozone,\n\t\tnanov2_size_class_t size_class, nanov2_arena_t *arena)\n{\n\tint block_offset = first_block_offset_by_size_class[size_class];\n\tnanov2_arena_metablock_t *meta_blockp =\n\t\t\tnanov2_metablock_address_for_ptr(nanozone, arena);\n\tnanov2_block_index_t block_index =\n\t\t\t(nanov2_block_index_t)(block_offset ^ nanozone->aslr_cookie);\n\tnanov2_meta_index_t meta_index = nanov2_block_index_to_meta_index(block_index);\n\treturn &meta_blockp->arena_block_meta[meta_index];\n}\n\n// Given a pointer to the metadata for a block in a given size class, returns\n// a pointer to the metadata for the next block, wrapping from the last block\n// to the first if necessary.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_block_meta_t *\nnanov2_next_block_for_size_class(nanozonev2_t *nanozone,\n\t\tnanov2_size_class_t size_class, nanov2_block_meta_t *meta_blockp,\n\t\tboolean_t *wrapped)\n{\n\t// To find the next block, get the index of the current block, which is in\n\t// the real address space, unscramble it to get a logical block number,\n\t// add 1 to it, wrapping if necessary, then scramble the result.\n\tnanov2_block_meta_t *base_meta_blockp =\n\t\t\t(nanov2_block_meta_t *)(((uintptr_t)meta_blockp) & (NANOV2_BLOCK_ADDRESS_MASK));\n\tnanov2_meta_index_t meta_index = (int)(meta_blockp - base_meta_blockp);\n\tnanov2_block_index_t block_index = nanov2_meta_index_to_block_index(meta_index);\n\tblock_index ^= nanozone->aslr_cookie;  // Unscramble\n\tint last_offset = last_block_offset_by_size_class[size_class];\n\tif (wrapped) *wrapped = block_index == last_offset;\n\tblock_index = block_index == last_offset ?\n\t\t\tfirst_block_offset_by_size_class[size_class] : block_index + 1;\n\tblock_index = (nanov2_block_index_t)(block_index ^ nanozone->aslr_cookie);\n\tmeta_index = nanov2_block_index_to_meta_index(block_index);\n\treturn &base_meta_blockp[meta_index];\n}\n\n// Given a pointer to the metadata for a block in a given size class, returns\n// a pointer to the metadata for the previous block, wrapping from the first\n// block to the last if necessary.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_block_meta_t *\nnanov2_previous_block_for_size_class(nanozonev2_t *nanozone,\n\t\tnanov2_size_class_t size_class, nanov2_block_meta_t *meta_blockp,\n\t\tboolean_t *wrapped)\n{\n\t// To find the previous block, get the index of the current block, which is\n\t// in the real address space, unscramble it to get a logical block number,\n\t// subtract 1 from it, wrapping if necessary, then scramble the result.\n\tnanov2_block_meta_t *base_meta_blockp =\n\t\t\t(nanov2_block_meta_t *)(((uintptr_t)meta_blockp) & (NANOV2_BLOCK_ADDRESS_MASK));\n\tnanov2_meta_index_t meta_index = (int)(meta_blockp - base_meta_blockp);\n\tnanov2_block_index_t block_index = nanov2_meta_index_to_block_index(meta_index);\n\tblock_index ^= nanozone->aslr_cookie;  // Unscramble\n\tint first_offset = first_block_offset_by_size_class[size_class];\n\tif (wrapped) *wrapped = block_index == first_offset;\n\tblock_index = block_index == first_offset ?\n\t\t\tlast_block_offset_by_size_class[size_class] : block_index - 1;\n\tblock_index = (nanov2_block_index_t)(block_index ^ nanozone->aslr_cookie);\n\tmeta_index = nanov2_block_index_to_meta_index(block_index);\n\treturn &base_meta_blockp[meta_index];\n}\n\n// Turns off the in-use bit in the meta data for a given block.\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE void\nnanov2_turn_off_in_use(nanov2_block_meta_t *block_metap)\n{\n\t// TODO: find a way to do this that is more efficient and readable.\n\tstatic nanov2_block_meta_t mask = {\n\t\t.in_use = 0,\n\t\t.next_slot = ~0,\n\t\t.free_count = ~0,\n\t\t.gen_count = ~0,\n\t};\n\tos_atomic_and((uint32_t *)block_metap, *(uint32_t *)&mask, relaxed);\n}\n\n#pragma mark -\n#pragma mark Policy Functions\n\n// Gets the index of the block in the zone's current_block array from which\n// allocations should be made. This function should be replaced to implement\n// a different strategy (e.g. for E- vs P-cores).\nstatic MALLOC_ALWAYS_INLINE MALLOC_INLINE int\nnanov2_get_allocation_block_index(void)\n{\n\tif (os_likely(nano_common_max_magazines_is_ncpu)) {\n\t\t// Default case is max magazines == physical number of CPUs, which\n\t\t// must be > _os_cpu_number() >> hyper_shift, so the modulo\n\t\t// operation is not required.\n\t\treturn _os_cpu_number() >> hyper_shift;\n\t}\n\tif (os_likely(_os_cpu_number_override == -1)) {\n\t\treturn (_os_cpu_number() >> hyper_shift) % nano_common_max_magazines;\n\t}\n\treturn (_os_cpu_number_override >> hyper_shift) % nano_common_max_magazines;\n}\n#endif // OS_VARIANT_RESOLVED\n\n#pragma mark -\n#pragma mark Allocator Initialization\n\n#if OS_VARIANT_NOTRESOLVED\n\nstatic const char madvise_policy_env[] = \"MallocNanoMadvisePolicy\";\nstatic const char madvise_policy_bootarg[] = \"nanov2_madvise_policy\";\nstatic const char madvise_immediate[] = \"immediate\";\nstatic const char madvise_warning[] = \"warning\";\nstatic const char madvise_critical[] = \"critical\";\n\nstatic const char single_arena_env[] = \"MallocNanoSingleArena\";\nstatic const char single_arena_bootarg[] = \"nanov2_single_arena\";\n\nstatic const char scan_policy_env[] = \"MallocNanoScanPolicy\";\nstatic const char scan_policy_bootarg[] = \"nanov2_scan_policy\";\n\nstatic const char size_class_blocks_env[] = \"MallocNanoSizeClassBlocks\";\nstatic const char size_class_blocks_bootarg[] = \"nanov2_size_class_blocks\";\n\n// Parse and set the madvise policy setting. If ptr is NULL, sets the default\n// policy.\nstatic void\nnanov2_set_madvise_policy(const char *name, const char *ptr)\n{\n\tnanov2_madvise_policy_t madvise_policy = NANO_MADVISE_IMMEDIATE;\n\tif (ptr) {\n\t\tif (!strncmp(ptr, madvise_immediate, sizeof(madvise_immediate) - 1)) {\n\t\t\tmadvise_policy = NANO_MADVISE_IMMEDIATE;\n\t\t} else if (!strncmp(ptr, madvise_warning, sizeof(madvise_warning) - 1)) {\n\t\t\tmadvise_policy = NANO_MADVISE_WARNING_PRESSURE;\n\t\t} else if (!strncmp(ptr, madvise_critical, sizeof(madvise_critical) - 1)) {\n\t\t\tmadvise_policy = NANO_MADVISE_CRITICAL_PRESSURE;\n\t\t} else {\n\t\t\tmalloc_report(ASL_LEVEL_ERR,\n\t\t\t\t\t\"%s value (%s) invalid - ignored.\\n\", name, ptr);\n\t\t}\n\t}\n\tnanov2_madvise_policy = madvise_policy;\n}\n\n// Parse and set the list of size classes that are allowed only one arena. If\n// ptr is NULL, no size classes are restricted to a single arena,\n// Format is a list of sizes separated by colons (e.g. 16:240). Each size must\n// be a multiple of NANO_REGIME_QUANTA_SIZE and must be between 16 and 256.\nstatic void\nnanov2_set_single_arena_size_classes(const char *name, const char *ptr)\n{\n\tuint16_t single_arena_size_classes = 0;\n\tif (ptr) {\n\t\tconst char *value = ptr;\n\t\tconst char *endp;\n\t\tboolean_t failed = FALSE;\n\t\twhile (*ptr) {\n\t\t\tlong size = malloc_common_convert_to_long(ptr, &endp);\n\t\t\tif (endp != ptr) {\n\t\t\t\tif (*endp && *endp != ':') {\n\t\t\t\t\tfailed = TRUE;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (size > NANO_MAX_SIZE || size < NANO_REGIME_QUANTA_SIZE ||\n\t\t\t\t\t\t(size % NANO_REGIME_QUANTA_SIZE) != 0) {\n\t\t\t\t\tfailed = TRUE;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tsingle_arena_size_classes |=\n\t\t\t\t\t\t1 << ((size/NANO_REGIME_QUANTA_SIZE) - 1);\n\t\t\t} else {\n\t\t\t\tfailed = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!*endp) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tptr = endp + 1;\n\t\t}\n\t\tif (failed) {\n\t\t\tmalloc_report(ASL_LEVEL_ERR,\n\t\t\t\t\t\"%s value (%s) invalid - ignored.\\n\", name, value);\n\t\t\tsingle_arena_size_classes = 0;\n\t\t}\n\t}\n\tnanov2_policy_config.single_arena_size_classes = single_arena_size_classes;\n}\n\n// Parse and set the block scan policy setting. If ptr is NULL, the default\n// policy is used. Format is either \"firstfit\" or \"minXX:maxYY:limZZ\", where\n// XX, YY and ZZ are numbers, XX and YY must be between 0 and 100 and XX must\n// not be greater than YY. min, max and lim may appear in any order or may be\n// omitted to get default values.\nstatic void\nnanov2_set_block_scan_policy(const char *name, const char *ptr)\n{\n\tstatic char first_fit_key[] = \"firstfit\";\n\tstatic char min_key[] = \"min\";\n\tstatic char max_key[] = \"max\";\n\tstatic char lim_key[] = \"lim\";\n\n\tnanov2_block_scan_policy_t block_scan_policy = NANO_SCAN_CAPACITY_BASED;\n\tint scan_min_capacity = DEFAULT_SCAN_MIN_CAPACITY;\n\tint scan_max_capacity = DEFAULT_SCAN_MAX_CAPACITY;\n\tint scan_limit = DEFAULT_SCAN_LIMIT;\n\tconst char *endp;\n\tboolean_t failed = FALSE;\n\tboolean_t min_found = FALSE;\n\tboolean_t max_found = FALSE;\n\tboolean_t lim_found = FALSE;\n\tconst char *value = ptr;\n\t\n\tif (ptr) {\n\t\tif (!strcmp(ptr, first_fit_key)) {\n\t\t\tblock_scan_policy = NANO_SCAN_FIRST_FIT;\n\t\t} else {\n\t\t\twhile (!failed && ptr && *ptr) {\n\t\t\t\tif (!strncmp(ptr, min_key, sizeof(min_key) - 1) && !min_found) {\n\t\t\t\t\tmin_found = TRUE;\n\t\t\t\t\tptr += sizeof(min_key) - 1;\n\t\t\t\t\tlong value = malloc_common_convert_to_long(ptr, &endp);\n\t\t\t\t\tif (ptr != endp && value >= 0 && value <= 100) {\n\t\t\t\t\t\tscan_min_capacity = (int)value;\n\t\t\t\t\t\tptr = endp;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfailed = TRUE;\n\t\t\t\t\t}\n\t\t\t\t} else if (!strncmp(ptr, max_key, sizeof(max_key) - 1)\n\t\t\t\t\t\t&& !max_found) {\n\t\t\t\t\tmax_found = TRUE;\n\t\t\t\t\tptr += sizeof(max_key) - 1;\n\t\t\t\t\tlong value = malloc_common_convert_to_long(ptr, &endp);\n\t\t\t\t\tif (ptr != endp && value >= 0 && value <= 100) {\n\t\t\t\t\t\tscan_max_capacity = (int)value;\n\t\t\t\t\t\tptr = endp;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfailed = TRUE;\n\t\t\t\t\t}\n\t\t\t\t} else if (!strncmp(ptr, lim_key, sizeof(lim_key) - 1)\n\t\t\t\t\t\t&& !lim_found) {\n\t\t\t\t\tlim_found = TRUE;\n\t\t\t\t\tptr += sizeof(lim_key) - 1;\n\t\t\t\t\tlong value = malloc_common_convert_to_long(ptr, &endp);\n\t\t\t\t\tif (ptr != endp && value >= 0) {\n\t\t\t\t\t\tscan_limit = (int)value;\n\t\t\t\t\t\tptr = endp;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfailed = TRUE;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tfailed = TRUE;\n\t\t\t\t}\n\t\t\t\tif (*ptr) {\n\t\t\t\t\tif (*ptr == ':') {\n\t\t\t\t\t\tptr++;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfailed = TRUE;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!failed && scan_min_capacity > scan_max_capacity) {\n\t\t\t\tfailed = TRUE;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (!failed) {\n\t\tnanov2_policy_config.block_scan_policy = block_scan_policy;\n\t\tnanov2_policy_config.block_scan_min_capacity = scan_min_capacity;\n\t\tnanov2_policy_config.block_scan_max_capacity = scan_max_capacity;\n\t\tnanov2_policy_config.block_scan_limit = scan_limit;\n\t} else {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"%s value (%s) invalid - ignored.\\n\",\n\t\t\t\tname, value);\n\t}\n}\n\n// Configures the nanov2_blocks_by_size_class array. If ptr is not NULL and\n// *ptr is not empty, it is expected to be a list of 16 positive integers\n// separated by commas that sum to TOTAL_BLOCK_UNITS (which is currently 64).\n// For example, as an environment variable:\n// \tMallocNanoSizeClassBlocks=2,7,6,6,6,5,5,5,5,2,2,2,2,2,6,1\n// or as a boot argument:\n//  nanov2_size_class_blocks=2,7,6,6,6,5,5,5,5,2,2,2,2,2,6,1\nstatic void\nnanov2_set_blocks_by_size_class(const char *name, const char *ptr)\n{\n\tint new_total_block_units = 0;\n\tint new_blocks_by_size_class[NANO_SIZE_CLASSES];\n\tMALLOC_STATIC_ASSERT(\n\t\t\tsizeof(new_blocks_by_size_class) == sizeof(block_units_by_size_class),\n\t\t\t\"Size mismatch in nanov2_set_blocks_by_size_class()\");\n\tconst char *endp;\n\tconst char *sptr = ptr;\n\tfor (int i = 0; i < NANO_SIZE_CLASSES; i++) {\n\t\tint count = (int)malloc_common_convert_to_long(ptr, &endp);\n\t\tchar separator = i == NANO_SIZE_CLASSES - 1 ? '\\0' : ',';\n\t\tif (endp == ptr || *endp != separator || count > TOTAL_BLOCK_UNITS) {\n\t\t\tmalloc_report(ASL_LEVEL_ERR,\n\t\t\t\t\t\"%s value invalid: [%s] - ignored.\\n\", name, sptr);\n\t\t\treturn;\n\t\t}\n\t\tnew_blocks_by_size_class[i] = count;\n\t\tnew_total_block_units += count;\n\t\tptr = endp + 1;\n\t}\n\n\tif (new_total_block_units != TOTAL_BLOCK_UNITS) {\n\t\tmalloc_report(ASL_LEVEL_ERR,\n\t\t\t\t\"%s value invalid - values must sum to %d, not %d - ignored.\\n\",\n\t\t\t\tname, TOTAL_BLOCK_UNITS, new_total_block_units);\n\t} else {\n\t\tmemcpy(block_units_by_size_class, new_blocks_by_size_class,\n\t\t\t\tsizeof(block_units_by_size_class));\n\t}\n}\n\n// First stage initialization. Called during libSystem initialization.\n// Reads environment variables and boot arguments and sets the madvise policy,\n// single arena list and the block scan policy. Environment variables override\n// boot arguments.\nvoid\nnanov2_init(const char *envp[], const char *apple[], const char *bootargs)\n{\n\t// Get and process the boot args and environment variables.\n\tchar value_buf[256];\n\tconst char *value = _simple_getenv(envp, madvise_policy_env);\n\tconst char *name = madvise_policy_env;\n\tif (!value) {\n\t\tvalue = malloc_common_value_for_key(bootargs, madvise_policy_bootarg);\n\t\tif (value) {\n\t\t\tname = madvise_policy_bootarg;\n\t\t}\n\t}\n\tnanov2_set_madvise_policy(name, value);\n\n\tname = single_arena_env;\n\tvalue = _simple_getenv(envp, single_arena_env);\n\tif (!value) {\n\t\tvalue = malloc_common_value_for_key_copy(bootargs, single_arena_bootarg,\n\t\t\t\tvalue_buf, sizeof(value_buf));\n\t\tif (value) {\n\t\t\tname = single_arena_bootarg;\n\t\t}\n\t}\n\tnanov2_set_single_arena_size_classes(name, value);\n\n\tname = scan_policy_env;\n\tvalue = _simple_getenv(envp, scan_policy_env);\n\tif (!value) {\n\t\tvalue = malloc_common_value_for_key_copy(bootargs, scan_policy_bootarg,\n\t\t\t\tvalue_buf, sizeof(value_buf));\n\t\tif (value) {\n\t\t\tname = scan_policy_bootarg;\n\t\t}\n\t}\n\tnanov2_set_block_scan_policy(name, value);\n\n\tname = size_class_blocks_env;\n\tvalue = _simple_getenv(envp, size_class_blocks_env);\n\tif (!value) {\n\t\tvalue = malloc_common_value_for_key_copy(bootargs, size_class_blocks_bootarg,\n\t\t\t\tvalue_buf, sizeof(value_buf));\n\t\tif (value) {\n\t\t\tname = size_class_blocks_bootarg;\n\t\t}\n\t}\n\tif (value) {\n\t\tnanov2_set_blocks_by_size_class(name, value);\n\t}\n}\n\nstatic void\nnanov2_configure_once(void *context MALLOC_UNUSED)\n{\n\t// Check that the block_units_by_size_class table is consistent.\n\tint total_blocks = 0;\n\tfor (int i = 0; i < NANO_SIZE_CLASSES; i++) {\n\t\ttotal_blocks += block_units_by_size_class[i] * BLOCKS_PER_UNIT;\n\t}\n\tMALLOC_ASSERT(total_blocks == NANOV2_BLOCKS_PER_ARENA);\n\n\t// Build the first_block_offset_by_size_class and\n\t// last_block_offset_by_size_class tables. The first entry is special\n\t// because block 0 is reserved for the metadata block, so the first offset\n\t// is 1 and the number of blocks allocated is reduced by 1.\n\tint next_offset = 1;\n\tfirst_block_offset_by_size_class[0] = next_offset;\n\tnext_offset = block_units_by_size_class[0] * BLOCKS_PER_UNIT;\n\tlast_block_offset_by_size_class[0] = next_offset - 1;\n\n\tfor (int i = 1; i < NANO_SIZE_CLASSES; i++) {\n\t\tfirst_block_offset_by_size_class[i] = next_offset;\n\t\tnext_offset += block_units_by_size_class[i] * BLOCKS_PER_UNIT;\n\t\tlast_block_offset_by_size_class[i] = next_offset - 1;\n\t}\n\tMALLOC_ASSERT(next_offset == NANOV2_BLOCKS_PER_ARENA);\n\n\t// Construct the ptr_offset_to_size_class map, which maps the part of the\n\t// logical address that depends on size class to the corresponding size\n\t// class. This would be a simple mask operation if all size classes were of\n\t// equal size, but sadly they are not.\n\tint next_index = 0;\n\tfor (int i = 0; i < NANO_SIZE_CLASSES; i++) {\n\t\tint block_units = block_units_by_size_class[i];\n\t\tfor (int j = 0; j < block_units; j++) {\n\t\t\tptr_offset_to_size_class[next_index++] = i;\n\t\t}\n\t}\n\tMALLOC_ASSERT(next_index == NANOV2_BLOCKS_PER_ARENA/BLOCKS_PER_UNIT);\n}\n\nstatic os_once_t nanov2_config_predicate;\n\nvoid\nnanov2_configure(void)\n{\n\tos_once(&nanov2_config_predicate, NULL, nanov2_configure_once);\n}\n#endif // OS_VARIANT_NOTRESOLVED\n\n#pragma mark -\n#pragma mark Zone Functions\n\n#if OS_VARIANT_RESOLVED\n// Returns the allocation size for a pointer. Uses nanov2_pointer_size() to\n// determine whether the pointer is for a Nano V2 allocation and, if not,\n// delegates to the helper zone. Returns 0 if the pointer is not to memory\n// allocated by Nano V2 or attributable to the helper zone.\nsize_t\nnanov2_size(nanozonev2_t *nanozone, const void *ptr)\n{\n\tsize_t size = nanov2_pointer_size(nanozone, (void *)ptr, FALSE);\n\treturn size ? size : nanozone->helper_zone->size(nanozone->helper_zone, ptr);\n}\n\nvoid *\nnanov2_malloc(nanozonev2_t *nanozone, size_t size)\n{\n\tsize_t rounded_size = _nano_common_good_size(size);\n\tif (rounded_size <= NANO_MAX_SIZE) {\n\t\tvoid *ptr = nanov2_allocate(nanozone, rounded_size, FALSE);\n\t\tif (ptr) {\n\t\t\tif (os_unlikely(size && (nanozone->debug_flags & MALLOC_DO_SCRIBBLE))) {\n\t\t\t\tmemset(ptr, SCRIBBLE_BYTE, size);\n\t\t\t}\n\t\t\treturn ptr;\n\t\t}\n\t}\n\n\t// If we reach this point, we couldn't allocate, so delegate to the\n\t// helper zone.\n\treturn nanozone->helper_zone->malloc(nanozone->helper_zone, size);\n}\n\nvoid\nnanov2_free_definite_size(nanozonev2_t *nanozone, void *ptr, size_t size)\n{\n\t// Check whether it's a Nano pointer and get the size. We should only get\n\t// here if it is and furthermore we already know that \"size\" is the actual\n\t// rounded size, so don't waste time rechecking that. This is just a\n\t// sanity check.\n\tif (ptr && nanov2_has_valid_signature(ptr)) {\n\t\tif (os_unlikely(nanozone->debug_flags & MALLOC_DO_SCRIBBLE)) {\n\t\t\tmemset(ptr, SCRABBLE_BYTE, size);\n\t\t}\n\t\tnanov2_free_to_block(nanozone, ptr, nanov2_size_class_from_size(size));\n\t\treturn;\n\t}\n\treturn nanozone->helper_zone->free_definite_size(nanozone->helper_zone, ptr,\n\t\t\tsize);\n}\n\nvoid\nnanov2_free(nanozonev2_t *nanozone, void *ptr)\n{\n\tif (ptr && nanov2_has_valid_signature(ptr)) {\n\t\t// Check whether it's a Nano pointer and get the size. If it's not\n\t\t// Nano, pass it to the helper zone.\n\t\tsize_t size = nanov2_pointer_size(nanozone, ptr, FALSE);\n\t\tif (size) {\n\t\t\tif (os_unlikely(nanozone->debug_flags & MALLOC_DO_SCRIBBLE)) {\n\t\t\t\tmemset(ptr, SCRABBLE_BYTE, size);\n\t\t\t}\n\t\t\tnanov2_free_to_block(nanozone, ptr, nanov2_size_class_from_size(size));\n\t\t\treturn;\n\t\t}\n\t}\n\treturn nanozone->helper_zone->free(nanozone->helper_zone, ptr);\n}\n\nvoid *\nnanov2_calloc(nanozonev2_t *nanozone, size_t num_items, size_t size)\n{\n\tsize_t total_bytes;\n\tif (calloc_get_size(num_items, size, 0, &total_bytes)) {\n\t\treturn NULL;\n\t}\n\tsize_t rounded_size = _nano_common_good_size(total_bytes);\n\tif (total_bytes <= NANO_MAX_SIZE) {\n\t\tvoid *ptr = nanov2_allocate(nanozone, rounded_size, TRUE);\n\t\tif (ptr) {\n\t\t\treturn ptr;\n\t\t}\n\t}\n\n\t// If we reach this point, we couldn't allocate, so delegate to the\n\t// helper zone.\n\treturn nanozone->helper_zone->calloc(nanozone->helper_zone, 1, total_bytes);\n}\n#endif // OS_VARIANT_RESOLVED\n\n#if OS_VARIANT_NOTRESOLVED\nstatic void *\nnanov2_valloc(nanozonev2_t *nanozone, size_t size)\n{\n\t// Always delegate this to the helper zone.\n\treturn nanozone->helper_zone->valloc(nanozone->helper_zone, size);\n}\n#endif // OS_VARIANT_NOTRESOLVED\n\n#if OS_VARIANT_RESOLVED\nvoid *\nnanov2_realloc(nanozonev2_t *nanozone, void *ptr, size_t new_size)\n{\n\t// If we are given a NULL pointer, just allocate memory of the requested\n\t// size.\n\tif (ptr == NULL) {\n\t\treturn nanov2_malloc(nanozone, new_size);\n\t}\n\n\tsize_t old_size = nanov2_pointer_size(nanozone, ptr, FALSE);\n\tif (!old_size) {\n\t\t// Not a Nano pointer - let the helper deal with it\n\t\treturn nanozone->helper_zone->realloc(nanozone->helper_zone, ptr, new_size);\n\t}\n\n\tvoid *new_ptr;\n\tif (new_size > NANO_MAX_SIZE) {\n\t\t// Too large for Nano. Try to allocate from the helper zone.\n\t\tnew_ptr = nanozone->helper_zone->malloc(nanozone->helper_zone, new_size);\n\t\tif (!new_ptr) {\n\t\t\t// Failed to allocate - leave the existing allocation alone.\n\t\t\treturn NULL;\n\t\t}\n\t} else if (!new_size) {\n\t\t// Resizing to zero. Free the existing memory and explicitly allocate\n\t\t// zero bytes.\n\t\tnanov2_free(nanozone, ptr);\n\t\treturn nanov2_malloc(nanozone, 0);\n\t} else {\n\t\tsize_t new_good_size = _nano_common_good_size(new_size);\n\t\tif (new_good_size > old_size || new_good_size <= old_size/2) {\n\t\t\t// Growing or shrinking to less than half size - we need to\n\t\t\t// reallocate.\n\t\t\tnew_ptr = nanov2_malloc(nanozone, new_good_size);\n\t\t\tif (!new_ptr) {\n\t\t\t\t// Failed to allocate - leave the existing allocation alone.\n\t\t\t\treturn NULL;\n\t\t\t}\n\t\t} else {\n\t\t\t// Same size or shrinking by less than half size. Keep the same\n\t\t\t// allocation and clear the area that's being released.\n\t\t\tif (new_size != old_size) {\n\t\t\t\tMALLOC_ASSERT(new_size < old_size);\n\t\t\t\tif (os_unlikely(nanozone->debug_flags & MALLOC_DO_SCRIBBLE)) {\n\t\t\t\t\tmemset(ptr + new_size, SCRABBLE_BYTE, old_size - new_size);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn ptr;\n\t\t}\n\t}\n\t\n\t// If we reach this point, we allocated new memory. Copy the existing\n\t// content to the new location and release the old allocation.\n\tMALLOC_ASSERT(new_ptr);\n\tmemcpy(new_ptr, ptr, MIN(old_size, new_size));\n\tnanov2_free(nanozone, ptr);\n\n\treturn new_ptr;\n}\n#endif // OS_VARIANT_RESOLVED\n\n#if OS_VARIANT_NOTRESOLVED\nstatic void\nnanov2_destroy(nanozonev2_t *nanozone)\n{\n\tnanozone->helper_zone->destroy(nanozone->helper_zone);\n\tnano_common_deallocate_pages((void *)nanozone, NANOZONEV2_ZONE_PAGED_SIZE,\n\t\t\tnanozone->debug_flags);\n}\n#endif // OS_VARIANT_NOTRESOLVED\n\n#if OS_VARIANT_RESOLVED\nboolean_t\nnanov2_claimed_address(nanozonev2_t *nanozone, void *ptr)\n{\n\treturn nanov2_pointer_size(nanozone, ptr, TRUE) != 0;\n}\n\nunsigned\nnanov2_batch_malloc(nanozonev2_t *nanozone, size_t size, void **results,\n\t\tunsigned count)\n{\n\tunsigned allocated = 0;\n\tsize_t rounded_size = _nano_common_good_size(size);\n\tif (rounded_size <= NANO_MAX_SIZE) {\n\t\twhile (allocated < count) {\n\t\t\tvoid *ptr = nanov2_allocate(nanozone, rounded_size, FALSE);\n\t\t\tif (!ptr) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t*results++ = ptr;\n\t\t\tallocated++;\n\t\t}\n\t\tif (allocated == count) {\n\t\t\t// Allocated everything.\n\t\t\treturn allocated;\n\t\t}\n\t}\n\n\t// We could not allocate everything. Let the helper zone do the rest.\n\treturn allocated + nanozone->helper_zone->batch_malloc(\n\t\t\tnanozone->helper_zone, size, results, count - allocated);\n}\n\nvoid\nnanov2_batch_free(nanozonev2_t *nanozone, void **to_be_freed, unsigned count)\n{\n\tif (count) {\n\t\twhile (count--) {\n\t\t\tvoid *ptr = to_be_freed[count];\n\t\t\tif (ptr) {\n\t\t\t\tnanov2_free(nanozone, ptr);\n\t\t\t}\n\t\t}\n\t}\n}\n#endif // OS_VARIANT_RESOLVED\n\n#if OS_VARIANT_NOTRESOLVED\nstatic void *\nnanov2_memalign(nanozonev2_t *nanozone, size_t alignment, size_t size)\n{\n\t// Always delegate this to the helper zone.\n\treturn nanozone->helper_zone->memalign(nanozone->helper_zone, alignment,\n\t\t\tsize);\n}\n#endif // OS_VARIANT_NOTRESOLVED\n\n#if OS_VARIANT_RESOLVED\n\nsize_t\nnanov2_pressure_relief(nanozonev2_t *nanozone, size_t goal)\n{\n\tif (nanov2_madvise_policy != NANO_MADVISE_WARNING_PRESSURE\n\t\t\t&& nanov2_madvise_policy != NANO_MADVISE_CRITICAL_PRESSURE) {\n\t\t// In the current implementation, we only get called on warning, so\n\t\t// act if the policy is either warning or critical. We would need to\n\t\t// add a new zone entry point to respond to critical.\n\t\treturn 0;\n\t}\n\tconst char *name = nanozone->basic_zone.zone_name;\n\tMAGMALLOC_PRESSURERELIEFBEGIN((void *)nanozone, name, (int)goal);\n\tMALLOC_TRACE(TRACE_nano_memory_pressure | DBG_FUNC_START,\n\t\t\t(uint64_t)nanozone, goal, 0, 0);\n\tsize_t total = 0;\n\n\t// Loop over all arenas madvising blocks that are marked as madvisable,\n\t// until we reach our goal.\n\tnanov2_region_t *region = nanozone->first_region_base;\n\tnanov2_meta_index_t metablock_meta_index = nanov2_metablock_meta_index(nanozone);\n\twhile (region) {\n\t\tnanov2_arena_t *arena = nanov2_first_arena_for_region(region);\n\t\tnanov2_arena_t *arena_after_region = nanov2_limit_arena_for_region(nanozone, region);\n\t\twhile (arena < arena_after_region) {\n\t\t\t// Scan all of the blocks in the arena, skipping the metadata block.\n\t\t\tnanov2_arena_metablock_t *meta_blockp =\n\t\t\t\t\tnanov2_metablock_address_for_ptr(nanozone, arena);\n\t\t\tnanov2_block_meta_t *block_metap = &meta_blockp->arena_block_meta[0];\n\n\t\t\t// We need to hold the zone madvise lock to madvise. We could take\n\t\t\t// it for the duration of this function, but that might hold up\n\t\t\t// ongoing allocation and free operations for too long. So just\n\t\t\t// lock and unlock for each arena.\n\t\t\t_malloc_lock_lock(&nanozone->madvise_lock);\n\t\t\tfor (nanov2_meta_index_t i = 0; i < NANOV2_BLOCKS_PER_ARENA;\n\t\t\t\t\ti++, block_metap++) {\n\t\t\t\tif (i != metablock_meta_index) {\n\t\t\t\t\tnanov2_block_meta_t meta = os_atomic_load(block_metap, relaxed);\n\t\t\t\t\tif (meta.next_slot == SLOT_CAN_MADVISE) {\n\t\t\t\t\t\tnanov2_block_t *blockp = nanov2_block_address_from_meta_index(\n\t\t\t\t\t\t\t\tnanozone, arena, i);\n\t\t\t\t\t\tif (nanov2_madvise_block(nanozone, block_metap,\n\t\t\t\t\t\t\t\tblockp, nanov2_size_class_for_ptr(nanozone, blockp))) {\n\t\t\t\t\t\t\ttotal += NANOV2_BLOCK_SIZE;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t_malloc_lock_unlock(&nanozone->madvise_lock);\n\t\t\tif (goal && total >= goal) {\n\t\t\t\tgoto done;\n\t\t\t}\n\t\t\tarena++;\n\t\t}\n\t\tregion = nanov2_next_region_for_region(nanozone, region);\n\t}\n\t\ndone:\n\tMAGMALLOC_PRESSURERELIEFEND((void *)nanozone, name, (int)goal, (int)total);\n\tMALLOC_TRACE(TRACE_nano_memory_pressure | DBG_FUNC_END,\n\t\t\t(uint64_t)nanozone, goal, total, 0);\n\n\treturn total;\n}\n#endif // OS_VARIANT_RESOLVED\n\n#pragma mark -\n#pragma mark Zone Introspection\n\n#if OS_VARIANT_NOTRESOLVED\n\n// NOTE: in the code that follows, address that we obtain from the Nano\n// structures are relative to the target process. They need to be translated\n// before they can be used to read the mapping in this process.\n\n#define NANOV2_ZONE_PTR_TO_MAPPED_PTR(type, zone_ptr, offset) \\\n\t\t(type)((mach_vm_address_t)zone_ptr - (mach_vm_offset_t)offset)\n#define NANOV2_MAPPED_PTR_TO_ZONE_PTR(type, mapped_ptr, offset) \\\n\t\t(type)((mach_vm_address_t)mapped_ptr + (mach_vm_offset_t)offset)\n\nstatic kern_return_t\nnanov2_ptr_in_use_enumerator(task_t task, void *context, unsigned type_mask,\n\t\tvm_address_t zone_address, memory_reader_t reader,\n\t\tvm_range_recorder_t recorder)\n{\n\t// Ensure that we have configured enough of the allocator to be able to\n\t// examine its data structures. In tools that do not directly use Nano, we\n\t// won't have done this yet. nanov2_configure() runs the initialization\n\t// only once.\n\tnanov2_configure();\n\n\t// Only MALLOC_PTR_IN_USE_RANGE_TYPE and MALLOC_PTR_REGION_RANGE_TYPE have\n\t// meaning for Nano. Anything else returns immediately.\n\tif (!(type_mask & (MALLOC_PTR_IN_USE_RANGE_TYPE|MALLOC_PTR_REGION_RANGE_TYPE))) {\n\t\treturn 0;\n\t}\n\n\t// Read the zone data.\n\tnanozonev2_t *nanozone;\n\tnanozonev2_t zone_copy;\n\tkern_return_t kr;\n\tbitarray_t slots;\n\n\tif (!reader) {\n\t\treader = nano_common_default_reader;\n\t}\n\n\tkr = reader(task, zone_address, sizeof(nanozonev2_t), (void **)&nanozone);\n\tif (kr) {\n\t\treturn kr;\n\t}\n\tboolean_t self_zone = (nanozonev2_t *)zone_address == nanozone;\n\tmemcpy(&zone_copy, nanozone, sizeof(zone_copy));\n\tnanozone = &zone_copy;\n\tnanov2_meta_index_t metablock_meta_index = nanov2_metablock_meta_index(nanozone);\n\n\t// Process the zone one region at a time. Report each in-use block as a\n\t// pointer range and each in-use slot as a pointer.\n\tnanov2_region_t *region = nanozone->first_region_base;\n\twhile (region) {\n\t\tmach_vm_address_t vm_addr = (mach_vm_address_t)NULL;\n\t\tkern_return_t kr = reader(task, (vm_address_t)region, NANOV2_REGION_SIZE, (void **)&vm_addr);\n\t\tif (kr) {\n\t\t\treturn kr;\n\t\t}\n\n\t\t// ptr_offset is the difference between an address in the target process\n\t\t// and its mapped address in this process.\n\t\tmach_vm_offset_t ptr_offset = (mach_vm_address_t)region - vm_addr;\n\t\tnanov2_arena_t *arena = nanov2_first_arena_for_region(region);\n\t\tnanov2_arena_t *limit_arena = nanov2_limit_arena_for_region(nanozone, region);\n\t\tvm_range_t ptr_range;\n\t\twhile (arena < limit_arena) {\n\t\t\t// Find the metadata block and process every entry, apart from the\n\t\t\t// one for the metadata block itself.\n\t\t\tnanov2_arena_metablock_t *arena_meta_blockp =\n\t\t\t\t\tNANOV2_ZONE_PTR_TO_MAPPED_PTR(nanov2_arena_metablock_t *,\n\t\t\t\t\tnanov2_metablock_address_for_ptr(nanozone, arena),\n\t\t\t\t\tptr_offset);\n\t\t\tnanov2_block_meta_t *block_metap = &arena_meta_blockp->arena_block_meta[0];\n\n\t\t\tfor (nanov2_meta_index_t i = 0; i < NANOV2_BLOCKS_PER_ARENA; i++, block_metap++) {\n\t\t\t\tif (i == metablock_meta_index) {\n\t\t\t\t\t// Skip the metadata block.\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tnanov2_block_meta_t meta = os_atomic_load(block_metap, relaxed);\n\t\t\t\tif (!nanov2_is_block_active(meta)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tnanov2_block_t *blockp = nanov2_block_address_from_meta_index(\n\t\t\t\t\t\tnanozone, arena, i);\n\t\t\t\tif (type_mask & MALLOC_PTR_REGION_RANGE_TYPE) {\n\t\t\t\t\t// Report this block as an in-use range.\n\t\t\t\t\tptr_range.address = (vm_address_t)blockp;\n\t\t\t\t\tptr_range.size = NANOV2_BLOCK_SIZE;\n\t\t\t\t\trecorder(task, context, MALLOC_PTR_REGION_RANGE_TYPE, &ptr_range, 1);\n\t\t\t\t}\n\t\t\t\tif (type_mask & MALLOC_PTR_IN_USE_RANGE_TYPE) {\n\t\t\t\t\t// Report all of the pointers in the block that are not on\n\t\t\t\t\t// the free list.\n\t\t\t\t\tnanov2_size_class_t size_class = nanov2_size_class_for_ptr(\n\t\t\t\t\t\t\tnanozone, blockp);\n\t\t\t\t\tint slot_size = nanov2_size_from_size_class(size_class);\n\t\t\t\t\tint slot_count = slots_by_size_class[size_class];\n\t\t\t\t\tvm_range_t ranges[NANOV2_MAX_SLOTS_PER_BLOCK];\n\t\t\t\t\tint range_count = 0;\n\t\t\t\t\tif (meta.next_slot == SLOT_BUMP || meta.next_slot == SLOT_FULL) {\n\t\t\t\t\t\t// Either the block is full or the freelist is empty. If\n\t\t\t\t\t\t// it's full, everything is in use. If the free list is\n\t\t\t\t\t\t// empty, everything up to slot_count - meta.free_count - 1\n\t\t\t\t\t\t// is in use.\n\t\t\t\t\t\trange_count = meta.next_slot == SLOT_BUMP ?\n\t\t\t\t\t\t\t\tslot_count - meta.free_count - 1 : slot_count;\n\t\t\t\t\t\tfor (int i = 0; i < range_count; i++) {\n\t\t\t\t\t\t\tranges[i].address = (vm_address_t)nanov2_slot_in_block_ptr(blockp, size_class, i);\n\t\t\t\t\t\t\tranges[i].size = slot_size;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// We need to scan the freelist to see what's in use.\n\t\t\t\t\t\tint log_size = 64 - __builtin_clzl(slot_count);\n\t\t\t\t\t\tif (self_zone) {\n\t\t\t\t\t\t\t// Don't allocate from ourselves!\n\t\t\t\t\t\t\tslots = nanozone->helper_zone->calloc(nanozone->helper_zone,\n\t\t\t\t\t\t\t\t\t1, bitarray_size(log_size));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tslots = bitarray_create(log_size);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (int i = 0; i < slot_count; i++) {\n\t\t\t\t\t\t\tbitarray_set(slots, log_size, i);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tint next_slot = meta.next_slot;\n\t\t\t\t\t\tint free_list_count = 0;\n\t\t\t\t\t\twhile (next_slot != SLOT_BUMP) {\n\t\t\t\t\t\t\tnext_slot--;   // meta.next_slot is 1-based.\n\t\t\t\t\t\t\tif (next_slot < 0 || next_slot >= slot_count ||\n\t\t\t\t\t\t\t\t\t!bitarray_get(slots, log_size, next_slot)) {\n\t\t\t\t\t\t\t\t// Out of range or already seen?? We may have\n\t\t\t\t\t\t\t\t// snapshotted the block while it was updating.\n\t\t\t\t\t\t\t\t// Don't go any further to avoid an infinite loop.\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbitarray_zap(slots, log_size, next_slot);\n\t\t\t\t\t\t\tvoid *ptr = nanov2_slot_in_block_ptr(blockp, size_class, next_slot);\n\t\t\t\t\t\t\tnanov2_free_slot_t *slotp = NANOV2_ZONE_PTR_TO_MAPPED_PTR(nanov2_free_slot_t *, ptr, ptr_offset);\n\t\t\t\t\t\t\tnext_slot = slotp->next_slot;\n\t\t\t\t\t\t\tfree_list_count++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Add a range for each slot that is not on the freelist,\n\t\t\t\t\t\t// unless that slot has never been allocated.\n\t\t\t\t\t\tint block_free_count = meta.free_count + 1; // actual free count.\n\t\t\t\t\t\tint in_use_count = slot_count - block_free_count;\n\t\t\t\t\t\tint slots_used_count = in_use_count + free_list_count;\n\t\t\t\t\t\tindex_t index;\n\t\t\t\t\t\twhile (bitarray_zap_first_set(slots, log_size, &index)) {\n\t\t\t\t\t\t\tif (index >= slots_used_count) {\n\t\t\t\t\t\t\t\t// Reached the end of the slots that have been\n\t\t\t\t\t\t\t\t// allocated at some point.\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tranges[range_count].address = (vm_address_t)nanov2_slot_in_block_ptr(blockp, size_class, index);\n\t\t\t\t\t\t\tranges[range_count].size = slot_size;\n\t\t\t\t\t\t\trange_count++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfree(slots);\n\t\t\t\t\t}\n\t\t\t\t\tif (range_count) {\n\t\t\t\t\t\t// Notify the in-use pointers that we found.\n\t\t\t\t\t\trecorder(task, context, MALLOC_PTR_IN_USE_RANGE_TYPE, ranges, range_count);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tarena++;\n\t\t}\n\n\t\t// We have to manually handle the linkage to the next region because\n\t\t// of the address slide between this process and the target.\n\t\tnanov2_region_linkage_t *region_linkagep =\n\t\t\t\t\t\tnanov2_region_linkage_for_region(nanozone, region);\n\t\tnanov2_region_linkage_t *mapped_region_linkagep =\n\t\t\t\tNANOV2_ZONE_PTR_TO_MAPPED_PTR(nanov2_region_linkage_t *,\n\t\t\t\tregion_linkagep, ptr_offset);\n\t\tint offset = mapped_region_linkagep->next_region_offset;\n\t\tregion = offset ? region + offset : NULL;\n\t}\n\treturn 0;\n}\n\nstatic size_t\nnanov2_good_size(nanozonev2_t *nanozone, size_t size)\n{\n\tif (size <= NANO_MAX_SIZE) {\n\t\treturn _nano_common_good_size(size);\n\t}\n\treturn nanozone->helper_zone->introspect->good_size(nanozone->helper_zone,\n\t\t\tsize);\n}\n\nstatic boolean_t\nnanov2_check(nanozonev2_t *nanozone)\n{\n\t// Does nothing, just like Nano V1.\n\treturn 1;\n}\n\nstatic void\nnanov2_print(nanozonev2_t *nanozone, boolean_t verbose)\n{\n\t// Zone-wide statistics\n\tmalloc_statistics_t stats;\n\tnanov2_statistics_t *nano_stats = &nanozone->statistics;\n\tnanov2_statistics(nanozone, &stats);\n\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\"Nanozonev2 %p: blocks in use: %llu, size in use: %llu allocated size: %llu, \"\n\t\t\t\"allocated regions: %d, region holes: %d\\n\",\n\t\t\tnanozone, (uint64_t)stats.blocks_in_use, (uint64_t)stats.size_in_use,\n\t\t\t(uint64_t)stats.size_allocated, nano_stats->allocated_regions,\n\t\t\tnano_stats->region_address_clashes);\n\n#if DEBUG_MALLOC\n\t// Per-size class statistics\n\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\"\\nPer size-class statistics:\\n\");\n\tfor (int i = 0; i < NANO_SIZE_CLASSES; i++) {\n\t\tnanov2_size_class_statistics *cs = &nano_stats->size_class_statistics[i];\n\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\"  Class %d: \", i);\n\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\"total alloc: %llu, total frees: %llu, madvised blocks: %llu, madvise races: %llu\",\n\t\t\tcs->total_allocations, cs->total_frees, cs->madvised_blocks,\n\t\t\tcs->madvise_races);\n\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"\\n\");\n\t}\n#endif // DEBUG_MALLOC\n\n\t// Per-context block pointers.\n\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\"Current Allocation Blocks By Size Class/Context [CPU]\\n\");\n\tfor (int i = 0; i < NANO_SIZE_CLASSES; i++) {\n\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\t\"  Class %d: \", i);\n\t\tfor (int j = 0; j < MAX_CURRENT_BLOCKS; j++) {\n\t\t\tif (nanozone->current_block[i][j]) {\n\t\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\t\t\t\"%d: %p; \", j, nanozone->current_block[i][j]);\n\t\t\t}\n\t\t}\n\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"\\n\");\n\t}\n\n\tnanov2_meta_index_t metablock_meta_index = nanov2_metablock_meta_index(nanozone);\n\tnanov2_region_t *region = nanozone->first_region_base;\n\tint region_index = 0;\n\twhile (region) {\n\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\t\"\\nRegion %d: base address %p\\n\", region_index, region);\n\n\t\tnanov2_arena_t *arena = nanov2_first_arena_for_region(region);\n\t\tnanov2_arena_t *limit_arena = nanov2_limit_arena_for_region(nanozone, region);\n\t\tint arena_index = 0;\n\t\twhile (arena < limit_arena) {\n\t\t\t// Find the metadata block and process every entry, apart from the\n\t\t\t// one for the metadata block itself.\n\t\t\tnanov2_arena_metablock_t *arena_meta_blockp =\n\t\t\t\t\tnanov2_metablock_address_for_ptr(nanozone, arena);\n\n\t\t\tnanov2_block_meta_t *block_metap = &arena_meta_blockp->arena_block_meta[0];\n\n\t\t\tint active_blocks = 0;\n\t\t\tint madvisable_blocks = 0;\n\t\t\tint unused_blocks = 0;\n\t\t\tint madvised_blocks = 0;\n\t\t\tint madvising_blocks = 0;\n\t\t\tfor (nanov2_meta_index_t i = 0; i < NANOV2_BLOCKS_PER_ARENA; i++) {\n\t\t\t\tif (i == metablock_meta_index) {\n\t\t\t\t\t// Skip the metadata block.\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tnanov2_block_meta_t meta = block_metap[i];\n\t\t\t\tswitch (meta.next_slot) {\n\t\t\t\tcase SLOT_NULL:\n\t\t\t\t\tunused_blocks++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase SLOT_MADVISED:\n\t\t\t\t\tmadvised_blocks++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase SLOT_MADVISING:\n\t\t\t\t\tmadvising_blocks++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase SLOT_CAN_MADVISE:\n\t\t\t\t\tmadvisable_blocks++;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tactive_blocks++;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\t\t\"Arena #%d: base address %p. Blocks - active: %d, \"\n\t\t\t\t\t\"madvisable: %d, madvising: %d, madvised: %d, unused: %d\\n\",\n\t\t\t\t\tarena_index, arena, active_blocks, madvisable_blocks,\n\t\t\t\t\tmadvising_blocks, madvised_blocks, unused_blocks);\n\n\t\t\t// Print which size classes have blocks allocated in this arena.\n\t\t\tint non_empty_size_classes[NANO_SIZE_CLASSES];\n\t\t\tfor (int i = 0; i < NANO_SIZE_CLASSES; i++) {\n\t\t\t\tnon_empty_size_classes[i] = 0;\n\t\t\t}\n\t\t\tfor (nanov2_meta_index_t i = 0; i < NANOV2_BLOCKS_PER_ARENA; i++) {\n\t\t\t\tif (i == metablock_meta_index) {\n\t\t\t\t\t// Skip the metadata block.\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tnanov2_block_meta_t meta = block_metap[i];\n\t\t\t\tnanov2_size_class_t size_class =\n\t\t\t\t\t\tnanov2_size_class_for_meta_index(nanozone, i);\n\t\t\t\tswitch (meta.next_slot) {\n\t\t\t\tcase SLOT_FULL:\n\t\t\t\tcase SLOT_BUMP:\n\t\t\t\tdefault:\n\t\t\t\t\tnon_empty_size_classes[size_class]++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase SLOT_NULL:\n\t\t\t\tcase SLOT_CAN_MADVISE:\n\t\t\t\tcase SLOT_MADVISING:\n\t\t\t\tcase SLOT_MADVISED:\n\t\t\t\t\t// Do not count these.\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\t\t\"Size classes with allocated blocks: \");\n\t\t\tfor (int i = 0; i < NANO_SIZE_CLASSES; i++) {\n\t\t\t\tif (non_empty_size_classes[i]) {\n\t\t\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\t\t\t\"%d \", i);\n\t\t\t\t}\n\t\t\t}\n\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"\\n\");\n\n\t\t\tfor (nanov2_meta_index_t i = 0; i < NANOV2_BLOCKS_PER_ARENA; i++) {\n\t\t\t\tif (i == metablock_meta_index) {\n\t\t\t\t\t// Skip the metadata block.\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tnanov2_block_meta_t meta = block_metap[i];\n\t\t\t\tif (!nanov2_is_block_active(meta) && !verbose) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tnanov2_size_class_t size_class =\n\t\t\t\t\t\tnanov2_size_class_for_meta_index(nanozone, i);\n\t\t\t\tchar *slot_text;\n\t\t\t\tswitch (meta.next_slot) {\n\t\t\t\tcase SLOT_NULL:\n\t\t\t\t\tslot_text = \"NOT USED\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase SLOT_FULL:\n\t\t\t\t\tslot_text = \"FULL\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase SLOT_CAN_MADVISE:\n\t\t\t\t\tslot_text = \"CAN MADVISE\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase SLOT_MADVISING:\n\t\t\t\t\tslot_text = \"MADVISING\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase SLOT_MADVISED:\n\t\t\t\t\tslot_text = \"MADVISED\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tslot_text = NULL;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\t\t\t\"    Block %d: base %p; metadata: %p, size %d (class %d) in-use: %d \",\n\t\t\t\t\t\ti, nanov2_block_address_from_meta_index(nanozone, arena, i),\n\t\t\t\t\t\t&block_metap[i], nanov2_size_from_size_class(size_class),\n\t\t\t\t\t\tsize_class, meta.in_use);\n\t\t\t\tif (slot_text) {\n\t\t\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\t\t\t\"%s\\n\", slot_text);\n\t\t\t\t} else {\n\t\t\t\t\tint allocated = slots_by_size_class[size_class] - meta.free_count - 1;\n\t\t\t\t\tif (meta.next_slot == SLOT_BUMP) {\n\t\t\t\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\t\t\t\t\t\"BUMP (free list empty)\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\t\t\t\t\"next_slot (1-based) = %d\", meta.next_slot);\n\n\t\t\t\t\t}\n\t\t\t\t\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,\n\t\t\t\t\t\t\", allocated slots: %d, free slots = %d, occupancy: %d%%\\n\",\n\t\t\t\t\t\tallocated, meta.free_count + 1,\n\t\t\t\t\t\t(100 * allocated)/slots_by_size_class[size_class]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tarena++;\n\t\t\tarena_index++;\n\t\t}\n\n\t\tregion = nanov2_next_region_for_region(nanozone, region);\n\t\tregion_index++;\n\t}\n}\n\nstatic void\nnanov2_log(malloc_zone_t *zone, void *log_address)\n{\n\t// Does nothing, just like Nano V1.\n}\n\nstatic void\nnanov2_force_lock(nanozonev2_t *nanozone)\n{\n\t// Nothing to do - Nano V2 does not have a zone lock.\n}\n\nstatic void\nnanov2_force_unlock(nanozonev2_t *nanozone)\n{\n\t// Nothing to do - Nano V2 does not have a zone lock.\n}\n\nstatic void\nnanov2_reinit_lock(nanozonev2_t *nanozone)\n{\n\t// Nothing to do - Nano V2 does not have a zone lock.\n}\n\nstatic boolean_t\nnanov2_locked(nanozonev2_t *nanozone)\n{\n\t// Nothing to do - Nano V2 does not have a zone lock.\n\treturn FALSE;\n}\n\nstatic void\nnanov2_statistics(nanozonev2_t *nanozone, malloc_statistics_t *stats)\n{\n\tmemset(stats, '\\0', sizeof(*stats));\n\n\tnanov2_region_t *region;\n\tnanov2_arena_t * arena;\n\tnanov2_meta_index_t metadata_block_index = nanov2_metablock_meta_index(nanozone);\n\n\t// Iterate over each arena in each region. Within each region, add\n\t// statistics for each slot in each block, excluding the meta data block.\n\tfor (region = nanozone->first_region_base; region;\n\t\t\tregion = nanov2_next_region_for_region(nanozone, region)) {\n\t\tfor (arena = nanov2_first_arena_for_region(region);\n\t\t\t\tarena < nanov2_limit_arena_for_region(nanozone, region);\n\t\t\t\tarena++) {\n\t\t\tnanov2_arena_metablock_t *meta_block =\n\t\t\t\t\tnanov2_metablock_address_for_ptr(nanozone, arena);\n\t\t\tfor (nanov2_meta_index_t i = 0; i < NANOV2_BLOCKS_PER_ARENA; i++) {\n\t\t\t\tif (i == metadata_block_index) {\n\t\t\t\t\t// Skip the metadata block.\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tnanov2_block_meta_t *block_metap = &meta_block->arena_block_meta[i];\n\t\t\t\tnanov2_size_class_t size_class =\n\t\t\t\t\t\tnanov2_size_class_for_meta_index(nanozone, i);\n\t\t\t\tint slot_size = nanov2_size_from_size_class(size_class);\n\n\t\t\t\tnanov2_block_meta_t meta = os_atomic_load(block_metap, relaxed);\n\t\t\t\tint slots_in_use = 0;\n\t\t\t\tswitch (meta.next_slot) {\n\t\t\t\tcase SLOT_NULL:\n\t\t\t\t\t// FALLTHRU\n\t\t\t\tcase SLOT_CAN_MADVISE:\n\t\t\t\t\t// FALLTHRU\n\t\t\t\tcase SLOT_MADVISING:\n\t\t\t\t\t// FALLTHRU\n\t\t\t\tcase SLOT_MADVISED:\n\t\t\t\t\t// These blocks have no active content.\n\t\t\t\t\tbreak;\n\t\t\t\tcase SLOT_FULL:\n\t\t\t\t\tslots_in_use = slots_by_size_class[size_class];\n\t\t\t\t\tbreak;\n\t\t\t\tcase SLOT_BUMP:\n\t\t\t\t\t// FALLTHRU\n\t\t\t\tdefault:\n\t\t\t\t\tslots_in_use = slots_by_size_class[size_class] - meta.free_count - 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// We can't report max_size_in_use because we don't have the\n\t\t\t\t// metadata to do so.\n\t\t\t\tif (slots_in_use) {\n\t\t\t\t\tstats->blocks_in_use += slots_in_use;\n\t\t\t\t\tstats->size_in_use += slots_in_use * slot_size;\n\t\t\t\t\tstats->size_allocated += NANOV2_BLOCK_SIZE;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nstatic const struct malloc_introspection_t nanov2_introspect = {\n\t.enumerator = \t(void *)nanov2_ptr_in_use_enumerator,\n\t.good_size =\t(void *)nanov2_good_size,\n\t.check = \t\t(void *)nanov2_check,\n\t.print =\t\t(void *)nanov2_print,\n\t.log = \t\t\t(void *)nanov2_log,\n\t.force_lock = \t(void *)nanov2_force_lock,\n\t.force_unlock =\t(void *)nanov2_force_unlock,\n\t.statistics = \t(void *)nanov2_statistics,\n\t.zone_locked =\t(void *)nanov2_locked,\n\t.enable_discharge_checking = NULL,\n\t.disable_discharge_checking = NULL,\n#ifdef __BLOCKS__\n\t.enumerate_discharged_pointers = NULL,\n#else // __BLOCKS__\n\t.enumerate_unavailable_without_blocks = NULL,\n#endif // __BLOCKS__\n\t.reinit_lock = \t(void *)nanov2_reinit_lock,\n};\n\n#endif // OS_VARIANT_NOTRESOLVED\n\n#pragma mark -\n#pragma mark Utility Functions\n\n#if OS_VARIANT_RESOLVED\n\n// Given a pointer that may be to Nano V2-allocated memory, returns the size of\n// the allocation, or 0 if the pointer does not correspond to an active\n// allocation. If allow_inner is true, the pointer need not point to the start\n// of the allocation.\nsize_t\nnanov2_pointer_size(nanozonev2_t *nanozone, void *ptr, boolean_t allow_inner)\n{\n\t// First check the address signature.\n\tif (!nanov2_has_valid_signature((void *)ptr)) {\n\t\treturn 0;\n\t}\n\n\t// Check for proper alignment, unless we could have an inner pointer.\n\tif (!allow_inner && ((uintptr_t)ptr) & NANO_QUANTA_MASK) {\n\t\treturn 0;\n\t}\n\n\t// Bounds check against the active address space.\n\tif (ptr < (void *)nanozone->first_region_base ||\n\t\t\tptr > (void *)nanozone->current_region_next_arena) {\n\t\treturn 0;\n\t}\n\n#if NANOV2_MULTIPLE_REGIONS\n\t// Need to check that the region part is valid because there could be holes.\n\t// Do this only if we know there is a hole.\n\t// NOTE: in M2 convergence, use a hashed structure to make this more\n\t// efficient.\n\tif (nanozone->statistics.region_address_clashes) {\n\t\tnanov2_region_t *ptr_region = nanov2_region_address_for_ptr(ptr);\n\t\tnanov2_region_t *region = nanozone->first_region_base;\n\t\twhile (region) {\n\t\t\tif (ptr_region == region) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tregion = nanov2_next_region_for_region(nanozone, region);\n\t\t}\n\t\tif (!region) {\n\t\t\t// Reached the end of the region list without matching - not a\n\t\t\t// valid Nano V2 pointer.\n\t\t\treturn 0;\n\t\t}\n\t}\n#endif // NANOV2_MULTIPLE_REGIONS\n\n\t// Get the size class for the pointer and the address of its meta block\n\t// header.\n\tnanov2_size_class_t size_class = nanov2_size_class_for_ptr(nanozone, ptr);\n\tnanov2_block_meta_t *block_metap = nanov2_meta_ptr_for_ptr(nanozone, ptr);\n\n\t// Reject if the block is not active, or it doesn't have any allocations.\n\tnanov2_block_meta_t meta = os_atomic_load(block_metap, relaxed);\n\tif (!nanov2_is_block_active(meta) || (meta.next_slot != SLOT_FULL &&\n\t\t\tmeta.free_count == slots_by_size_class[size_class] - 1)) {\n\t\treturn 0;\n\t}\n\n\tsize_t size = nanov2_size_from_size_class(size_class);\n\tnanov2_addr_t addr = { .addr = ptr };\n\tif (!allow_inner && (addr.fields.nano_offset % size)) {\n\t\treturn 0;\n\t}\n\n\t// The only reasonable way to check whether the pointer is free is to\n\t// inspect the canary value at the start of the slot, since we cannot take\n\t// a huge hit for walking the free list.\n\tnanov2_free_slot_t *slotp = (nanov2_free_slot_t *)ptr;\n\tuintptr_t guard = os_atomic_load(&slotp->double_free_guard, relaxed);\n\tif ((guard ^ nanozone->slot_freelist_cookie) == (uintptr_t)ptr) {\n\t\treturn 0;\n\t}\n\n\treturn size;\n}\n\n#pragma mark -\n#pragma mark Madvise Management\n\n// Given a pointer to a block and its metadata, calls madvise() on that block\n// if it is in state SLOT_CAN_MADVISE. Returns true on success, false if the\n// block is not in the correct state or if the state changed during the\n// operation.\n//\n// This function must be called with the zone's madvise_lock held\nboolean_t\nnanov2_madvise_block(nanozonev2_t *nanozone, nanov2_block_meta_t *block_metap,\n\t\tnanov2_block_t *blockp, nanov2_size_class_t size_class)\n{\n\t_malloc_lock_assert_owner(&nanozone->madvise_lock);\n\n\tboolean_t madvised = FALSE;\n\tnanov2_block_meta_t old_meta = os_atomic_load(block_metap, relaxed);\n\tif (old_meta.next_slot == SLOT_CAN_MADVISE) {\n\t\t// Nobody raced with us. We can safely madvise this block. First change\n\t\t// the state to SLOT_MADVISING so that other threads don't try to\n\t\t// grab the block for new allocations.\n\t\tnanov2_block_meta_t new_meta = {\n\t\t\t.next_slot = SLOT_MADVISING,\n\t\t\t.gen_count = old_meta.gen_count + 1,\n\t\t};\n\t\tif (!os_atomic_cmpxchgv(block_metap, old_meta, new_meta, &old_meta,\n\t\t\t\t\t\t\t\trelaxed)) {\n\t\t\t// Somebody else tampered with this block. This can happen if\n\t\t\t// another thread raced with us to allocate in this block. Count\n\t\t\t// the contended access.\n\t\t\tnanozone->statistics.size_class_statistics[size_class].madvise_races++;\n\t\t\treturn false;\n\t\t}\n\n\t\tif (mvm_madvise_free(nanozone, nanov2_region_address_for_ptr(blockp),\n\t\t\t\t(uintptr_t)blockp, (uintptr_t)(blockp + 1), NULL, FALSE)) {\n\t\t\tmalloc_zone_error(0, false, \"Failed to madvise block at blockp: %p, error: %d\\n\", blockp, errno);\n\t\t} else {\n\t\t\tnanozone->statistics.size_class_statistics[size_class].madvised_blocks++;\n\t\t\tmadvised = TRUE;\n\t\t}\n\n\t\tnanov2_block_meta_t final_meta = {\n\t\t\t.next_slot = SLOT_MADVISED,\n\t\t\t.gen_count = new_meta.gen_count + 1,\n\t\t};\n\n\t\tif (!os_atomic_cmpxchgv(block_metap, new_meta, final_meta, &old_meta,\n\t\t\t\trelaxed)) {\n\t\t\t// This should not happen since we should have exclusive interest\n\t\t\t// in this block.\n\t\t\tmalloc_zone_error(nanozone->debug_flags, false,\n\t\t\t\t\t\"Failed when changing state from MADVISING to MADVISED, \"\n\t\t\t\t\t\"block_metap = %p, blockp = %p\\n\", block_metap, blockp);\n\t\t}\n\t}\n\treturn madvised;\n}\n\n#endif // OS_VARIANT_RESOLVED\n\n#pragma mark -\n#pragma mark Region Management\n\n#if OS_VARIANT_NOTRESOLVED\n\n#if NANOV2_MULTIPLE_REGIONS\nstatic nanov2_addr_t nanov2_max_region_base = {\n\t.fields.nano_signature = NANOZONE_SIGNATURE,\n\t.fields.nano_region = NANOV2_MAX_REGION_NUMBER\n};\n#endif // NANOV2_MULTIPLE_REGIONS\n\n// Attempts to allocate VM space for a region at a given address and returns\n// whether the allocation succeeded.\nstatic boolean_t\nnanov2_allocate_region(nanov2_region_t *region)\n{\n\tMALLOC_TRACE(TRACE_nanov2_region_allocation | DBG_FUNC_START,\n\t\t\t(uint64_t)region, 0, 0, 0);\n\tboolean_t result = nano_common_allocate_vm_space((mach_vm_address_t)region,\n\t\t\tNANOV2_REGION_SIZE);\n\tMALLOC_TRACE(TRACE_nanov2_region_allocation | DBG_FUNC_END,\n\t\t\t(uint64_t)region, result, 0, 0);\n\treturn result;\n}\n\n// Allocates a new region adjacent to the current one. If the allocation fails,\n// keep sliding up by the size of a region until we either succeed or run out of\n// address space. The caller must own the Nanozone regions lock.\nboolean_t\nnanov2_allocate_new_region(nanozonev2_t *nanozone)\n{\n#if NANOV2_MULTIPLE_REGIONS\n\tboolean_t result = FALSE;\n\n\t_malloc_lock_assert_owner(&nanozone->regions_lock);\n\tnanov2_region_t *current_region = nanozone->current_region_base;\n\tnanov2_region_t *next_region = (nanov2_region_t *)nanozone->current_region_limit;\n\twhile ((void *)next_region <= nanov2_max_region_base.addr) {\n\t\tif (nanov2_allocate_region(next_region)) {\n\t\t\tnanozone->current_region_base = next_region;\n\t\t\tnanozone->current_region_next_arena = (nanov2_arena_t *)next_region;\n\t\t\tnanozone->current_region_limit = next_region + 1;\n\t\t\tnanozone->statistics.allocated_regions++;\n\t\t\tresult = TRUE;\n\t\t\tbreak;\n\t\t}\n\t\tnext_region++;\n\t\tnanozone->statistics.region_address_clashes++;\n\t}\n\n\tif (result) {\n\t\t// Link this region to the previous one.\n\t\tnanov2_region_linkage_t *current_region_linkage =\n\t\t\t\tnanov2_region_linkage_for_region(nanozone, current_region);\n\t\tnanov2_region_linkage_t *next_region_linkage =\n\t\t\t\tnanov2_region_linkage_for_region(nanozone, next_region);\n\t\tuint16_t offset = next_region - current_region;\n\t\tcurrent_region_linkage->next_region_offset = offset;\n\t\tnext_region_linkage->next_region_offset = 0;\n\t}\n\n\treturn result;\n#else // NANOV2_MULTIPLE_REGIONS\n\t// On iOS, only one region is supported, so we fail since the first\n\t// region is allocated separately.\n\treturn FALSE;\n#endif // CONFIG_NANOV2_MULTIPLE_REGIONS\n}\n#endif // OS_VARIANT_NOTRESOLVED\n\n#pragma mark -\n#pragma mark Allocation\n\n#if OS_VARIANT_RESOLVED\n\n// Allocates memory from the block that corresponds to a given block meta data\n// pointer. The memory is taken from the free list if possible, or from the\n// unused region of the block if not. If the block is no longer in use or is\n// full, NULL is returned and the caller is expected to find another block to\n// allocate from.\nvoid *\nnanov2_allocate_from_block(nanozonev2_t *nanozone,\n\t\tnanov2_block_meta_t *block_metap, nanov2_size_class_t size_class)\n{\n\tnanov2_block_meta_view_t old_meta_view;\n\told_meta_view.meta = os_atomic_load(block_metap, relaxed);\n\n\t// Calculating blockp and ptr is relatively expensive. Do both lazily to\n\t// minimize the time in the block starting with \"again:\" and ending with the\n\t// atomic update so that we lose at little time as possible if we have to\n\t// repeat that loop due to contention. This should also reduce the risk of\n\t// contention.\n\tnanov2_block_t *blockp = NULL;\n\nagain:\n\tif (!nanov2_can_allocate_from_block(old_meta_view.meta)) {\n\t\t// Move along, nothing to allocate here...\n\t\treturn NULL;\n\t}\n\n\tint slot;\n\tvoid *ptr = NULL;\n\tboolean_t from_free_list = FALSE;\n\tnanov2_block_meta_t new_meta = {\n\t\t.in_use = 1,\n\t\t.free_count = old_meta_view.meta.free_count - 1,\n\t\t.gen_count = old_meta_view.meta.gen_count + 1\n\t};\n\n\t// Grab a slot from the free list or get the next unused slot. We know there\n\t// should be one because the block is not full.\n\tboolean_t slot_full = old_meta_view.meta.free_count == 0;\n\tif (old_meta_view.meta.next_slot == SLOT_BUMP\n\t\t\t\t|| old_meta_view.meta.next_slot == SLOT_CAN_MADVISE) {\n\t\t// Free list empty, grab the next unused slot.\n\t\tnew_meta.next_slot = slot_full ? SLOT_FULL : SLOT_BUMP;\n\t\tslot = slots_by_size_class[size_class] - old_meta_view.meta.free_count - 1;\n\t} else {\n\t\t// Grab the first item from the free list.\n\t\tfrom_free_list = TRUE;\n\t\tif (!blockp) {\n\t\t\tblockp = nanov2_block_address_from_meta_ptr(nanozone, block_metap);\n\t\t}\n\t\tslot = old_meta_view.meta.next_slot - 1; // meta.next_slot is 1-based.\n\t\tptr = nanov2_slot_in_block_ptr(blockp, size_class, slot);\n\t\tnanov2_free_slot_t *slotp = (nanov2_free_slot_t *)ptr;\n\t\tnew_meta.next_slot = slot_full ? SLOT_FULL : slotp->next_slot;\n\t}\n\n\t// Write the updated meta data; try again if we raced with another thread.\n\tif (!os_atomic_cmpxchgv(block_metap, old_meta_view.meta, new_meta,\n\t\t\t\t&old_meta_view.meta, dependency)) {\n\t\tif (old_meta_view.meta.next_slot == SLOT_CAN_MADVISE ||\n\t\t\t\told_meta_view.meta.next_slot == SLOT_MADVISING ||\n\t\t\t\told_meta_view.meta.next_slot == SLOT_MADVISED) {\n\t\t\t_malloc_lock_lock(&nanozone->madvise_lock);\n\t\t\tif (old_meta_view.meta.next_slot == SLOT_MADVISED) {\n\t\t\t\t// We raced against another thread madvising this block. We need\n\t\t\t\t// to redo the madvise because we may have touched it when\n\t\t\t\t// reading the next pointer in the freelist.\n\t\t\t\tif (!blockp) {\n\t\t\t\t\tblockp = nanov2_block_address_from_meta_ptr(nanozone, block_metap);\n\t\t\t\t}\n\t\t\t\tif (mvm_madvise_free(nanozone, nanov2_region_address_for_ptr(blockp),\n\t\t\t\t\t\t(uintptr_t)blockp, (uintptr_t)(blockp + 1), NULL, FALSE)) {\n\t\t\t\t\tmalloc_zone_error(0, false,\n\t\t\t\t\t\t\t\"Failed to remadvise block at blockp: %p, error: %d\\n\", blockp, errno);\n\t\t\t\t}\n\t\t\t}\n\t\t\t_malloc_lock_unlock(&nanozone->madvise_lock);\n\t\t}\n\t\tgoto again;\n\t}\n\n\tif (!ptr) {\n\t\tif (!blockp) {\n\t\t\tblockp = nanov2_block_address_from_meta_ptr(nanozone, block_metap);\n\t\t}\n\t\tptr = nanov2_slot_in_block_ptr(blockp, size_class, slot);\n\t}\n\n\tnanov2_free_slot_t *slotp =\n\t\t\t(nanov2_free_slot_t *)os_atomic_force_dependency_on(ptr,\n\t\t\t(unsigned long)old_meta_view.bits);\n\tif (from_free_list) {\n\t\t// We grabbed the item from the free list. Check the free list canary\n\t\t// and crash if it's not valid. We can't do this check before the\n\t\t// cmpxchgv because another thread may race with us, claim the slot and\n\t\t// write to it.\n\t\tuintptr_t guard = os_atomic_load(&slotp->double_free_guard, relaxed);\n\t\tif ((guard ^ nanozone->slot_freelist_cookie) != (uintptr_t)ptr) {\n\t\t\tmalloc_zone_error(MALLOC_ABORT_ON_CORRUPTION, false,\n\t\t\t\t\t\"Heap corruption detected, free list is damaged at %p\\n\"\n\t\t\t\t\t\"*** Incorrect guard value: %lu\\n\", ptr, guard);\n\t\t\t__builtin_unreachable();\n\t\t}\n\t}\n\n\t// Reset the canary value so that the slot no longer looks free.\n\tos_atomic_store(&slotp->double_free_guard, 0, relaxed);\n\t\n#if DEBUG_MALLOC\n\tnanozone->statistics.size_class_statistics[size_class].total_allocations++;\n#endif // DEBUG_MALLOC\n\n\treturn ptr;\n}\n\n// Finds a block for allocation in an arena and returns a pointer to its\n// metadata header. The search begins from the block with metadata pointer\n// start_block (which must not be NULL). If no acceptable block was found,\n// NULL is returned and it is expected that the caller will take appropriate\n// action (typically allocate a new arena).\n//\n// The search starts with start_block. If this is in-use and not full, that\n// block is returned. Otherwise, a scan for a usable block is initiated. The\n// search starts from start_block and initially works backward towards the\n// start of the arena. If this does not succeed, a forward search from\n// start_block is made.\n//\n// A block is considered a candidate if it is not in use. As the scan proceeds,\n// we remember blocks which have been madvisable, blocks which have been\n// madvised or never used and those blocks which still have allocated slots\n// but which fall within the reuse criteria (i.e. their occupancy is within the\n// max/min occupancy range).\n//\n// If the scan policy is NANO_SCAN_FIRST_FIT, we just return the first block\n// from the above list that we find. This is the fastest option, but likely\n// maximises fragmentation.\n//\n// Otherwise, the scan policy is NANO_SCAN_CAPACITY_BASED. If we find a block\n// that fits the reuse criteria, we return it immediately. Otherwise, we\n// continue to scan until we find such a block, or we find a less ideal block\n// and we reach the scan limit or exhaust the arena. At that point, we return\n// one of the candidate blocks that we found, choosing based on the state of\n// that block:\n// - blocks that have allocations that are greater than the minimum capacity\n//   are preferred.\n// - failing that, return an unused or madvise'd block.\n// - failing that, return a block that is waiting to be madvised.\n//\n// In order to avoid races, this function must be called with the\n// current_block_lock for the calling context [CPU] and size class locked.\n// On return, the selected block has been marked as in-use, so the caller must\n// either assign it as the active allocation block for the calling context or\n// clear the in-use bit.\n//\nMALLOC_ALWAYS_INLINE MALLOC_INLINE nanov2_block_meta_t *\nnanov2_find_block_in_arena(nanozonev2_t *nanozone,\n\t\tnanov2_arena_t *arena, nanov2_size_class_t size_class,\n\t\tnanov2_block_meta_t *start_block)\n{\n\t// If we don't have a starting point, start with the first block in the\n\t// arena for the given size class. This is the case where we are looking for\n\t// the first allocation block for a new context (i.e probably a new CPU, so\n\t// take the first fit to avoid having to scan the whole size class for this\n\t// very common start up case.)\n\tboolean_t use_first_fit = !start_block ||\n\t\t\tnanov2_policy_config.block_scan_policy == NANO_SCAN_FIRST_FIT;\n\tnanov2_block_meta_t *first_block = nanov2_first_block_for_size_class_in_arena(\n\t\t\tnanozone, size_class, arena);\n\tboolean_t scanning_backwards;\n\tif (!start_block) {\n\t\tstart_block = first_block;\n\t}\n\tint slots_in_block = slots_by_size_class[size_class];\n\tnanov2_block_meta_t old_meta;\n\tnanov2_block_meta_t *this_block;\n\tnanov2_block_meta_t *found_block;\n\tnanov2_block_meta_t *madvisable_block;\n\tnanov2_block_meta_t *free_block;\n\tnanov2_block_meta_t *fallback_block;\n\tboolean_t fallback_below_max;\n\tint scan_limit;\n\n\t// Check all of the blocks in the size class until we find one that we can\n\t// use, based on nanov2_block_scan_policy.\nretry:\n\tthis_block = start_block;\n\tfound_block = NULL;\n\tmadvisable_block = NULL;\n\tfree_block = NULL;\n\tfallback_block = NULL;\n\tfallback_below_max = FALSE;\n\tscan_limit = nanov2_policy_config.block_scan_limit;\n\tscanning_backwards = TRUE;\n\n\tdo {\n\t\told_meta = os_atomic_load(this_block, relaxed);\n\t\tif (!old_meta.in_use && old_meta.next_slot != SLOT_FULL\n\t\t\t\t&& old_meta.next_slot != SLOT_MADVISING) {\n\t\t\tif (old_meta.next_slot == SLOT_CAN_MADVISE) {\n\t\t\t\tif (!madvisable_block) {\n\t\t\t\t\t// We can use this block as a last-ditch fallback.\n\t\t\t\t\tmadvisable_block = this_block;\n\t\t\t\t}\n\t\t\t} else if (old_meta.next_slot == SLOT_NULL\n\t\t\t\t\t|| old_meta.next_slot == SLOT_MADVISED) {\n\t\t\t\tif (!free_block) {\n\t\t\t\t\tfree_block = this_block;\n\t\t\t\t}\n\t\t\t} else if (use_first_fit) {\n\t\t\t\tfound_block = this_block;\n\t\t\t} else {\n\t\t\t\tMALLOC_ASSERT(nanov2_policy_config.block_scan_policy == NANO_SCAN_CAPACITY_BASED);\n\t\t\t\tint percent_used = (100 * old_meta.free_count)/slots_in_block;\n\t\t\t\tif (percent_used >= nanov2_policy_config.block_scan_min_capacity\n\t\t\t\t\t\t&& percent_used <= nanov2_policy_config.block_scan_max_capacity) {\n\t\t\t\t\t// Within specified limits -- take this one.\n\t\t\t\t\tfound_block = this_block;\n\t\t\t\t} else if (percent_used >= nanov2_policy_config.block_scan_min_capacity) {\n\t\t\t\t\tif (!fallback_block || fallback_below_max) {\n\t\t\t\t\t\t// More full than we want, but still acceptable as a\n\t\t\t\t\t\t// fallback.\n\t\t\t\t\t\tfallback_block = this_block;\n\t\t\t\t\t}\n\t\t\t\t} else if (!fallback_block\n\t\t\t\t\t\t&& percent_used < nanov2_policy_config.block_scan_min_capacity) {\n\t\t\t\t\t// Less full than we want. Keep it as a backup, but set\n\t\t\t\t\t// fallback_below_max to allow a block that's above max to\n\t\t\t\t\t// be preferred. The rationale behind this is to allow\n\t\t\t\t\t// blocks that have low occupancy to drain so that they can\n\t\t\t\t\t// be madvised.\n\t\t\t\t\tfallback_block = this_block;\n\t\t\t\t\tfallback_below_max = TRUE;\n\t\t\t\t} else if (!free_block) {\n\t\t\t\t\t// Not ideal, but we could use it.\n\t\t\t\t\tfree_block = this_block;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (use_first_fit && (found_block || fallback_block || free_block)) {\n\t\t\t\t// Take whatever we got.\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (scan_limit > 0) {\n\t\t\t// Only enforce the scan limit once we have a candidate.\n\t\t\tif ((fallback_block || free_block) && --scan_limit == 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (scanning_backwards) {\n\t\t\tboolean_t wrapped;\n\t\t\tnanov2_block_meta_t *prev_block = nanov2_previous_block_for_size_class(\n\t\t\t\t\tnanozone, size_class, this_block, &wrapped);\n\t\t\tif (wrapped) {\n\t\t\t\t// We wrapped. Scan forward from the start block instead.\n\t\t\t\tscan_limit = nanov2_policy_config.block_scan_limit;\n\t\t\t\tscanning_backwards = FALSE;\n\t\t\t\tthis_block = start_block;\n\t\t\t} else {\n\t\t\t\tthis_block = prev_block;\n\t\t\t}\n\t\t} else {\n\t\t\t// Move to the next block, wrapping when we reach the last one for\n\t\t\t// this size class. Stop once we get to the block where we started.\n\t\t\tthis_block = nanov2_next_block_for_size_class(nanozone, size_class,\n\t\t\t\t\tthis_block, NULL);\n\t\t\tif (this_block == start_block) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} while (!found_block);\n\n\tif (!found_block) {\n\t\tif (fallback_block) {\n\t\t\tfound_block = fallback_block;\n\t\t} else if (free_block) {\n\t\t\tfound_block = free_block;\n\t\t} else if (madvisable_block) {\n\t\t\tfound_block = madvisable_block;\n\t\t}\n\t}\n\n\tif (found_block) {\n\t\t// Now we need to activate the block. If this fails, we look for\n\t\t// another block.\n\t\t// If we are bringing a block that is draining back into use, we\n\t\t// just need to set in_use to 1. Otherwise, we fully initialize it.\n\t\told_meta = os_atomic_load(found_block, relaxed);\n\t\tif (old_meta.next_slot == SLOT_MADVISING) {\n\t\t\tgoto retry;\n\t\t}\n\t\tboolean_t reset_slot = old_meta.next_slot == SLOT_NULL\n\t\t\t\t|| old_meta.next_slot == SLOT_CAN_MADVISE\n\t\t\t\t|| old_meta.next_slot == SLOT_MADVISED;\n\t\tnanov2_block_meta_t new_meta = {\n\t\t\t.in_use = 1,\n\t\t\t.free_count = reset_slot ? slots_in_block - 1 : old_meta.free_count,\n\t\t\t.next_slot = reset_slot ? SLOT_BUMP : old_meta.next_slot,\n\t\t\t.gen_count = reset_slot ? 0 : old_meta.gen_count + 1,\n\t\t};\n\t\tif (!os_atomic_cmpxchgv(found_block, old_meta, new_meta, &old_meta,\n\t\t\t\trelaxed)) {\n\t\t\tgoto retry;\n\t\t}\n\t}\n\n\treturn found_block;\n}\n\n// Finds a block to allocate from and allocates memory from it. The search\n// for a block starts from *block_metapp if not NULL, otherwise from the first\n// arena in the first block (which is the case when the first block is allocated\n// for a size class for a CPU).\n// If none of the blocks for a size class in the current arena can be used, a\n// new arena is allocated and, if necessary, a new region is added.\n//\n// The address of the allocated memory is returned and its metadata pointer is\n// stored in *block_metapp. If a new region is required and it can't be\n// allocated, NULL is returned and *block_metapp is unmodified.\n//\n// On success, the returned block is marked as in-use and the block originally\n// pointed to by *block_metapp has its in-use bit cleared.\n//\n// In order to avoid races, this function must be called with the\n// current_block_lock for the calling context [CPU] and size class locked.\nMALLOC_NOINLINE void *\nnanov2_find_block_and_allocate(nanozonev2_t *nanozone,\n\t\tnanov2_size_class_t size_class, nanov2_block_meta_t **block_metapp)\n{\n\tnanov2_arena_t *arena;\n\tnanov2_block_meta_t *start_block = os_atomic_load(block_metapp, relaxed);\n\tnanov2_block_meta_t *orig_block = start_block;\n\tif (start_block) {\n\t\t// Use the arena for the starting block.\n\t\tarena = nanov2_arena_address_for_ptr(start_block);\n\t} else {\n\t\t// Start from the first arena.\n\t\tarena = nanov2_arena_address_for_ptr(nanozone->first_region_base);\n\t}\n\n\tnanov2_region_t *start_region;\nretry:\n\tstart_region = nanov2_region_address_for_ptr(arena);\n\tnanov2_arena_t *start_arena = arena;\n\tnanov2_region_t *region = start_region;\n\tnanov2_arena_t *limit_arena = nanov2_limit_arena_for_region(nanozone, start_region);\n\tnanov2_arena_t *initial_region_next_arena = nanozone->current_region_next_arena;\n\tdo {\n\t\tnanov2_block_meta_t *block_metap = nanov2_find_block_in_arena(nanozone,\n\t\t\t\tarena, size_class, start_block);\n\t\tif (block_metap) {\n\t\t\t// Try to allocate from this block and return if it succeeds. Note\n\t\t\t// that the block is now marked as in-use, so effectively belongs\n\t\t\t// to the calling context.\n\t\t\tvoid *ptr = nanov2_allocate_from_block(nanozone, block_metap, size_class);\n\t\t\tif (ptr) {\n\t\t\t\t// Make the new block the current one for the calling context.\n\t\t\t\tos_atomic_store(block_metapp, block_metap, relaxed);\n\n\t\t\t\t// Turn off in-use in old block_metap, if there is one.\n\t\t\t\tif (orig_block) {\n\t\t\t\t\t// Turn off in-use in the original current block.\n\t\t\t\t\tnanov2_turn_off_in_use(orig_block);\n\t\t\t\t}\n\t\t\t\treturn ptr;\n\t\t\t}\n\n\t\t\t// We found a block but failed to allocate from it, probably because\n\t\t\t// it became full. Look for a new block, using the one that we just\n\t\t\t// failed with as the starting point. First, we need to turn off the\n\t\t\t// in-use bit for the block that we just failed to allocate from.\n\t\t\tnanov2_turn_off_in_use(block_metap);\n\n\t\t\tstart_block = block_metap;\n\t\t\tgoto retry;\n\t\t}\n\n\t\t// Try the next arena. If this is the last arena in the region, try the\n\t\t// next region.\n\t\tstart_block = NULL;\n\t\tarena++;\n\t\tif (arena >= limit_arena) {\n\t\t\tregion = nanov2_next_region_for_region(nanozone, region);\n\t\t\tif (!region) {\n\t\t\t\t// Reached the last region -- loop back to the first.\n\t\t\t\tregion = nanozone->first_region_base;\n\t\t\t}\n\t\t\tarena = nanov2_first_arena_for_region(region);\n\t\t\tlimit_arena = nanov2_limit_arena_for_region(nanozone, region);\n\t\t}\n\t} while (arena != start_arena);\n\n\t// If we get to this point, we need to allocate a new arena and possibly\n\t// a new region. If we are not permitted to do so by policy, return NULL.\n\tif (nanov2_policy_config.single_arena_size_classes & (1 << size_class)) {\n\t\treturn NULL;\n\t}\n\n\t// Allocate a new arena and maybe a new region. To do either of those\n\t// things, we need to take the regions_lock. After doing so, check that\n\t// the state is unchanged. If it has, just assume that we might have some\n\t// new space to allocate into and try again.\n\tboolean_t failed = FALSE;\n\tarena = initial_region_next_arena;\n\t_malloc_lock_lock(&nanozone->regions_lock);\n\tif (nanozone->current_region_next_arena == arena) {\n\t\tif ((void *)arena >= nanozone->current_region_limit) {\n\t\t\t// Reached the end of the region. Allocate a new one, if we can.\n\t\t\tif (nanov2_allocate_new_region(nanozone)) {\n\t\t\t\tarena = nanozone->current_region_next_arena++;\n\t\t\t} else {\n\t\t\t\tfailed = TRUE;\n\t\t\t}\n\t\t} else {\n\t\t\t// Assign the new arena, in the same region.\n\t\t\tnanozone->current_region_next_arena = arena + 1;\n\t\t}\n\t}\n\t_malloc_lock_unlock(&nanozone->regions_lock);\n\n\tif (!failed) {\n\t\t// Now allocate from the new arena. Since we updated the nanozone, it's\n\t\t// possible that some other thread has already raced with us to allocate\n\t\t// some space from it, so just use the normal allocation path to avoid\n\t\t// assumptions. It's a little more expensive, but this path is rare.\n\t\tstart_block = NULL;\n\t\tgoto retry;\n\t}\n\n\t// We need more space and we can't get it. We'll delegate to the helper.\n\treturn NULL;\n}\n\n// Allocates memory of a given size (which must be a multiple of the Nano\n// quantum size) and optionally clears it (for calloc).\n//\n// Allocation is attempted first from the block last used for the caller's\n// context (which is initially the physical CPU by default). If there is no\n// last block, or the block is full or now out of use, find another one, if\n// possible. See the comments for nanov2_get_allocation_block() for the details.\n//\n// If the allocation fails, NULL is returned.\nvoid *\nnanov2_allocate(nanozonev2_t *nanozone, size_t rounded_size, boolean_t clear)\n{\n\tvoid *ptr = NULL;\n\tnanov2_size_class_t size_class = nanov2_size_class_from_size(rounded_size);\n\tMALLOC_ASSERT(size_class < NANO_SIZE_CLASSES);\n\tMALLOC_ASSERT(rounded_size != 0);\n\tnanov2_block_meta_t *block_metap;\n\tnanov2_block_meta_t **block_metapp;\n\n\t// Get the index of the pointer to the block from which we are should be\n\t// allocating. This currently depends on the physical CPU number.\n\tint allocation_index = nanov2_get_allocation_block_index() & MAX_CURRENT_BLOCKS_MASK;\n\n\t// Get the current allocation block meta data pointer. If this is NULL,\n\t// we need to find a new allocation block.\n\tblock_metapp = &nanozone->current_block[size_class][allocation_index];\n\tblock_metap = os_atomic_load(block_metapp, relaxed);\n\tif (block_metap) {\n\t\t// Fast path: we have a block -- try to allocate from it.\n\t\tptr = nanov2_allocate_from_block(nanozone, block_metap, size_class);\n\t\tif (ptr) {\n\t\t\tgoto done;\n\t\t}\n\t}\n\n\t// No current allocation block, or we were unable to allocate. We need to\n\t// get a new block. Before doing so, delegate to the helper allocator if\n\t// the size class was full and has not released enough memory yet.\n\tif (nanozone->delegate_allocations & (1 << size_class)) {\n\t\tptr = nanozone->helper_zone->malloc(nanozone->helper_zone, rounded_size);\n\t\tgoto done;\n\t}\n\n\t// Before we try to get another block, lock and try another allocation,\n\t// which may succeed because another thread may have beaten us to it, or\n\t// some space may have freed up in the current block.\n\t_malloc_lock_s *lock = &nanozone->current_block_lock[size_class][allocation_index];\n\t_malloc_lock_lock(lock);\n\n\tblock_metap = os_atomic_load(block_metapp, relaxed);\n\tif (block_metap) {\n\t\tptr = nanov2_allocate_from_block(nanozone, block_metap, size_class);\n\t\tif (ptr) {\n\t\t\t// Good to go - keep the current block.\n\t\t\tgoto unlock;\n\t\t}\n\t}\n\n\t// At this point, we do not have a current allocation block and the old one,\n\t// if there was one, has been marked as not in use. We need to find and\n\t// assign a new block. Since we have the lock, nobody else can change the\n\t// current_block pointer.\n\tptr = nanov2_find_block_and_allocate(nanozone, size_class, block_metapp);\n\nunlock:\n\t_malloc_lock_unlock(lock);\n\n\tif (!ptr) {\n\t\t// We could not find a block to allocate from -- make future\n\t\t// allocations for this size class go to the helper zone until\n\t\t// we have enough free space.\n\t\t_malloc_lock_lock(&nanozone->delegate_allocations_lock);\n\t\tnanozone->delegate_allocations |= 1 << size_class;\n\t\t_malloc_lock_unlock(&nanozone->delegate_allocations_lock);\n\t}\n\ndone:\n\tif (ptr) {\n\t\tif (clear) {\n\t\t\tmemset(ptr, '\\0', rounded_size);\n\t\t} else {\n\t\t\t// Always clear the double-free guard so that we can recognize that\n\t\t\t// this block is not on the free list.\n\t\t\tnanov2_free_slot_t *slotp = (nanov2_free_slot_t *)ptr;\n\t\t\tos_atomic_store(&slotp->double_free_guard, 0, relaxed);\n\t\t}\n\t}\n\treturn ptr;\n}\n\n#pragma mark -\n#pragma mark Freeing\n\n// Frees an allocation to its owning block and updates the block's state.\n// If the block becomes empty, it is marked as SLOT_CAN_MADVISE and is\n// madvised immediately if the policy is NANO_MADVISE_IMMEDIATE.\nvoid\nnanov2_free_to_block(nanozonev2_t *nanozone, void *ptr,\n\t\tnanov2_size_class_t size_class)\n{\n\tnanov2_block_t *blockp = nanov2_block_address_for_ptr(ptr);\n\tnanov2_block_meta_t *block_metap = nanov2_meta_ptr_for_ptr(nanozone, ptr);\n\n\t// Release the slot memory onto the block's freelist.\n\tnanov2_block_meta_t old_meta = os_atomic_load(block_metap, relaxed);\n\tint slot_count = slots_by_size_class[size_class];\n\tnanov2_block_meta_t new_meta;\n\tboolean_t was_full;\n\nagain:\n\twas_full = old_meta.next_slot == SLOT_FULL;\n\tnew_meta.free_count = old_meta.free_count + 1;\n\tnew_meta.in_use = old_meta.in_use;\n\tnew_meta.gen_count = old_meta.gen_count + 1;\n\tboolean_t freeing_last_active_slot = !was_full &&\n\t\t\tnew_meta.free_count == slots_by_size_class[size_class] - 1;\n\tif (freeing_last_active_slot) {\n\t\t// Releasing the last active slot onto the free list. Mark the block as\n\t\t// ready to be madvised if it's not in use, otherwise reset next_slot\n\t\t// to SLOT_BUMP.\n\t\tnew_meta.next_slot = new_meta.in_use ? SLOT_BUMP : SLOT_CAN_MADVISE;\n\t\t// Write the updated meta data; try again if we raced with another thread.\n\t\tif (!os_atomic_cmpxchgv(block_metap, old_meta, new_meta, &old_meta, relaxed)) {\n\t\t\tgoto again;\n\t\t}\n\n\t\t// If the block is now empty and it's not in use, madvise it if the policy\n\t\t// is to do so immediately.\n\t\tif (new_meta.next_slot == SLOT_CAN_MADVISE &&\n\t\t\t\tnanov2_madvise_policy == NANO_MADVISE_IMMEDIATE) {\n\t\t\t_malloc_lock_lock(&nanozone->madvise_lock);\n\t\t\tnanov2_madvise_block(nanozone, block_metap, blockp, size_class);\n\t\t\t_malloc_lock_unlock(&nanozone->madvise_lock);\n\t\t}\n\t} else {\n\t\tint slot_index = nanov2_slot_index_in_block(blockp, size_class, ptr);\n\t\tnew_meta.next_slot = slot_index + 1;  // meta.next_slot is 1-based\n\t\tnanov2_free_slot_t *slotp = (nanov2_free_slot_t *)ptr;\n\t\tslotp->next_slot = was_full ? SLOT_BUMP : old_meta.next_slot;\n\t\tos_atomic_store(&slotp->double_free_guard,\n\t\t\t\tnanozone->slot_freelist_cookie ^ (uintptr_t)ptr, relaxed);\n\n\t\t// The double_free_guard change must be visible when the os_atomic_cmpxchgv\n\t\t// completes.\n\t\t// Write the updated meta data; try again if we raced with another thread.\n\t\tif (!os_atomic_cmpxchgv(block_metap, old_meta, new_meta, &old_meta, release)) {\n\t\t\tgoto again;\n\t\t}\n\t}\n\n\t// If this size class has been marked as full and this block is below an\n\t// acceptable level of occupancy, turn off delegation to the helper. Do this\n\t// only if the block is not in-use, because an in-use block cannot be a\n\t// candidate when searching for a new block.\n\tuint16_t class_mask = 1 << size_class;\n\tif (!new_meta.in_use && (nanozone->delegate_allocations & class_mask) &&\n\t\t\t(new_meta.free_count >= 0.75 * slot_count)) {\n\t\t_malloc_lock_lock(&nanozone->delegate_allocations_lock);\n\t\tnanozone->delegate_allocations &= ~class_mask;\n\t\t_malloc_lock_unlock(&nanozone->delegate_allocations_lock);\n\t}\n\n#if DEBUG_MALLOC\n\tnanozone->statistics.size_class_statistics[size_class].total_frees++;\n#endif // DEBUG_MALLOC\n}\n\n#endif // OS_VARIANT_RESOLVED\n\n#if OS_VARIANT_NOTRESOLVED\n\n#pragma mark -\n#pragma mark Zone Operations\n\nmalloc_zone_t *\nnanov2_create_zone(malloc_zone_t *helper_zone, unsigned debug_flags)\n{\n\t// Note: It is important that nanov2_create_zone resets _malloc_engaged_nano\n \t// if it is unable to enable the nanozone (and chooses not to abort). As\n\t// several functions rely on _malloc_engaged_nano to determine if they\n\t// should manipulate the nanozone, and these should not run if we failed\n \t// to create the zone.\n\tMALLOC_ASSERT(_malloc_engaged_nano == NANO_V2);\n\n\t// Get memory for the zone and disable Nano if we fail.\n\tnanozonev2_t *nanozone = nano_common_allocate_based_pages(\n\t\t\tNANOZONEV2_ZONE_PAGED_SIZE, 0, 0, VM_MEMORY_MALLOC, 0);\n\tif (!nanozone) {\n\t\t_malloc_engaged_nano = NANO_NONE;\n\t\treturn NULL;\n\t}\n\n\t// Set up the basic_zone portion of the nanozonev2 structure\n\tnanozone->basic_zone.version = 10;\n\tnanozone->basic_zone.size = OS_RESOLVED_VARIANT_ADDR(nanov2_size);\n\tnanozone->basic_zone.malloc = OS_RESOLVED_VARIANT_ADDR(nanov2_malloc);\n\tnanozone->basic_zone.calloc = OS_RESOLVED_VARIANT_ADDR(nanov2_calloc);\n\tnanozone->basic_zone.valloc = (void *)nanov2_valloc;\n\tnanozone->basic_zone.free = OS_RESOLVED_VARIANT_ADDR(nanov2_free);\n\tnanozone->basic_zone.realloc = OS_RESOLVED_VARIANT_ADDR(nanov2_realloc);\n\tnanozone->basic_zone.destroy = (void *)nanov2_destroy;\n\tnanozone->basic_zone.batch_malloc = OS_RESOLVED_VARIANT_ADDR(nanov2_batch_malloc);\n\tnanozone->basic_zone.batch_free = OS_RESOLVED_VARIANT_ADDR(nanov2_batch_free);\n\tnanozone->basic_zone.introspect =\n\t\t\t(struct malloc_introspection_t *)&nanov2_introspect;\n\tnanozone->basic_zone.memalign = (void *)nanov2_memalign;\n\tnanozone->basic_zone.free_definite_size = OS_RESOLVED_VARIANT_ADDR(nanov2_free_definite_size);\n\tnanozone->basic_zone.pressure_relief = OS_RESOLVED_VARIANT_ADDR(nanov2_pressure_relief);\n\tnanozone->basic_zone.claimed_address = OS_RESOLVED_VARIANT_ADDR(nanov2_claimed_address);\n\n\t// Set these both to zero as required by CFAllocator.\n\tnanozone->basic_zone.reserved1 = 0;\n\tnanozone->basic_zone.reserved2 = 0;\n\n\t// Prevent overwriting the function pointers in basic_zone.\n\tmprotect(nanozone, sizeof(nanozone->basic_zone), PROT_READ);\n\n\t// Nano V2 zone does not support MALLOC_ADD_GUARD_PAGES\n\tif (debug_flags & MALLOC_ADD_GUARD_PAGES) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"nano does not support guard pages\\n\");\n\t\tdebug_flags &= ~MALLOC_ADD_GUARD_PAGES;\n\t}\n\n\t// Set up the remainder of the nanozonev2 structure\n\tnanozone->debug_flags = debug_flags;\n\tnanozone->helper_zone = helper_zone;\n\n\t// Initialize the cookies used to detect double freeing and for the ASLR\n\t// scramble mapping.\n#define COOKIE_ENTROPY_MASK\t\t0x0000ffffffff0000ULL\n#define DEFAULT_ENTROPY_BITS\t0x0000DEADDEAD0000ULL\n\tuintptr_t cookie = (uintptr_t)malloc_entropy[0] & COOKIE_ENTROPY_MASK;\n\tif (!cookie) {\n\t\tcookie = malloc_entropy[1] & COOKIE_ENTROPY_MASK;\n\t\tif (!cookie) {\n\t\t\t// The cookie can't be zero, because it's used to compute the guard\n\t\t\t// value in free slots, so make sure we have a non-zero value. Using\n\t\t\t// a fixed value allows us to recognize that it isn't real entropy.\n\t\t\tcookie = DEFAULT_ENTROPY_BITS;\n\t\t}\n\t}\n\tnanozone->slot_freelist_cookie = cookie;\n\n\t// For the ASLR cookie, we take the top 12 bits of malloc_entropy[1] and\n\t// align it to the block field of a Nano address.\n\tnanozone->aslr_cookie = malloc_entropy[1] >> (64 - NANOV2_BLOCK_BITS);\n\tnanozone->aslr_cookie_aligned = nanozone->aslr_cookie << NANOV2_OFFSET_BITS;\n\t\n\t_malloc_lock_init(&nanozone->blocks_lock);\n\t_malloc_lock_init(&nanozone->regions_lock);\n\t_malloc_lock_init(&nanozone->madvise_lock);\n\n\t// Allocate the initial region. If this does not succeed, we disable Nano.\n\tnanov2_addr_t p = {.fields.nano_signature = NANOZONE_SIGNATURE};\n\tnanov2_region_t *region = (nanov2_region_t *)p.addr;\n\tboolean_t result = nanov2_allocate_region(region);\n\tif (!result) {\n\t\tnano_common_deallocate_pages(nanozone, NANOZONEV2_ZONE_PAGED_SIZE, 0);\n\t\t_malloc_engaged_nano = NANO_NONE;\n\t\tmalloc_report(ASL_LEVEL_NOTICE, \"nano zone abandoned due to inability \"\n\t\t\t\t\"to preallocate reserved vm space.\\n\");\n\t\treturn NULL;\n\t}\n\tnanov2_region_linkage_t *region_linkage =\n\t\t\tnanov2_region_linkage_for_region(nanozone, region);\n\tregion_linkage->next_region_offset = 0;\n\n\t// Install the first region and pre-allocate the first arena.\n\tnanozone->first_region_base = region;\n\tnanozone->current_region_base = region;\n\tnanozone->current_region_next_arena = ((nanov2_arena_t *)region) + 1;\n\tnanozone->current_region_limit = region + 1;\n\tnanozone->statistics.allocated_regions = 1;\n\n\treturn (malloc_zone_t *)nanozone;\n}\n#endif // OS_VARIANT_NOTRESOLVED\n\n#pragma mark -\n#pragma mark Zone Fork Handling\n\n// Nanomalloc assumes that after a fork, it would be dangerous to rely on\n// the integrity of the zone data. During a fork, some of the zone handlers are\n// switched to the versions below, which do the following:\n// 1. Delegate all new allocation to the helper zone.\n// 2. Do nothing when asked to free memory that Nano allocated. There will be a\n// leak, but this is better than possibly crashing.\n\n#if OS_VARIANT_RESOLVED\nvoid *\nnanov2_forked_malloc(nanozonev2_t *nanozone, size_t size)\n{\n\t// Just hand to the helper zone.\n\treturn nanozone->helper_zone->malloc(nanozone->helper_zone, size);\n}\n#endif // OS_VARIANT_RESOLVED\n\n#if OS_VARIANT_NOTRESOLVED\n\nstatic void *\nnanov2_forked_calloc(nanozonev2_t *nanozone, size_t num_items, size_t size)\n{\n\t// Just hand to the helper zone.\n\treturn nanozone->helper_zone->calloc(nanozone->helper_zone, num_items,\n\t\t\tsize);\n}\n\n#endif // OS_VARIANT_NOTRESOLVED\n\n#if OS_VARIANT_RESOLVED\n\nvoid\nnanov2_forked_free(nanozonev2_t *nanozone, void *ptr)\n{\n\tif (!ptr) {\n\t\treturn; // Protect against malloc_zone_free() passing NULL.\n\t}\n\n\t// <rdar://problem/26481467> exhausting a slot may result in a pointer with\n\t// the nanozone prefix being given to nano_free via malloc_zone_free. Calling\n\t// vet_and_size here, instead of in _nano_free_check_scribble means we can\n\t// early-out into the helper_zone if it turns out nano does not own this ptr.\n\tsize_t sz = nanov2_pointer_size(nanozone, ptr, FALSE);\n\tif (sz || nanov2_has_valid_signature(ptr)) {\n\t\t/* Drop it on the floor as nanozone metadata could be fouled by fork. */\n\t\treturn;\n\t} else {\n\t\tnanozone->helper_zone->free(nanozone->helper_zone, ptr);\n\t\treturn;\n\t}\n\t/* NOTREACHED */\n}\n\nvoid\nnanov2_forked_free_definite_size(nanozonev2_t *nanozone, void *ptr, size_t size)\n{\n\tnanov2_forked_free(nanozone, ptr);\n}\n\nvoid *\nnanov2_forked_realloc(nanozonev2_t *nanozone, void *ptr, size_t new_size)\n{\n\t// could occur through malloc_zone_realloc() path\n\tif (!ptr) {\n\t\t// If ptr is a null pointer, realloc() shall be equivalent to malloc()\n\t\t// for the specified size.\n\t\treturn nanov2_forked_malloc(nanozone, new_size);\n\t}\n\n\tsize_t old_size = nanov2_pointer_size(nanozone, ptr, FALSE);\n\tif (!old_size) {\n\t\t// not-nano pointer, hand down to helper zone\n\t\tmalloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);\n\t\treturn zone->realloc(zone, ptr, new_size);\n\t} else {\n\t\tif (!new_size) {\n\t\t\t// If size is 0 and ptr is not a null pointer, the object pointed to\n\t\t\t// is freed. However as nanozone metadata could be fouled by fork,\n\t\t\t// we'll intentionally leak it.\n\n\t\t\t// If size is 0, either a null pointer or a unique pointer that can\n\t\t\t// be successfully passed to free() shall be returned.\n\t\t\treturn nanov2_forked_malloc(nanozone, 1);\n\t\t}\n\n\t\tvoid *new_ptr = nanozone->helper_zone->malloc(nanozone->helper_zone,\n\t\t\t\tnew_size);\n\t\tif (new_ptr) {\n\t\t\tsize_t valid_size = MIN(old_size, new_size);\n\t\t\tmemcpy(new_ptr, ptr, valid_size);\n\t\t\t// Original pointer is intentionally leaked as nanozone metadata\n\t\t\t// could be fouled by fork.\n\t\t\treturn new_ptr;\n\t\t} else {\n\t\t\t// Original ptr is left intact\n\t\t\treturn NULL;\n\t\t}\n\t\t/* NOTREACHED */\n\t}\n\t/* NOTREACHED */\n}\n#endif // OS_VARIANT_RESOLVED\n\n#if OS_VARIANT_NOTRESOLVED\n\nstatic unsigned\nnanov2_forked_batch_malloc(nanozonev2_t *nanozone, size_t size, void **results,\n\t\tunsigned count)\n{\n\t// Just pass this to the helper zone.\n\treturn nanozone->helper_zone->batch_malloc(nanozone->helper_zone, size,\n\t\t\tresults, count);\n}\n#endif // OS_VARIANT_NOTRESOLVED\n\n#if OS_VARIANT_RESOLVED\n\nvoid\nnanov2_forked_batch_free(nanozonev2_t *nanozone, void **to_be_freed,\n\t\tunsigned count)\n{\n\tif (!count) {\n\t\treturn;\n\t}\n\n\twhile (count--) {\n\t\tvoid *ptr = to_be_freed[count];\n\t\tif (ptr) {\n\t\t\tnanov2_forked_free(nanozone, ptr);\n\t\t}\n\t}\n}\n#endif // OS_VARIANT_RESOLVED\n\n#if OS_VARIANT_NOTRESOLVED\n\nstatic boolean_t\nnanov2_forked_claimed_address(struct _malloc_zone_t *zone, void *ptr)\n{\n\t// This does not operate after fork - default to true to avoid\n\t// false negatives.\n\treturn true;\n}\n\nvoid\nnanov2_forked_zone(nanozonev2_t *nanozone)\n{\n\t// Hobble the nano zone in the child of a fork prior to an exec since\n\t// the state of the zone can be made inconsistent by a parent thread while\n\t// the fork is underway. All new allocations will be referred to the helper\n\t// zone (which is more stable.) All free()'s of existing nano objects will\n\t// be leaked.\n\tmprotect(nanozone, sizeof(nanozone->basic_zone), PROT_READ | PROT_WRITE);\n\n\tnanozone->basic_zone.size = OS_RESOLVED_VARIANT_ADDR(nanov2_size);\t// Unchanged\n\tnanozone->basic_zone.malloc = OS_RESOLVED_VARIANT_ADDR(nanov2_forked_malloc);\n\tnanozone->basic_zone.calloc = (void *)nanov2_forked_calloc;\n\tnanozone->basic_zone.valloc = (void *)nanov2_valloc;\t\t// Unchanged\n\tnanozone->basic_zone.free = OS_RESOLVED_VARIANT_ADDR(nanov2_forked_free);\n\tnanozone->basic_zone.realloc = OS_RESOLVED_VARIANT_ADDR(nanov2_forked_realloc);\n\tnanozone->basic_zone.destroy = (void *)nanov2_destroy;\t\t// Unchanged\n\tnanozone->basic_zone.batch_malloc = (void *)nanov2_forked_batch_malloc;\n\tnanozone->basic_zone.batch_free = OS_RESOLVED_VARIANT_ADDR(nanov2_forked_batch_free);\n\tnanozone->basic_zone.introspect =\n\t\t\t(struct malloc_introspection_t *)&nanov2_introspect;// Unchanged\n\tnanozone->basic_zone.memalign = (void *)nanov2_memalign; \t// Unchanged\n\tnanozone->basic_zone.free_definite_size =\n\t\t\tOS_RESOLVED_VARIANT_ADDR(nanov2_forked_free_definite_size);\n\tnanozone->basic_zone.claimed_address = nanov2_forked_claimed_address;\n\tmprotect(nanozone, sizeof(nanozone->basic_zone), PROT_READ);\n}\n\n#endif // OS_VARIANT_NOTRESOLVED\n\n#endif // CONFIG_NANOZONE\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/nanov2_malloc.h",
    "content": "/*\n * Copyright (c) 2018 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __NANOV2_MALLOC_H\n#define __NANOV2_MALLOC_H\n\n// Forward declaration for the nanozonev2 structure.\ntypedef struct nanozonev2_s nanozonev2_t;\n\nMALLOC_NOEXPORT\nvoid\nnanov2_init(const char *envp[], const char *apple[], const char *bootargs);\n\nMALLOC_NOEXPORT\nvoid\nnanov2_configure(void);\n\nMALLOC_NOEXPORT\nmalloc_zone_t *\nnanov2_create_zone(malloc_zone_t *helper_zone, unsigned debug_flags);\n\nMALLOC_NOEXPORT\nvoid\nnanov2_forked_zone(nanozonev2_t *nanozone);\n\n#endif // __NANOV2_MALLOC_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/nanov2_zone.h",
    "content": "/*\n * Copyright (c) 2018 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __NANOV2_ZONE_H\n#define __NANOV2_ZONE_H\n\n#if CONFIG_NANOZONE\n\n#pragma mark -\n#pragma mark Address Structure\n\n#if TARGET_OS_OSX || TARGET_OS_SIMULATOR\n\n#define NANOV2_REGION_BITS\t\t15\n#define NANOV2_ARENA_BITS\t\t3\n#define NANOV2_BLOCK_BITS\t\t12\n#define NANOV2_OFFSET_BITS\t\t14\n\n#else // TARGET_OS_OSX || TARGET_OS_SIMULATOR\n\n#define NANOV2_REGION_BITS\t\t0\n#define NANOV2_ARENA_BITS\t\t3\n#define NANOV2_BLOCK_BITS\t\t12\n#define NANOV2_OFFSET_BITS\t\t14\n\n#endif // TARGET_OS_OSX || TARGET_OS_SIMULATOR\n\n#if NANOV2_REGION_BITS > 0\n#define NANOV2_MULTIPLE_REGIONS\t1\n#else\t// NANOV2_REGION_BITS > 0\n#define NANOV2_MULTIPLE_REGIONS\t0\n#endif\t// NANOV2_REGION_BITS > 0\n\n// Size of a block (currently 16KB)\n#define NANOV2_BLOCK_SIZE\t\t(1 << NANOV2_OFFSET_BITS)\n\n// Size of an arena (currently 64MB)\n#define NANOV2_ARENA_SIZE\t\t(64 * 1024 * 1024)\n\n// Size of a region (currently 512MB)\n#define NANOV2_REGION_SIZE\t\t(512 * 1024 * 1024)\n\n// Number of blocks per arena (currently 4096)\n#define NANOV2_BLOCKS_PER_ARENA\t(NANOV2_ARENA_SIZE/NANOV2_BLOCK_SIZE)\n\n// Number of arenas per region (currently 8)\n#define NANOV2_ARENAS_PER_REGION\t(NANOV2_REGION_SIZE/NANOV2_ARENA_SIZE)\n\n// Maximum number of slots per block\n#define NANOV2_MAX_SLOTS_PER_BLOCK\t(NANOV2_BLOCK_SIZE/NANO_REGIME_QUANTA_SIZE)\n\n// Highest region number.\n#if NANOV2_MULTIPLE_REGIONS\n#define NANOV2_MAX_REGION_NUMBER\t((1 << NANOV2_REGION_BITS) - 1)\n#else \t// NANOV2_MULTIPLE_REGIONS\n#define NANOV2_MAX_REGION_NUMBER\t0\n#endif\t// NANOV2_MULTIPLE_REGIONS\n\n// clang-format really dislikes the bitfields here\n// clang-format off\n#if defined(__BIG_ENDIAN__)\n\n// Nano V2 address structure.\nstruct nanov2_addr_s {\n    uintptr_t nano_signature : NANOZONE_SIGNATURE_BITS;\n#if NANOV2_MULTIPLE_REGIONS\n    uintptr_t nano_region: NANOV2_REGION_BITS;\n#endif // NANOV2_MULTIPLE_REGIONS\n\tuintptr_t nano_arena : NANOV2_ARENA_BITS;\n\tuintptr_t nano_block : NANOV2_BLOCK_BITS;\n\tuintptr_t nano_offset : NANOV2_OFFSET_BITS;\n};\nMALLOC_STATIC_ASSERT(sizeof(struct nanov2_addr_s) == sizeof(uintptr_t),\n\t\t\"Wrong size for nanov2_addr_s\");\n\n#else\t// defined(__BIG_ENDIAN__)\n\n// least significant bits declared first\nstruct nanov2_addr_s {\n    uintptr_t nano_offset : NANOV2_OFFSET_BITS;\n\tuintptr_t nano_block : NANOV2_BLOCK_BITS;\n\tuintptr_t nano_arena : NANOV2_ARENA_BITS;\n#if NANOV2_MULTIPLE_REGIONS\n\tuintptr_t nano_region: NANOV2_REGION_BITS;\n#endif // NANOV2_MULTIPLE_REGIONS\n\tuintptr_t nano_signature : NANOZONE_SIGNATURE_BITS;\n};\nMALLOC_STATIC_ASSERT(sizeof(struct nanov2_addr_s) == sizeof(uintptr_t),\n\t\t\"Wrong size for nanov2_addr_s\");\n\n#endif\t// defined(__BIG_ENDIAN__)\n\n// clang-format on\n\n// Union that allows easy extraction of the fields in a Nano V2 address.\ntypedef union  {\n    void *addr;\n    struct nanov2_addr_s fields;\n} nanov2_addr_t;\n\n// Typedef that tags a size class value. Range is 0 to NANO_SIZE_CLASSES - 1.\ntypedef unsigned nanov2_size_class_t;\n\n#pragma mark -\n#pragma mark Block Definitions\n\n// A block is a chunk of NANOV2_BLOCK_SIZE bytes of memory.\ntypedef struct {\n\tunsigned char content[NANOV2_BLOCK_SIZE];\n} nanov2_block_t;\n\nMALLOC_STATIC_ASSERT(sizeof(nanov2_block_t) == NANOV2_BLOCK_SIZE,\n\t\t\"nanov2_block_t must be the same size as a block\");\n\n#pragma mark -\n#pragma mark Arena and Block Definitions\n\n// An arena is an array of NANOV2_BLOCKS_PER_ARENA blocks.\ntypedef struct {\n\tnanov2_block_t blocks[NANOV2_BLOCKS_PER_ARENA];\n} nanov2_arena_t;\n\nMALLOC_STATIC_ASSERT(sizeof(nanov2_arena_t) == NANOV2_BLOCK_SIZE * NANOV2_BLOCKS_PER_ARENA,\n\t\t\"nanov2_arena_t must be the same size as its blocks\");\n\n// Per-block header structure, embedded in the arena metadata block.\ntypedef struct {\n    uint32_t next_slot : 11;\t// Next slot on free list, 1-based.\n    uint32_t free_count : 10;\t// Free slots in this block - 1\n    uint32_t gen_count : 10;\t// A-B-A count\n    uint32_t in_use : 1;\t\t// Being used for allocations.\n} nanov2_block_meta_t;\nMALLOC_STATIC_ASSERT(sizeof(nanov2_block_meta_t) == sizeof(uint32_t),\n\t\t\"Incorrect size for nanov2_block_meta_t\");\n\n// Distinguished values of next_slot\n#define SLOT_NULL\t\t\t0\t\t// Slot has never been used.\n#define SLOT_BUMP \t\t\t0x7fb\t// Marks the end of the free list\n#define SLOT_FULL\t\t\t0x7fc\t// Slot is full (no free slots)\n#define SLOT_CAN_MADVISE \t0x7fd\t// Block can be madvised (and in_use == 0)\n#define SLOT_MADVISING\t\t0x7fe\t// Block is being madvised. Do not touch\n#define SLOT_MADVISED \t\t0x7ff\t// Block has been madvised.\n\n// View of the per-block header structure that allows it to be used where a\n// primitive type is required.\ntypedef union {\n\tnanov2_block_meta_t meta;\n\tuint32_t bits;\n} nanov2_block_meta_view_t;\n\n// Structure overlaid onto an arena's metadata block. This must be exactly\n// the same size as a block.\ntypedef struct {\n\tnanov2_block_meta_t arena_block_meta[NANOV2_BLOCKS_PER_ARENA];\n} nanov2_arena_metablock_t;\n\nMALLOC_STATIC_ASSERT(sizeof(nanov2_arena_metablock_t) == NANOV2_BLOCK_SIZE,\n\t\t\"nanov2_arena_metablock_t must be the same size as a block\");\n\n// Structure overlaid on slots that are on the block freelist.\ntypedef struct {\n    uint64_t double_free_guard;\n    uint16_t next_slot;\n} nanov2_free_slot_t;\n\nMALLOC_STATIC_ASSERT(\n\t\tsizeof(nanov2_free_slot_t) <= NANO_REGIME_QUANTA_SIZE,\n\t\t\"nanov2_free_slot_t too large\");\n\n// Type for the index of a block in its hosting arena.\ntypedef unsigned nanov2_block_index_t;\n\n// Type for the index of a block meta structure in its hosting metadata block.\ntypedef unsigned nanov2_meta_index_t;\n\n#pragma mark -\n#pragma mark Region Definitions\n\n// A region is an array of NANOV2_ARENAS_PER_REGION arenas.\ntypedef struct {\n\tnanov2_arena_t arenas[NANOV2_ARENAS_PER_REGION];\n} nanov2_region_t;\n\n// Linkage between regions. Overlays the nanov2_block_meta_t that corresponds\n// to the arena metadata block, so must be the same size as nanov2_block_meta_t.\ntypedef struct {\n    uint16_t next_region_offset;\t// Offset to next region in 512MB blocks\n\tuint16_t unused;\n} nanov2_region_linkage_t;\n\nMALLOC_STATIC_ASSERT(\n\t\tsizeof (nanov2_block_meta_t) == sizeof(nanov2_region_linkage_t),\n\t\t\"nanov2_block_meta_t must be the same size as nanov2_region_linkage_t\");\n\n#pragma mark -\n#pragma mark Statistics\n\ntypedef struct {\n\tuint64_t\ttotal_allocations;\n\tuint64_t\ttotal_frees;\n\tuint64_t\tmadvised_blocks;\t// Does not reduce when reused.\n\tuint64_t\tmadvise_races;\t\t// Reused while being madvised.\n} nanov2_size_class_statistics;\n\ntypedef struct {\n\t// Number of allocated regions\n\tunsigned allocated_regions;\n\n\t// Number of times a region could not be placed at its preferred location\n\tunsigned region_address_clashes;\n\n\t// Statistics collected by size class\n\tnanov2_size_class_statistics size_class_statistics[NANO_SIZE_CLASSES];\n} nanov2_statistics_t;\n\n#pragma mark -\n#pragma mark Zone Definitions\n\n// Maximum number of currently active allocation blocks per size class.\n// Initially, the default is for each physical CPU to have a dedicated block.\n#define MAX_CURRENT_BLOCKS 16\n#define MAX_CURRENT_BLOCKS_MASK (MAX_CURRENT_BLOCKS - 1)\nMALLOC_STATIC_ASSERT(MAX_CURRENT_BLOCKS > 1 &&\n\t\t!(MAX_CURRENT_BLOCKS & MAX_CURRENT_BLOCKS_MASK),\n\t\t\"MAX_CURRENT_BLOCKS must be a power of 2\");\n\ntypedef struct nanozonev2_s {\n    // first page will be given read-only protection\n    malloc_zone_t\t\tbasic_zone;\n    uint8_t\t\t\t\tpad[PAGE_MAX_SIZE - sizeof(malloc_zone_t)];\n\n\t// Current allocation blocks. Indexed by a factor that may change in the\n\t// future (and may be tuneable). Initially indexed by physical CPU number.\n\tnanov2_block_meta_t *current_block[NANO_SIZE_CLASSES][MAX_CURRENT_BLOCKS];\n\n\t// Locks for the current allocation blocks.\n\t_malloc_lock_s\t\tcurrent_block_lock[NANO_SIZE_CLASSES][MAX_CURRENT_BLOCKS];\n\n\t// Lock for delegate_allocations.\n\t_malloc_lock_s\t\tdelegate_allocations_lock;\n\n\t// Mask of size classes for which allocation should be delegated when a new\n\t// block is needed and the class has become full.\n\tuint16_t\t\t\tdelegate_allocations;\n\n\t// Zone debug flags.\n    unsigned\t\t\tdebug_flags;\n\t\n\t// Cookie used for ASLR within an arena.\n\tuint64_t\t\t\taslr_cookie;\n\tuint64_t\t\t\taslr_cookie_aligned;\n\n    // cookie used to protect linkage on the block freelist\n    uintptr_t\t\t\tslot_freelist_cookie;\n\n\t// The zone to which allocations that cannot be satisfied by Nano V2\n\t// will be handed off.\n\tmalloc_zone_t\t\t*helper_zone;\n\t\n\t// Lock used to serialize access to current_block.\n\t_malloc_lock_s\t\tblocks_lock;\n\n\t// Lock used to protect current_region_base, current_region_next_arena and\n\t// current_region_limit.\n\t_malloc_lock_s\t\tregions_lock;\n\t\n\t// Base address of the first region. Fixed once set.\n\tnanov2_region_t \t*first_region_base;\n\t\n\t// Base address of the current region. Always the most recently allocated\n\t// region and therefore the one with the highest base address.\n\tnanov2_region_t \t*current_region_base;\n\t\n\t// Address to use for the next arena. Always between current_region_base\n\t// and current_region_limit.\n\tnanov2_arena_t\t\t*current_region_next_arena;\n\t\n \t// Limit address of the current region (first byte after the region).\n \tvoid\t\t\t\t*current_region_limit;\n\t\n\t// Lock used when madvising.\n\t_malloc_lock_s\t\tmadvise_lock;\n\n\t// Global and per-size class statistics\n\tnanov2_statistics_t\tstatistics;\n} nanozonev2_t;\n\n#define NANOZONEV2_ZONE_PAGED_SIZE\tmach_vm_round_page(sizeof(nanozonev2_t))\n\n#pragma mark -\n#pragma mark Address Manipulation\n\n#define NANOV2_BLOCK_ADDRESS_MASK ~((1ULL << (NANOV2_OFFSET_BITS)) - 1)\n#define NANOV2_ARENA_ADDRESS_MASK \\\n\t\t~((1ULL << (NANOV2_BLOCK_BITS + NANOV2_OFFSET_BITS)) - 1)\n#define NANOV2_REGION_ADDRESS_MASK \\\n\t\t~((1ULL << (NANOV2_ARENA_BITS + NANOV2_BLOCK_BITS + NANOV2_OFFSET_BITS)) - 1)\n\n#endif // CONFIG_NANOZONE\n\n#endif // __NANOV2_ZONE_H\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/platform.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __PLATFORM_H\n#define __PLATFORM_H\n\n#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n#define MALLOC_TARGET_IOS 1\n#else // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n#define MALLOC_TARGET_IOS 0\n#endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\n#ifdef __LP64__\n#define MALLOC_TARGET_64BIT 1\n#else // __LP64__\n#define MALLOC_TARGET_64BIT 0\n#endif\n\n// <rdar://problem/12596555>\n#if MALLOC_TARGET_IOS\n# define CONFIG_MADVISE_PRESSURE_RELIEF 0\n#else // MALLOC_TARGET_IOS\n# define CONFIG_MADVISE_PRESSURE_RELIEF 1\n#endif // MALLOC_TARGET_IOS\n\n// <rdar://problem/12596555>\n#if MALLOC_TARGET_IOS\n# define CONFIG_RECIRC_DEPOT 1\n# define CONFIG_AGGRESSIVE_MADVISE 1\n#else // MALLOC_TARGET_IOS\n# define CONFIG_RECIRC_DEPOT 1\n# define CONFIG_AGGRESSIVE_MADVISE 0\n#endif // MALLOC_TARGET_IOS\n\n// <rdar://problem/10397726>\n#define CONFIG_RELAXED_INVARIANT_CHECKS 1\n\n// <rdar://problem/19818071>\n#define CONFIG_MADVISE_STYLE MADV_FREE_REUSABLE\n\n#if MALLOC_TARGET_64BIT\n#define CONFIG_NANOZONE 1\n#define CONFIG_ASLR_INTERNAL 0\n#else // MALLOC_TARGET_64BIT\n#define CONFIG_NANOZONE 0\n#define CONFIG_ASLR_INTERNAL 1\n#endif // MALLOC_TARGET_64BIT\n\n// enable nano checking for corrupt free list\n#define NANO_FREE_DEQUEUE_DILIGENCE 1\n\n// This governs a last-free cache of 1 that bypasses the free-list for each region size\n#define CONFIG_TINY_CACHE 1\n#define CONFIG_SMALL_CACHE 1\n\n// The large last-free cache (aka. death row cache)\n#if MALLOC_TARGET_IOS\n#define CONFIG_LARGE_CACHE 0\n#else\n#define CONFIG_LARGE_CACHE 1\n#endif\n\n// <rdar://problem/26823590> compile-time MALLOC_SMALL cut-off size\n#if MALLOC_TARGET_IOS\n#if MALLOC_TARGET_64BIT\nMALLOC_STATIC_ASSERT(PAGE_MAX_SIZE == 16 * 1024, \"Expected 16k pages\");\n// TODO: rdar://problem/35395572\n#define CONFIG_SMALL_CUTOFF_DYNAMIC 0\n#endif\n#else\n#define CONFIG_SMALL_CUTOFF_LARGEMEM 1\n#endif // MALLOC_TARGET_IOS\n\n// memory resource exception handling\n#if MALLOC_TARGET_IOS || TARGET_OS_SIMULATOR\n#define ENABLE_MEMORY_RESOURCE_EXCEPTION_HANDLING 0\n#else\n#define ENABLE_MEMORY_RESOURCE_EXCEPTION_HANDLING 1\n#endif\n\n// presence of commpage memsize\n#define CONFIG_HAS_COMMPAGE_MEMSIZE 1\n\n// presence of commpage number of cpu count\n#define CONFIG_HAS_COMMPAGE_NCPUS 1\n\n// Use of hyper-shift for magazine selection.\n#define CONFIG_TINY_USES_HYPER_SHIFT 0\n#define CONFIG_SMALL_USES_HYPER_SHIFT 0\n\n#endif // __PLATFORM_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/printf.h",
    "content": "/*\n * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#define\tMALLOC_REPORT_NOLOG\t\t\t0x10\n#define\tMALLOC_REPORT_NOPREFIX\t\t0x20\n#define MALLOC_REPORT_CRASH\t\t\t0x40\n#define MALLOC_REPORT_DEBUG\t\t\t0x80\n\n// Most internal logging should use malloc_report() or malloc_vreport(). The\n// flags argument should be a combination of the MALLOC_REPORT_xxx values and\n// an optional log level encoded using the ASL_LEVEL_xxx constants. The log\n// level is ignored if MALLOC_REPORT_NOLOG is set.\n//\n// The flags do the following:\n//\tMALLOC_REPORT_NOLOG:\n//\t\t\tDoes not send the text to _simple_asl_log().\n//\tMALLOC_REPORT_NO_PREFIX:\n//\t\t\tDoes not write the program name, pid and thread identifier before\n//\t\t\tthe report text.\n//\tMALLOC_REPORTDEBUG:\n//\t\t\tincludes text suggesting that a breakpoint could be set\n//\t\t\ton malloc_error_break() to debug this kind of error.\n//\tMALLOC_REPORT_CRASH:\n//\t\t\tSame as MALLOC_REPORTDEBUG, but crashes after writing the report\n//\t\t\tmessage.\n//\n// In addition, if MALLOC_REPORT_CRASH or MALLOC_REPORTDEBUG are specified, this\n// function will sleep for an hour or send a SIGSTOP signal to the process if\n// the MallocErrorSleep and MallocErrorStop environment variables were set and\n// the report text will include a message indicating that this is\n// happening. In the case of MALLOC_REPORT_CRASH, the crash occurs after all of\n// the other actions have completed.\nMALLOC_NOEXPORT MALLOC_NOINLINE void\nmalloc_report(uint32_t flags, const char *fmt, ...) __printflike(2,3);\n\n// Like malloc_report(), but precedes the output message with prefix_msg\n// as a format string using prefix_arg as a single substition parameter,\n// allows the length of time to sleep while reporting an error to be\n// specified and passes the arguments to the fmt parameter in a va_list.\nMALLOC_NOEXPORT MALLOC_NOINLINE void\nmalloc_vreport(uint32_t flags, unsigned sleep_time, const char *prefix_msg,\n\t\tconst void *prefix_arg, const char *fmt, va_list ap);\n\n// Higher-level functions used by zone implementations to report errors.\nMALLOC_NOEXPORT MALLOC_NOINLINE void\nmalloc_zone_error(uint32_t flags, bool is_corruption, const char *fmt, ...) __printflike(3,4);\n\nMALLOC_NOEXPORT MALLOC_NOINLINE void\nmalloc_zone_check_fail(const char *msg, const char *fmt, ...) __printflike(2,3);\n\n// Configures where malloc logging goes based on environment variables. By\n// default, goes to stderr if it's a tty, and is otherwise dropped.\nMALLOC_NOEXPORT void\nmalloc_print_configure(bool restricted);\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/purgeable_malloc.c",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n\n#include \"internal.h\"\n\n//\n// purgeable zones have their own \"large\" allocation pool, but share \"tiny\" and \"large\"\n// heaps with a helper_zone identified in the call to create_purgeable_zone()\n//\nstatic size_t\npurgeable_size(szone_t *szone, const void *ptr)\n{\n\t// Only claim our large allocations, leave the shared tiny/small for the helper zone to claim.\n\treturn szone_size_try_large(szone, ptr);\n}\n\nstatic void *\npurgeable_malloc(szone_t *szone, size_t size)\n{\n\tif (size <= szone->large_threshold) {\n\t\treturn szone_malloc(szone->helper_zone, size);\n\t} else {\n\t\treturn szone_malloc(szone, size);\n\t}\n}\n\nstatic void *\npurgeable_calloc(szone_t *szone, size_t num_items, size_t size)\n{\n\tsize_t total_bytes;\n\n\tif (calloc_get_size(num_items, size, 0, &total_bytes)) {\n\t\treturn NULL;\n\t}\n\n\tif (total_bytes <= szone->large_threshold) {\n\t\treturn szone_calloc(szone->helper_zone, 1, total_bytes);\n\t} else {\n\t\treturn szone_calloc(szone, 1, total_bytes);\n\t}\n}\n\nstatic void *\npurgeable_valloc(szone_t *szone, size_t size)\n{\n\tif (size <= szone->large_threshold) {\n\t\treturn szone_valloc(szone->helper_zone, size);\n\t} else {\n\t\treturn szone_valloc(szone, size);\n\t}\n}\n\nstatic void\npurgeable_free(szone_t *szone, void *ptr)\n{\n\tlarge_entry_t *entry;\n\n\tSZONE_LOCK(szone);\n\tentry = large_entry_for_pointer_no_lock(szone, ptr);\n\tSZONE_UNLOCK(szone);\n\tif (entry) {\n\t\treturn free_large(szone, ptr);\n\t} else {\n\t\treturn szone_free(szone->helper_zone, ptr);\n\t}\n}\n\nstatic void\npurgeable_free_definite_size(szone_t *szone, void *ptr, size_t size)\n{\n\tif (size <= szone->large_threshold) {\n\t\treturn szone_free_definite_size(szone->helper_zone, ptr, size);\n\t} else {\n\t\treturn szone_free_definite_size(szone, ptr, size);\n\t}\n}\n\nstatic void *\npurgeable_realloc(szone_t *szone, void *ptr, size_t new_size)\n{\n\tsize_t old_size;\n\n\tif (NULL == ptr) {\n\t\t// If ptr is a null pointer, realloc() shall be equivalent to malloc() for the specified size.\n\t\treturn purgeable_malloc(szone, new_size);\n\t} else if (0 == new_size) {\n\t\t// If size is 0 and ptr is not a null pointer, the object pointed to is freed.\n\t\tpurgeable_free(szone, ptr);\n\t\t// If size is 0, either a null pointer or a unique pointer that can be successfully passed\n\t\t// to free() shall be returned.\n\t\treturn purgeable_malloc(szone, 1);\n\t}\n\n\told_size = purgeable_size(szone, ptr); // Now ptr can be safely size()'d\n\tif (!old_size) {\n\t\told_size = szone_size(szone->helper_zone, ptr);\n\t}\n\n\tif (!old_size) {\n\t\tmalloc_zone_error(szone->debug_flags, true, \"pointer %p being reallocated was not allocated\\n\", ptr);\n\t\treturn NULL;\n\t}\n\n\t// Distinguish 4 cases: {oldsize, newsize} x { <= , > large_threshold }\n\t// and deal with the allocation crossing from the purgeable zone to the helper zone and vice versa.\n\tif (old_size <= szone->large_threshold) {\n\t\tif (new_size <= szone->large_threshold) {\n\t\t\treturn szone_realloc(szone->helper_zone, ptr, new_size);\n\t\t} else {\n\t\t\t// allocation crosses from helper to purgeable zone\n\t\t\tvoid *new_ptr = purgeable_malloc(szone, new_size);\n\t\t\tif (new_ptr) {\n\t\t\t\tmemcpy(new_ptr, ptr, old_size);\n\t\t\t\tszone_free_definite_size(szone->helper_zone, ptr, old_size);\n\t\t\t}\n\t\t\treturn new_ptr; // in state VM_PURGABLE_NONVOLATILE\n\t\t}\n\t} else {\n\t\tif (new_size <= szone->large_threshold) {\n\t\t\t// allocation crosses from purgeable to helper zone\n\t\t\tvoid *new_ptr = szone_malloc(szone->helper_zone, new_size);\n\t\t\tif (new_ptr) {\n\t\t\t\tmemcpy(new_ptr, ptr, new_size);\n\t\t\t\tpurgeable_free_definite_size(szone, ptr, old_size);\n\t\t\t}\n\t\t\treturn new_ptr;\n\t\t} else {\n\t\t\tvoid *new_ptr = purgeable_malloc(szone, new_size);\n\t\t\tif (new_ptr) {\n\t\t\t\tmemcpy(new_ptr, ptr, MIN(old_size, new_size));\n\t\t\t\tpurgeable_free_definite_size(szone, ptr, old_size);\n\t\t\t}\n\t\t\treturn new_ptr; // in state VM_PURGABLE_NONVOLATILE\n\t\t}\n\t}\n\t/* NOTREACHED */\n}\n\nstatic void\npurgeable_destroy(szone_t *szone)\n{\n\t/* destroy large entries */\n\tsize_t index = szone->num_large_entries;\n\tlarge_entry_t *large;\n\tvm_range_t range_to_deallocate;\n\n\twhile (index--) {\n\t\tlarge = szone->large_entries + index;\n\t\tif (large->address) {\n\t\t\t// we deallocate_pages, including guard pages\n\t\t\tmvm_deallocate_pages((void *)(large->address), large->size, szone->debug_flags);\n\t\t}\n\t}\n\tlarge_entries_free_no_lock(szone, szone->large_entries, szone->num_large_entries, &range_to_deallocate);\n\tif (range_to_deallocate.size) {\n\t\tmvm_deallocate_pages((void *)range_to_deallocate.address, (size_t)range_to_deallocate.size, 0);\n\t}\n\n\t/* Now destroy the separate szone region */\n\tmvm_deallocate_pages((void *)szone, SZONE_PAGED_SIZE, 0);\n}\n\nstatic unsigned\npurgeable_batch_malloc(szone_t *szone, size_t size, void **results, unsigned count)\n{\n\treturn szone_batch_malloc(szone->helper_zone, size, results, count);\n}\n\nstatic void\npurgeable_batch_free(szone_t *szone, void **to_be_freed, unsigned count)\n{\n\treturn szone_batch_free(szone->helper_zone, to_be_freed, count);\n}\n\nstatic void *\npurgeable_memalign(szone_t *szone, size_t alignment, size_t size)\n{\n\tif (size <= szone->large_threshold) {\n\t\treturn szone_memalign(szone->helper_zone, alignment, size);\n\t} else {\n\t\treturn szone_memalign(szone, alignment, size);\n\t}\n}\n\nstatic kern_return_t\npurgeable_ptr_in_use_enumerator(task_t task,\n\t\t\t\t\t\t\t\tvoid *context,\n\t\t\t\t\t\t\t\tunsigned type_mask,\n\t\t\t\t\t\t\t\tvm_address_t zone_address,\n\t\t\t\t\t\t\t\tmemory_reader_t reader,\n\t\t\t\t\t\t\t\tvm_range_recorder_t recorder)\n{\n\tszone_t *szone;\n\tkern_return_t err;\n\n\tif (!reader) {\n\t\treader = _szone_default_reader;\n\t}\n\n\terr = reader(task, zone_address, sizeof(szone_t), (void **)&szone);\n\tif (err) {\n\t\treturn err;\n\t}\n\n\terr = large_in_use_enumerator(\n\t\t\t\t\t\t\t\t  task, context, type_mask, (vm_address_t)szone->large_entries, szone->num_large_entries, reader, recorder);\n\treturn err;\n}\n\nstatic size_t\npurgeable_good_size(szone_t *szone, size_t size)\n{\n\tif (size <= szone->large_threshold) {\n\t\treturn szone_good_size(szone->helper_zone, size);\n\t} else {\n\t\treturn szone_good_size(szone, size);\n\t}\n}\n\nstatic boolean_t\npurgeable_check(szone_t *szone)\n{\n\treturn 1;\n}\n\nstatic void\npurgeable_print(szone_t *szone, boolean_t verbose)\n{\n\tmalloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, \"Scalable zone %p: inUse=%u(%y) flags=%d\\n\", szone,\n\t\t\t\t   szone->num_large_objects_in_use, (int)szone->num_bytes_in_large_objects, szone->debug_flags);\n}\n\nstatic void\npurgeable_log(malloc_zone_t *zone, void *log_address)\n{\n\tszone_t *szone = (szone_t *)zone;\n\n\tszone->log_address = log_address;\n}\n\nstatic void\npurgeable_force_lock(szone_t *szone)\n{\n\tSZONE_LOCK(szone);\n}\n\nstatic void\npurgeable_force_unlock(szone_t *szone)\n{\n\tSZONE_UNLOCK(szone);\n}\n\nstatic void\npurgeable_reinit_lock(szone_t *szone)\n{\n\tSZONE_REINIT_LOCK(szone);\n}\n\nstatic void\npurgeable_statistics(szone_t *szone, malloc_statistics_t *stats)\n{\n\tstats->blocks_in_use = szone->num_large_objects_in_use;\n\tstats->size_in_use = stats->max_size_in_use = stats->size_allocated = szone->num_bytes_in_large_objects;\n}\n\nstatic boolean_t\npurgeable_locked(szone_t *szone)\n{\n\tint tookLock;\n\n\ttookLock = SZONE_TRY_LOCK(szone);\n\tif (tookLock == 0) {\n\t\treturn 1;\n\t}\n\tSZONE_UNLOCK(szone);\n\treturn 0;\n}\n\nstatic size_t\npurgeable_pressure_relief(szone_t *szone, size_t goal)\n{\n\treturn szone_pressure_relief(szone, goal) + szone_pressure_relief(szone->helper_zone, goal);\n}\n\nstatic const struct malloc_introspection_t purgeable_introspect = {\n\t(void *)purgeable_ptr_in_use_enumerator, (void *)purgeable_good_size, (void *)purgeable_check, (void *)purgeable_print,\n\tpurgeable_log, (void *)purgeable_force_lock, (void *)purgeable_force_unlock, (void *)purgeable_statistics,\n\t(void *)purgeable_locked, NULL, NULL, NULL, NULL, /* Zone enumeration version 7 and forward. */\n\t(void *)purgeable_reinit_lock, // reinit_lock version 9 and foward\n}; // marked as const to spare the DATA section\n\n\nstatic boolean_t\npurgeable_claimed_address(szone_t *szone, void *ptr)\n{\n\treturn szone_claimed_address(szone->helper_zone, ptr);\n}\n\nmalloc_zone_t *\ncreate_purgeable_zone(size_t initial_size, malloc_zone_t *malloc_default_zone, unsigned debug_flags)\n{\n\tszone_t *szone;\n\tuint64_t hw_memsize = 0;\n\n\t/* get memory for the zone. */\n\tszone = mvm_allocate_pages(SZONE_PAGED_SIZE, 0, 0, VM_MEMORY_MALLOC);\n\tif (!szone) {\n\t\treturn NULL;\n\t}\n\n\t/* set up the szone structure */\n#if 0\n#warning LOG enabled\n\tszone->log_address = ~0;\n#endif\n\n#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__)\n\thw_memsize = *(uint64_t *)(uintptr_t)_COMM_PAGE_MEMORY_SIZE;\n#else\n\tsize_t uint64_t_size = sizeof(hw_memsize);\n\n\tsysctlbyname(\"hw.memsize\", &hw_memsize, &uint64_t_size, 0, 0);\n#endif\n\n\track_init(&szone->tiny_rack, RACK_TYPE_TINY, 0, debug_flags | MALLOC_PURGEABLE);\n\track_init(&szone->small_rack, RACK_TYPE_SMALL, 0, debug_flags | MALLOC_PURGEABLE);\n\n\t/* Purgeable zone does not participate in the adaptive \"largemem\" sizing. */\n\tszone->is_largemem = 0;\n\tszone->large_threshold = LARGE_THRESHOLD;\n\tszone->vm_copy_threshold = VM_COPY_THRESHOLD;\n\n#if CONFIG_LARGE_CACHE\n\t// madvise(..., MADV_REUSABLE) death-row arrivals above this threshold [~0.1%]\n\tszone->large_entry_cache_reserve_limit = (size_t)(hw_memsize >> 10);\n\n\t/* <rdar://problem/6610904> Reset protection when returning a previous large allocation? */\n\tint32_t libSystemVersion = NSVersionOfLinkTimeLibrary(\"System\");\n\tif ((-1 != libSystemVersion) && ((libSystemVersion >> 16) < 112) /* CFSystemVersionSnowLeopard */) {\n\t\tszone->large_legacy_reset_mprotect = TRUE;\n\t} else {\n\t\tszone->large_legacy_reset_mprotect = FALSE;\n\t}\n#endif\n\n\tszone->basic_zone.version = 10;\n\tszone->basic_zone.size = (void *)purgeable_size;\n\tszone->basic_zone.malloc = (void *)purgeable_malloc;\n\tszone->basic_zone.calloc = (void *)purgeable_calloc;\n\tszone->basic_zone.valloc = (void *)purgeable_valloc;\n\tszone->basic_zone.free = (void *)purgeable_free;\n\tszone->basic_zone.realloc = (void *)purgeable_realloc;\n\tszone->basic_zone.destroy = (void *)purgeable_destroy;\n\tszone->basic_zone.batch_malloc = (void *)purgeable_batch_malloc;\n\tszone->basic_zone.batch_free = (void *)purgeable_batch_free;\n\tszone->basic_zone.introspect = (struct malloc_introspection_t *)&purgeable_introspect;\n\tszone->basic_zone.memalign = (void *)purgeable_memalign;\n\tszone->basic_zone.free_definite_size = (void *)purgeable_free_definite_size;\n\tszone->basic_zone.pressure_relief = (void *)purgeable_pressure_relief;\n\tszone->basic_zone.claimed_address = (void *)purgeable_claimed_address;\n\n\tszone->basic_zone.reserved1 = 0;\t\t\t\t\t   /* Set to zero once and for all as required by CFAllocator. */\n\tszone->basic_zone.reserved2 = 0;\t\t\t\t\t   /* Set to zero once and for all as required by CFAllocator. */\n\tmprotect(szone, sizeof(szone->basic_zone), PROT_READ); /* Prevent overwriting the function pointers in basic_zone. */\n\n\tszone->debug_flags = debug_flags | MALLOC_PURGEABLE;\n\n\t/* Purgeable zone does not support MALLOC_ADD_GUARD_PAGES. */\n\tif (szone->debug_flags & MALLOC_ADD_GUARD_PAGES) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"purgeable zone does not support guard pages\\n\");\n\t\tszone->debug_flags &= ~MALLOC_ADD_GUARD_PAGES;\n\t}\n\n\t_malloc_lock_init(&szone->large_szone_lock);\n\n\tszone->helper_zone = (struct szone_s *)malloc_default_zone;\n\n\tCHECK(szone, __PRETTY_FUNCTION__);\n\treturn (malloc_zone_t *)szone;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/purgeable_malloc.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __PURGEABLE_MALLOC_H\n#define __PURGEABLE_MALLOC_H\n\n/* Create a new zone that supports malloc_make{un}purgeable() discipline. */\nMALLOC_NOEXPORT\nmalloc_zone_t *\ncreate_purgeable_zone(size_t initial_size, malloc_zone_t *malloc_default_zone, unsigned debug_flags);\n\n#endif // __PURGEABLE_MALLOC_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/radix_tree.c",
    "content": "/*\n * Copyright (c) 2016 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include <assert.h>\n#include <mach/mach.h>\n#include <mach/mach_vm.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/reason.h>\n#include <unistd.h>\n\n#include <radix_tree.h>\n#include <radix_tree_internal.h>\n\n#if 0\nint radix_tree_indent = 0;\nbool radix_tree_should_print __attribute__((visibility(\"default\")))= true;\n#include <stdio.h>\n#define D(s, ...)                                   \\\n\tif (radix_tree_should_print) {                  \\\n\t\tfor (int i = 0; i < radix_tree_indent; i++) \\\n\t\t\tputchar(' ');                           \\\n\t\tprintf(s, __VA_ARGS__);                     \\\n\t}\n#define DINDENT(x)                    \\\n\tif (radix_tree_should_print) {    \\\n\t\tfor (int i = 0; i < (x); i++) \\\n\t\t\tputchar(' ');             \\\n\t}\n#define DINC(x) radix_tree_indent += x;\n#define DDEC(x) radix_tree_indent -= x;\n#else\n#define DINDENT(x)\n#define D(s, ...)\n#define DINC(x)\n#define DDEC(x)\n#endif\n\nstatic void __attribute__((noreturn)) radix_tree_panic(const char *fmt, ...)\n{\n\tva_list args;\n\tva_start(args, fmt);\n\tchar buf[256];\n\tvsnprintf(buf, sizeof(buf), fmt, args);\n\tva_end(args);\n\tabort_with_reason(OS_REASON_TEST, 0, buf, 0);\n}\n\nstruct interval {\n\tuint64_t start;\n\tuint64_t size;\n};\n\nstruct answer {\n\tstruct interval interval;\n\tuint64_t stackid;\n\tuint64_t limit;\n};\n\nstatic inline bool\nin_interval(uint64_t x, struct interval interval)\n{\n\treturn x >= interval.start && ((x - interval.start) < interval.size);\n}\n\nstatic inline bool\nintervals_intersect(struct interval a, struct interval b)\n{\n\tif (a.size == 0 || b.size == 0)\n\t\treturn false;\n\treturn (in_interval(a.start, b) || in_interval(a.start + a.size - 1, b) || in_interval(b.start, a) ||\n\t\t\tin_interval(b.start + b.size - 1, a));\n}\n\n__unused static inline bool\ninterval_is_subset(struct interval a, struct interval b)\n{\n\treturn in_interval(a.start, b) && in_interval(a.start + a.size - 1, b);\n}\n\nstatic inline struct interval\ntruncate_interval(struct interval a, uint64_t limit)\n{\n\tif (a.start >= limit) {\n\t\treturn (struct interval){.start = a.start, .size = 0};\n\t} else {\n\t\treturn (struct interval){.start = a.start, .size = limit - a.start};\n\t}\n}\n\nstatic inline bool\nanswer_found(struct answer answer)\n{\n\treturn answer.stackid != radix_tree_invalid_value;\n}\n\n/*\n * Modify the node to maintain the invariant that the lesser edge is first.\n * Return true if node needed to be modified.\n */\nstatic bool\nfixnode(struct radix_node *node)\n{\n\tbool swap = false;\n\tif (node->edges[0].labelBits && node->edges[1].labelBits) {\n\t\tunsigned label0 = node->edges[0].label << (RADIX_LABEL_BITS - node->edges[0].labelBits);\n\t\tunsigned label1 = node->edges[1].label << (RADIX_LABEL_BITS - node->edges[1].labelBits);\n\t\tif (label1 < label0)\n\t\t\tswap = true;\n\t} else if (node->edges[0].labelBits == 0 && node->edges[1].labelBits != 0) {\n\t\tswap = true;\n\t}\n\tif (swap) {\n\t\tstruct radix_edge edge0 = node->edges[0];\n\t\tnode->edges[0] = node->edges[1];\n\t\tnode->edges[1] = edge0;\n\t}\n\treturn swap;\n}\n\nstatic struct answer\nradix_tree_lookup_recursive(struct radix_tree *tree,\n\t\tstruct interval keys,\t // keys we're looking for\n\t\tstruct interval nodekeys, // keys it is possible that we will find\n\t\tstruct radix_node *node,\n\t\tint keyshift)\n{\n\tDINDENT(keyshift);\n\tD(\"LOOKUPREC %p keys=[%llx-%llx] nodekeys=[%llx-%llx]\\n\", node, keys.start, keys.start + keys.size, nodekeys.start,\n\t\t\tnodekeys.start + nodekeys.size);\n\n\tassert(node);\n\tassert(intervals_intersect(nodekeys, keys));\n\tassert(keyshift < RADIX_TREE_KEY_BITS);\n\tassert(!fixnode(node));\n\n\tif (keys.start < nodekeys.start) {\n\t\tuint64_t diff = nodekeys.start - keys.start;\n\t\tif (keys.size > diff) {\n\t\t\tkeys.start += diff;\n\t\t\tkeys.size -= diff;\n\t\t\tassert(keys.start == nodekeys.start);\n\t\t} else {\n\t\t\tDINDENT(keyshift);\n\t\t\tD(\"LOOKUPREC(<) quit keys.size=%llx diff=%llx\\n\", keys.size, diff);\n\t\t\treturn (struct answer){.limit = nodekeys.start, .stackid = radix_tree_invalid_value};\n\t\t}\n\t\tDINDENT(keyshift);\n\t\tD(\"LOOKUPREC(<) %p keys=[%llx-%llx]\\n\", node, keys.start, keys.start + keys.size);\n\t}\n\n\tassert(keys.start >= nodekeys.start);\n\tassert(intervals_intersect(nodekeys, keys));\n\n\tfor (int i = 1; i >= 0; i--) {\n\t\tstruct radix_edge *edge = &node->edges[i];\n\t\tif (!edge_valid(edge)) {\n\t\t\tcontinue;\n\t\t}\n\t\tuint64_t edgekeys_start = extend_key(nodekeys.start, edge->labelBits, keyshift, edge->label);\n\t\tassert(edgekeys_start >= nodekeys.start);\n\t\tstruct interval edgekeys = {.start = edgekeys_start, .size = nodekeys.size - (edgekeys_start - nodekeys.start)};\n\n\t\tDINDENT(keyshift);\n\t\tD(\"LOOKUPREC(edge%d) edgekeys=[%llx-%llx] nodekeys=[%llx-%llx]\\n\", i, edgekeys.start, edgekeys.start + edgekeys.size,\n\t\t\t\tnodekeys.start, nodekeys.start + nodekeys.size);\n\n\t\tassert(interval_is_subset(edgekeys, nodekeys));\n\t\tif (intervals_intersect(edgekeys, keys)) {\n\t\t\tif (edge->isLeaf) {\n\t\t\t\tstruct radix_node *leaf = getnode(tree, edge->index);\n\t\t\t\tassert(leaf);\n\t\t\t\tassert(keyshift + edge->labelBits == RADIX_TREE_KEY_BITS);\n\t\t\t\tuint64_t size = leaf_size(tree, leaf);\n\t\t\t\tassert(size <= edgekeys.size);\n\t\t\t\tedgekeys.size = size; // edgekeys is now exact.\n\t\t\t\tif (intervals_intersect(edgekeys, keys)) {\n\t\t\t\t\tDINDENT(keyshift);\n\t\t\t\t\tD(\"LOOKUPREC(found) leaf=(%d)%p %llx\\n\", edge->index, leaf, leaf->stackid);\n\t\t\t\t\treturn (struct answer){.interval = edgekeys, .stackid = leaf->stackid};\n\t\t\t\t}\n\t\t\t\tnodekeys = truncate_interval(nodekeys, edgekeys.start);\n\t\t\t} else {\n\t\t\t\tstruct answer answer =\n\t\t\t\t\t\tradix_tree_lookup_recursive(tree, keys, edgekeys, getnode(tree, edge->index), keyshift + edge->labelBits);\n\t\t\t\tif (answer_found(answer)) {\n\t\t\t\t\tDINDENT(keyshift);\n\t\t\t\t\tD(\"LOOKUPREC(found) %llx\\n\", answer.stackid);\n\t\t\t\t\treturn answer;\n\t\t\t\t}\n\t\t\t\tnodekeys = truncate_interval(nodekeys, answer.limit);\n\t\t\t}\n\t\t}\n\t}\n\n\tstruct answer ans = {.limit = nodekeys.start + nodekeys.size, .stackid = radix_tree_invalid_value};\n\tDINDENT(keyshift);\n\tD(\"LOOKUPREC(notfound) limit=%llx\\n\", ans.limit);\n\treturn ans;\n}\n\nstatic struct answer\nradix_tree_lookup_interval(struct radix_tree *tree, struct interval keys)\n{\n\tstruct interval max_interval = {.start = 0, .size = (uint64_t)-1};\n\tstruct answer ans = radix_tree_lookup_recursive(tree, keys, max_interval, getnode(tree, 0), 0);\n\tD(\"LOOKUP [%llx-%llx] -> [%llx, %llx] %llx\\n\", keys.start, keys.start + keys.size, ans.interval.start,\n\t\t\tans.interval.start + ans.interval.size, ans.stackid);\n\tassert(!answer_found(ans) || intervals_intersect(keys, ans.interval));\n\treturn ans;\n}\n\nuint64_t\nradix_tree_lookup(struct radix_tree *tree, uint64_t key)\n{\n\treturn radix_tree_lookup_interval(tree, (struct interval){.start = key, .size = 1}).stackid;\n}\n\nstatic void radix_tree_grow(struct radix_tree **treep);\n\nstatic unsigned\nradix_tree_allocate_node(struct radix_tree **treep)\n{\n\tif (!(*treep)->next_free)\n\t\tradix_tree_grow(treep);\n\n\tif (!(*treep)->next_free)\n\t\treturn 0;\n\n\tstruct radix_tree *tree = *treep;\n\n\tunsigned ret = tree->next_free;\n\tstruct radix_node *node = getnode(tree, tree->next_free);\n\tassert(node);\n\ttree->next_free = node->next_free;\n\tif (node->next_free && !node->next_free_is_initialized) {\n\t\tstruct radix_node *next = getnode(tree, node->next_free);\n\t\tassert(next);\n\t\tnext->next_free = (node->next_free + 1 < tree->num_nodes) ? node->next_free + 1 : 0;\n\t}\n\tnode->as_u64 = 0;\n\treturn ret;\n}\n\nstatic void\nradix_tree_free_node(struct radix_tree *tree, unsigned index)\n{\n\tstruct radix_node *node = getnode(tree, index);\n\tassert(node);\n\tnode->next_free = tree->next_free;\n\tnode->next_free_is_initialized = true;\n\ttree->next_free = index;\n}\n\nstatic bool\nradix_tree_insert_recursive(struct radix_tree **treep, struct interval keys, uint64_t value, unsigned node_index, int keyshift)\n{\n\tstruct radix_node *node = getnode(*treep, node_index);\n\n\tDINDENT(keyshift);\n\tD(\"INSERTREC %p keys=[%llx-%llx]\\n\", node, keys.start, keys.start + keys.size);\n\n\tassert(keyshift < RADIX_TREE_KEY_BITS);\n\tassert(node);\n\n\tfor (int i = 0; i < 2; i++) {\n\t\tstruct radix_edge *edge = &node->edges[i];\n\t\tint matching_bits = count_matching_bits(edge, keys.start, keyshift);\n\t\tif (matching_bits) {\n\t\t\tif (matching_bits == edge->labelBits) {\n\t\t\t\tif (edge->isLeaf) {\n\t\t\t\t\tassert(false); // it should have been deleted before we got here\n\t\t\t\t\tstruct radix_node *leaf = getnode(*treep, edge->index);\n\t\t\t\t\tassert(leaf);\n\t\t\t\t\tassert(keyshift + edge->labelBits == RADIX_TREE_KEY_BITS);\n\t\t\t\t\tleaf->stackid = value;\n\t\t\t\t\tset_leaf_size(*treep, leaf, keys.size);\n\t\t\t\t\tDINDENT(keyshift);\n\t\t\t\t\tD(\"inserted %p\\n\", node);\n\t\t\t\t\treturn true;\n\t\t\t\t} else {\n\t\t\t\t\treturn radix_tree_insert_recursive(treep, keys, value, edge->index, keyshift + edge->labelBits);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tunsigned index = radix_tree_allocate_node(treep);\n\t\t\t\tif (!index) {\n\t\t\t\t\tDINDENT(keyshift);\n\t\t\t\t\tD(\"FAILED! %p\\n\", node);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t/* pointers may have changed */\n\t\t\t\tnode = getnode(*treep, node_index);\n\t\t\t\tedge = &node->edges[i];\n\n\t\t\t\tstruct radix_node *newnode = getnode(*treep, index);\n\t\t\t\tDINDENT(keyshift);\n\t\t\t\tD(\"splitting edge newnode=%p isleaf=%s matching_bits=%d oldLabelBits=%d\\n\", newnode,\n\t\t\t\t\t\tedge->isLeaf ? \"true\" : \"false\", matching_bits, edge->labelBits);\n\t\t\t\tnewnode->edges[0].labelBits = (edge->labelBits - matching_bits);\n\t\t\t\tnewnode->edges[0].isLeaf = edge->isLeaf;\n\t\t\t\tnewnode->edges[0].index = edge->index;\n\t\t\t\tnewnode->edges[0].label = edge->label & ((1 << (edge->labelBits - matching_bits)) - 1);\n\n\t\t\t\tedge->label = edge->label >> (edge->labelBits - matching_bits);\n\t\t\t\tedge->labelBits = matching_bits;\n\t\t\t\tedge->isLeaf = false;\n\t\t\t\tedge->index = index;\n\n\t\t\t\tfixnode(node);\n\t\t\t\treturn radix_tree_insert_recursive(treep, keys, value, index, keyshift + matching_bits);\n\t\t\t}\n\t\t}\n\t\tif (edge->labelBits == 0) {\n\t\t\tif (RADIX_TREE_KEY_BITS - keyshift <= RADIX_LABEL_BITS) {\n\t\t\t\tunsigned index = radix_tree_allocate_node(treep);\n\t\t\t\tif (!index) {\n\t\t\t\t\tDINDENT(keyshift);\n\t\t\t\t\tD(\"FAILED! %p\\n\", node);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t/* pointers may have changed */\n\t\t\t\tnode = getnode(*treep, node_index);\n\t\t\t\tedge = &node->edges[i];\n\n\t\t\t\tedge->labelBits = RADIX_TREE_KEY_BITS - keyshift;\n\t\t\t\tedge->isLeaf = true;\n\t\t\t\tedge->index = index;\n\t\t\t\tedge->label = keybits(keys.start, RADIX_TREE_KEY_BITS - keyshift, keyshift);\n\t\t\t\tstruct radix_node *leaf = getnode(*treep, index);\n\t\t\t\tDINDENT(keyshift);\n\t\t\t\tD(\"new leaf node %p\\n\", leaf);\n\t\t\t\tleaf->stackid = value;\n\t\t\t\tset_leaf_size(*treep, leaf, keys.size);\n\t\t\t\tfixnode(node);\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\tunsigned index = radix_tree_allocate_node(treep);\n\t\t\t\tif (!index) {\n\t\t\t\t\tDINDENT(keyshift);\n\t\t\t\t\tD(\"FAILED! %p\\n\", node);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t/* pointers may have changed */\n\t\t\t\tnode = getnode(*treep, node_index);\n\t\t\t\tedge = &node->edges[i];\n\n\t\t\t\tedge->labelBits = RADIX_LABEL_BITS;\n\t\t\t\tedge->isLeaf = false;\n\t\t\t\tedge->index = index;\n\t\t\t\tedge->label = keybits(keys.start, RADIX_LABEL_BITS, keyshift);\n\n\t\t\t\tstruct radix_node *newnode = getnode(*treep, index);\n\t\t\t\tnewnode->as_u64 = 0;\n\t\t\t\tDINDENT(keyshift);\n\t\t\t\tD(\"new internal node %p\\n\", newnode);\n\n\t\t\t\tfixnode(node);\n\t\t\t\treturn radix_tree_insert_recursive(treep, keys, value, index, keyshift + RADIX_LABEL_BITS);\n\t\t\t}\n\t\t}\n\t}\n\n\tradix_tree_panic(\"MallocStackLogging INTERNAL ERROR: at least one edge must prefix-match or be unused\");\n}\n\nbool\nradix_tree_insert(struct radix_tree **treep, uint64_t key, uint64_t size, uint64_t value)\n{\n\tD(\"INSERT %llx-%llx\\n\", key, key + size);\n\tDINC(4);\n\tif (key + size < key) {\n\t\tradix_tree_panic(\"MallocStackLogging INTERNAL ERROR: interval wraps around the end of the address space: %llx, size=%llx\\n\",\n\t\t\t\tkey, size);\n\t}\n\tstruct radix_node node = {.stackid = value, .size = size >> (*treep)->leaf_size_shift};\n\tif (node.stackid != value || (((uint64_t)node.size) << (*treep)->leaf_size_shift) != size) {\n\t\tradix_tree_panic(\"MallocStackLogging INTERNAL ERROR: cannot represent value:%llx or size:%llx (key is %llx)\\n\", value, size, key);\n\t\treturn false;\n\t}\n\tuint64_t mask = ((uint64_t)-1) << (64 - RADIX_TREE_KEY_BITS);\n\tif ((key & mask) != key) {\n\t\tradix_tree_panic(\"MallocStackLogging INTERNAL ERROR: cannot represent key: %llx\\n\", key);\n\t}\n\tbool ok;\n\tok = radix_tree_delete(treep, key, size);\n\tif (!ok) {\n\t\tgoto out;\n\t}\n\tok = radix_tree_insert_recursive(treep, (struct interval){.start = key, .size = size}, value, 0, 0);\nout:\n\tDDEC(4);\n\treturn ok;\n}\n\nstatic bool\nradix_tree_delete_recursive(struct radix_tree *tree, uint64_t key, struct radix_node *node, int keyshift)\n{\n\tassert(keyshift < RADIX_TREE_KEY_BITS);\n\tassert(node);\n\n\tfor (int i = 0; i < 2; i++) {\n\t\tstruct radix_edge *edge = &node->edges[i];\n\t\tif (edge_matches(edge, key, keyshift)) {\n\t\t\tif (edge->isLeaf) {\n\t\t\t\tradix_tree_free_node(tree, edge->index);\n\t\t\t\tif (i == 0) {\n\t\t\t\t\tnode->edges[0] = node->edges[1];\n\t\t\t\t\tnode->edges[1].labelBits = 0;\n\t\t\t\t} else {\n\t\t\t\t\tnode->edges[1].labelBits = 0;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\tbool deleted = radix_tree_delete_recursive(tree, key, getnode(tree, edge->index), keyshift + edge->labelBits);\n\t\t\t\tif (deleted) {\n\t\t\t\t\tstruct radix_node *child = getnode(tree, edge->index);\n\t\t\t\t\tassert(child);\n\t\t\t\t\tif (child->edges[0].labelBits == 0 && child->edges[1].labelBits == 0) {\n\t\t\t\t\t\tradix_tree_free_node(tree, edge->index);\n\t\t\t\t\t\tif (i == 0) {\n\t\t\t\t\t\t\tnode->edges[0] = node->edges[1];\n\t\t\t\t\t\t\tnode->edges[1].labelBits = 0;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tnode->edges[1].labelBits = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn deleted;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\nbool\nradix_tree_delete(struct radix_tree **treep, uint64_t key, uint64_t size)\n{\n\tD(\"BALETE %llx-%llx\\n\", key, key + size);\n\tDINC(4);\n\tstruct interval keys = {.start = key, .size = size};\n\tbool ok = true;\n\twhile (1) {\n\t\tstruct answer answer = radix_tree_lookup_interval(*treep, keys);\n\t\tif (!answer_found(answer)) {\n\t\t\tbreak;\n\t\t}\n\t\tok = radix_tree_delete_recursive(*treep, answer.interval.start, getnode(*treep, 0), 0);\n\t\tassert(ok);\n\t\tD(\"BALETED %llx-%llx -> %llx\\n\", answer.interval.start, answer.interval.start + answer.interval.size, answer.stackid);\n\t\tif (answer.interval.start < keys.start) {\n\t\t\tD(\"REINSERTING %llx-%llx -> %llx\\n\", answer.interval.start,\n\t\t\t\t\tanswer.interval.start + (keys.start - answer.interval.start), answer.stackid);\n\t\t\tok = radix_tree_insert(treep, answer.interval.start, keys.start - answer.interval.start, answer.stackid);\n\t\t\tif (!ok) {\n\t\t\t\tgoto out;\n\t\t\t}\n\t\t}\n\t\tuint64_t answer_end = answer.interval.start + answer.interval.size;\n\t\tuint64_t keys_end = keys.start + keys.size;\n\t\tif (answer_end > keys_end) {\n\t\t\tD(\"REINSERTING %llx-%llx -> %llx\\n\", keys_end, keys_end + (answer_end - keys_end), answer.stackid);\n\t\t\tok = radix_tree_insert(treep, keys_end, answer_end - keys_end, answer.stackid);\n\t\t\tif (!ok) {\n\t\t\t\tgoto out;\n\t\t\t}\n\t\t}\n\t}\nout:\n\tDDEC(4);\n\treturn ok;\n}\n\nstruct radix_tree *\nradix_tree_init(void *buf, size_t size)\n{\n\tstruct radix_tree *tree = buf;\n\tmemcpy(tree->header, \"radixv2\", 8);\n\tvoid *nodestart = &tree->nodes[0];\n\tvoid *nodesend = buf + size;\n\tassert(nodestart < nodesend);\n\ttree->num_nodes = (uint32_t)(nodesend - nodestart) / sizeof(struct radix_node);\n\tassert(tree->num_nodes >= 3);\n\ttree->next_free = 1;\n\ttree->nodes[0].as_u64 = tree->nodes[1].as_u64 = 0;\n\ttree->nodes[1].next_free = 2;\n\ttree->leaf_size_shift = 12; // smallest size of a VM region is 4096\n\treturn tree;\n}\n\nstruct radix_tree *\nradix_tree_create()\n{\n\tmach_vm_size_t size = PAGE_SIZE;\n\tmach_vm_address_t allocated;\n\tkern_return_t kr =\n\t\t\tmach_vm_allocate(mach_task_self(), &allocated, size, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL));\n\tif (kr != KERN_SUCCESS) {\n\t\treturn NULL;\n\t}\n\treturn radix_tree_init((void *)allocated, PAGE_SIZE);\n\treturn NULL;\n}\n\nstatic void\nradix_tree_grow(struct radix_tree **treep)\n{\n\tmach_vm_size_t max_size = (1 << 16) * sizeof(struct radix_node);\n\n\tassert((*treep)->next_free == 0);\n\tmach_vm_size_t size = sizeof(struct radix_tree) + sizeof(struct radix_node) * (*treep)->num_nodes;\n\tassert(size % PAGE_SIZE == 0);\n\tmach_vm_size_t newsize = size * 2;\n\tif (newsize > max_size) {\n\t\tnewsize = max_size;\n\t}\n\tif (newsize <= size) {\n\t\treturn;\n\t}\n\tmach_vm_address_t allocated;\n\tkern_return_t kr =\n\t\t\tmach_vm_allocate(mach_task_self(), &allocated, newsize, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL));\n\tif (kr != KERN_SUCCESS) {\n\t\treturn;\n\t}\n\tD(\"GROW %p -> %p\\n\", *treep, (void *)allocated);\n\tkr = mach_vm_copy(mach_task_self(), (mach_vm_address_t)*treep, size, allocated);\n\tif (kr != KERN_SUCCESS) {\n\t\tmach_vm_deallocate(mach_task_self(), allocated, newsize);\n\t\treturn;\n\t}\n\tuint32_t old_num_nodes = (*treep)->num_nodes;\n\tmach_vm_deallocate(mach_task_self(), (mach_vm_address_t)*treep, size);\n\t*treep = (void *)allocated;\n\n\tvoid *nodestart = &(*treep)->nodes[0];\n\tvoid *nodesend = ((void *)(*treep)) + newsize;\n\t(*treep)->num_nodes = (uint32_t)(nodesend - nodestart) / sizeof(struct radix_node);\n\t(*treep)->next_free = old_num_nodes;\n\n\t(*treep)->nodes[old_num_nodes].next_free_is_initialized = 0;\n\t(*treep)->nodes[old_num_nodes].next_free = old_num_nodes + 1;\n}\n\nvoid\nradix_tree_destory(struct radix_tree *tree)\n{\n\tmach_vm_size_t size = sizeof(struct radix_tree) + sizeof(struct radix_node) * tree->num_nodes;\n\tassert(size % PAGE_SIZE == 0);\n\tmach_vm_deallocate(mach_task_self(), (mach_vm_address_t)tree, size);\n}\n\nstatic uint64_t\nradix_tree_count_recursive(struct radix_tree *tree, struct radix_node *node)\n{\n\tuint64_t count = 0;\n\tfor (int i = 0; i < 2; i++) {\n\t\tstruct radix_edge *edge = &node->edges[i];\n\t\tif (edge->labelBits == 0)\n\t\t\tcontinue;\n\t\tif (edge->isLeaf) {\n\t\t\tcount += leaf_size(tree, getnode(tree, edge->index));\n\t\t} else {\n\t\t\tcount += radix_tree_count_recursive(tree, getnode(tree, edge->index));\n\t\t}\n\t}\n\treturn count;\n}\n\nuint64_t\nradix_tree_count(struct radix_tree *tree)\n{\n\treturn radix_tree_count_recursive(tree, getnode(tree, 0));\n}\n\nuint64_t\nradix_tree_size(struct radix_tree *tree)\n{\n\tmach_vm_size_t size = sizeof(struct radix_tree) + sizeof(struct radix_node) * tree->num_nodes;\n\treturn size;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/radix_tree.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n\n#ifndef __RADIX_TREE_H\n#define __RADIX_TREE_H\n\n#include <stdbool.h>\n#include <stdint.h>\n\n/*\n * This is a radix tree implementation mapping 64 bit keys to 64 bit values.\n *\n * Its in-memory representation is also valid as a serial representation.\n */\n\nstruct radix_tree; \n\nstatic const uint64_t radix_tree_invalid_value = (uint64_t) -1; \n\n/*\n * Lookup a key in the radix tree and return its value.  Returns \n * radix_tree_invalid_value (ie -1) if not found \n */\n__attribute__((visibility(\"default\")))\nuint64_t \nradix_tree_lookup(struct radix_tree *tree, uint64_t key);\n\n/*\n * Insert an range of keys into a radix tree (possibly reallocing it).  Returns true on\n * success.\n *\n * Arguments:\n *\n *   treep: The tree to modify.  Will write to *treep if the tree needs to be realloc'd\n *   key: The first key to set\n *   size: The number of keys to set\n *   value: The value to set them too\n\n */\nbool \nradix_tree_insert(struct radix_tree **treep, uint64_t key, uint64_t size, uint64_t value);\n\n\n/* \n * Delete a range of keys from a radix tree.  Returns true on success.\n *\n * Arguments\n *\n *   treep: The tree to modify.  Will write to *treep if the tree needs to be realloc'd\n *   key: The first key to delete\n *   size: The number of keys to delete\n */\nbool\nradix_tree_delete(struct radix_tree **treep, uint64_t key, uint64_t size);\n\n\n/*\n * Create a radix tree\n */\nstruct radix_tree *\nradix_tree_create();\n\n/*\n * deallocate a radix tree\n */\nvoid\nradix_tree_destory(struct radix_tree *tree);\n\n/*\n * Count the number of keys in a radix tree.\n */\n__attribute__((visibility(\"default\")))\nuint64_t\nradix_tree_count(struct radix_tree *tree);\n\n/*\n * Get the size of the radix tree buffer\n */\nuint64_t\nradix_tree_size(struct radix_tree *tree);\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/radix_tree_debug.c",
    "content": "/*\n * Copyright (c) 2017 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include <radix_tree.h>\n#include <radix_tree_internal.h>\n\n#include <stdio.h>\n\nstatic\nbool\nradix_tree_fsck_recursive(struct radix_tree *tree, struct radix_node *node,\n\t\t\t\t\t\t  uint64_t key, int keyshift,\n\t\t\t\t\t\t  uint64_t min)\n{\n\tbool ok = true;\n\tfor (int i = 0; i < 2; i++) {\n\t\tstruct radix_edge *edge = &node->edges[i];\n\t\tif (edge->labelBits == 0)\n\t\t\tcontinue;\n\n\t\tuint64_t edgekey = extend_key(key, edge->labelBits, keyshift, edge->label);\n\n\t\tif (edge->isLeaf) {\n\t\t\tif (edgekey < min)\n\t\t\t{\n\t\t\t\tfprintf(stderr, \"!!!! node=%p min=%llx edge=%d edgekey=%llx\\n\", node, min, i, edgekey);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tstruct radix_node *leaf = getnode(tree, edge->index);\n\t\t\tmin = edgekey + leaf_size(tree, leaf);\n\t\t} else {\n\t\t\tok = ok && radix_tree_fsck_recursive(tree, getnode(tree, edge->index), edgekey, keyshift+edge->labelBits, min);\n\t\t}\n\t}\n\treturn ok;\n}\n\nbool\nradix_tree_fsck(struct radix_tree *tree)\n{\n\treturn radix_tree_fsck_recursive(tree, getnode(tree, 0), 0, 0, 0);\n}\n\nstatic\nvoid\nradix_tree_print_recursive(struct radix_tree *tree, struct radix_node *node, int indent,\n\t\t\t\t\t\t   uint64_t key, int keyshift) {\n\tif (node->edges[0].labelBits == 0 && node->edges[1].labelBits == 0) {\n\t\tprintf(\"%p:\", node);\n\t\tfor (int i = 0; i < indent; i++) printf(\" \");\n\t\tprintf(\"empty\\n\");\n\t}\n\tfor (int i = 0; i < 2; i++) {\n\t\tstruct radix_edge *edge = &node->edges[i];\n\t\tif (edge->labelBits == 0)\n\t\t\tcontinue;\n\t\tprintf(\"%p:\", node);\n\t\tfor (int i = 0; i < indent; i++) printf(\" \");\n\t\tprintf (\"0x%x/%d\", edge->label, edge->labelBits);\n\t\tif (edge->isLeaf) {\n\t\t\tstruct radix_node *leaf = getnode(tree, edge->index);\n\t\t\tprintf(\" [%llx-%llx] -> stack=%llx\\n\",\n\t\t\t\t   extend_key(key, edge->labelBits, keyshift, edge->label),\n\t\t\t\t   extend_key(key, edge->labelBits, keyshift, edge->label) + leaf_size(tree, leaf),\n\t\t\t\t   leaf->stackid);\n\t\t} else {\n\t\t\tprintf(\"\\n\");\n\t\t\tradix_tree_print_recursive(tree, getnode(tree, edge->index), indent + 4,\n\t\t\t\t\t\t\t\t\t   extend_key(key, edge->labelBits, keyshift, edge->label),\n\t\t\t\t\t\t\t\t\t   keyshift + edge->labelBits);\n\t\t}\n\t}\n}\n\nvoid\nradix_tree_print(struct radix_tree *tree)\n{\n\tradix_tree_print_recursive(tree, getnode(tree, 0), 0, 0, 0);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/radix_tree_internal.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __RADIX_TREE_INTERNAL_H\n#define __RADIX_TREE_INTERNAL_H\n\n#include <radix_tree.h>\n#include <stdbool.h>\n#include <stdlib.h>\n#include <assert.h>\n\n#define RADIX_LABEL_BITS 11 //max number of label bits per edge\n#define RADIX_TREE_KEY_BITS (64 - 12) //number of keybits we use (starting from MSB)\n\nstruct radix_edge {\n    unsigned label : RADIX_LABEL_BITS;\n    unsigned index : 16;\n    unsigned labelBits : 4;\n    unsigned isLeaf : 1;\n};\n\n_Static_assert(sizeof(struct radix_edge) == 4, \"size of radix_edge must be 4\");\n\nstruct radix_node {\n    union {\n        struct { \n            struct radix_edge edges[2];\n        };\n\t\tstruct {\n\t\t\tuint64_t stackid : 32;\n\t\t\tuint64_t size : 32;\n\t\t};\n        struct { \n            uint16_t next_free;\n            bool next_free_is_initialized;\n        };\n\t\tuint64_t as_u64;\n    };\n};\n\n_Static_assert(sizeof(struct radix_node) == 8, \"size of radix_node must be 8\");\n\n\nstruct radix_tree {\n\tchar header[8];\n\tuint32_t leaf_size_shift;\n    uint32_t num_nodes;\n    uint32_t next_free;\n    struct radix_node nodes[];\n};\n\nstatic inline\nuint64_t\nleaf_size(struct radix_tree *tree, struct radix_node *node)\n{\n\treturn ((uint64_t)node->size) << tree->leaf_size_shift;\n}\n\nstatic inline\nvoid\nset_leaf_size(struct radix_tree *tree, struct radix_node *node, uint64_t size)\n{\n\tnode->size = size >> tree->leaf_size_shift;\n\tassert(leaf_size(tree, node) == size);\n}\n\n\n/*\n * Does this edge even exist?\n */\nstatic inline \nbool \nedge_valid(struct radix_edge *edge) \n{\n    return edge->labelBits != 0;\n}\n\n/*\n * Read the most significant labelBits out of (key << keyshift)\n */\nstatic inline \nunsigned\nkeybits(uint64_t key, int labelBits, int keyshift)\n{\n    uint64_t mask = (1 << labelBits) - 1;\n    return (unsigned) (key >> (64 - labelBits - keyshift)) & mask;\n}\n\n/*\n * Add labelBits to key.\n */\nstatic inline\nuint64_t\nextend_key(uint64_t key, int labelBits, int keyshift, uint64_t label) {\n\tuint64_t mask __unused = (1 << labelBits) - 1;\n\tassert((label & ~mask) == 0);\n\tint shift = 64 - keyshift - labelBits; // [ keyshift | labelbits | 64 - keyshift - labelbits ]\n\tassert((key & (mask << shift)) == 0);\n\treturn key | (label << shift);\n}\n\n/*\n * Return true if exact radix tree traversal should follow this edge.\n * That is, return true if the edge label matches the key bits exactly.\n */\nstatic inline \nbool \nedge_matches(struct radix_edge *edge, uint64_t key, int keyshift) \n{\n    if (!edge_valid(edge)) {\n        return false;\n    }\n    return keybits(key, edge->labelBits, keyshift) == edge->label;\n}\n\n\n/*\n * Count the number of most-significant bits that (key << keyshift) has in\n * common with edge.\n */\nstatic inline \nint \ncount_matching_bits(struct radix_edge *edge, uint64_t key, int keyshift)\n{\n    int labelBits = edge->labelBits;\n    uint64_t label = edge->label; \n    while (labelBits) {\n        if (keybits(key, labelBits, keyshift) == label) { \n            return labelBits; \n        } \n        labelBits--; \n        label >>= 1;\n    }\n    return 0;\n}\n\n/*\n * Lookup a radix tree node by index.  Returns NULL for invalid index.\n */\nstatic inline \nstruct radix_node *\ngetnode(struct radix_tree *tree, unsigned index)\n{ \n    if (index > tree->num_nodes) {\n        return NULL;\n    } else { \n        return &tree->nodes[index];\n    }\n}\n\n/*\n * Initialize a radix tree in a new buffer\n */\nstruct radix_tree *\nradix_tree_init(void *buf, size_t size);\n\n\n/*\n * Print a representation of a radix tree to stdout.\n */\nvoid\nradix_tree_print(struct radix_tree *tree);\n\n/*\n * Check a radix tree for consistency.  Returns true if everything is ok.\n */\nbool\nradix_tree_fsck(struct radix_tree *tree);\n\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/stack_logging_disk.c",
    "content": "/*\n * Copyright (c) 2007-2013 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"internal.h\"\n#include \"radix_tree.h\"\n\n#pragma mark -\n#pragma mark Defines\n\n#if TARGET_OS_IPHONE\n// malloc_report(ASL_LEVEL_INFO...) on iOS doesn't show up in the Xcode Console log of the device,\n// but ASL_LEVEL_NOTICE does.  So raising the log level is helpful.\n#undef ASL_LEVEL_INFO\n#define ASL_LEVEL_INFO ASL_LEVEL_NOTICE\n#endif // TARGET_OS_IPHONE\n\n#ifdef TEST_DISK_STACK_LOGGING\n#define malloc_report fprintf\n#undef ASL_LEVEL_INFO\n#define ASL_LEVEL_INFO stderr\n#endif\n\n#define STACK_LOGGING_BLOCK_WRITING_SIZE 8192\n#define STACK_LOGGING_MAX_SIMUL_REMOTE_TASKS_INSPECTED 3\n\n#define BACKTRACE_UNIQUING_DEBUG 0\n\n// The expansion factor controls the shifting up of table size. A factor of 1 will double the size upon expanding,\n// 2 will quadruple the size, etc. Maintaining a 66% fill in an ideal table requires the collision allowance to\n// increase by 3 for every quadrupling of the table size (although this the constant applied to insertion\n// performance O(c*n))\n#define EXPAND_FACTOR 2\n#define COLLISION_GROWTH_RATE 3\n\n// For a uniquing table, the useful node size is slots := floor(table_byte_size / (2 * sizeof(mach_vm_address_t)))\n// Some useful numbers for the initial max collision value (desiring 66% fill):\n// 16K-23K slots -> 16 collisions\n// 24K-31K slots -> 17 collisions\n// 32K-47K slots -> 18 collisions\n// 48K-79K slots -> 19 collisions\n// 80K-96K slots -> 20 collisions\n#define INITIAL_MAX_COLLIDE 19\n#define DEFAULT_UNIQUING_PAGE_SIZE 256\n\n#pragma mark -\n#pragma mark Macros\n\n#define STACK_LOGGING_FLAGS_SHIFT 56\n#define STACK_LOGGING_USER_TAG_SHIFT 24\n#define STACK_LOGGING_FLAGS(longlongvar) (uint32_t)((uint64_t)(longlongvar) >> STACK_LOGGING_FLAGS_SHIFT)\n#define STACK_LOGGING_FLAGS_AND_USER_TAG(longlongvar) \\\n\t(uint32_t)(STACK_LOGGING_FLAGS(longlongvar) | (((uint64_t)(longlongvar)&0x00FF000000000000ull) >> STACK_LOGGING_USER_TAG_SHIFT))\n\n#define STACK_LOGGING_OFFSET_MASK 0x0000FFFFFFFFFFFFull\n#define STACK_LOGGING_OFFSET(longlongvar) ((longlongvar)&STACK_LOGGING_OFFSET_MASK)\n\n#define STACK_LOGGING_OFFSET_AND_FLAGS(longlongvar, type_flags)                                                    \\\n\t(((uint64_t)(longlongvar)&STACK_LOGGING_OFFSET_MASK) | ((uint64_t)(type_flags) << STACK_LOGGING_FLAGS_SHIFT) | \\\n\t\t\t(((uint64_t)(type_flags)&0xFF000000ull) << STACK_LOGGING_USER_TAG_SHIFT))\n\n#pragma mark -\n#pragma mark Types\n\ntypedef struct {\n\tuintptr_t argument;\n\tuintptr_t address;\n\tuint64_t offset_and_flags; // top 8 bits are actually the flags!\n} stack_logging_index_event;\n\ntypedef struct {\n\tuint32_t argument;\n\tuint32_t address;\n\tuint64_t offset_and_flags; // top 8 bits are actually the flags!\n} stack_logging_index_event32;\n\ntypedef struct {\n\tuint64_t argument;\n\tuint64_t address;\n\tuint64_t offset_and_flags; // top 8 bits are actually the flags!\n} stack_logging_index_event64;\n\n// backtrace uniquing table chunks used in client-side stack log reading code,\n// in case we can't read the whole table in one mach_vm_read() call.\ntypedef struct table_chunk_header {\n\tuint64_t num_nodes_in_chunk;\n\tuint64_t table_chunk_size;\n\tmach_vm_address_t *table_chunk;\n\tstruct table_chunk_header *next_table_chunk_header;\n} table_chunk_header_t;\n\n#pragma pack(push, 4)\ntypedef struct backtrace_uniquing_table {\n\tuint64_t numPages; // number of pages of the table\n\tuint64_t numNodes;\n\tuint64_t tableSize;\n\tuint64_t untouchableNodes;\n\tmach_vm_address_t table_address;\n\tint32_t max_collide;\n// 'table_address' is just an always 64-bit version of the pointer-sized 'table' field to remotely read;\n// it's important that the offset of 'table_address' in the struct does not change between 32 and 64-bit.\n#if BACKTRACE_UNIQUING_DEBUG\n\tuint64_t nodesFull;\n\tuint64_t backtracesContained;\n#endif\n\tunion {\n\t\tmach_vm_address_t *table;\t\t\t\t\t // in \"target\" process;  allocated using vm_allocate()\n\t\ttable_chunk_header_t *first_table_chunk_hdr; // in analysis process\n\t} u;\n\tuint64_t max_table_size;\n\tbool in_client_process : 1;\n\tbool nodes_use_refcount : 1;\n\tunsigned refcount;\n} backtrace_uniquing_table;\n#pragma pack(pop)\n\n// for storing/looking up allocations that haven't yet be written to disk; consistent size across 32/64-bit processes.\n// It's important that these fields don't change alignment due to the architecture because they may be accessed from an\n// analyzing process with a different arch - hence the pragmas.\n#pragma pack(push, 4)\ntypedef struct {\n\tuint64_t start_index_offset;\n\tuint32_t next_free_index_buffer_offset;\n\tchar index_buffer[STACK_LOGGING_BLOCK_WRITING_SIZE];\n\tbacktrace_uniquing_table *uniquing_table;\n\tstruct radix_tree *vm_stackid_table;\n\tuint64_t vm_stackid_table_size;\n} stack_buffer_shared_memory;\n#pragma pack(pop)\n\n// target process address -> record table (for __mach_stack_logging_get_frames)\ntypedef struct {\n\tuint64_t address;\n\tuint64_t index_file_offset;\n} remote_index_node;\n\n// for caching index information client-side:\ntypedef struct {\n\tsize_t cache_size;\n\tsize_t cache_node_capacity;\n\tuint32_t collision_allowance;\n\tremote_index_node *table_memory;\t // this can be malloced; it's on the client side.\n\tstack_buffer_shared_memory *shmem;   // shared memory\n\tstack_buffer_shared_memory snapshot; // memory snapshot of the remote process' shared memory\n\tuint32_t last_pre_written_index_size;\n\tuint64_t last_index_file_offset;\n\tbacktrace_uniquing_table uniquing_table_snapshot; // snapshot of the remote process' uniquing table\n\tboolean_t lite_mode;\n\tstruct radix_tree *vm_stackid_table;\n} remote_index_cache;\n\n// for reading stack history information from remote processes:\ntypedef struct {\n\ttask_t remote_task;\n\tpid_t remote_pid;\n\tint32_t task_is_64_bit;\n\tboolean_t task_uses_lite_or_vmlite_mode;\n\tint32_t in_use_count;\n\tFILE *index_file_stream;\n\tuint64_t remote_stack_buffer_shared_memory_address;\n\tremote_index_cache *cache;\n} remote_task_file_streams;\n\ntypedef mach_vm_address_t slot_address;\ntypedef uint64_t slot_parent;\ntypedef uint64_t slot_refcount;\ntypedef uint64_t table_slot_index;\n\n#pragma pack(push,16)\ntypedef struct {\n\tunion {\n\t\tstruct {\n\t\t\tuint64_t slot0;\n\t\t\tuint64_t slot1;\n\t\t} slots;\n\t\t\n\t\tstruct {\n\t\t\tslot_address address:48;\n\t\t\tslot_parent parent:32;\n\t\t\tslot_refcount refcount:48;\n\t\t} refcount_slot;\n\t\t\n\t\tstruct {\n\t\t\tslot_address address:64;\n\t\t\tslot_parent parent:64;\n\t\t} normal_slot;\n\t};\n\t\n} table_slot_t;\n#pragma pack(pop)\n\n_Static_assert(sizeof(table_slot_t) == 16, \"table_slot_t must be 128 bits\");\n\n#pragma mark -\n#pragma mark Constants/Globals\n\nint stack_logging_enable_logging = 0;\nint stack_logging_dontcompact = 0;\nint stack_logging_finished_init = 0;\nint stack_logging_postponed = 0;\nint stack_logging_mode = stack_logging_mode_none;\n\n#define MAX_PARENT_NORMAL\n#define MAX_PARENT_REFCOUNT\n\nstatic const slot_parent slot_no_parent_normal =   0xFFFFFFFFFFFFFFFF;\t    // 64 bits\nstatic const slot_parent slot_no_parent_refcount = 0xFFFFFFFF;\t\t\t\t// 32 bits\n\nstatic _malloc_lock_s stack_logging_lock = _MALLOC_LOCK_INIT;\nstatic vm_address_t thread_doing_logging = 0;\n\n// single-thread access variables\nstatic stack_buffer_shared_memory *pre_write_buffers;\nstatic vm_address_t *stack_buffer;\nstatic uintptr_t last_logged_malloc_address = 0;\n\n// Constants to define part of stack logging file path names.\n// File names are of the form stack-logs.<pid>.<address>.<progname>.XXXXXX.index\n// where <address> is the address of the pre_write_buffers VM region in the target\n// process that will need to be mapped into analysis tool processes.\nstatic const char *stack_log_file_base_name = \"stack-logs.\";\nstatic const char *stack_log_file_suffix = \".index\";\n\nstatic FILE *open_log_file_at_path(char *pathname, remote_task_file_streams *streams);\n\nchar *__stack_log_file_path__ = NULL;\nstatic int index_file_descriptor = -1;\n\n// for accessing remote log files\nstatic remote_task_file_streams remote_fds[STACK_LOGGING_MAX_SIMUL_REMOTE_TASKS_INSPECTED];\nstatic uint32_t next_remote_task_fd = 0;\nstatic uint32_t remote_task_fd_count = 0;\nstatic _malloc_lock_s remote_fd_list_lock = _MALLOC_LOCK_INIT;\n\nuint64_t __mach_stack_logging_shared_memory_address = 0;\n\n// activation variables\nstatic int logging_use_compaction = 1; // set this to zero to always disable compaction.\n\n// We set malloc_logger to NULL to disable logging, if we encounter errors\n// during file writing\ntypedef void(malloc_logger_t)(uint32_t type,\n\t\tuintptr_t arg1,\n\t\tuintptr_t arg2,\n\t\tuintptr_t arg3,\n\t\tuintptr_t result,\n\t\tuint32_t num_hot_frames_to_skip);\nextern malloc_logger_t *malloc_logger;\n\nextern malloc_logger_t *__syscall_logger; // use this to set up syscall logging (e.g., vm_allocate, vm_deallocate, mmap, munmap)\n\n#pragma mark -\n#pragma mark In-Memory Backtrace Uniquing\n\nstatic __attribute__((always_inline)) inline void *\nsld_allocate_pages(uint64_t memSize)\n{\n\tmach_vm_address_t allocatedMem = 0ull;\n\tif (mach_vm_allocate(mach_task_self(), &allocatedMem, memSize, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL)) !=\n\t\t\tKERN_SUCCESS) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"allocate_pages(): virtual memory exhausted!\\n\");\n\t}\n\treturn (void *)(uintptr_t)allocatedMem;\n}\n\nstatic __attribute__((always_inline)) inline int\nsld_deallocate_pages(void *memPointer, uint64_t memSize)\n{\n\treturn mach_vm_deallocate(mach_task_self(), (mach_vm_address_t)(uintptr_t)memPointer, memSize);\n}\n\nstatic const uint64_t max_table_size_lite = UINT32_MAX;\nstatic const uint64_t max_table_size_normal = UINT64_MAX;\n\nstatic backtrace_uniquing_table *\n__create_uniquing_table(boolean_t lite_or_vmlite_mode)\n{\n\tbacktrace_uniquing_table *uniquing_table =\n\t\t\t(backtrace_uniquing_table *)sld_allocate_pages((uint64_t)round_page(sizeof(backtrace_uniquing_table)));\n\tif (!uniquing_table) {\n\t\treturn NULL;\n\t}\n\tbzero(uniquing_table, sizeof(backtrace_uniquing_table));\n\tuniquing_table->numPages = DEFAULT_UNIQUING_PAGE_SIZE;\n\tuniquing_table->tableSize = uniquing_table->numPages * vm_page_size;\n\tuniquing_table->numNodes = ((uniquing_table->tableSize / (sizeof(mach_vm_address_t) * 2)) >> 1) << 1; // make sure it's even.\n\tuniquing_table->u.table = (mach_vm_address_t *)(uintptr_t)sld_allocate_pages(uniquing_table->tableSize);\n\tuniquing_table->table_address = (uintptr_t)uniquing_table->u.table;\n\tuniquing_table->max_collide = INITIAL_MAX_COLLIDE;\n\tuniquing_table->untouchableNodes = 0;\n\tuniquing_table->max_table_size = (lite_or_vmlite_mode) ? max_table_size_lite : max_table_size_normal;\n\tuniquing_table->nodes_use_refcount = lite_or_vmlite_mode;\n\tuniquing_table->in_client_process = 0;\n\n#if BACKTRACE_UNIQUING_DEBUG\n\tmalloc_report(ASL_LEVEL_INFO, \"create_uniquing_table(): creating. size: %lldKB == %lldMB, numnodes: %lld (%lld untouchable)\\n\",\n\t\t\tuniquing_table->tableSize >> 10, uniquing_table->tableSize >> 20, uniquing_table->numNodes,\n\t\t\tuniquing_table->untouchableNodes);\n\tmalloc_report(ASL_LEVEL_INFO, \"create_uniquing_table(): table: %p; end: %p\\n\", uniquing_table->u.table,\n\t\t\t(void *)((uintptr_t)uniquing_table->u.table + (uintptr_t)uniquing_table->tableSize));\n#endif\n\treturn uniquing_table;\n}\n\nstatic void\n__destroy_uniquing_table(backtrace_uniquing_table *table)\n{\n\tassert(!table->in_client_process);\n\tsld_deallocate_pages(table->u.table, table->tableSize);\n\tsld_deallocate_pages(table, sizeof(backtrace_uniquing_table));\n}\n\nstatic boolean_t\n__expand_uniquing_table(backtrace_uniquing_table *uniquing_table)\n{\n\tassert(!uniquing_table->in_client_process);\n\tmach_vm_address_t *oldTable = uniquing_table->u.table;\n\tuint64_t oldsize = uniquing_table->tableSize;\n\tuint64_t oldnumnodes = uniquing_table->numNodes;\n\n\tuint64_t newsize = (uniquing_table->numPages << EXPAND_FACTOR) * vm_page_size;\n\t\n\tif (newsize > uniquing_table->max_table_size) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"no more space in uniquing table\\n\");\n\t\treturn false;\n\t}\n\t\n\tuniquing_table->numPages = uniquing_table->numPages << EXPAND_FACTOR;\n\tuniquing_table->tableSize = uniquing_table->numPages * vm_page_size;\n\tuniquing_table->numNodes = ((uniquing_table->tableSize / (sizeof(mach_vm_address_t) * 2)) >> 1) << 1; // make sure it's even.\n\tmach_vm_address_t *newTable = (mach_vm_address_t *)(uintptr_t)sld_allocate_pages(uniquing_table->tableSize);\n\n\tuniquing_table->u.table = newTable;\n\tuniquing_table->table_address = (uintptr_t)uniquing_table->u.table;\n\tuniquing_table->max_collide = uniquing_table->max_collide + COLLISION_GROWTH_RATE;\n\n\tif (mach_vm_copy(mach_task_self(), (mach_vm_address_t)(uintptr_t)oldTable, oldsize, (mach_vm_address_t)(uintptr_t)newTable) !=\n\t\t\tKERN_SUCCESS) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"expandUniquingTable(): VMCopyFailed\\n\");\n\t}\n\tuniquing_table->untouchableNodes = oldnumnodes;\n\n#if BACKTRACE_UNIQUING_DEBUG\n\tmalloc_report(ASL_LEVEL_INFO,\n\t\t\t\"expandUniquingTable(): expanded from nodes full: %lld of: %lld (~%2d%%); to nodes: %lld (inactive = %lld); unique \"\n\t\t\t\"bts: %lld\\n\",\n\t\t\tuniquing_table->nodesFull, oldnumnodes, (int)(((uniquing_table->nodesFull * 100.0) / (double)oldnumnodes) + 0.5),\n\t\t\tuniquing_table->numNodes, uniquing_table->untouchableNodes, uniquing_table->backtracesContained);\n\tmalloc_report(ASL_LEVEL_INFO, \"expandUniquingTable(): allocate: %p; end: %p\\n\", newTable,\n\t\t\t(void *)((uintptr_t)newTable + (uintptr_t)(uniquing_table->tableSize)));\n\tmalloc_report(ASL_LEVEL_INFO, \"expandUniquingTable(): deallocate: %p; end: %p\\n\", oldTable, (void *)((uintptr_t)oldTable + (uintptr_t)oldsize));\n\tmalloc_report(ASL_LEVEL_INFO, \"expandUniquingTable(): new size = %llu\\n\", newsize);\n#endif\n\n\tif (sld_deallocate_pages(oldTable, oldsize) != KERN_SUCCESS) {\n\t\tmalloc_report(ASL_LEVEL_ERR, \"expandUniquingTable(): mach_vm_deallocate failed. [%p]\\n\", uniquing_table->u.table);\n\t}\n\t\n\treturn true;\n}\n\nstatic void\nadd_new_slot(table_slot_t *table_slot, mach_vm_address_t address, table_slot_index parent, bool use_refcount, size_t ptr_size)\n{\n\tassert(use_refcount == (ptr_size > 0));\n\t\n\ttable_slot_t new_slot;\n\t\n\tif (use_refcount) {\n\t\tnew_slot.refcount_slot.address = address;\n\t\tnew_slot.refcount_slot.parent = parent;\n\t\tnew_slot.refcount_slot.refcount = ptr_size;\n\t} else {\n\t\tnew_slot.normal_slot.address = address;\n\t\tnew_slot.normal_slot.parent = parent;\n\t}\n\t\n\t*table_slot = new_slot;\n}\n\nstatic void\nincrement_slot_refcount(table_slot_t *table_slot, size_t ptr_size)\n{\n\ttable_slot->refcount_slot.refcount += ptr_size;\n}\n\nstatic int\nenter_frames_in_table(backtrace_uniquing_table *uniquing_table, uint64_t *foundIndex, mach_vm_address_t *frames, int32_t count, size_t ptr_size)\n{\n\tassert(!uniquing_table->in_client_process);\n\tboolean_t use_refcount = (ptr_size > 0);\n\t\n\t// The hash values need to be the same size as the addresses (because we use the value -1), for clarity, define a new type\n\ttypedef mach_vm_address_t hash_index_t;\n\t\n\thash_index_t uParent = use_refcount ? slot_no_parent_refcount : slot_no_parent_normal;\n\thash_index_t modulus = (uniquing_table->numNodes-uniquing_table->untouchableNodes-1);\n\t\n\tint32_t lcopy = count;\n\tint32_t returnVal = 1;\n\thash_index_t hash_multiplier = ((uniquing_table->numNodes - uniquing_table->untouchableNodes)/(uniquing_table->max_collide*2+1));\n\t\n\twhile (--lcopy >= 0) {\n\t\tmach_vm_address_t thisPC = frames[lcopy];\n\t\thash_index_t hash = uniquing_table->untouchableNodes + (((uParent << 4) ^ (thisPC >> 2)) % modulus);\n\t\tint32_t collisions = uniquing_table->max_collide;\n\n\t\twhile (collisions--) {\n\t\t\ttable_slot_t *table_slot = (table_slot_t *) (uniquing_table->u.table + (hash * 2));\n\t\t\t\n\t\t\tif (table_slot->slots.slot0 == 0 && table_slot->slots.slot1 == 0) {\n\t\t\t\tadd_new_slot(table_slot, thisPC, uParent, uniquing_table->nodes_use_refcount, ptr_size);\n\t\t\t\tuParent = hash;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tslot_address address = use_refcount ? table_slot->refcount_slot.address : table_slot->normal_slot.address;\n\t\t\tslot_parent parent = use_refcount ? table_slot->refcount_slot.parent : table_slot->normal_slot.parent;\n\t\t\t\n\t\t\tif (address == thisPC && parent == uParent) {\n\t\t\t\tuParent = hash;\n\t\t\t\t\n\t\t\t\tif (use_refcount)\n\t\t\t\t\tincrement_slot_refcount(table_slot, ptr_size);\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\thash += collisions * hash_multiplier + 1;\n\n\t\t\tif (hash >= uniquing_table->numNodes) {\n\t\t\t\thash -= (uniquing_table->numNodes - uniquing_table->untouchableNodes); // wrap around.\n\t\t\t}\n\t\t}\n\n\t\tif (collisions < 0) {\n\t\t\treturnVal = 0;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (returnVal) {\n\t\t*foundIndex = uParent;\n\t}\n\n\treturn returnVal;\n}\n\n#pragma mark -\n#pragma mark Disk Stack Logging\n\n// pre-declarations\nstatic void delete_log_files(void);\nstatic int delete_logging_file(char *log_location);\nstatic bool getenv_from_process(pid_t pid, char *env_var_name, char *env_var_value_buf, size_t max_path_len);\n\n#define BASE10 10\n#define BASE16 16\n\nstatic void\nappend_int(char *filename, uint64_t inputValue, unsigned base, size_t maxLength)\n{\n\tconst char *digits = \"0123456789abcdef\";\n\tif (base > strlen(digits)) {\n\t\treturn; // sanity check\n\t}\n\tsize_t len = strlen(filename);\n\n\tuint32_t count = 0;\n\tuint64_t value = inputValue;\n\twhile (value > 0) {\n\t\tvalue /= base;\n\t\tcount++;\n\t}\n\n\tif (len + count >= maxLength) {\n\t\treturn; // don't modify the string if it would violate maxLength\n\t}\n\tfilename[len + count] = '\\0';\n\n\tvalue = inputValue;\n\tuint32_t i;\n\tfor (i = 0; i < count; i++) {\n\t\tfilename[len + count - 1 - i] = digits[value % base];\n\t\tvalue /= base;\n\t}\n}\n\n/*\n * <rdar://problem/11128080> if we needed to call confstr during init then setting this\n * flag will postpone stack logging until after Libsystem's initialiser has run.\n */\nstatic void\npostpone_stack_logging(void)\n{\n\tmalloc_report(ASL_LEVEL_INFO, \"stack logging postponed until after initialization.\\n\");\n\tstack_logging_postponed = 1;\n}\n\n/*\n * Check various logging directory options, in order of preference:\n *\n *      value of MallocStackLoggingDirectory env var if user has set it.  Typically\n *\t\t\tused on Mac OS X to write to a non-root file system with more free space.\n *\n *      _PATH_TMP - /tmp usually writable for desktop apps and internal iOS apps\n *\n *      value of TMPDIR env var - for sandboxed apps that can't write into /tmp\n *\n *      confstr(_CS_DARWIN_USER_TEMP_DIR, ...) - should be same as TMPDIR if that is set,\n *          but will create it safely if it doesn't yet exist.  (See <rdar://problem/4706096>)\n *\n * Allocating and releasing target buffer is the caller's responsibility.\n */\nstatic bool\nget_writeable_logging_directory(char *target)\n{\n\tif (!target) {\n\t\treturn false;\n\t}\n\n\tchar *evn_log_directory = getenv(\"MallocStackLoggingDirectory\");\n\tif (evn_log_directory) {\n\t\tif (-1 != access(evn_log_directory, W_OK)) {\n\t\t\tstrlcpy(target, evn_log_directory, (size_t)PATH_MAX);\n\t\t\treturn true;\n\t\t} else {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"MallocStackLoggingDirectory env var set to unwritable path '%s'\\n\", evn_log_directory);\n\t\t}\n\t}\n\n\tif (-1 != access(_PATH_TMP, W_OK)) {\n\t\tstrlcpy(target, _PATH_TMP, (size_t)PATH_MAX);\n\t\treturn true;\n\t}\n\n\tevn_log_directory = getenv(\"TMPDIR\");\n\tif (evn_log_directory && (-1 != access(evn_log_directory, W_OK))) {\n\t\tstrlcpy(target, evn_log_directory, (size_t)PATH_MAX);\n\t\treturn true;\n\t}\n\n\tif (stack_logging_finished_init) {\n\t\tsize_t n = confstr(_CS_DARWIN_USER_TEMP_DIR, target, (size_t)PATH_MAX);\n\t\tif ((n > 0) && (n < PATH_MAX)) {\n\t\t\treturn true;\n\t\t}\n\t} else {\n\t\t/* <rdar://problem/11128080> Can't call confstr during init, so postpone\n\t\t * logging till after */\n\t\tpostpone_stack_logging();\n\t}\n\t*target = '\\0';\n\treturn false;\n}\n\n// Stolen from libc.  Ugly hack because arc4random uses malloc so we can't call Libc's mkstemps.\nint getentropy(void *, size_t);\nstatic int\nmy_mkstemps(char *path, size_t slen)\n{\n\tchar *start, *trv, *suffp, *carryp;\n\tchar *pad;\n\tchar carrybuf[MAXPATHLEN];\n\tint fd;\n\n\tfor (trv = path; *trv != '\\0'; ++trv) {\n\t\t;\n\t}\n\ttrv -= slen;\n\tsuffp = trv;\n\t--trv;\n\n\t/* Fill space with random characters */\n\tuint8_t randbuf[8];\n\tunsigned int randbuf_offset = 0;\n\tgetentropy(randbuf, sizeof(randbuf));\n\tstatic const char padchar[] = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\n\twhile (trv >= path && *trv == 'X') {\n\t\t*trv-- = padchar[randbuf[randbuf_offset++ % sizeof(randbuf)] % sizeof(padchar)];\n\t}\n\tstart = trv + 1;\n\n\t/* save first combination of random characters */\n\tmemcpy(carrybuf, start, suffp - start);\n\n\tfor (;;) {\n\t\tif ((fd = open(path, O_CREAT | O_EXCL | O_RDWR, 0600)) >= 0) {\n\t\t\treturn fd;\n\t\t}\n\t\tif (errno != EEXIST) {\n\t\t\treturn -1;\n\t\t}\n\n\t\t/* If we have a collision, cycle through the space of filenames */\n\t\tfor (trv = start, carryp = carrybuf;;) {\n\t\t\t/* have we tried all possible permutations? */\n\t\t\tif (trv == suffp) {\n\t\t\t\treturn -1; /* yes - exit with EEXIST */\n\t\t\t}\n\t\t\tpad = strchr(padchar, *trv);\n\t\t\tif (pad == NULL) {\n\t\t\t\t/* this should never happen */\n\t\t\t\terrno = EIO;\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\t/* increment character */\n\t\t\t*trv = (*++pad == '\\0') ? padchar[0] : *pad;\n\t\t\t/* carry to next position? */\n\t\t\tif (*trv == *carryp) {\n\t\t\t\t/* increment position and loop */\n\t\t\t\t++trv;\n\t\t\t\t++carryp;\n\t\t\t} else {\n\t\t\t\t/* try with new name */\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\n// If successful, returns path to log file that was created, otherwise NULL.\nstatic char *\ncreate_log_file()\n{\n\tpid_t pid = getpid();\n\tconst char *progname = getprogname();\n\tchar *created_log_location = NULL;\n\n\tif (__stack_log_file_path__ == NULL) {\n\t\t// On first use, allocate space directly from the OS without using malloc\n\t\t__stack_log_file_path__ = sld_allocate_pages((uint64_t)round_page(PATH_MAX));\n\t\tif (__stack_log_file_path__ == NULL) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"unable to allocate memory for stack log file path\\n\");\n\t\t\treturn NULL;\n\t\t}\n\t}\n\n\tif (!get_writeable_logging_directory(__stack_log_file_path__)) {\n\t\tif (!stack_logging_postponed) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"No writeable tmp dir\\n\");\n\t\t}\n\t\treturn NULL;\n\t}\n\n\t// Add the '/' only if it's not already there.  Having multiple '/' characters works\n\t// but is unsightly when we print these stack log file names out.\n\tsize_t stack_log_len = strlen(__stack_log_file_path__);\n\tif (__stack_log_file_path__[stack_log_len - 1] != '/') {\n\t\t// use strlcat to null-terminate for the next strlcat call, and to check buffer size\n\t\tstrlcat(__stack_log_file_path__ + stack_log_len, \"/\", (size_t)PATH_MAX);\n\t}\n\n\t// Append the file name to __stack_log_file_path__ but don't use snprintf since\n\t// it can cause malloc() calls.\n\t//\n\t// The file name is of the form \"stack-logs.<pid>.<address>.<progname>.XXXXXX.index\"\n\t// where <address> is the address of the pre_write_buffers VM region in the target\n\t// process that will need to be mapped into analysis tool processes. We used to just\n\t// use a shared memory segment for that, but sandbox'ed target apps may not be able\n\t// to create shared memory segments so including the address of the VM region in the\n\t// file name is a simple way to communicate the address to analysis tools so the\n\t// stack log reading code can map in the region with mach_vm_remap().\n\n\tstrlcat(__stack_log_file_path__, stack_log_file_base_name, (size_t)PATH_MAX);\n\tappend_int(__stack_log_file_path__, pid, BASE10, (size_t)PATH_MAX);\n\tstrlcat(__stack_log_file_path__, \".\", (size_t)PATH_MAX);\n\tappend_int(__stack_log_file_path__, (uint64_t)pre_write_buffers, BASE16, (size_t)PATH_MAX);\n\tif (progname && progname[0] != '\\0') {\n\t\tstrlcat(__stack_log_file_path__, \".\", (size_t)PATH_MAX);\n\t\tstrlcat(__stack_log_file_path__, progname, (size_t)PATH_MAX);\n\t}\n\tstrlcat(__stack_log_file_path__, \".XXXXXX\", (size_t)PATH_MAX);\n\tstrlcat(__stack_log_file_path__, stack_log_file_suffix, (size_t)PATH_MAX);\n\t\n\t// Securely create the log file.\n\tif ((index_file_descriptor = my_mkstemps(__stack_log_file_path__, (int)strlen(stack_log_file_suffix))) != -1) {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"stack logs being written into %s\\n\", __stack_log_file_path__);\n\t\tcreated_log_location = __stack_log_file_path__;\n\t} else {\n\t\tmalloc_report(ASL_LEVEL_INFO, \"unable to create stack logs at %s\\n\", __stack_log_file_path__);\n\t\t__stack_log_file_path__[0] = '\\0';\n\t\tcreated_log_location = NULL;\n\t}\n\n\treturn created_log_location;\n}\n\n// This function may be called from either the target process when exiting, or from either the the target process or\n// a stack log analysis process, when reaping orphaned stack log files.\n// Returns -1 if the files exist and they couldn't be removed, returns 0 otherwise.\nstatic int\ndelete_logging_file(char *log_location)\n{\n\tif (log_location == NULL || log_location[0] == '\\0') {\n\t\treturn 0;\n\t}\n\n\tstruct stat statbuf;\n\tif (unlink(log_location) != 0 && stat(log_location, &statbuf) == 0) {\n\t\treturn -1;\n\t}\n\treturn 0;\n}\n\n// This function will be called from atexit() in the target process.\nstatic void\ndelete_log_files(void)\n{\n\tif (__stack_log_file_path__ && __stack_log_file_path__[0]) {\n\t\tif (delete_logging_file(__stack_log_file_path__) == 0) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"stack logs deleted from %s\\n\", __stack_log_file_path__);\n\t\t\t__stack_log_file_path__[0] = '\\0';\n\t\t} else {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"unable to delete stack logs from %s\\n\", __stack_log_file_path__);\n\t\t}\n\t}\n}\n\nstatic bool\nis_process_running(pid_t pid)\n{\n\tstruct kinfo_proc kpt[1];\n\tsize_t size = sizeof(struct kinfo_proc);\n\tint mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};\n\n\tsysctl(mib, 4, kpt, &size, NULL, (size_t)0); // size is either 1 or 0 entries when we ask for a single pid\n\n\treturn (size == sizeof(struct kinfo_proc));\n}\n\n// Stack log files can be quite large and aren't useful after the process that created them no longer exists because\n// the stack backtrace uniquing tree was only kept in the process memory, not on disk.  Normally the log files\n// should get removed when the process exits, by the delete_log_files() atexit function.  However, there are\n// several situations in which that atexit function doesn't get called so the log files remain:\n//\t\t- if the process crashes or is force-killed\n//\t\t- if the app supported sudden termination, and was terminated through that\n//\t\t- if a process such as a shell execs another binary to transform the pid into a different process;\n//\t\t\tthe new process will get a new log file but the old one would still be there.\n//\n// So, reap any stack log files for processes that no longer exist, or for the current process if we find a file\n// other than __stack_log_file_path__\n//\n// This function looks for log files with prefix name \"stack-logs.<pid>.\" underneath <directory>.\n// <remaining_path_format> specifies a simple pattern of where stack logs can be down inside <directory>.\n// The pattern is essentially a relative path, where a level that start with '<' matches any name, otherwise\n// it has to be an exact name match.  See the calling function for examples.\nstatic void\nreap_orphaned_log_files_in_hierarchy(char *directory, char *remaining_path_format, pid_t target_pid, remote_task_file_streams *streams)\n{\n\tDIR *dp;\n\tstruct dirent *entry;\n\n\t// Ensure that we can access this directory - permissions or sandbox'ing might prevent it.\n\tif (access(directory, R_OK | W_OK | X_OK) == -1 || (dp = opendir(directory)) == NULL) {\n\t\t//malloc_report(ASL_LEVEL_INFO, \"reaping: no access to %s\\n\", directory);\n\t\treturn;\n\t}\n\n\tchar pathname[PATH_MAX];\n\tstrlcpy(pathname, directory, (size_t)PATH_MAX);\n\tsize_t pathname_len = strlen(pathname);\n\tif (pathname[pathname_len - 1] != '/') {\n\t\tpathname[pathname_len++] = '/';\n\t}\n\tchar *suffix = pathname + pathname_len;\n\n\t// Recurse down to deeper levels of the temp directory hierarchy if necessary.\n\tif (remaining_path_format) {\n\t\tchar *separator = remaining_path_format;\n\t\twhile (*separator != '/' && *separator != '\\0') {\n\t\t\tseparator++;\n\t\t}\n\t\tsize_t length_to_match = (*remaining_path_format == '<') ? 0 : separator - remaining_path_format;\n\t\tchar *next_remaining_path_format = (*separator == '\\0') ? NULL : separator + 1;\n\n\t\twhile ((entry = readdir(dp)) != NULL) {\n\t\t\tif (entry->d_type == DT_DIR && entry->d_name[0] != '.') {\n\t\t\t\tif (length_to_match > 0 && strncmp(entry->d_name, remaining_path_format, length_to_match) != 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tstrlcpy(suffix, entry->d_name, (size_t)PATH_MAX - pathname_len);\n\t\t\t\treap_orphaned_log_files_in_hierarchy(pathname, next_remaining_path_format, target_pid, streams);\n\t\t\t}\n\t\t}\n\t\tclosedir(dp);\n\n\t\treturn;\n\t}\n\n\t// OK, we found a lowest-level directory matching <remaining_path_format>, and we have access to it.\n\t// Reap any unnecessary stack log files in here.\n\n\t//malloc_report(ASL_LEVEL_INFO, \"reaping: looking in %s\\n\", directory);\n\n\t// __stack_log_file_path__ may be NULL if this code is running in an analysis tool client process that is not\n\t// itself running with MallocStackLogging set.\n\tchar *curproc_stack_log_file = __stack_log_file_path__ ? strrchr(__stack_log_file_path__, '/') + 1 : NULL;\n\tpid_t curpid = getpid();\n\tsize_t prefix_length = strlen(stack_log_file_base_name);\n\n\twhile ((entry = readdir(dp)) != NULL) {\n\t\tif ((entry->d_type == DT_REG || entry->d_type == DT_LNK) &&\n\t\t\t\t(strncmp(entry->d_name, stack_log_file_base_name, prefix_length) == 0)) {\n\t\t\tlong pid = strtol(&entry->d_name[prefix_length], (char **)NULL, 10);\n\t\t\tif (pid == target_pid && streams != NULL) {\n\t\t\t\tstrlcpy(suffix, entry->d_name, (size_t)PATH_MAX - pathname_len);\n\t\t\t\topen_log_file_at_path(pathname, streams);\n\t\t\t}\n\t\t\telse if (!is_process_running((pid_t)pid) ||\n\t\t\t\t\t(pid == curpid && curproc_stack_log_file && strcmp(entry->d_name, curproc_stack_log_file) != 0)) {\n\t\t\t\tstrlcpy(suffix, entry->d_name, (size_t)PATH_MAX - pathname_len);\n\t\t\t\tif (delete_logging_file(pathname) == 0) {\n\t\t\t\t\tif (pid == curpid) {\n\t\t\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"stack logs deleted from %s\\n\", pathname);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"process %ld no longer exists, stack logs deleted from %s\\n\", pid, pathname);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tclosedir(dp);\n}\n\nstatic void\nreap_orphaned_log_files(pid_t target_pid, remote_task_file_streams *streams)\n{\n\treap_orphaned_log_files_in_hierarchy(_PATH_TMP, NULL, target_pid, streams);\n\t\n\tchar *env_var_names[] = {\"TMPDIR\", \"MallocStackLoggingDirectory\"};\n\tfor (unsigned i = 0; i < sizeof(env_var_names) / sizeof(char *); i++) {\n\t\tchar directory[PATH_MAX];\n\t\tbool success = getenv_from_process(target_pid, env_var_names[i], directory, sizeof(directory));\n\t\tif (success && strcmp(directory, _PATH_TMP) != 0) {\n\t\t\treap_orphaned_log_files_in_hierarchy(directory, NULL, target_pid, streams);\n\t\t}\n\t}\n\t\n\t// Now reap files left over in any other accessible app-specific temp directories.\n\t// These could be from sandbox'ed apps.\n#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\tchar *root_of_temp_directories = \"/private/var/mobile/Containers/Data/Application\"; // ugh - hard-coding to user name \"mobile\".\n\t// Works for all iOS's up to now.\n\tchar *temp_directories_path_format = \"<application-UUID>/tmp\";\n#else // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\tchar *root_of_temp_directories = \"/private/var/folders\";\n\tchar *temp_directories_path_format = \"<xx>/<random>/T\";\n#endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\treap_orphaned_log_files_in_hierarchy(root_of_temp_directories, temp_directories_path_format, target_pid, streams);\n}\n\n/*\n * Since there a many errors that could cause stack logging to get disabled, this is a convenience method\n * for disabling any future logging in this process and for informing the user.\n */\nstatic void\ndisable_stack_logging(void)\n{\n\tmalloc_report(ASL_LEVEL_INFO, \"stack logging disabled due to previous errors.\\n\");\n\tstack_logging_enable_logging = 0;\n\tmalloc_logger = NULL;\n\t__syscall_logger = NULL;\n\tdisable_stack_logging_lite();\n}\n\nstatic boolean_t uniquing_table_memory_was_deleted = false;\n\n__attribute__((visibility(\"hidden\"))) boolean_t\n__uniquing_table_memory_was_deleted(void)\n{\n\treturn uniquing_table_memory_was_deleted;\n}\n\n__attribute__((visibility(\"hidden\"))) void\n__delete_uniquing_table_memory_while_locked(void)\n{\n\t// Clean out the memory (if not done already)\n\tif (pre_write_buffers && pre_write_buffers->uniquing_table != NULL) {\n\t\t__destroy_uniquing_table(pre_write_buffers->uniquing_table);\n\t\tpre_write_buffers->uniquing_table = NULL;\n\t\tuniquing_table_memory_was_deleted = true;\n\t}\n\t\n\t// Clear the shared memory address so client tools won't look for the uniquing table memory\n\t__mach_stack_logging_shared_memory_address = 0;\n}\n\n/* A wrapper around write() that will try to reopen the index/stack file and\n * write to it if someone closed it underneath us (e.g. the process we just\n * started decide to close all file descriptors except stin/err/out). Some\n * programs like to do that and calling abort() on them is rude.\n */\nstatic ssize_t\nrobust_write(int fd, const void *buf, size_t nbyte)\n{\n\textern int errno;\n\tssize_t written = write(fd, buf, nbyte);\n\tif (written == -1 && errno == EBADF) {\n\t\tchar *file_to_reopen = NULL;\n\t\tint *fd_to_reset = NULL;\n\n\t\t// descriptor was closed on us. We need to reopen it\n\t\tif (fd == index_file_descriptor) {\n\t\t\tfile_to_reopen = __stack_log_file_path__;\n\t\t\tfd_to_reset = &index_file_descriptor;\n\t\t} else {\n\t\t\t// We don't know about this file. Return (and abort()).\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"Unknown file descriptor; expecting stack logging index file\\n\");\n\t\t\treturn -1;\n\t\t}\n\n\t\t// The file *should* already exist. If not, fail.\n\t\tfd = open(file_to_reopen, O_WRONLY | O_APPEND);\n\t\tif (fd < 3) {\n\t\t\t// If we somehow got stdin/out/err, we need to relinquish them and\n\t\t\t// get another fd.\n\t\t\tint fds_to_close[3] = {0};\n\t\t\twhile (fd < 3) {\n\t\t\t\tif (fd == -1) {\n\t\t\t\t\tmalloc_report(ASL_LEVEL_INFO, \"unable to re-open stack logging file %s\\n\", file_to_reopen);\n\t\t\t\t\tdelete_log_files();\n\t\t\t\t\treturn -1;\n\t\t\t\t}\n\t\t\t\tfds_to_close[fd] = 1;\n\t\t\t\tfd = dup(fd);\n\t\t\t}\n\n\t\t\t// We have an fd we like. Close the ones we opened.\n\t\t\tif (fds_to_close[0]) {\n\t\t\t\tclose(0);\n\t\t\t}\n\t\t\tif (fds_to_close[1]) {\n\t\t\t\tclose(1);\n\t\t\t}\n\t\t\tif (fds_to_close[2]) {\n\t\t\t\tclose(2);\n\t\t\t}\n\t\t}\n\n\t\t*fd_to_reset = fd;\n\t\twritten = write(fd, buf, nbyte);\n\t}\n\treturn written;\n}\n\nstatic void\nflush_data(void)\n{\n\tssize_t written; // signed size_t\n\tsize_t remaining;\n\tchar *p;\n\n\tif (index_file_descriptor == -1) {\n\t\tif (create_log_file() == NULL) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// Write the events before the index so that hopefully the events will be on disk if the index refers to them.\n\tp = pre_write_buffers->index_buffer;\n\tremaining = (size_t)pre_write_buffers->next_free_index_buffer_offset;\n\twhile (remaining > 0) {\n\t\twritten = robust_write(index_file_descriptor, p, remaining);\n\t\tif (written == -1) {\n\t\t\tmalloc_report(\n\t\t\t\t\tASL_LEVEL_INFO, \"Unable to write to stack logging file %s (%s)\\n\", __stack_log_file_path__, strerror(errno));\n\t\t\tdisable_stack_logging();\n\t\t\treturn;\n\t\t}\n\t\tp += written;\n\t\tremaining -= written;\n\t}\n\n\tpre_write_buffers->start_index_offset += pre_write_buffers->next_free_index_buffer_offset;\n\tpre_write_buffers->next_free_index_buffer_offset = 0;\n}\n\n__attribute__((visibility(\"hidden\"))) boolean_t\n__prepare_to_log_stacks(boolean_t lite_or_vmlite_mode)\n{\n\tif (!pre_write_buffers) {\n\t\tlast_logged_malloc_address = 0ul;\n\t\tlogging_use_compaction = (stack_logging_dontcompact ? 0 : logging_use_compaction);\n\n\t\t// Create a VM region to hold the pre-write index and stack buffers. The address of this VM region will be\n\t\t// encoded into the stack log file name, so that the stack log reading code running in remote analysis\n\t\t// processes can find it and map it into the analysis process. This allows remote analysis processes to access\n\t\t// these buffers to get logs for even the most recent allocations. The remote process will need to pause this\n\t\t// process to assure that the contents of these buffers don't change while being inspected.\n\t\t//\n\t\t// We used to use shm_open() to create a shared memory region for this, but since this code runs in arbitrary\n\t\t// processes that may have sandbox restrictions that don't allow the creation of shared memory regions,\n\t\t// we're using this \"create a region and put its address in the stack log file name\" approach.\n\t\tsize_t full_shared_mem_size = sizeof(stack_buffer_shared_memory);\n\t\tpre_write_buffers = mmap(\n\t\t\t\t0, full_shared_mem_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL), 0);\n\t\tif (MAP_FAILED == pre_write_buffers) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"error creating VM region for stack logging output buffers\\n\");\n\t\t\tdisable_stack_logging();\n\t\t\treturn false;\n\t\t}\n\n\t\t// Store and use the buffer offsets in shared memory so that they can be accessed remotely\n\t\tpre_write_buffers->start_index_offset = 0ull;\n\t\tpre_write_buffers->next_free_index_buffer_offset = 0;\n\n\t\t// create the backtrace uniquing table\n\t\tpre_write_buffers->uniquing_table = __create_uniquing_table(lite_or_vmlite_mode);\n\t\tif (!pre_write_buffers->uniquing_table) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"error while allocating stack uniquing table\\n\");\n\t\t\tdisable_stack_logging();\n\t\t\treturn false;\n\t\t}\n\n\t\tpre_write_buffers->vm_stackid_table = NULL;\n\n\t\tuint64_t stack_buffer_sz = (uint64_t)round_page(sizeof(vm_address_t) * STACK_LOGGING_MAX_STACK_SIZE);\n\t\tstack_buffer = (vm_address_t *)sld_allocate_pages(stack_buffer_sz);\n\t\tif (!stack_buffer) {\n\t\t\tmalloc_report(ASL_LEVEL_INFO, \"error while allocating stack trace buffer\\n\");\n\t\t\tdisable_stack_logging();\n\t\t\treturn false;\n\t\t}\n\n\t\t// lite_mode doesn't use a file\n\t\tif (lite_or_vmlite_mode) {\n\t\t\t__mach_stack_logging_shared_memory_address = (uint64_t) pre_write_buffers;\n\t\t} else {\n\t\t\t// this call ensures that the log files exist; analyzing processes will rely on this assumption.\n\t\t\tif (create_log_file() == NULL) {\n\t\t\t\t/* postponement support requires cleaning up these structures now */\n\t\t\t\t__destroy_uniquing_table(pre_write_buffers->uniquing_table);\n\t\t\t\tsld_deallocate_pages(stack_buffer, stack_buffer_sz);\n\t\t\t\tstack_buffer = NULL;\n\n\t\t\t\tmunmap(pre_write_buffers, full_shared_mem_size);\n\t\t\t\tpre_write_buffers = NULL;\n\n\t\t\t\tif (!stack_logging_postponed) {\n\t\t\t\t\tdisable_stack_logging();\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn true;\n}\n\n__attribute__((visibility(\"hidden\"))) void\n__prepare_to_log_stacks_stage2(void)\n{\n\tstatic int stage2done = 0;\n\n\tif (!stage2done) {\n\t\t// malloc() can be called by the following, so these need to be done outside the stack_logging_lock but after the buffers\n\t\t// have been set up.\n\t\tatexit(delete_log_files); // atexit() can call malloc()\n\n\t\t// Reaping orphaned stack log files from dead processes is a nicety, to help\n\t\t// reduce wasted disk space.  But we don't *always* have to do it.  Specifically,\n\t\t// do not reap orphaned stack log files if the process name is sandboxd or taskgated,\n\t\t// or if the MallocStackLoggingNoReaping env var is set to any value other than \"no\"\n\t\t// (case-insensitive) or \"0\".  This provides multiple ways to fix\n\t\t// <rdar://problem/14409213> \"processes hang if sandboxd is running with\n\t\t// MallocStackLogging enabled\", which happened because there were two different\n\t\t// places down inside reap_orphaned_log_files() which called sysctl() for KERN_PROCARGS2\n\t\t// or KERN_PROC_PID, causing iteration of the process list in the kernel, which takes\n\t\t// a lock, which can't happen when processes are in a transitional state.\n\t\tbool should_reap = true;\n\t\tconst char *progname = getprogname();\n\t\tif (progname && (strcmp(progname, \"sandboxd\") == 0 || strcmp(progname, \"taskgated\") == 0)) {\n\t\t\tshould_reap = false;\n\t\t}\n\t\tif (should_reap) {\n\t\t\tchar *noreap = getenv(\"MallocStackLoggingNoReaping\");\n\t\t\tif (noreap && strcasecmp(noreap, \"no\") != 0 && strcmp(noreap, \"0\") != 0) {\n\t\t\t\tshould_reap = false;\n\t\t\t}\n\t\t}\n\t\tif (should_reap) {\n\t\t\treap_orphaned_log_files(getpid(), NULL); // this calls opendir() which calls malloc()\n\t\t}\n\n\t\tstage2done = 1;\n\t}\n}\n\n__attribute__((visibility(\"hidden\"))) void\n__malloc_lock_stack_logging()\n{\n\t_malloc_lock_lock(&stack_logging_lock);\n\tthread_doing_logging = (vm_address_t)_os_tsd_get_direct(__TSD_THREAD_SELF);\n}\n\n__attribute__((visibility(\"hidden\"))) void\n__malloc_unlock_stack_logging()\n{\n\tthread_doing_logging = 0;\n\t_malloc_lock_unlock(&stack_logging_lock);\n}\n\nconst uint64_t __invalid_stack_id = (uint64_t)(-1ll);\n\n// returns the stack id or invalid_stack_id if any kind of error\n// this needs to be done while stack_logging_lock is locked)\n\n__attribute__((visibility(\"hidden\"))) uint64_t\n__enter_stack_into_table_while_locked(vm_address_t self_thread, uint32_t num_hot_to_skip, boolean_t add_thread_id, size_t ptr_size)\n{\n\t// gather stack\n\tuint32_t count;\n\tthread_stack_pcs(stack_buffer, STACK_LOGGING_MAX_STACK_SIZE - 1, &count); // only gather up to STACK_LOGGING_MAX_STACK_SIZE-1 since we append thread id\n\t\n\tif (add_thread_id) {\n\t\tstack_buffer[count++] = self_thread + 1;   // stuffing thread # in the coldest slot. Add 1 to match what the old stack logging did.\n\t}\n\t\n\t// skip stack frames after the malloc call\n\tnum_hot_to_skip += 3; // __disk_stack_logging_log_stack | __enter_stack_into_table_while_locked | thread_stack_pcs\n\t\n\tif (count <= num_hot_to_skip) {\n\t\t// Oops!  Didn't get a valid backtrace from thread_stack_pcs().\n\t\treturn __invalid_stack_id;\n\t}\n\t\n\t// unique stack in memory\n\tcount -= num_hot_to_skip;\n\t\n#if __LP64__\n\tmach_vm_address_t *frames = (mach_vm_address_t*)stack_buffer + num_hot_to_skip;\n#else\n\tmach_vm_address_t frames[STACK_LOGGING_MAX_STACK_SIZE];\n\tuint32_t i;\n\tfor (i = 0; i < count; i++) {\n\t\tframes[i] = stack_buffer[i+num_hot_to_skip];\n\t}\n#endif\n\t\n\tuint64_t uniqueStackIdentifier = __invalid_stack_id;\n\t\n\twhile (!enter_frames_in_table(pre_write_buffers->uniquing_table, &uniqueStackIdentifier, frames, count, ptr_size)) {\n\t\tif (!__expand_uniquing_table(pre_write_buffers->uniquing_table))\n\t\t\treturn __invalid_stack_id;\n\t}\n\t\n\treturn uniqueStackIdentifier;\n}\n\nstatic void\ndecrement_ref_count(table_slot_t *table_slot, size_t ptr_size)\n{\n\tif (table_slot->refcount_slot.refcount > 0) {\n\t\ttable_slot->refcount_slot.refcount -= ptr_size;\n\t\t\n\t\tif (table_slot->refcount_slot.refcount == 0) {\n\t\t\ttable_slot->slots.slot0 = table_slot->slots.slot1 = 0;\n\t\t}\n\t}\n}\n\n__attribute__((visibility(\"hidden\"))) void\n__decrement_table_slot_refcount(uint64_t stack_id, size_t ptr_size)\n{\n\t__malloc_lock_stack_logging();\n\n\t// see if msl lite was disabled behind our backs\n\tif (!is_stack_logging_lite_enabled()) {\n\t\t__malloc_unlock_stack_logging();\n\t\treturn;\n\t}\n\n\tbacktrace_uniquing_table *uniquing_table = pre_write_buffers->uniquing_table;\n\t\n\tassert(uniquing_table->nodes_use_refcount);\n\tassert(!uniquing_table->in_client_process);\n\n\tslot_parent parent = stack_id;\n\tslot_parent prev_parent = __invalid_stack_id;\n\t\n\tdo {\n\t\tif (parent == prev_parent) {\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"circular parent reference in __decrement_table_slot_refcount\\n\");\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\tprev_parent = parent;\n\t\t\n\t\ttable_slot_t *table_slot = (table_slot_t *) (uniquing_table->u.table + (parent * 2));\n\t\t\n\t\tparent = table_slot->refcount_slot.parent;\n\t\tdecrement_ref_count(table_slot, ptr_size);\n\t} while (parent != slot_no_parent_refcount);\n\t\n\t__malloc_unlock_stack_logging();\n}\n\nvoid\n__disk_stack_logging_log_stack(uint32_t type_flags,\n\t\tuintptr_t zone_ptr,\n\t\tuintptr_t arg2,\n\t\tuintptr_t arg3,\n\t\tuintptr_t return_val,\n\t\tuint32_t num_hot_to_skip)\n{\n\tif (!stack_logging_enable_logging || stack_logging_postponed) {\n\t\treturn;\n\t}\n\t\n\tbool stack_logging_mode_lite_or_vmlite = stack_logging_mode == stack_logging_mode_lite || stack_logging_mode == stack_logging_mode_vmlite;\n\n\tif (stack_logging_mode_lite_or_vmlite &&\n\t\t!((type_flags & stack_logging_type_vm_allocate) || (type_flags & stack_logging_type_vm_deallocate))) {\n\t\treturn;\n\t}\n\n\tuintptr_t size;\n\tuintptr_t ptr_arg;\n\n\t// check incoming data\n\tif (type_flags & stack_logging_type_alloc && type_flags & stack_logging_type_dealloc) {\n\t\tsize = arg3;\n\t\tptr_arg = arg2; // the original pointer\n\t\tif (ptr_arg == 0) { // realloc(NULL, size) same as malloc(size)\n\t\t\ttype_flags ^= stack_logging_type_dealloc;\n\t\t} else {\n\t\t\t// realloc(arg1, arg2) -> result is same as free(arg1); malloc(arg2) -> result\n\t\t\t__disk_stack_logging_log_stack(\n\t\t\t\t\tstack_logging_type_dealloc, zone_ptr, ptr_arg, (uintptr_t)0, (uintptr_t)0, num_hot_to_skip + 1);\n\t\t\t__disk_stack_logging_log_stack(stack_logging_type_alloc, zone_ptr, size, (uintptr_t)0, return_val, num_hot_to_skip + 1);\n\t\t\treturn;\n\t\t}\n\t}\n\tif (type_flags & stack_logging_type_dealloc || type_flags & stack_logging_type_vm_deallocate) {\n\t\t// For VM deallocations we need to know the size, since they don't always match the\n\t\t// VM allocations.  It would be nice if arg2 was the size, for consistency with alloc and\n\t\t// realloc events.  However we can't easily make that change because all projects\n\t\t// (malloc.c, GC auto_zone, and gmalloc) have historically put the pointer in arg2 and 0 as\n\t\t// the size in arg3.  We'd need to change all those projects in lockstep, which isn't worth\n\t\t// the trouble.\n\t\tptr_arg = arg2;\n\t\tsize = arg3;\n\t\tif (ptr_arg == 0) {\n\t\t\treturn; // free(nil)\n\t\t}\n\t}\n\tif (type_flags & stack_logging_type_alloc || type_flags & stack_logging_type_vm_allocate) {\n\t\tif (return_val == 0 || return_val == (uintptr_t)MAP_FAILED) {\n\t\t\treturn; // alloc that failed\n\t\t}\n\t\tsize = arg2;\n\t}\n\n\tif (type_flags & stack_logging_type_vm_allocate || type_flags & stack_logging_type_vm_deallocate) {\n\t\tmach_port_t targetTask = (mach_port_t)zone_ptr;\n\t\t// For now, ignore \"injections\" of VM into other tasks.\n\t\tif (targetTask != mach_task_self()) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\ttype_flags &= stack_logging_valid_type_flags;\n\n\tvm_address_t self_thread = (vm_address_t)_os_tsd_get_direct(__TSD_THREAD_SELF);\n\n\tif (thread_doing_logging == self_thread) {\n\t\t// Prevent a thread from deadlocking against itself if vm_allocate() or malloc()\n\t\t// is called below here, from __prepare_to_log_stacks() or _prepare_to_log_stacks_stage2(),\n\t\t// or if we are logging an event and need to call __expand_uniquing_table() which calls\n\t\t// vm_allocate() to grow stack logging data structures.  Any such \"administrative\"\n\t\t// vm_allocate or malloc calls would attempt to recursively log those events.\n\t\treturn;\n\t}\n\n\t// lock and enter\n\t_malloc_lock_lock(&stack_logging_lock);\n\n\tthread_doing_logging = self_thread; // for preventing deadlock'ing on stack logging on a single thread\n\n\tif (stack_logging_mode_lite_or_vmlite && (type_flags & stack_logging_type_vm_deallocate)) {\n\t\tif (pre_write_buffers && pre_write_buffers->vm_stackid_table) {\n\t\t\tradix_tree_delete(&pre_write_buffers->vm_stackid_table,\n\t\t\t\t\t\t\t  trunc_page(ptr_arg), round_page(ptr_arg + size) - trunc_page(ptr_arg));\n\t\t\tgoto out;\n\t\t}\n\t}\n\n\t// now actually begin\n\t__prepare_to_log_stacks(false);\n\n\t// since there could have been a fatal (to stack logging) error such as the log files not being created, check these variables\n\t// before continuing\n\tif (!stack_logging_enable_logging || stack_logging_postponed) {\n\t\tgoto out;\n\t}\n\n\tif (type_flags & stack_logging_type_alloc) {\n\t\t// Only do this second stage of setup when we first record a malloc (as opposed to a VM allocation),\n\t\t// to ensure that the malloc zone has already been created as is necessary for this.\n\t\t__prepare_to_log_stacks_stage2();\n\t}\n\n\t// compaction\n\tif (last_logged_malloc_address && (type_flags & stack_logging_type_dealloc) &&\n\t\t\tSTACK_LOGGING_DISGUISE(ptr_arg) == last_logged_malloc_address) {\n\t\t// *waves hand* the last allocation never occurred\n\t\tpre_write_buffers->next_free_index_buffer_offset -= (uint32_t)sizeof(stack_logging_index_event);\n\t\tlast_logged_malloc_address = 0ul;\n\t\tgoto out;\n\t}\n\n\tuint64_t uniqueStackIdentifier;\n\tif (stack_logging_mode_lite_or_vmlite) {\n\t\tuniqueStackIdentifier = __enter_stack_into_table_while_locked(self_thread, num_hot_to_skip, false, 1);\n\t} else {\n\t\tuniqueStackIdentifier = __enter_stack_into_table_while_locked(self_thread, num_hot_to_skip, true, 0);\n\t}\n\t\n\tif (uniqueStackIdentifier == __invalid_stack_id) {\n\t\tgoto out;\n\t}\n\n\tif (stack_logging_mode_lite_or_vmlite && (type_flags & stack_logging_type_vm_allocate)) {\n\t\tif (pre_write_buffers) {\n\t\t\tif (!pre_write_buffers->vm_stackid_table) {\n\t\t\t\tpre_write_buffers->vm_stackid_table\t= radix_tree_create();\n\t\t\t\tpre_write_buffers->vm_stackid_table_size = radix_tree_size(pre_write_buffers->vm_stackid_table);\n\t\t\t}\n\t\t\tif (pre_write_buffers->vm_stackid_table) {\n\t\t\t\tuint64_t address = return_val;\n\t\t\t\tradix_tree_insert(&pre_write_buffers->vm_stackid_table,\n\t\t\t\t\t\t\t\t  trunc_page(address), round_page(address+size) - trunc_page(address),\n\t\t\t\t\t\t\t\t  uniqueStackIdentifier);\n\t\t\t\tpre_write_buffers->vm_stackid_table_size = radix_tree_size(pre_write_buffers->vm_stackid_table);\n\t\t\t}\n\t\t}\n\t\tgoto out;\n\t}\n\n\tstack_logging_index_event current_index;\n\tif (type_flags & stack_logging_type_alloc || type_flags & stack_logging_type_vm_allocate) {\n\t\tcurrent_index.address = STACK_LOGGING_DISGUISE(return_val);\n\t\tcurrent_index.argument = size;\n\t\tif (logging_use_compaction) {\n\t\t\tlast_logged_malloc_address = current_index.address; // disguised\n\t\t}\n\t} else {\n\t\tcurrent_index.address = STACK_LOGGING_DISGUISE(ptr_arg);\n\t\tcurrent_index.argument = size;\n\t\tlast_logged_malloc_address = 0ul;\n\t}\n\tcurrent_index.offset_and_flags = STACK_LOGGING_OFFSET_AND_FLAGS(uniqueStackIdentifier, type_flags);\n\n\t//\tthe following line is a good debugging tool for logging each allocation event as it happens.\n\t//\tmalloc_report(ASL_LEVEL_INFO, \"{0x%lx, %lld}\\n\", STACK_LOGGING_DISGUISE(current_index.address), uniqueStackIdentifier);\n\n\t// flush the data buffer to disk if necessary\n\tif (pre_write_buffers->next_free_index_buffer_offset + sizeof(stack_logging_index_event) >= STACK_LOGGING_BLOCK_WRITING_SIZE) {\n\t\tflush_data();\n\t}\n\n\t// store bytes in buffers\n\tmemcpy(pre_write_buffers->index_buffer + pre_write_buffers->next_free_index_buffer_offset, &current_index,\n\t\t\tsizeof(stack_logging_index_event));\n\tpre_write_buffers->next_free_index_buffer_offset += (uint32_t)sizeof(stack_logging_index_event);\n\nout:\n\tthread_doing_logging = 0;\n\t_malloc_lock_unlock(&stack_logging_lock);\n}\n\nvoid\n__stack_logging_fork_prepare(void)\n{\n\t_malloc_lock_lock(&stack_logging_lock);\n}\n\nvoid\n__stack_logging_fork_parent(void)\n{\n\t_malloc_lock_unlock(&stack_logging_lock);\n}\n\nvoid\n__stack_logging_fork_child(void)\n{\n\tmalloc_logger = NULL;\n\tstack_logging_enable_logging = 0;\n\t_malloc_lock_init(&stack_logging_lock);\n}\n\nvoid\n__stack_logging_early_finished(void)\n{\n\tstack_logging_finished_init = 1;\n\tstack_logging_postponed = 0;\n}\n\n// support for gdb and others checking for stack_logging locks\n__attribute__((visibility(\"hidden\"))) boolean_t\n__stack_logging_locked(void)\n{\n\tbool acquired_lock = _malloc_lock_trylock(&stack_logging_lock);\n\tif (acquired_lock) {\n\t\t_malloc_lock_unlock(&stack_logging_lock);\n\t}\n\treturn (acquired_lock ? false : true);\n}\n\n#pragma mark -\n#pragma mark Remote Stack Log Access\n\n#pragma mark - Design notes:\n\n/*\n *\n * this first one will look through the index, find the \"stack_identifier\" (i.e. the offset in the log file), and call the third\n * function listed here.\n * extern kern_return_t __mach_stack_logging_get_frames(task_t task, mach_vm_address_t address, mach_vm_address_t\n * stack_frames_buffer, uint32_t max_stack_frames, uint32_t *num_frames);\n * //  Gets the last allocation record about address\n *\n * if !address, will load index and iterate through (expensive)\n * else will load just index, search for stack, and then use third function here to retrieve. (also expensive)\n * extern kern_return_t __mach_stack_logging_enumerate_records(task_t task, mach_vm_address_t address, void\n * enumerator(mach_stack_logging_record_t, void *), void *context);\n * // Applies enumerator to all records involving address sending context as enumerator's second parameter; if !address, applies\n * enumerator to all records\n *\n * this function will load the stack file, look for the stack, and follow up to STACK_LOGGING_FORCE_FULL_BACKTRACE_EVERY references\n * to\n * reconstruct.\n * extern kern_return_t __mach_stack_logging_frames_for_uniqued_stack(task_t task, uint64_t stack_identifier, mach_vm_address_t\n * stack_frames_buffer, uint32_t max_stack_frames, uint32_t *count);\n * // Given a uniqued_stack fills stack_frames_buffer\n *\n */\n\n#pragma mark -\n#pragma mark Backtrace Uniquing Table Reading and Lookup\n\n// This is client-side code to get a stack log from a uniquing_table.\nstatic void\nfree_uniquing_table_chunks(backtrace_uniquing_table *uniquing_table)\n{\n\ttable_chunk_header_t *table_chunk_header = uniquing_table->u.first_table_chunk_hdr;\n\tassert(uniquing_table->in_client_process);\n\twhile (table_chunk_header) {\n\t\tmach_vm_deallocate(mach_task_self(), (mach_vm_address_t)(uintptr_t)(table_chunk_header->table_chunk),\n\t\t\t\ttable_chunk_header->table_chunk_size);\n\t\ttable_chunk_header_t *next = table_chunk_header->next_table_chunk_header;\n\t\tfree(table_chunk_header);\n\t\ttable_chunk_header = next;\n\t}\n}\n\nstatic kern_return_t\nread_uniquing_table_from_task(task_t remote_task, backtrace_uniquing_table *uniquing_table)\n{\n\tassert(uniquing_table->in_client_process);\n\tmach_vm_address_t next_address_to_read = uniquing_table->table_address;\n\tuint64_t remaining_size_to_read = uniquing_table->tableSize;\n\tconst mach_vm_size_t two_gigabytes =\n\t\t\t2ull * 1024 * 1024 * 1024; // attempting to read 4 GB in one call fails, so try a max of 2 GB\n\ttable_chunk_header_t **table_chunk_hdr_ptr = &(uniquing_table->u.first_table_chunk_hdr);\n\t*table_chunk_hdr_ptr = NULL;\n\n\twhile (remaining_size_to_read > 0ull) {\n\t\tvm_address_t local_table_chunk_address = 0ul;\n\t\tmach_msg_type_number_t local_table_chunk_size = 0;\n\n\t\tmach_vm_size_t next_size_to_read = (remaining_size_to_read > two_gigabytes) ? two_gigabytes : remaining_size_to_read;\n\t\twhile (1) {\n\t\t\tkern_return_t err = mach_vm_read(\n\t\t\t\t\tremote_task, next_address_to_read, next_size_to_read, &local_table_chunk_address, &local_table_chunk_size);\n\t\t\tif (err == KERN_SUCCESS) {\n\t\t\t\t*table_chunk_hdr_ptr = malloc(sizeof(table_chunk_header_t));\n\t\t\t\ttable_chunk_header_t *table_chunk_hdr = *table_chunk_hdr_ptr;\n\t\t\t\ttable_chunk_hdr->num_nodes_in_chunk = local_table_chunk_size / (sizeof(mach_vm_address_t) * 2);\n\t\t\t\t;\n\t\t\t\ttable_chunk_hdr->table_chunk = (mach_vm_address_t *)local_table_chunk_address;\n\t\t\t\ttable_chunk_hdr->table_chunk_size = local_table_chunk_size;\n\t\t\t\ttable_chunk_hdr->next_table_chunk_header = NULL;\t\t\t\t   // initialize it, in case it is the last chunk\n\t\t\t\ttable_chunk_hdr_ptr = &(table_chunk_hdr->next_table_chunk_header); // set up to assign next chunk to this\n\n\t\t\t\tnext_address_to_read += local_table_chunk_size;\n\t\t\t\tremaining_size_to_read -= local_table_chunk_size;\n\t\t\t\t// fprintf(stderr, \"requested %#qx, got %#x of %#qx at %p from backtrace uniquing table of target process\\n\",\n\t\t\t\t// next_size_to_read, local_table_chunk_size, uniquing_table->tableSize, table_chunk_hdr);\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\t// fprintf(stderr, \"requested %#qx, failed\\n\", next_size_to_read);\n\t\t\t\tnext_size_to_read /= 2;\n\t\t\t\tif (next_size_to_read <= 1024 * 1024) {\n\t\t\t\t\t// We couldn't even map one megabyte?  Let's call that an error...\n\t\t\t\t\tfree_uniquing_table_chunks(uniquing_table);\n\t\t\t\t\treturn err;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn KERN_SUCCESS;\n}\n\nstatic mach_vm_address_t *\nget_node_from_uniquing_table(backtrace_uniquing_table *uniquing_table, uint64_t index_pos)\n{\n\tassert(uniquing_table->in_client_process);\n\ttable_chunk_header_t *table_chunk_hdr = uniquing_table->u.first_table_chunk_hdr;\n\tuint64_t start_node_of_chunk = 0;\n\twhile (table_chunk_hdr && index_pos > start_node_of_chunk + table_chunk_hdr->num_nodes_in_chunk) {\n\t\ttable_chunk_hdr = table_chunk_hdr->next_table_chunk_header;\n\t\tif (table_chunk_hdr) {\n\t\t\tstart_node_of_chunk += table_chunk_hdr->num_nodes_in_chunk;\n\t\t}\n\t}\n\t\n\t// Handle case where someone passes an invalid stack id\n\t// <rdar://problem/25337823> get_node_from_uniquing_table should be more tolerant\n\tif (!table_chunk_hdr) {\n\t\treturn NULL;\n\t}\n\n\tuint64_t index_in_chunk = index_pos - start_node_of_chunk;\n\tmach_vm_address_t *node = table_chunk_hdr->table_chunk + (index_in_chunk * 2);\n\treturn node;\n}\n\nstatic void\nunwind_stack_from_table_index(backtrace_uniquing_table *uniquing_table,\n\t\tuint64_t index_pos,\n\t\tmach_vm_address_t *out_frames_buffer,\n\t\tuint32_t *out_frames_count,\n\t\tuint32_t max_frames,\n\t\tboolean_t use_refcount)\n{\n\tmach_vm_address_t *node = get_node_from_uniquing_table(uniquing_table, index_pos);\n\tuint32_t foundFrames = 0;\n\tslot_parent end_parent = use_refcount ? slot_no_parent_refcount : slot_no_parent_normal;\n\t\n\tif (node && index_pos < uniquing_table->numNodes) {\n\t\twhile (foundFrames < max_frames) {\n\t\t\ttable_slot_t *table_slot = (table_slot_t *) (node);\n\t\t\t\n\t\t\tslot_address address = use_refcount ? table_slot->refcount_slot.address : table_slot->normal_slot.address;\n\t\t\t\n\t\t\tout_frames_buffer[foundFrames++] = address;\n\t\t\t\n\t\t\tif (use_refcount && table_slot->refcount_slot.refcount == 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tslot_parent parent = use_refcount ? table_slot->refcount_slot.parent : table_slot->normal_slot.parent;\n\t\t\t\n\t\t\tif (parent == end_parent) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tnode = get_node_from_uniquing_table(uniquing_table, parent);\n\t\t}\n\t}\n\n\t*out_frames_count = foundFrames;\n}\n\n#pragma mark - caching\n\n__attribute__((always_inline)) static inline size_t\nhash_index(uint64_t address, size_t max_pos)\n{\n\treturn (size_t)((address >> 2) % (max_pos - 1)); // simplicity rules.\n}\n\n__attribute__((always_inline)) static inline size_t\nhash_multiplier(size_t capacity, uint32_t allowed_collisions)\n{\n\treturn (capacity / (allowed_collisions * 2 + 1));\n}\n\n__attribute__((always_inline)) static inline size_t\nnext_hash(size_t hash, size_t multiplier, size_t capacity, uint32_t collisions)\n{\n\thash += multiplier * collisions;\n\tif (hash >= capacity) {\n\t\thash -= capacity;\n\t}\n\treturn hash;\n}\n\nstatic void\ntransfer_node(remote_index_cache *cache, remote_index_node *old_node)\n{\n\tuint32_t collisions = 0;\n\tsize_t pos = hash_index(old_node->address, cache->cache_node_capacity);\n\tsize_t multiplier = hash_multiplier(cache->cache_node_capacity, cache->collision_allowance);\n\tdo {\n\t\tif (cache->table_memory[pos].address == old_node->address) { // hit like this shouldn't happen.\n\t\t\tfprintf(stderr, \"impossible collision! two address==address lists! (transfer_node)\\n\");\n\t\t\tbreak;\n\t\t} else if (cache->table_memory[pos].address == 0) { // empty\n\t\t\tcache->table_memory[pos] = *old_node;\n\t\t\tbreak;\n\t\t} else {\n\t\t\tcollisions++;\n\t\t\tpos = next_hash(pos, multiplier, cache->cache_node_capacity, collisions);\n\t\t}\n\t} while (collisions <= cache->collision_allowance);\n\n\tif (collisions > cache->collision_allowance) {\n\t\tfprintf(stderr, \"reporting bad hash function! disk stack logging reader %lu bit. (transfer_node)\\n\", sizeof(void *) * 8);\n\t}\n}\n\nstatic void\nexpand_cache(remote_index_cache *cache)\n{\n\t// keep old stats\n\tsize_t old_node_capacity = cache->cache_node_capacity;\n\tremote_index_node *old_table = cache->table_memory;\n\n\t// double size\n\tcache->cache_size <<= 2;\n\tcache->cache_node_capacity <<= 2;\n\tcache->collision_allowance += 3;\n\tcache->table_memory = (void *)calloc(cache->cache_node_capacity, sizeof(remote_index_node));\n\n\t// repopulate (expensive!)\n\tsize_t i;\n\tfor (i = 0; i < old_node_capacity; i++) {\n\t\tif (old_table[i].address) {\n\t\t\ttransfer_node(cache, &old_table[i]);\n\t\t}\n\t}\n\tfree(old_table);\n\t//\tprintf(\"cache expanded to %0.2f mb (eff: %3.0f%%, capacity: %lu, nodes: %llu, llnodes: %llu)\\n\",\n\t//((float)(cache->cache_size))/(1 << 20), ((float)(cache->cache_node_count)*100.0)/((float)(cache->cache_node_capacity)),\n\t// cache->cache_node_capacity, cache->cache_node_count, cache->cache_llnode_count);\n}\n\nstatic void\ninsert_node(remote_index_cache *cache, uint64_t address, uint64_t index_file_offset)\n{\n\tuint32_t collisions = 0;\n\tsize_t pos = hash_index(address, cache->cache_node_capacity);\n\tsize_t multiplier = hash_multiplier(cache->cache_node_capacity, cache->collision_allowance);\n\n\twhile (1) {\n\t\tif (cache->table_memory[pos].address == 0ull || cache->table_memory[pos].address == address) { // hit or empty\n\t\t\tcache->table_memory[pos].address = address;\n\t\t\tcache->table_memory[pos].index_file_offset = index_file_offset;\n\t\t\t// Inserted it!  Break out of the loop.\n\t\t\tbreak;\n\t\t}\n\n\t\tcollisions++;\n\t\tpos = next_hash(pos, multiplier, cache->cache_node_capacity, collisions);\n\n\t\tif (collisions > cache->collision_allowance) {\n\t\t\texpand_cache(cache);\n\t\t\tpos = hash_index(address, cache->cache_node_capacity);\n\t\t\tmultiplier = hash_multiplier(cache->cache_node_capacity, cache->collision_allowance);\n\t\t\tcollisions = 0;\n\t\t}\n\t}\n}\n\n// Kudos to Daniel Delwood for this function.  This is called in an analysis tool process\n// to share a VM region from a target process, without the target process needing to explicitly\n// share the region itself via shm_open().  The VM_FLAGS_RETURN_DATA_ADDR flag is necessary\n// for iOS in case the target process uses a different VM page size than the analysis tool process.\nstatic mach_vm_address_t\nmap_shared_memory_from_task(task_t sourceTask, mach_vm_address_t sourceAddress, mach_vm_size_t sourceSize)\n{\n#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\tint mapRequestFlags = VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR;\n\tmach_vm_address_t mapRequestAddress = sourceAddress;\n\tmach_vm_size_t mapRequestSize = sourceSize;\n#else // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\t// Sadly, VM_FLAGS_RETURN_DATA_ADDR isn't available to us; align everything manually.\n\tint mapRequestFlags = VM_FLAGS_ANYWHERE;\n\tmach_vm_address_t mapRequestAddress = trunc_page(sourceAddress);\n\tmach_vm_size_t mapRequestSize = round_page(sourceAddress + sourceSize) - mapRequestAddress;\n#endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\tmach_vm_address_t mappedAddress = 0;\n\tvm_prot_t outCurrentProt = VM_PROT_NONE;\n\tvm_prot_t outMaxProt = VM_PROT_NONE;\n\tkern_return_t err = mach_vm_remap(mach_task_self(), &mappedAddress, mapRequestSize, 0, mapRequestFlags, sourceTask,\n\t\t\tmapRequestAddress, false, &outCurrentProt, &outMaxProt, VM_INHERIT_NONE);\n\tif (err != KERN_SUCCESS) {\n\t\treturn 0;\n\t}\n\treturn mappedAddress + (sourceAddress - mapRequestAddress);\n}\n\nstatic kern_return_t\nupdate_cache_for_file_streams(remote_task_file_streams *descriptors)\n{\n\tremote_index_cache *cache = descriptors->cache;\n\n\t// create from scratch if necessary.\n\tif (!cache) {\n\t\tdescriptors->cache = cache = (remote_index_cache *)calloc((size_t)1, sizeof(remote_index_cache));\n\t\tcache->cache_node_capacity = 1 << 14;\n\t\tcache->collision_allowance = 17;\n\t\tcache->last_index_file_offset = 0;\n\t\tcache->cache_size = cache->cache_node_capacity * sizeof(remote_index_node);\n\t\tcache->table_memory = (void *)calloc(cache->cache_node_capacity, sizeof(remote_index_node));\n\n\t\tcache->shmem = (stack_buffer_shared_memory *)map_shared_memory_from_task(descriptors->remote_task,\n\t\t\t\tdescriptors->remote_stack_buffer_shared_memory_address, sizeof(stack_buffer_shared_memory));\n\t\tif (!cache->shmem) {\n\t\t\t// failed to connect to the shared memory region; warn and continue.\n\t\t\tmalloc_report(ASL_LEVEL_INFO,\n\t\t\t\t\t\"warning: unable to map shared memory from %llx in target process %d; no stack backtraces will be available.\\n\",\n\t\t\t\t\tdescriptors->remote_stack_buffer_shared_memory_address, descriptors->remote_pid);\n\t\t}\n\t\tcache->lite_mode = descriptors->task_uses_lite_or_vmlite_mode;\n\n\t\tif (cache->shmem && cache->shmem->vm_stackid_table) {\n\t\t\tcache->vm_stackid_table = (struct radix_tree *)map_shared_memory_from_task(\n\t\t\t\tdescriptors->remote_task, (mach_vm_address_t) cache->shmem->vm_stackid_table, cache->shmem->vm_stackid_table_size);\n\t\t\tif (!cache->vm_stackid_table) {\n\t\t\t\tmalloc_report(ASL_LEVEL_INFO,\n\t\t\t\t\t\t\t   \"warning: unable to map vm_stackid table from %llx in target process %d; no VM stack backtraces will be available.\\n\",\n\t\t\t\t\t\t\t   (mach_vm_address_t) cache->shmem->vm_stackid_table, descriptors->remote_pid);\n\t\t\t}\n\t\t}\n\t}\n\n\t// suspend and see how much updating there is to do. there are three scenarios, listed below\n\tbool update_snapshot = false;\n\tif (descriptors->remote_task != mach_task_self()) {\n\t\ttask_suspend(descriptors->remote_task);\n\t}\n\n\tstruct stat file_statistics;\n\t\n\tif (descriptors->index_file_stream) {\n\t\tfstat(fileno(descriptors->index_file_stream), &file_statistics);\n\t} else {\n\t\tfile_statistics.st_size = 0;\n\t}\n\t\t\n\tsize_t read_size = (descriptors->task_is_64_bit ? sizeof(stack_logging_index_event64) : sizeof(stack_logging_index_event32));\n\tuint64_t read_this_update = 0;\n\n\t// the delta indecies is a complex number; there are three cases:\n\t// 1. there is no shared memory (or we can't connect); diff the last_index_file_offset from the filesize.\n\t// 2. the only updates have been in shared memory; disk file didn't change at all. delta_indecies should be zero, scan snapshot\n\t// only.\n\t// 3. the updates have flushed to disk, meaning that most likely there is new data on disk that wasn't read from shared memory.\n\t//    correct delta_indecies for the pre-scanned amount and read the new data from disk and shmem.\n\tuint64_t delta_indecies = (file_statistics.st_size - cache->last_index_file_offset) / read_size;\n\tuint32_t last_snapshot_scan_index = 0;\n\tif (delta_indecies && cache->shmem) {\n\t\t// case 3: add cache scanned to known from disk and recalc\n\t\tcache->last_index_file_offset += cache->snapshot.next_free_index_buffer_offset;\n\t\tdelta_indecies = (file_statistics.st_size - cache->last_index_file_offset) / read_size;\n\t\tupdate_snapshot = true;\n\t} else if (cache->shmem) {\n\t\t// case 2: set the last snapshot scan count so we don't rescan something we've seen.\n\t\tlast_snapshot_scan_index = cache->snapshot.next_free_index_buffer_offset / (uint32_t)read_size;\n\t}\n\n\t// no update necessary for the file; check if need a snapshot.\n\tif (delta_indecies == 0) {\n\t\tif (cache->shmem && !update_snapshot) {\n\t\t\tupdate_snapshot = (cache->shmem->next_free_index_buffer_offset != cache->snapshot.next_free_index_buffer_offset);\n\t\t}\n\t}\n\n\t// need to update the snapshot if in lite mode and haven't yet read the uniquing table\n\tif (descriptors->task_uses_lite_or_vmlite_mode && cache->uniquing_table_snapshot.numPages == 0) {\n\t\tupdate_snapshot = true;\n\t}\n\t\n\t// if a snapshot is necessary, memcpy from remote frozen process' memory\n\t// note: there were two ways to do this - spin lock or suspend. suspend allows us to\n\t// analyze processes even if they were artificially suspended. with a lock, there'd be\n\t// worry that the target was suspended with the lock taken.\n\tkern_return_t err = KERN_SUCCESS;\n\tif (update_snapshot) {\n\t\tmemcpy(&cache->snapshot, cache->shmem, sizeof(stack_buffer_shared_memory));\n\t\t// also need to update our version of the remote uniquing table\n\t\tvm_address_t local_uniquing_address = 0ul;\n\t\tmach_msg_type_number_t local_uniquing_size = 0;\n\t\tmach_vm_size_t desired_size = round_page(sizeof(backtrace_uniquing_table));\n\t\tif ((err = mach_vm_read(descriptors->remote_task, (mach_vm_address_t)cache->shmem->uniquing_table, desired_size,\n\t\t\t\t\t &local_uniquing_address, &local_uniquing_size)) != KERN_SUCCESS ||\n\t\t\t\tlocal_uniquing_size != desired_size) {\n\t\t\tfprintf(stderr, \"error while attempting to mach_vm_read remote stack uniquing table (%d): %s\\n\", err,\n\t\t\t\t\tmach_error_string(err));\n\t\t} else {\n\t\t\t// the mach_vm_read was successful, so acquire the uniquing table\n\n\t\t\t// need to re-read the table, so deallocate the current memory\n\t\t\tcache->uniquing_table_snapshot.in_client_process = true;\n\t\t\tfree_uniquing_table_chunks(&cache->uniquing_table_snapshot);\n\n\t\t\t// The following line copies the uniquing table structure data, but the actual uniquing table memory is invalid\n\t\t\t// since it's a pointer from the remote process.\n\t\t\tcache->uniquing_table_snapshot = *((backtrace_uniquing_table *)local_uniquing_address);\n\t\t\tcache->uniquing_table_snapshot.nodes_use_refcount = cache->lite_mode;\n\t\t\tcache->uniquing_table_snapshot.u.first_table_chunk_hdr = NULL;\n\t\t\tcache->uniquing_table_snapshot.in_client_process = true;\n\n\n\t\t\t// Read the uniquing table memory from the target process.\n\t\t\terr = read_uniquing_table_from_task(descriptors->remote_task, &(cache->uniquing_table_snapshot));\n\t\t\tif (err) {\n\t\t\t\tfprintf(stderr, \"error while attempting to mach_vm_read remote stack uniquing table contents (%d): %s\\n\", err,\n\t\t\t\t\t\tmach_error_string(err));\n\t\t\t}\n\t\t\t// Check the error status below, after further deallocating and resuming the target task.\n\n\t\t\tmach_vm_deallocate(mach_task_self(), (mach_vm_address_t)local_uniquing_address, (mach_vm_size_t)local_uniquing_size);\n\t\t}\n\t}\n\n\t// resume\n\tif (descriptors->remote_task != mach_task_self()) {\n\t\ttask_resume(descriptors->remote_task);\n\t}\n\n\tif (err != KERN_SUCCESS) {\n\t\t// To Do:  further clean up allocated resources, and also try to prevent printing numerous identical \"out of memory\" errors\n\t\t// (maybe we should abort?).\n\t\treturn err;\n\t}\n\n\tif (!update_snapshot && delta_indecies == 0) {\n\t\treturn KERN_SUCCESS; // absolutely no updating needed.\n\t}\n\tFILE *the_index = (descriptors->index_file_stream);\n\n\t// prepare for the read; target process could be 32 or 64 bit.\n\n\tstack_logging_index_event32 *target_32_index = NULL;\n\tstack_logging_index_event64 *target_64_index = NULL;\n\n\t// perform the update from the file\n\tuint32_t i;\n\tif (delta_indecies) {\n\t\tchar bufferSpace[4096]; // 4 kb\n\t\ttarget_32_index = (stack_logging_index_event32 *)bufferSpace;\n\t\ttarget_64_index = (stack_logging_index_event64 *)bufferSpace;\n\t\tsize_t number_slots = (size_t)(4096 / read_size);\n\n\t\tsize_t read_count = 0;\n\t\tif (fseeko(the_index, (off_t)(cache->last_index_file_offset), SEEK_SET)) {\n\t\t\tfprintf(stderr,\n\t\t\t\t\t\"error while attempting to cache information from remote stack index file. (update_cache_for_file_streams)\\n\");\n\t\t}\n\t\toff_t current_index_position = cache->last_index_file_offset;\n\t\tdo {\n\t\t\tnumber_slots = (size_t)MIN(delta_indecies - read_this_update, number_slots);\n\t\t\tread_count = fread(bufferSpace, read_size, number_slots, the_index);\n\t\t\tif (descriptors->task_is_64_bit) {\n\t\t\t\tfor (i = 0; i < read_count; i++) {\n\t\t\t\t\tinsert_node(cache, STACK_LOGGING_DISGUISE(target_64_index[i].address), (uint64_t)current_index_position);\n\t\t\t\t\tread_this_update++;\n\t\t\t\t\tcurrent_index_position += read_size;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (i = 0; i < read_count; i++) {\n\t\t\t\t\tinsert_node(cache, (mach_vm_address_t)STACK_LOGGING_DISGUISE(target_32_index[i].address),\n\t\t\t\t\t\t\t(uint64_t)current_index_position);\n\t\t\t\t\tread_this_update++;\n\t\t\t\t\tcurrent_index_position += read_size;\n\t\t\t\t}\n\t\t\t}\n\t\t} while (read_count);\n\n\t\tif (read_this_update < delta_indecies) {\n\t\t\tfprintf(stderr, \"insufficient data in remote stack index file; expected more records.\\n\");\n\t\t}\n\t\tcache->last_index_file_offset += read_this_update * read_size;\n\t}\n\n\tif (update_snapshot) {\n\t\ttarget_32_index = (stack_logging_index_event32 *)(cache->snapshot.index_buffer);\n\t\ttarget_64_index = (stack_logging_index_event64 *)(cache->snapshot.index_buffer);\n\n\t\tuint32_t free_snapshot_scan_index = cache->snapshot.next_free_index_buffer_offset / (uint32_t)read_size;\n\t\toff_t current_index_position = cache->snapshot.start_index_offset;\n\t\tif (descriptors->task_is_64_bit) {\n\t\t\tfor (i = last_snapshot_scan_index; i < free_snapshot_scan_index; i++) {\n\t\t\t\tinsert_node(cache, STACK_LOGGING_DISGUISE(target_64_index[i].address),\n\t\t\t\t\t\t(uint64_t)(current_index_position + (i * read_size)));\n\t\t\t}\n\t\t} else {\n\t\t\tfor (i = last_snapshot_scan_index; i < free_snapshot_scan_index; i++) {\n\t\t\t\tinsert_node(cache, (mach_vm_address_t)STACK_LOGGING_DISGUISE(target_32_index[i].address),\n\t\t\t\t\t\t(uint64_t)(current_index_position + (i * read_size)));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn KERN_SUCCESS;\n}\n\nstatic void\ndestroy_cache_for_file_streams(remote_task_file_streams *descriptors)\n{\n\tif (!descriptors->cache) {\n\t\treturn;\n\t}\n\tif (descriptors->cache->shmem) {\n\t\tmunmap(descriptors->cache->shmem, sizeof(stack_buffer_shared_memory));\n\t}\n\tfree(descriptors->cache->table_memory);\n\tfree_uniquing_table_chunks(&descriptors->cache->uniquing_table_snapshot);\n\tfree(descriptors->cache);\n\tdescriptors->cache = NULL;\n}\n\n#pragma mark - internal\n\nstatic FILE *\nopen_log_file_at_path(char *pathname, remote_task_file_streams *streams) {\n\tFILE *file = fopen(pathname, \"r\");\n\tif (!file) {\n\t\treturn NULL;\n\t}\n\t\n\tchar *log_file_name = strrchr(pathname, '/');\n\tchar *p = log_file_name;\n\t\n\t// File names are of the form stack-logs.<pid>.<address>.<progname>.XXXXXX.index\n\tif (p) p = strchr(p, '.');\t\t\t// skip past \"stack-logs\"\n\tif (p) p = strchr(p + 1, '.');\t\t// skip past \".<pid>\"\n\tif (p) p++;\t\t\t\t\t\t\t// skip past '.'\n\t\t\n\tif (!p) {\n\t\treturn NULL;\n\t}\n\t\n\tchar *shared_memory_address_string = p;\n\t\n\t// The hex address of the remote_index_cache in the target process\n\t// is given in the stack log file name, following the pid and a period.\n\tstreams->remote_stack_buffer_shared_memory_address = strtoll(shared_memory_address_string, NULL, 16);\n\tstreams->index_file_stream = file;\n\t\n\treturn file;\n}\n\n// In the stack log analysis process, find the stack logging file for target process <pid>\n// by scanning the given directory for entries with names of the form \"stack-logs.<pid>.*.index\"\n// If we find such an entry then open that stack logging file.\nstatic FILE *\nopen_log_file_from_directory(pid_t pid, char *directory, remote_task_file_streams *streams)\n{\n\tDIR *dp;\n\tstruct dirent *entry;\n\tchar prefix_and_pid[PATH_MAX];\n\tchar pathname[PATH_MAX];\n\tFILE *file = NULL;\n\n\t// Check for access permissions in case we're sandbox'ed.\n\tif (access(directory, R_OK | X_OK) == 0 && (dp = opendir(directory)) != NULL) {\n\t\t// It's OK to use snprintf in this routine since it should only be called by the clients\n\t\t// of stack logging, and thus calls to malloc are OK.\n\t\tsnprintf(prefix_and_pid, (size_t)PATH_MAX, \"%s%d.\", stack_log_file_base_name,\n\t\t\t\tpid); // make sure to use \"%s%d.\" rather than just \"%s%d\" to match the whole pid\n\t\tsize_t prefix_and_pid_length = strlen(prefix_and_pid);\n\n\t\twhile ((entry = readdir(dp)) != NULL) {\n\t\t\tif (strncmp(entry->d_name, prefix_and_pid, prefix_and_pid_length) == 0) {\n\t\t\t\tsnprintf(pathname, (size_t)PATH_MAX, \"%s/%s\", directory, entry->d_name);\n\t\t\t\tfile = open_log_file_at_path(pathname, streams);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tclosedir(dp);\n\t}\n\n\treturn file;\n}\n\n// Read the launch data of the target process from the kernel to find the\n// value of the environment variable named env_var_name.  Since this function\n// uses alloca() to temporarily allocate space for data copied from the kernel,\n// and we don't want to malloc space so that this can be called from malloc stack\n// logging code in the target process as well, we copy the result into the\n// env_var_value_buf of length max_path_len supplied by the caller.\nstatic bool\ngetenv_from_process(pid_t pid, char *env_var_name, char *env_var_value_buf, size_t buf_length)\n{\n\tenv_var_value_buf[0] = '\\0';\n\n\t// Just call getenv() if pid is the current process, partly to avoid the sysctl()\n\t// call which can cause system deadlock (<rdar://problem/14409213> \"processes hang\n\t// if sandboxd is running with MallocStackLogging enabled\").  But it probably\n\t// doesn't completely fix that since there is another sysctl() call in is_process_running()\n\t// when checking to see if the process corresponding to an existing stack log file\n\t// is still running.\n\tif (pid == getpid()) {\n\t\tchar *env_var_value = getenv(env_var_name);\n\t\tif (!env_var_value) {\n\t\t\treturn false;\n\t\t} else {\n\t\t\tstrlcpy(env_var_value_buf, env_var_value, buf_length);\n\t\t\treturn true;\n\t\t}\n\t}\n\n\tint mib[3];\n\tsize_t argbufSize = 0; // Must initialize this to 0 so this works when compiled for x86_64.\n\n\t// First get the maximum arguments size, to determine the necessary buffer size.\n\tmib[0] = CTL_KERN;\n\tmib[1] = KERN_ARGMAX;\n\n\tsize_t size = sizeof(argbufSize);\n\tint ret = sysctl(mib, 2, &argbufSize, &size, NULL, 0);\n\tif (ret != 0) {\n\t\treturn false;\n\t}\n\n\tmib[0] = CTL_KERN;\n\tmib[1] = KERN_PROCARGS2; // The older KERN_PROCARGS is deprecated.\n\tmib[2] = pid;\n\n\tchar *argbuf = (char *)alloca(argbufSize);\n\tret = sysctl(mib, 3, argbuf, &argbufSize, (void *)NULL, 0);\n\tif (ret != 0) {\n\t\treturn false;\n\t}\n\targbuf[argbufSize - 1] = '\\0'; // make sure the buffer is null-terminated\n\tchar *p = argbuf;\n\tchar *endp = &argbuf[argbufSize];\n\n\t// Skip over argc, which is always 4 bytes long (int-sized), even in 64-bit architectures.\n\tint argumentCount = *((int *)argbuf);\n\tp += sizeof(argumentCount);\n\n\t// Skip over arguments, using the argumentCount read from the start of argbuf.\n\targumentCount++; // increment argumentCount to also skip saved exec path, which comes first\n\tfor (int argumentNum = 0; argumentNum < argumentCount && p < endp; argumentNum++) {\n\t\twhile (p < endp && *p != '\\0')\n\t\t\tp++;\n\t\twhile (p < endp && *p == '\\0')\n\t\t\tp++; // saved exec path sometimes has multiple nul's\n\t}\n\n\tsize_t env_var_name_length = strlen(env_var_name);\n\n\t// Examine environment variables.\n\twhile ((p + env_var_name_length + 1) < endp && *p != '\\0') {\n\t\tif (strncmp(p, env_var_name, env_var_name_length) == 0 && p[env_var_name_length] == '=') {\n\t\t\tp += env_var_name_length + 1;\n\t\t\tstrlcpy(env_var_value_buf, p, buf_length);\n\t\t\t//malloc_report(ASL_LEVEL_INFO, \"found env var %s='%s'\\n\", env_var_name, env_var_value_buf);\n\t\t\treturn true;\n\t\t}\n\t\twhile (p < endp && *p != '\\0')\n\t\t\tp++;\n\t\tp++;\n\t}\n\treturn false;\n}\n\nstatic FILE *\nopen_log_file(pid_t target_pid, remote_task_file_streams *streams)\n{\n\tstatic bool already_reaped = false;\n\tif (!already_reaped) {\n\t\t// reap any left-over log files (for non-existent processes, but not for this analysis process)\n\t\treap_orphaned_log_files(target_pid, streams);\n\t\talready_reaped = true;\n\t}\n\t\n\tif (streams->index_file_stream !=  NULL) { // reap_orphaned_log_files opened the file\n\t\treturn streams->index_file_stream;\n\t}\n\t\n\t// Since we're searching for the log file here, not creating it, we can search in any order we want.\n\t// So look at MallocStackLoggingDirectory last since that is almost never set.\n\tFILE *file = open_log_file_from_directory(target_pid, _PATH_TMP, streams);\n\tif (!file) {\n\t\tchar *env_var_names[] = {\"TMPDIR\", \"MallocStackLoggingDirectory\"};\n\t\tfor (unsigned i = 0; i < sizeof(env_var_names) / sizeof(char *); i++) {\n\t\t\tchar directory[PATH_MAX];\n\t\t\tbool success = getenv_from_process(target_pid, env_var_names[i], directory, sizeof(directory));\n\t\t\tif (success) {\n\t\t\t\tfile = open_log_file_from_directory(target_pid, directory, streams);\n\t\t\t\tif (file) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn file;\n}\n\n// shared_memory_address is non-zero when in lite mode and this is called for the first time on a task\nstatic remote_task_file_streams *\nretain_file_streams_for_task(task_t task, vm_address_t shared_memory_address)\n{\n\tif (task == MACH_PORT_NULL) {\n\t\treturn NULL;\n\t}\n\n\t_malloc_lock_lock(&remote_fd_list_lock);\n\n\t// see if they're already in use\n\tuint32_t i = 0;\n\tfor (i = 0; i < remote_task_fd_count; i++) {\n\t\tif (remote_fds[i].remote_task == task) {\n\t\t\tremote_fds[i].in_use_count++;\n\t\t\t_malloc_lock_unlock(&remote_fd_list_lock);\n\t\t\treturn &remote_fds[i];\n\t\t}\n\t}\n\n\t// open them\n\tuint32_t failures = 0;\n\tif (remote_task_fd_count == STACK_LOGGING_MAX_SIMUL_REMOTE_TASKS_INSPECTED) {\n\t\twhile (remote_fds[next_remote_task_fd].in_use_count > 0) {\n\t\t\tnext_remote_task_fd++;\n\t\t\tif (next_remote_task_fd == STACK_LOGGING_MAX_SIMUL_REMOTE_TASKS_INSPECTED) {\n\t\t\t\tnext_remote_task_fd = 0;\n\t\t\t}\n\t\t\tfailures++;\n\t\t\tif (failures >= STACK_LOGGING_MAX_SIMUL_REMOTE_TASKS_INSPECTED) {\n\t\t\t\t_malloc_lock_unlock(&remote_fd_list_lock);\n\t\t\t\treturn NULL;\n\t\t\t}\n\t\t}\n\t\tfclose(remote_fds[next_remote_task_fd].index_file_stream);\n\t\tdestroy_cache_for_file_streams(&remote_fds[next_remote_task_fd]);\n\t}\n\n\tpid_t pid;\n\tkern_return_t err = pid_for_task(task, &pid);\n\tif (err != KERN_SUCCESS) {\n\t\t_malloc_lock_unlock(&remote_fd_list_lock);\n\t\treturn NULL;\n\t}\n\n\tremote_task_file_streams *this_task_streams = &remote_fds[next_remote_task_fd];\n\n\tif (shared_memory_address != 0) {\n\t\tthis_task_streams->remote_stack_buffer_shared_memory_address = shared_memory_address;\n\t\tthis_task_streams->task_uses_lite_or_vmlite_mode = true;\n\t} else {\n\t\topen_log_file(pid, this_task_streams);\n\t\t\n\t\tif (this_task_streams->index_file_stream == NULL) {\n\t\t\t_malloc_lock_unlock(&remote_fd_list_lock);\n\t\t\treturn NULL;\n\t\t}\n\t}\n\n\t// check if target pid is running 64-bit\n\tint mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};\n\tstruct kinfo_proc processInfo;\n\tsize_t bufsize = sizeof(processInfo);\n\tif (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, &bufsize, NULL, (size_t)0) == 0 && bufsize > 0) {\n\t\tthis_task_streams->task_is_64_bit = processInfo.kp_proc.p_flag & P_LP64;\n\t} else {\n\t\tthis_task_streams->task_is_64_bit = 0;\n\t}\n\n\t// otherwise set vars and go\n\tthis_task_streams->in_use_count = 1;\n\tthis_task_streams->remote_task = task;\n\tthis_task_streams->remote_pid = pid;\n\tnext_remote_task_fd++;\n\tif (next_remote_task_fd == STACK_LOGGING_MAX_SIMUL_REMOTE_TASKS_INSPECTED) {\n\t\tnext_remote_task_fd = 0;\n\t}\n\tremote_task_fd_count = MIN(remote_task_fd_count + 1, STACK_LOGGING_MAX_SIMUL_REMOTE_TASKS_INSPECTED);\n\n\t_malloc_lock_unlock(&remote_fd_list_lock);\n\treturn this_task_streams;\n}\n\nstatic void\nrelease_file_streams_for_task(task_t task)\n{\n\t_malloc_lock_lock(&remote_fd_list_lock);\n\n\t// decrement in-use count\n\tuint32_t i = 0;\n\tfor (i = 0; i < remote_task_fd_count; i++) {\n\t\tif (remote_fds[i].remote_task == task) {\n\t\t\tremote_fds[i].in_use_count--;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t_malloc_lock_unlock(&remote_fd_list_lock);\n}\n\n#pragma mark - extern\n\nkern_return_t\n__mach_stack_logging_start_reading(task_t task, vm_address_t shared_memory_address, boolean_t *uses_lite_mode)\n{\n\tremote_task_file_streams *remote_fd = retain_file_streams_for_task(task, shared_memory_address);\n\tif (remote_fd == NULL) {\n\t\treturn KERN_FAILURE;\n\t}\n\t\n\t*uses_lite_mode = remote_fd->task_uses_lite_or_vmlite_mode;\n\t\n\treturn KERN_SUCCESS;\n}\n\nkern_return_t\n__mach_stack_logging_stop_reading(task_t task)\n{\n\tkern_return_t err = KERN_SUCCESS;\n\t\n\trelease_file_streams_for_task(task);\n\n\t_malloc_lock_lock(&remote_fd_list_lock);\n\t\n\tfor (uint32_t i = 0; i < remote_task_fd_count; i++) {\n\t\tif (remote_fds[i].remote_task == task) {\n\t\t\tif (remote_fds[i].in_use_count > 0) {\n\t\t\t\t// Hmm... the client is in the middle of a stack log reading call?\n\t\t\t\terr = KERN_FAILURE;\n\t\t\t} else {\n\t\t\t\t// remote_fds[i].in_use_count is 0 so don't decrement it!\n\t\t\t\tfclose(remote_fds[i].index_file_stream);\n\t\t\t\tremote_fds[i].index_file_stream = NULL;\n\t\t\t\tdestroy_cache_for_file_streams(&remote_fds[i]);\n\t\t\t\tremote_fds[i].remote_task = 0;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n\t_malloc_lock_unlock(&remote_fd_list_lock);\n\t\n\treturn err;\n}\n\n// This function is no longer used.  It was a hack that required an analysis tool process\n// to read the target tasks's __stack_log_file_path__ variable then pass the value of\n// that to this function.  This is now handled automatically all within this file, by\n// having the stack log reading code read the environment variables of the target process.\n// This function should be removed once no clients are calling it.\nkern_return_t\n__mach_stack_logging_set_file_path(task_t task, char *file_path)\n{\n\treturn KERN_SUCCESS;\n}\n\nkern_return_t\n__mach_stack_logging_get_frames(task_t task,\n\t\tmach_vm_address_t address,\n\t\tmach_vm_address_t *stack_frames_buffer,\n\t\tuint32_t max_stack_frames,\n\t\tuint32_t *count)\n{\n\tremote_task_file_streams *remote_fd = retain_file_streams_for_task(task, 0);\n\tif (remote_fd == NULL) {\n\t\treturn KERN_FAILURE;\n\t}\n\n\tkern_return_t err = update_cache_for_file_streams(remote_fd);\n\tif (err != KERN_SUCCESS) {\n\t\trelease_file_streams_for_task(task);\n\t\treturn err;\n\t}\n\n\tuint32_t collisions = 0;\n\tsize_t hash = hash_index(address, remote_fd->cache->cache_node_capacity);\n\tsize_t multiplier = hash_multiplier(remote_fd->cache->cache_node_capacity, remote_fd->cache->collision_allowance);\n\tuint64_t located_file_position = 0;\n\n\tbool found = false;\n\tdo {\n\t\tif (remote_fd->cache->table_memory[hash].address == address) { // hit!\n\t\t\tlocated_file_position = remote_fd->cache->table_memory[hash].index_file_offset;\n\t\t\tfound = true;\n\t\t\tbreak;\n\t\t} else if (remote_fd->cache->table_memory[hash].address == 0ull) { // failure!\n\t\t\tbreak;\n\t\t}\n\n\t\tcollisions++;\n\t\thash = next_hash(hash, multiplier, remote_fd->cache->cache_node_capacity, collisions);\n\n\t} while (collisions <= remote_fd->cache->collision_allowance);\n\n\tif (found) {\n\t\t// prepare for the read; target process could be 32 or 64 bit.\n\t\tstack_logging_index_event32 *target_32_index = NULL;\n\t\tstack_logging_index_event64 *target_64_index = NULL;\n\n\t\tif (located_file_position >= remote_fd->cache->last_index_file_offset) {\n\t\t\t// must be in shared memory\n\t\t\tif (remote_fd->cache->shmem) {\n\t\t\t\tif (remote_fd->task_is_64_bit) {\n\t\t\t\t\ttarget_64_index = (stack_logging_index_event64 *)(remote_fd->cache->snapshot.index_buffer +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  (located_file_position -\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  remote_fd->cache->snapshot.start_index_offset));\n\t\t\t\t\tlocated_file_position = STACK_LOGGING_OFFSET(target_64_index->offset_and_flags);\n\t\t\t\t} else {\n\t\t\t\t\ttarget_32_index = (stack_logging_index_event32 *)(remote_fd->cache->snapshot.index_buffer +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  (located_file_position -\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  remote_fd->cache->snapshot.start_index_offset));\n\t\t\t\t\tlocated_file_position = STACK_LOGGING_OFFSET(target_32_index->offset_and_flags);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfound = false;\n\t\t\t}\n\n\t\t} else {\n\t\t\t// it's written to disk\n\t\t\tchar bufferSpace[128];\n\n\t\t\tsize_t read_size =\n\t\t\t\t\t(remote_fd->task_is_64_bit ? sizeof(stack_logging_index_event64) : sizeof(stack_logging_index_event32));\n\t\t\tfseeko(remote_fd->index_file_stream, (off_t)located_file_position, SEEK_SET);\n\t\t\tsize_t read_count = fread(bufferSpace, read_size, (size_t)1, remote_fd->index_file_stream);\n\t\t\tif (read_count) {\n\t\t\t\tif (remote_fd->task_is_64_bit) {\n\t\t\t\t\ttarget_64_index = (stack_logging_index_event64 *)bufferSpace;\n\t\t\t\t\tlocated_file_position = STACK_LOGGING_OFFSET(target_64_index->offset_and_flags);\n\t\t\t\t} else {\n\t\t\t\t\ttarget_32_index = (stack_logging_index_event32 *)bufferSpace;\n\t\t\t\t\tlocated_file_position = STACK_LOGGING_OFFSET(target_32_index->offset_and_flags);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfound = false;\n\t\t\t}\n\t\t}\n\t}\n\n\trelease_file_streams_for_task(task);\n\n\tif (!found) {\n\t\treturn KERN_FAILURE;\n\t}\n\n\treturn __mach_stack_logging_get_frames_for_stackid(task, located_file_position, stack_frames_buffer, max_stack_frames, count, NULL);\n}\n\nkern_return_t\n__mach_stack_logging_enumerate_records(task_t task,\n\t\tmach_vm_address_t address,\n\t\tvoid enumerator(mach_stack_logging_record_t, void *),\n\t\tvoid *context)\n{\n\tremote_task_file_streams *remote_fd = retain_file_streams_for_task(task, 0);\n\tif (remote_fd == NULL) {\n\t\treturn KERN_FAILURE;\n\t}\n\n\tbool reading_all_addresses = (address == 0 ? true : false);\n\tmach_stack_logging_record_t pass_record;\n\tkern_return_t err = KERN_SUCCESS;\n\n\t// update (read index file once and only once)\n\terr = update_cache_for_file_streams(remote_fd);\n\tif (err != KERN_SUCCESS) {\n\t\trelease_file_streams_for_task(task);\n\t\treturn err;\n\t}\n\n\tFILE *the_index = (remote_fd->index_file_stream);\n\n\t// prepare for the read; target process could be 32 or 64 bit.\n\tchar bufferSpace[2048]; // 2 kb\n\tstack_logging_index_event32 *target_32_index = (stack_logging_index_event32 *)bufferSpace;\n\tstack_logging_index_event64 *target_64_index = (stack_logging_index_event64 *)bufferSpace;\n\tuint32_t target_addr_32 = (uint32_t)STACK_LOGGING_DISGUISE((uint32_t)address);\n\tuint64_t target_addr_64 = STACK_LOGGING_DISGUISE((uint64_t)address);\n\tsize_t read_size = (remote_fd->task_is_64_bit ? sizeof(stack_logging_index_event64) : sizeof(stack_logging_index_event32));\n\tsize_t number_slots = (size_t)(2048 / read_size);\n\tuint64_t total_slots = remote_fd->cache->last_index_file_offset / read_size;\n\n\t// perform the search\n\tsize_t read_count = 0;\n\tint64_t current_file_offset = 0;\n\tuint32_t i;\n\tdo {\n\t\t// at this point, we need to read index events; read them from the file until it's necessary to grab them from the shared\n\t\t// memory snapshot\n\t\t// and crop file reading to the point where we last scanned\n\t\tnumber_slots = (size_t)MIN(number_slots, total_slots);\n\n\t\t// if out of file to read (as of the time we entered this function), try to use shared memory snapshot\n\t\tif (number_slots == 0) {\n\t\t\tif (remote_fd->cache->shmem &&\n\t\t\t\t\tremote_fd->cache->snapshot.start_index_offset + remote_fd->cache->snapshot.next_free_index_buffer_offset >\n\t\t\t\t\t\t\t(uint64_t)current_file_offset) {\n\t\t\t\t// use shared memory\n\t\t\t\ttarget_32_index = (stack_logging_index_event32 *)remote_fd->cache->snapshot.index_buffer;\n\t\t\t\ttarget_64_index = (stack_logging_index_event64 *)remote_fd->cache->snapshot.index_buffer;\n\t\t\t\tread_count = (uint32_t)(remote_fd->cache->snapshot.start_index_offset +\n\t\t\t\t\t\t\t\t\t\tremote_fd->cache->snapshot.next_free_index_buffer_offset - current_file_offset) /\n\t\t\t\t\t\t\t read_size;\n\t\t\t\tcurrent_file_offset += read_count * read_size;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\t// get and save index (enumerator could modify)\n\t\t\tfseeko(the_index, current_file_offset, SEEK_SET);\n\t\t\tread_count = fread(bufferSpace, read_size, number_slots, the_index);\n\t\t\tcurrent_file_offset = ftello(the_index);\n\t\t\ttotal_slots -= read_count;\n\t\t}\n\n\t\tif (remote_fd->task_is_64_bit) {\n\t\t\tfor (i = 0; i < read_count; i++) {\n\t\t\t\tif (reading_all_addresses || target_64_index[i].address == target_addr_64) {\n\t\t\t\t\tpass_record.address = STACK_LOGGING_DISGUISE(target_64_index[i].address);\n\t\t\t\t\tpass_record.argument = target_64_index[i].argument;\n\t\t\t\t\tpass_record.stack_identifier = STACK_LOGGING_OFFSET(target_64_index[i].offset_and_flags);\n\t\t\t\t\tpass_record.type_flags = STACK_LOGGING_FLAGS_AND_USER_TAG(target_64_index[i].offset_and_flags);\n\t\t\t\t\tenumerator(pass_record, context);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor (i = 0; i < read_count; i++) {\n\t\t\t\tif (reading_all_addresses || target_32_index[i].address == target_addr_32) {\n\t\t\t\t\tpass_record.address = STACK_LOGGING_DISGUISE(target_32_index[i].address);\n\t\t\t\t\tpass_record.argument = target_32_index[i].argument;\n\t\t\t\t\tpass_record.stack_identifier = STACK_LOGGING_OFFSET(target_32_index[i].offset_and_flags);\n\t\t\t\t\tpass_record.type_flags = STACK_LOGGING_FLAGS_AND_USER_TAG(target_32_index[i].offset_and_flags);\n\t\t\t\t\tenumerator(pass_record, context);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} while (read_count);\n\n\trelease_file_streams_for_task(task);\n\treturn err;\n}\n\nuint64_t\n__mach_stack_logging_stackid_for_vm_region(task_t task, mach_vm_address_t address)\n{\n\tremote_task_file_streams *remote_fd = retain_file_streams_for_task(task, 0);\n\tif (remote_fd == NULL) {\n\t\treturn __invalid_stack_id;\n\t}\n\n\tkern_return_t err = update_cache_for_file_streams(remote_fd);\n\tif (err != KERN_SUCCESS) {\n\t\trelease_file_streams_for_task(task);\n\t\treturn __invalid_stack_id;\n\t}\n\n\tuint64_t stackid = __invalid_stack_id;\n\n\tif (remote_fd->cache && remote_fd->cache->vm_stackid_table) {\n\t\tstackid = radix_tree_lookup(remote_fd->cache->vm_stackid_table, address);\n\t}\n\n\trelease_file_streams_for_task(task);\n\treturn stackid;\n}\n\nkern_return_t\n__mach_stack_logging_frames_for_uniqued_stack(task_t task,\n\t\t\t\t\t\t\t\t\t\t\t  uint64_t stack_identifier,\n\t\t\t\t\t\t\t\t\t\t\t  mach_vm_address_t *stack_frames_buffer,\n\t\t\t\t\t\t\t\t\t\t\t  uint32_t max_stack_frames,\n\t\t\t\t\t\t\t\t\t\t\t  uint32_t *count)\n{\n\treturn __mach_stack_logging_get_frames_for_stackid(task, stack_identifier, stack_frames_buffer, max_stack_frames, count, NULL);\n}\n\n\nkern_return_t\n__mach_stack_logging_get_frames_for_stackid(task_t task,\n\t\t\t\t\t\t\t\t\t\t\tuint64_t stack_identifier,\n\t\t\t\t\t\t\t\t\t\t\tmach_vm_address_t *stack_frames_buffer,\n\t\t\t\t\t\t\t\t\t\t\tuint32_t max_stack_frames,\n\t\t\t\t\t\t\t\t\t\t\tuint32_t *count,\n\t\t\t\t\t\t\t\t\t\t\tbool *last_frame_is_threadid)\n{\n\tremote_task_file_streams *remote_fd = retain_file_streams_for_task(task, 0);\n\tif (remote_fd == NULL) {\n\t\treturn KERN_FAILURE;\n\t}\n\t\n\t// ensure that the uniquing table snapshot is valid\n\tkern_return_t err = update_cache_for_file_streams(remote_fd);\n\tif (err != KERN_SUCCESS) {\n\t\trelease_file_streams_for_task(task);\n\t\treturn err;\n\t}\n\t\n\tbool lite_mode = remote_fd->cache->lite_mode;\n\t\n\tunwind_stack_from_table_index(&remote_fd->cache->uniquing_table_snapshot, stack_identifier, stack_frames_buffer, count, max_stack_frames, lite_mode);\n\n\trelease_file_streams_for_task(task);\n\n\tif (last_frame_is_threadid) {\n\t\t*last_frame_is_threadid = !lite_mode;\n\t}\n\n\tif (*count) {\n\t\treturn KERN_SUCCESS;\n\t} else {\n\t\treturn KERN_FAILURE;\n\t}\n}\n\nkern_return_t\n__attribute__((visibility(\"default\")))\n__mach_stack_logging_uniquing_table_read_stack(struct backtrace_uniquing_table *uniquing_table,\n\t\t\t\t\t\t\t\t\t\t\t   uint64_t stackid,\n\t\t\t\t\t\t\t\t\t\t\t   mach_vm_address_t *out_frames_buffer,\n\t\t\t\t\t\t\t\t\t\t\t   uint32_t *out_frames_count,\n\t\t\t\t\t\t\t\t\t\t\t   uint32_t max_frames)\n{\n\tunwind_stack_from_table_index(uniquing_table, stackid, out_frames_buffer, out_frames_count, max_frames, uniquing_table->\n\t\t\t\t\t\t\t\t  nodes_use_refcount);\n\treturn *out_frames_count ? KERN_SUCCESS : KERN_FAILURE;\n}\n\n\nstruct backtrace_uniquing_table *\n__mach_stack_logging_copy_uniquing_table(task_t task)\n{\n\tremote_task_file_streams *remote_fd = retain_file_streams_for_task(task, 0);\n\tif (remote_fd == NULL) {\n\t\treturn NULL;\n\t}\n\n\t// ensure that the uniquing table snapshot is valid\n\tkern_return_t err = update_cache_for_file_streams(remote_fd);\n\tif (err != KERN_SUCCESS || remote_fds->cache->uniquing_table_snapshot.numPages == 0) {\n\t\trelease_file_streams_for_task(task);\n\t\treturn NULL;\n\t}\n\n\t/* Steal the uniqing table snapshot.   A new snapshot will be taken next time someone calls\n\t * update_cache_for_file_streams\n\t */\n\tbacktrace_uniquing_table *table = malloc(sizeof(backtrace_uniquing_table));\n\tmemcpy(table, &remote_fds->cache->uniquing_table_snapshot, sizeof(backtrace_uniquing_table));\n\tbzero(&remote_fds->cache->uniquing_table_snapshot, sizeof(backtrace_uniquing_table));\n\tremote_fds->cache->uniquing_table_snapshot.in_client_process = true;\n\n\ttable->refcount = 1;\n\n\trelease_file_streams_for_task(task);\n\n\treturn table;\n}\n\n\nvoid\n__mach_stack_logging_uniquing_table_release(struct backtrace_uniquing_table *table)\n{\n\tif (!table) {\n\t\treturn;\n\t}\n\tassert(table->refcount > 0);\n\ttable->refcount--;\n\tif (table->refcount == 0) {\n\t\tfree_uniquing_table_chunks(table);\n\t\tfree(table);\n\t}\n}\n\nvoid\n__mach_stack_logging_uniquing_table_retain(struct backtrace_uniquing_table *table)\n{\n\tassert(table->refcount > 0);\n\ttable->refcount++;\n}\n\nstatic const size_t uniquingTableDataAlign = 16 * 1024;\nstatic const size_t uniquingTableHeaderLength = 16;\n\nstatic inline size_t roundUp(size_t x, size_t alignment)\n{\n\treturn x + (-x % alignment);\n}\n\nsize_t\n__mach_stack_logging_uniquing_table_sizeof(struct backtrace_uniquing_table *table)\n{\n\tsize_t size = 0;\n\tsize += uniquingTableHeaderLength; //header\n\tsize += sizeof(backtrace_uniquing_table);\n\tsize = roundUp(size, uniquingTableDataAlign);\n\tassert(table->in_client_process);\n\ttable_chunk_header_t *table_chunk_header = table->u.first_table_chunk_hdr;\n\twhile (table_chunk_header) {\n\t\tsize += 2 * sizeof(mach_vm_address_t) * table_chunk_header->num_nodes_in_chunk;\n\t\ttable_chunk_header = table_chunk_header->next_table_chunk_header;\n\t}\n\treturn size;\n}\n\n\nvoid *\n__mach_stack_logging_uniquing_table_serialize(struct backtrace_uniquing_table *table, mach_vm_size_t *size)\n{\n\t*size = __mach_stack_logging_uniquing_table_sizeof(table);\n\n\tmach_vm_address_t buffer_address = 0;\n\tkern_return_t kr = mach_vm_allocate(mach_task_self(), &buffer_address, *size, VM_FLAGS_ANYWHERE);\n\tif (kr != KERN_SUCCESS) {\n\t\t*size = 0;\n\t\treturn NULL;\n\t}\n\n\tvoid *buffer = (void*)buffer_address;\n\n\tuint8_t *p = buffer;\n\n\tmemcpy(p, \"MslUniquingTable\", uniquingTableHeaderLength);\n\tp += uniquingTableHeaderLength;\n\n\tmemcpy(p, table, sizeof(backtrace_uniquing_table));\n\tp += sizeof(backtrace_uniquing_table);\n\n\tp = ((uint8_t*)buffer) + roundUp(p - (uint8_t*)buffer, uniquingTableDataAlign);\n\n\ttable_chunk_header_t *table_chunk_header = table->u.first_table_chunk_hdr;\n\tuint64_t num_nodes = 0;\n\twhile (table_chunk_header) {\n\t\tnum_nodes += table_chunk_header->num_nodes_in_chunk;\n\t\tsize_t chunk_size = 2 * sizeof(mach_vm_address_t) *  (size_t)table_chunk_header->num_nodes_in_chunk;\n\t\tkr = mach_vm_copy(mach_task_self(), (mach_vm_address_t)table_chunk_header->table_chunk, chunk_size, (vm_address_t)p);\n\t\tif (kr != KERN_SUCCESS) {\n\t\t\tmemcpy(p, table_chunk_header->table_chunk, chunk_size);\n\t\t}\n\t\tp += chunk_size;\n\t\ttable_chunk_header = table_chunk_header->next_table_chunk_header;\n\t}\n\n\tassert(num_nodes == table->numNodes);\n\n\treturn buffer;\n}\n\nstruct backtrace_uniquing_table *\n__mach_stack_logging_uniquing_table_copy_from_serialized(void *buffer, size_t size)\n{\n\tif (size < uniquingTableHeaderLength + sizeof(backtrace_uniquing_table)) {\n\t\treturn NULL;\n\t}\n\tuint8_t *p = buffer;\n\n\tif (strncmp(buffer, \"MslUniquingTable\", uniquingTableHeaderLength) != 0) {\n\t\treturn NULL;\n\t}\n\tp += uniquingTableHeaderLength;\n\n\tbacktrace_uniquing_table *table = malloc(sizeof(backtrace_uniquing_table));\n\tmemcpy(table, p, sizeof(backtrace_uniquing_table));\n\tp += sizeof(backtrace_uniquing_table);\n\n\tp = ((uint8_t*)buffer) + roundUp(p - (uint8_t*)buffer, uniquingTableDataAlign);\n\n\ttable->u.first_table_chunk_hdr = malloc(sizeof(table_chunk_header_t));\n\ttable->refcount = 1;\n\n\tmach_vm_size_t chunkSize = 2 * table->numNodes * sizeof(mach_vm_address_t);\n\n\tmach_vm_address_t chunkAddr = 0;\n\n\tif (roundUp(uniquingTableHeaderLength + sizeof(backtrace_uniquing_table), uniquingTableDataAlign) + chunkSize < size ) {\n\t\tgoto fail;\n\t}\n\n\tkern_return_t kr = mach_vm_allocate(mach_task_self(), &chunkAddr, chunkSize, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL));\n\tif (kr != KERN_SUCCESS) {\n\t\tgoto fail;\n\t}\n\n\ttable->u.first_table_chunk_hdr->num_nodes_in_chunk = table->numNodes;\n\ttable->u.first_table_chunk_hdr->table_chunk_size = chunkSize;\n\ttable->u.first_table_chunk_hdr->table_chunk = (mach_vm_address_t*) chunkAddr;\n\ttable->u.first_table_chunk_hdr->next_table_chunk_header = NULL;\n\n\tkr = mach_vm_copy(mach_task_self(), (mach_vm_address_t)p, chunkSize, (mach_vm_address_t) table->u.first_table_chunk_hdr->table_chunk);\n\tif (kr != KERN_SUCCESS) {\n\t\tgoto fail;\n\t}\n\n\treturn table;\n\nfail:\n\tif (table) {\n\t\tif (table->u.first_table_chunk_hdr) {\n\t\t\tfree(table->u.first_table_chunk_hdr);\n\t\t}\n\t\tfree(table);\n\t}\n\tif (chunkAddr) {\n\t\tmach_vm_deallocate(mach_task_self(), chunkAddr, chunkSize);\n\t}\n\treturn NULL;\n}\n\n\n#ifdef TEST_DISK_STACK_LOGGING\n\n// cc -o stack_logging_disk stack_logging_disk.c -DTEST_DISK_STACK_LOGGING\n\n#include <sys/wait.h>\n\nint\nmain()\n{\n\tint status;\n\tint i;\n\tsize_t total_globals = 0ul;\n\n\tfprintf(stderr, \"master test process is %d\\n\", getpid());\n\tfprintf(stderr, \"sizeof pre_write_buffers: %lu\\n\", sizeof(pre_write_buffers));\n\ttotal_globals += sizeof(pre_write_buffers);\n\tfprintf(stderr, \"sizeof stack_buffer: %lu\\n\", sizeof(stack_buffer));\n\ttotal_globals += sizeof(stack_buffer);\n\tfprintf(stderr, \"sizeof last_logged_malloc_address: %lu\\n\", sizeof(last_logged_malloc_address));\n\ttotal_globals += sizeof(last_logged_malloc_address);\n\tfprintf(stderr, \"sizeof stack_log_file_base_name: %lu\\n\", sizeof(stack_log_file_base_name));\n\ttotal_globals += sizeof(stack_log_file_base_name);\n\tfprintf(stderr, \"sizeof stack_log_file_suffix: %lu\\n\", sizeof(stack_log_file_suffix));\n\ttotal_globals += sizeof(stack_log_file_suffix);\n\tfprintf(stderr, \"sizeof __stack_log_file_path__ (index_file_path): %lu\\n\", (size_t)PATH_MAX);\n\ttotal_globals += (size_t)PATH_MAX;\n\tfprintf(stderr, \"sizeof index_file_descriptor: %lu\\n\", sizeof(index_file_descriptor));\n\ttotal_globals += sizeof(index_file_descriptor);\n\tfprintf(stderr, \"sizeof remote_fds: %lu\\n\", sizeof(remote_fds));\n\ttotal_globals += sizeof(remote_fds);\n\tfprintf(stderr, \"sizeof next_remote_task_fd: %lu\\n\", sizeof(next_remote_task_fd));\n\ttotal_globals += sizeof(next_remote_task_fd);\n\tfprintf(stderr, \"sizeof remote_task_fd_count: %lu\\n\", sizeof(remote_task_fd_count));\n\ttotal_globals += sizeof(remote_task_fd_count);\n\tfprintf(stderr, \"sizeof remote_fd_list_lock: %lu\\n\", sizeof(remote_fd_list_lock));\n\ttotal_globals += sizeof(remote_fd_list_lock);\n\tfprintf(stderr, \"sizeof logging_use_compaction: %lu\\n\", sizeof(logging_use_compaction));\n\ttotal_globals += sizeof(logging_use_compaction);\n\n\tfprintf(stderr, \"size of all global data: %lu\\n\", total_globals);\n\n\tcreate_log_file();\n\n\t// create a few child processes and exit them cleanly so their logs should get cleaned up\n\tfprintf(stderr, \"\\ncreating child processes and exiting cleanly\\n\");\n\tfor (i = 0; i < 3; i++) {\n\t\tif (fork() == 0) {\n\t\t\tfprintf(stderr, \"\\nin child processes %d\\n\", getpid());\n\t\t\tcreate_log_file();\n\t\t\tfprintf(stderr, \"exiting child processes %d\\n\", getpid());\n\t\t\texit(1);\n\t\t}\n\t\twait(&status);\n\t}\n\n\t// create a few child processes and abruptly _exit them, leaving their logs around\n\tfprintf(stderr, \"\\ncreating child processes and exiting abruptly, leaving logs around\\n\");\n\tfor (i = 0; i < 3; i++) {\n\t\tif (fork() == 0) {\n\t\t\tfprintf(stderr, \"\\nin child processes %d\\n\", getpid());\n\t\t\tcreate_log_file();\n\t\t\tfprintf(stderr, \"exiting child processes %d\\n\", getpid());\n\t\t\t_exit(1);\n\t\t}\n\t\twait(&status);\n\t}\n\n\t// this should reap any remaining logs\n\tfprintf(stderr, \"\\nexiting master test process %d\\n\", getpid());\n\tdelete_log_files();\n\treturn 0;\n}\n\n#endif\n\n/* vim: set noet:ts=4:sw=4:cindent: */\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/stack_logging_internal.h",
    "content": "/*\n * Copyright (c) 2016, Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef stack_logging_disk_h\n#define stack_logging_disk_h\n\nextern int stack_logging_enable_logging; /* when clear, no logging takes place */\nextern int stack_logging_dontcompact; /* default is to compact; when set does not compact alloc/free logs; useful for tracing history */\nextern int stack_logging_finished_init; /* set after we've returned from the Libsystem initialiser */\nextern int stack_logging_postponed; /* set if we needed to postpone logging till after initialisation */\nextern int stack_logging_mode;\n\nextern const uint64_t __invalid_stack_id;\n\n// returns the stack id\nuint64_t __enter_stack_into_table_while_locked(vm_address_t self_thread, uint32_t num_hot_to_skip, boolean_t add_thread_id, size_t ptr_size);\n\nvoid __malloc_lock_stack_logging();\nvoid __malloc_unlock_stack_logging();\n\n// support for gdb and others checking for stack_logging locks\nextern boolean_t __stack_logging_locked();\n\nextern boolean_t __prepare_to_log_stacks(boolean_t lite_or_vmlite_mode);\nextern void __prepare_to_log_stacks_stage2();\n\n// support for multi-threaded forks\nextern void __stack_logging_fork_prepare();\nextern void __stack_logging_fork_parent();\nextern void __stack_logging_fork_child();\nextern void __stack_logging_early_finished();\n\nvoid __decrement_table_slot_refcount(uint64_t stackID, size_t size);\n\nvoid __delete_uniquing_table_memory_while_locked();\nboolean_t __uniquing_table_memory_was_deleted(void);\n\n// Returns true if the stack logging lite malloc zone is enabled. Does not indicate if VM-only lite mode is enabled.\nboolean_t is_stack_logging_lite_enabled(void);\n\n\n#endif /* stack_logging_disk_h */\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/thresholds.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __THRESHOLDS_H\n#define __THRESHOLDS_H\n\n/*\n * Tiny region size definitions; these are split into quanta of 16 bytes, \n * 64520 blocks is the magical value of how many quanta we can fit in a 1mb\n * region including the region trailer and metadata.\n */\n#define SHIFT_TINY_QUANTUM 4\n#define SHIFT_TINY_CEIL_BLOCKS 16 // ceil(log2(NUM_TINY_BLOCKS))\n#define TINY_QUANTUM (1 << SHIFT_TINY_QUANTUM)\n#define NUM_TINY_BLOCKS 64520\n#define NUM_TINY_CEIL_BLOCKS (1 << SHIFT_TINY_CEIL_BLOCKS)\n\n/* \n * Small region size definitions.\n *\n * We can only represent up to 1<<15 for msize; but we choose to stay\n * even below that to avoid the convention msize=0 => msize = (1<<15)\n */\n#define SHIFT_SMALL_QUANTUM (SHIFT_TINY_QUANTUM + 5) // 9\n#define SMALL_QUANTUM (1 << SHIFT_SMALL_QUANTUM)\t // 512 bytes\n#define SHIFT_SMALL_CEIL_BLOCKS 14 // ceil(log2(NUM_SMALL_BLOCKs))\n#define NUM_SMALL_BLOCKS 16319\n#define NUM_SMALL_CEIL_BLOCKS (1 << SHIFT_SMALL_CEIL_BLOCKS)\n#define SMALL_BLOCKS_ALIGN (SHIFT_SMALL_CEIL_BLOCKS + SHIFT_SMALL_QUANTUM) // 23\n\n#if MALLOC_TARGET_64BIT\n#define NUM_TINY_SLOTS 64 // number of slots for free-lists\n#else // MALLOC_TARGET_64BIT\n#define NUM_TINY_SLOTS 32 // number of slots for free-lists\n#endif // MALLOC_TARGET_64BIT\n\n/* \n * The threshold above which we start allocating from the small\n * magazines. Computed from the largest allocation we can make\n * in the tiny region (currently 1008 bytes on 64-bit, and \n * 496 bytes on 32-bit).\n */\n#define SMALL_THRESHOLD ((NUM_TINY_SLOTS - 1) * TINY_QUANTUM)\n\n/*\n * The threshold above which we start allocating from the large\n * \"region\" (ie. direct vm_allocates). The LARGEMEM size is used\n * on macOS and 64bit iOS with 16k pages, > 2gb and > 2 cores once\n * CONFIG_SMALL_CUTOFF_DYNAMIC is enabled (TODO: rdar://problem/35395572)\n * Must be a multiple of SMALL_QUANTUM (512 bytes)\n */\n#if MALLOC_TARGET_IOS\n#if MALLOC_TARGET_64BIT\n#define LARGE_THRESHOLD (15 * 1024)\t\t\t\t\t\t// <1 * 16k pages\n#define LARGE_THRESHOLD_LARGEMEM (64 * 1024)\t\t\t//  4 * 16k pages\n#else\n#define LARGE_THRESHOLD (15 * 1024)\t\t\t\t\t\t// <4 * 4k pages\n#define LARGE_THRESHOLD_LARGEMEM (64 * 1024)\t\t\t// 16 * 4k pages\n#endif\n#else\n#define LARGE_THRESHOLD (15 * 1024)\t\t\t\t\t\t//  <4 * 4k pages\n#define LARGE_THRESHOLD_LARGEMEM (127 * 1024)\t\t\t// <32 * 4k pages\n#endif\n\n/*\n * The number of slots in the free-list for small blocks.  To avoid going to\n * vm system as often on large memory machines, increase the number of free list\n * spots above some amount of RAM installed in the system.\n */\n#define NUM_SMALL_SLOTS (LARGE_THRESHOLD >> SHIFT_SMALL_QUANTUM)\n#define NUM_SMALL_SLOTS_LARGEMEM (LARGE_THRESHOLD_LARGEMEM >> SHIFT_SMALL_QUANTUM)\n\n/*\n * When all memory is touched after a copy, vm_copy() is always a lose\n * But if the memory is only read, vm_copy() wins over memmove() at 3 or 4 pages\n * (on a G3/300MHz)\n *\n * This must be >= LARGE_THRESHOLD\n */\n#if MALLOC_TARGET_IOS && MALLOC_TARGET_64BIT\n#define VM_COPY_THRESHOLD (48 * 1024)\t\t\t\t\t// 3 * 16k pages\n#define VM_COPY_THRESHOLD_LARGEMEM (96 * 1024)\t\t\t// 6 * 16k pages\n#else\n#define VM_COPY_THRESHOLD (40 * 1024)\t\t\t\t\t// 10 * 4k pages\n#define VM_COPY_THRESHOLD_LARGEMEM (128 * 1024) \t\t// 32 * 4k pages\n#endif\n\n/*\n * Large entry cache (death row) sizes. The large cache is bounded with\n * an overall top limit size, each entry is allowed a given slice of\n * that limit.\n */\n#if MALLOC_TARGET_64BIT\n#define LARGE_ENTRY_CACHE_SIZE 16\n#define LARGE_CACHE_SIZE_LIMIT ((vm_size_t)0x80000000) /* 2Gb */\n#define LARGE_CACHE_SIZE_ENTRY_LIMIT (LARGE_CACHE_SIZE_LIMIT / LARGE_ENTRY_CACHE_SIZE)\n#else // MALLOC_TARGET_64BIT\n#define LARGE_ENTRY_CACHE_SIZE 8\n#define LARGE_CACHE_SIZE_LIMIT ((vm_size_t)0x02000000) /* 32Mb */\n#define LARGE_CACHE_SIZE_ENTRY_LIMIT (LARGE_CACHE_SIZE_LIMIT / LARGE_ENTRY_CACHE_SIZE)\n#endif // MALLOC_TARGET_64BIT\n\n/*\n * Large entry cache (death row) \"flotsam\" limits. Until the large cache\n * contains at least \"high\" bytes, the cache is not cleaned under memory\n * pressure. After that, memory pressure notifications cause cache cleaning\n * until the large cache drops below the \"low\" limit.\n */\n#define SZONE_FLOTSAM_THRESHOLD_LOW (1024 * 512)\n#define SZONE_FLOTSAM_THRESHOLD_HIGH (1024 * 1024)\n\n/*\n * The magazine freelist array must be large enough to accomdate the allocation\n * granularity of both the tiny and small allocators. In addition, the last\n * slot in the list is special and reserved for coalesced regions bigger than\n * the overall max allocation size of the allocator.\n */\n#define MAGAZINE_FREELIST_SLOTS (NUM_SMALL_SLOTS_LARGEMEM + 1)\n#define MAGAZINE_FREELIST_BITMAP_WORDS ((MAGAZINE_FREELIST_SLOTS + 31) >> 5)\n\n/*\n * Density threshold used in determining the level of emptiness before\n * moving regions to the recirc depot.\n */\n#define DENSITY_THRESHOLD(a) \\\n\t((a) - ((a) >> 2)) // \"Emptiness\" f = 0.25, so \"Density\" is (1 - f)*a. Generally: ((a) - ((a) >> -log2(f)))\n\n/*\n * Minimum number of regions to retain in a recirc depot.\n */\n#define DEFAULT_RECIRC_RETAINED_REGIONS 2\n\n/* Sanity checks. */\n\nMALLOC_STATIC_ASSERT(NUM_SMALL_SLOTS_LARGEMEM == LARGE_THRESHOLD_LARGEMEM >> SHIFT_SMALL_QUANTUM,\n\t\t\"NUM_SMALL_SLOTS_LARGEMEM must match LARGE_THRESHOLD_LARGEMEM >> SHIFT_SMALL_QUANTUM\");\n\nMALLOC_STATIC_ASSERT(NUM_TINY_SLOTS <= NUM_SMALL_SLOTS_LARGEMEM,\n\t\t\"NUM_TINY_SLOTS must be less than or equal to NUM_SMALL_SLOTS_LARGEMEM\");\n\nMALLOC_STATIC_ASSERT((LARGE_THRESHOLD % SMALL_QUANTUM) == 0,\n\t\t\"LARGE_THRESHOLD must be a multiple of SMALL_QUANTUM\");\nMALLOC_STATIC_ASSERT((LARGE_THRESHOLD_LARGEMEM % SMALL_QUANTUM) == 0,\n\t\t\"LARGE_THRESHOLD_LARGEMEM must be a multiple of SMALL_QUANTUM\");\n\nMALLOC_STATIC_ASSERT((LARGE_THRESHOLD / SMALL_QUANTUM) <= NUM_SMALL_SLOTS,\n\t\t\"LARGE_THRESHOLD must be less than NUM_SMALL_SLOTS * SMALL_QUANTUM\");\nMALLOC_STATIC_ASSERT((LARGE_THRESHOLD_LARGEMEM / SMALL_QUANTUM) <=  NUM_SMALL_SLOTS_LARGEMEM,\n\t\t\"LARGE_THRESHOLD_LARGEMEM must be less than NUM_SMALL_SLOTS * SMALL_QUANTUM\");\n\nMALLOC_STATIC_ASSERT(VM_COPY_THRESHOLD >= LARGE_THRESHOLD,\n\t\t\"VM_COPY_THRESHOLD must be larger than LARGE_THRESHOLD\");\nMALLOC_STATIC_ASSERT(VM_COPY_THRESHOLD_LARGEMEM >= LARGE_THRESHOLD_LARGEMEM,\n\t\t\"VM_COPY_THRESHOLD_LARGEMEM must be larger than LARGE_THRESHOLD_LARGEMEM\");\n\n#endif // __THRESHOLDS_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/trace.h",
    "content": "/*\n * Copyright (c) 2016 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __TRACE_H\n#define __TRACE_H\n\n// <sys/kdebug.h> defines these two subclasses for us:\n//   DBG_UMALLOC_EXTERNAL - for external entry points into malloc\n//   DBG_UMALLOC_INTERNAL - for tracing internal malloc state\n\n#ifndef _MALLOC_BUILDING_CODES_\n#include <sys/kdebug.h>\n#define MALLOC_TRACE(code,arg1,arg2,arg3,arg4) \\\n\t{ if (malloc_tracing_enabled) { kdebug_trace(code, arg1, arg2, arg3, arg4); } }\n#define TRACE_CODE(name, subclass, code) \\\n\tstatic const int TRACE_##name = KDBG_EVENTID(DBG_UMALLOC, subclass, code)\n#else\n# define DBG_UMALLOC 51\n# define DBG_UMALLOC_EXTERNAL 0x1\n# define DBG_UMALLOC_INTERNAL 0x2\n# define STR(x) #x\n# define TRACE_CODE(name, subclass, code) \\\n\tprintf(\"0x%x\\t%s\\n\", ((DBG_UMALLOC << 24) | ((subclass & 0xff) << 16) | ((code & 0x3fff) << 2)), STR(name))\n#endif\n\n// \"external\" trace points\nTRACE_CODE(malloc, DBG_UMALLOC_EXTERNAL, 0x01);\nTRACE_CODE(free, DBG_UMALLOC_EXTERNAL, 0x02);\nTRACE_CODE(realloc, DBG_UMALLOC_EXTERNAL, 0x03);\nTRACE_CODE(memalign, DBG_UMALLOC_EXTERNAL, 0x04);\nTRACE_CODE(calloc, DBG_UMALLOC_EXTERNAL, 0x05);\nTRACE_CODE(valloc, DBG_UMALLOC_EXTERNAL, 0x06);\n\n// \"internal\" trace points\nTRACE_CODE(nano_malloc, DBG_UMALLOC_INTERNAL, 0x1);\nTRACE_CODE(tiny_malloc, DBG_UMALLOC_INTERNAL, 0x2);\nTRACE_CODE(small_malloc, DBG_UMALLOC_INTERNAL, 0x3);\nTRACE_CODE(large_malloc, DBG_UMALLOC_INTERNAL, 0x4);\nTRACE_CODE(nano_free, DBG_UMALLOC_INTERNAL, 0x5);\nTRACE_CODE(tiny_free, DBG_UMALLOC_INTERNAL, 0x6);\nTRACE_CODE(small_free, DBG_UMALLOC_INTERNAL, 0x7);\nTRACE_CODE(large_free, DBG_UMALLOC_INTERNAL, 0x8);\nTRACE_CODE(malloc_memory_pressure, DBG_UMALLOC_INTERNAL, 0x9);\nTRACE_CODE(nano_memory_pressure, DBG_UMALLOC_INTERNAL, 0xa);\nTRACE_CODE(madvise, DBG_UMALLOC_INTERNAL, 0xb);\n\nTRACE_CODE(nanov2_region_allocation, DBG_UMALLOC_INTERNAL, 0x10);\n\n#endif // __TRACE_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/vm.c",
    "content": "/*\n * Copyright (c) 2016 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"internal.h\"\n\nstatic volatile uintptr_t entropic_address = 0;\nstatic volatile uintptr_t entropic_limit = 0;\n\nMALLOC_NOEXPORT\nuint64_t malloc_entropy[2] = {0, 0};\n\n#define ENTROPIC_KABILLION 0x10000000 /* 256Mb */\n\n// <rdar://problem/22277891> align 64bit ARM shift to 32MB PTE entries\n#if MALLOC_TARGET_IOS && MALLOC_TARGET_64BIT\n#define ENTROPIC_SHIFT 25\n#else // MALLOC_TARGET_IOS && MALLOC_TARGET_64BIT\n#define ENTROPIC_SHIFT SMALL_BLOCKS_ALIGN\n#endif\n\nvoid\nmvm_aslr_init(void)\n{\n\t// Prepare ASLR\n#if __i386__ || __x86_64__ || __arm64__ || (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)\n#if __i386__\n\tuintptr_t stackbase = 0x8fe00000;\n\tint entropic_bits = 3;\n#elif __x86_64__\n\tuintptr_t stackbase = USRSTACK64;\n\tint entropic_bits = 16;\n#elif __arm64__\n#if __LP64__\n\tuintptr_t stackbase = USRSTACK64;\n\tint entropic_bits = 7;\n#else // __LP64__\n\tuintptr_t stackbase = USRSTACK;\n\tint entropic_bits = 3;\n#endif\n#else\n\tuintptr_t stackbase = USRSTACK;\n\tint entropic_bits = 3;\n#endif\n\t// assert(((1 << entropic_bits) - 1) << SMALL_BLOCKS_ALIGN < (stackbase - MAXSSIZ - ENTROPIC_KABILLION));\n\n\tif (mvm_aslr_enabled()) {\n\t\tif (0 == entropic_address) {\n\t\t\tuintptr_t t = stackbase - MAXSSIZ - ((uintptr_t)(malloc_entropy[1] & ((1 << entropic_bits) - 1)) << ENTROPIC_SHIFT);\n\t\t\tOSAtomicCompareAndSwapLong(0, t, (volatile long *)&entropic_limit);\n\t\t\tOSAtomicCompareAndSwapLong(0, t - ENTROPIC_KABILLION, (volatile long *)&entropic_address);\n\t\t}\n\t} else {\n\t\t// zero slide when ASLR has been disabled by boot-arg. Eliminate cloaking.\n\t\tmalloc_entropy[0] = 0;\n\t\tmalloc_entropy[1] = 0;\n\t}\n#else // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n#error ASLR unhandled on this platform\n#endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n}\n\nvoid *\nmvm_allocate_pages(size_t size, unsigned char align, unsigned debug_flags, int vm_page_label)\n{\n\tboolean_t add_guard_pages = debug_flags & MALLOC_ADD_GUARD_PAGES;\n\tboolean_t purgeable = debug_flags & MALLOC_PURGEABLE;\n\tmach_vm_address_t vm_addr;\n\tuintptr_t addr;\n\tmach_vm_size_t allocation_size = round_page_quanta(size);\n\tmach_vm_offset_t allocation_mask = ((mach_vm_offset_t)1 << align) - 1;\n\tint alloc_flags = VM_FLAGS_ANYWHERE | VM_MAKE_TAG(vm_page_label);\n\tkern_return_t kr;\n\n\tif (!allocation_size) {\n\t\tallocation_size = vm_page_quanta_size;\n\t}\n\tif (add_guard_pages) {\n\t\tif (align > vm_page_quanta_shift) {\n\t\t\t/* <rdar://problem/16601499> alignment greater than pagesize needs more work */\n\t\t\tallocation_size += (1 << align) + vm_page_quanta_size;\n\t\t} else {\n\t\t\tallocation_size += 2 * vm_page_quanta_size;\n\t\t}\n\t}\n\n\tif (purgeable) {\n\t\talloc_flags |= VM_FLAGS_PURGABLE;\n\t}\n\tif (allocation_size < size) { // size_t arithmetic wrapped!\n\t\treturn NULL;\n\t}\n\n\tvm_addr = vm_page_quanta_size;\n\tkr = mach_vm_map(mach_task_self(), &vm_addr, allocation_size, allocation_mask, alloc_flags, MEMORY_OBJECT_NULL, 0, FALSE,\n\t\t\t\t\t VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);\n\tif (kr) {\n\t\tmalloc_zone_error(debug_flags, false, \"can't allocate region\\n*** mach_vm_map(size=%lu) failed (error code=%d)\\n\", size, kr);\n\t\treturn NULL;\n\t}\n\taddr = (uintptr_t)vm_addr;\n\n\tif (add_guard_pages) {\n\t\tif (align > vm_page_quanta_shift) {\n\t\t\t/* <rdar://problem/16601499> calculate the first address inside the alignment padding\n\t\t\t * where we can place the guard page and still be aligned.\n\t\t\t *\n\t\t\t * |-----------------------------------------------------------|\n\t\t\t * |leading|gp|                  alloc                  |gp| t |\n\t\t\t * |-----------------------------------------------------------|\n\t\t\t */\n\t\t\tuintptr_t alignaddr = ((addr + vm_page_quanta_size) + (1 << align) - 1) & ~((1 << align) - 1);\n\t\t\tsize_t leading = alignaddr - addr - vm_page_quanta_size;\n\t\t\tsize_t trailing = (1 << align) - vm_page_quanta_size - leading;\n\n\t\t\t/* Unmap the excess area. */\n\t\t\tkr = mach_vm_deallocate(mach_task_self(), addr, leading);\n\t\t\tif (kr) {\n\t\t\t\tmalloc_zone_error(debug_flags, false, \"can't unmap excess guard region\\n\"\n\t\t\t\t\t\t\"*** mach_vm_deallocate(addr=%p, size=%lu) failed (code=%d)\\n\",\n\t\t\t\t\t\t(void *)addr, leading, kr);\n\t\t\t\treturn NULL;\n\t\t\t}\n\n\t\t\tkr = mach_vm_deallocate(mach_task_self(), addr + allocation_size - trailing, trailing);\n\t\t\tif (kr) {\n\t\t\t\tmalloc_zone_error(debug_flags, false, \"can't unmap excess trailing guard region\\n\"\n\t\t\t\t\t\t\"*** mach_vm_deallocate(addr=%p, size=%lu) failed (code=%d)\\n\",\n\t\t\t\t\t\t(void *)(addr + allocation_size - trailing), trailing, kr);\n\t\t\t\treturn NULL;\n\t\t\t}\n\n\t\t\taddr = alignaddr;\n\t\t} else {\n\t\t\taddr += vm_page_quanta_size;\n\t\t}\n\t\tmvm_protect((void *)addr, size, PROT_NONE, debug_flags);\n\t}\n\treturn (void *)addr;\n}\n\nvoid *\nmvm_allocate_pages_securely(size_t size, unsigned char align, int vm_page_label, uint32_t debug_flags)\n{\n\tmach_vm_address_t vm_addr;\n\tuintptr_t addr;\n\tmach_vm_size_t allocation_size = round_page_quanta(size);\n\tmach_vm_offset_t allocation_mask = ((mach_vm_offset_t)1 << align) - 1;\n\tint alloc_flags = VM_FLAGS_ANYWHERE | VM_MAKE_TAG(vm_page_label);\n\tkern_return_t kr;\n\n\tif (debug_flags & DISABLE_ASLR) {\n\t\treturn mvm_allocate_pages(size, align, 0, vm_page_label);\n\t}\n\n\tif (!allocation_size) {\n\t\tallocation_size = vm_page_quanta_size;\n\t}\n\tif (allocation_size < size) { // size_t arithmetic wrapped!\n\t\treturn NULL;\n\t}\n\nretry:\n\tvm_addr = entropic_address;\n\tkr = mach_vm_map(mach_task_self(), &vm_addr, allocation_size, allocation_mask, alloc_flags, MEMORY_OBJECT_NULL, 0, FALSE,\n\t\t\t\t\t VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);\n\tif (kr == KERN_NO_SPACE) {\n\t\tvm_addr = vm_page_quanta_size;\n\t\tkr = mach_vm_map(mach_task_self(), &vm_addr, allocation_size, allocation_mask, alloc_flags, MEMORY_OBJECT_NULL, 0, FALSE,\n\t\t\t\t\t\t VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);\n\t}\n\tif (kr) {\n\t\tmalloc_zone_error(debug_flags, false, \"can't allocate region securely\\n\",\n\t\t\t\t\"*** mach_vm_map(size=%lu) failed (error code=%d)\\n\", size, kr);\n\t\treturn NULL;\n\t}\n\taddr = (uintptr_t)vm_addr;\n\n\t// Don't allow allocation to rise above entropic_limit (for tidiness).\n\tif (addr + allocation_size > entropic_limit) { // Exhausted current range?\n\t\tuintptr_t t = entropic_address;\n\t\tuintptr_t u = t - ENTROPIC_KABILLION;\n\n\t\tif (u < t) { // provided we don't wrap, deallocate and retry, in the expanded entropic range\n\t\t\tmach_vm_deallocate(mach_task_self(), vm_addr, allocation_size);\n\t\t\tOSAtomicCompareAndSwapLong(t, u, (volatile long *)&entropic_address);  // Just one reduction please\n\t\t\tgoto retry;\n\t\t}\n\t\t// fall through to use what we got\n\t}\n\n\tif (addr < entropic_address) { // we wrapped to find this allocation, expand the entropic range\n\t\tuintptr_t t = entropic_address;\n\t\tuintptr_t u = t - ENTROPIC_KABILLION;\n\t\tif (u < t) {\n\t\t\tOSAtomicCompareAndSwapLong(t, u, (volatile long *)&entropic_address);  // Just one reduction please\n\t\t}\n\t\t// fall through to use what we got\n\t}\n\treturn (void *)addr;\n}\n\nvoid\nmvm_deallocate_pages(void *addr, size_t size, unsigned debug_flags)\n{\n\tboolean_t add_guard_pages = debug_flags & MALLOC_ADD_GUARD_PAGES;\n\tmach_vm_address_t vm_addr = (mach_vm_address_t)addr;\n\tmach_vm_size_t allocation_size = size;\n\tkern_return_t kr;\n\n\tif (add_guard_pages) {\n\t\tvm_addr -= vm_page_quanta_size;\n\t\tallocation_size += 2 * vm_page_quanta_size;\n\t}\n\tkr = mach_vm_deallocate(mach_task_self(), vm_addr, allocation_size);\n\tif (kr) {\n\t\tmalloc_zone_error(debug_flags, false, \"Can't deallocate_pages region at %p\\n\", addr);\n\t}\n}\n\nvoid\nmvm_protect(void *address, size_t size, unsigned protection, unsigned debug_flags)\n{\n\tkern_return_t err;\n\n\tif (!(debug_flags & MALLOC_DONT_PROTECT_PRELUDE)) {\n\t\terr = mprotect((void *)((uintptr_t)address - vm_page_quanta_size), vm_page_quanta_size, protection);\n\t\tif (err) {\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** can't mvm_protect(%u) region for prelude guard page at %p\\n\", protection,\n\t\t\t\t\t(void *)((uintptr_t)address - vm_page_quanta_size));\n\t\t}\n\t}\n\tif (!(debug_flags & MALLOC_DONT_PROTECT_POSTLUDE)) {\n\t\terr = mprotect((void *)(round_page_quanta(((uintptr_t)address + size))), vm_page_quanta_size, protection);\n\t\tif (err) {\n\t\t\tmalloc_report(ASL_LEVEL_ERR, \"*** can't mvm_protect(%u) region for postlude guard page at %p\\n\", protection,\n\t\t\t\t\t(void *)((uintptr_t)address + size));\n\t\t}\n\t}\n}\n\nint\nmvm_madvise_free(void *rack, void *r, uintptr_t pgLo, uintptr_t pgHi, uintptr_t *last, boolean_t scribble)\n{\n\tif (pgHi > pgLo) {\n\t\tsize_t len = pgHi - pgLo;\n\n\t\tif (scribble) {\n\t\t\tmemset((void *)pgLo, SCRUBBLE_BYTE, len); // Scribble on MADV_FREEd memory\n\t\t}\n\n#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\t\tif (last) {\n\t\t\tif (*last == pgLo) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\t*last = pgLo;\n\t\t}\n#endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\n\t\tMAGMALLOC_MADVFREEREGION(rack, r, (void *)pgLo, (int)len); // DTrace USDT Probe\n\t\tif (-1 == madvise((void *)pgLo, len, CONFIG_MADVISE_STYLE)) {\n\t\t\t/* -1 return: VM map entry change makes this unfit for reuse. Something evil lurks. */\n#if DEBUG_MADVISE\n\t\t\tmalloc_zone_error(NULL, false,\n\t\t\t\t\t\"madvise_free_range madvise(..., MADV_FREE_REUSABLE) failed for %p, length=%d\\n\",\n\t\t\t\t\t(void *)pgLo, len);\n#endif\n\t\t\treturn 1;\n\t\t} else {\n\t\t\tMALLOC_TRACE(TRACE_madvise, (uintptr_t)r, (uintptr_t)pgLo, len, CONFIG_MADVISE_STYLE);\n\t\t}\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/src/vm.h",
    "content": "/*\n * Copyright (c) 2016 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n\n#ifndef __VM_H\n#define __VM_H\n\nstatic inline bool\nmvm_aslr_enabled(void)\n{\n\treturn _dyld_get_image_slide((const struct mach_header *)_NSGetMachExecuteHeader()) != 0;\n}\n\nMALLOC_NOEXPORT\nvoid\nmvm_aslr_init(void);\n\nMALLOC_NOEXPORT\nvoid *\nmvm_allocate_pages(size_t size, unsigned char align, unsigned debug_flags, int vm_page_label);\n\nMALLOC_NOEXPORT\nvoid *\nmvm_allocate_pages_securely(size_t size, unsigned char align, int vm_page_label, uint32_t debug_flags);\n\nMALLOC_NOEXPORT\nvoid\nmvm_deallocate_pages(void *addr, size_t size, unsigned debug_flags);\n\nMALLOC_NOEXPORT\nint\nmvm_madvise_free(void *szone, void *r, uintptr_t pgLo, uintptr_t pgHi, uintptr_t *last, boolean_t scribble);\n\nMALLOC_NOEXPORT\nvoid\nmvm_protect(void *address, size_t size, unsigned protection, unsigned debug_flags);\n\n#endif // __VM_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/Makefile",
    "content": "PROJECT := libmalloc\nTEST_DIR := tests/\n\nDEVELOPER_DIR ?= /Applications/Xcode.app/Contents/Developer/\n\ninclude $(DEVELOPER_DIR)/AppleInternal/Makefiles/darwintest/Makefile.common\n\nTRACE_FILES := \\\n\t$(notdir $(wildcard $(SRCROOT)/../traces/*.mtrace))\n\n# add trace files without the traces/ prefix, fex:\n#   exclude_this_file.mtrace\nEXCLUDED_TRACE_FILES :=\n\nOTHER_TEST_TARGETS = \\\n\t$(addprefix nano-trace-replay_, $(basename $(filter-out $(EXCLUDED_TRACE_FILES), $(TRACE_FILES))))\n\nBATS_PLISTS = \\\n\t$(patsubst %,$(SYMROOT)/%.plist,$(OTHER_TEST_TARGETS))\n\nCUSTOM_TARGETS = \\\n\tsingle-churn \\\n\tsingle-list_allocate \\\n\tsingle-tree_allocate \\\n\tsingle-tree_churn \\\n\tsingle-fragment \\\n\tsingle-fragment_iterate \\\n\tsingle-message_one \\\n\tsingle-message_many \\\n\tparallel-churn \\\n\tparallel-list_allocate \\\n\tparallel-tree_allocate \\\n\tparallel-tree_churn \\\n\tparallel-fragment \\\n\tparallel-fragment_iterate\n\n#\tsingle-medium \\\n#\tsingle-big \\\n#\tparallel-medium \\\n#\tparallel-big\n\nMALLOCBENCH_SOURCE := $(wildcard MallocBench/*.cpp)\nEXCLUDED_SOURCES := \\\n\tMallocBench.cpp \\\n\tnano_trace_replay.c\nCXX := $(shell $(XCRUN) -sdk \"$(TARGETSDK)\" -find clang++)\n\nWARNING_CFLAGS := -Wno-format-invalid-specifier -Wno-format-extra-args\nOTHER_CFLAGS += \\\n\t-DDARWINTEST \\\n\t-DOS_UNFAIR_LOCK_INLINE=1 \\\n\t-lCrashReporterClient \\\n\t-I$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders \\\n\t-I$(SRCROOT)/../include/malloc \\\n\t$(WARNING_CFLAGS)\n\n$(OBJROOT)/MallocBench/%.o: MallocBench/%.cpp\n\t@mkdir -p $(OBJROOT)/MallocBench\n\t$(CXX) $(CFLAGS) -I$(SRCROOT)/MallocBench -std=gnu++11 -stdlib=libc++ -c -o $@ $<\n\nsingle-%: $(addprefix $(OBJROOT)/, $(MALLOCBENCH_SOURCE:.cpp=.o))\n\t$(CXX) -c -o $(OBJROOT)/MallocBench-$@.o \\\n\t\t-I$(SRCROOT)/MallocBench \\\n\t\t$(CFLAGS) \\\n\t\t-DBENCHMARK_NAME=\\\"$*\\\" \\\n\t\t-DPARALLEL=false \\\n\t\t$(SRCROOT)/MallocBench.cpp\n\t$(CXX) -o $(SYMROOT)/$@ \\\n\t\t$(CFLAGS) \\\n\t\t$^ \\\n\t\t$(OBJROOT)/MallocBench-$@.o\n\ninstall-single-%: $(CUSTOM_TARGETS)\n\t@mkdir -p $(INSTALLDIR)\n\tcp $(SYMROOT)/$(patsubst install-%,%,$@) $(INSTALLDIR)/$(patsubst install-%,%,$@)\n\nparallel-%: $(addprefix $(OBJROOT)/, $(MALLOCBENCH_SOURCE:.cpp=.o))\n\t$(CXX) -c -o $(OBJROOT)/MallocBench-$@.o \\\n\t\t-I$(SRCROOT)/MallocBench \\\n\t\t$(CFLAGS) \\\n\t\t-DBENCHMARK_NAME=\\\"$*\\\" \\\n\t\t-DPARALLEL=true \\\n\t\t$(SRCROOT)/MallocBench.cpp\n\t$(CXX) -o $(SYMROOT)/$@ \\\n\t\t$(CFLAGS) \\\n\t\t$^ \\\n\t\t$(OBJROOT)/MallocBench-$@.o\n\ninstall-parallel-%: $(CUSTOM_TARGETS)\n\t@mkdir -p $(INSTALLDIR)\n\tcp $(SYMROOT)/$(patsubst install-%,%,$@) $(INSTALLDIR)/$(patsubst install-%,%,$@)\n\nnano-trace-replay_%: $(SRCROOT)/nano_trace_replay.c\n\t$(CC) \\\n\t\t$(CFLAGS) $(DT_CFLAGS) $(OTHER_CFLAGS) \\\n\t\t$(LDFLAGS) $(DT_LDFLAGS) $(OTHER_LDFLAGS) \\\n\t\t-DTRACE_NAME=\"$(patsubst nano-trace-replay_%,%,$(notdir $@))\" \\\n\t\t-o $@ \\\n\t\t$(SRCROOT)/nano_trace_replay.c\n\n$(BATS_PLISTS): %.plist : %\n\t$(EXTRACTMETA) extract -i /$(INSTALLPATH)/$(notdir $<) -b $(SYMROOT)/$(notdir $<) -o $@\n\t@plutil -convert binary1 $@\n\nSANITIZER_DYLIB_PATH := /usr/local/lib/sanitizers/\nasan: OTHER_CFLAGS += -fsanitize=address\nasan: OTHER_LDFLAGS += -Wl,-rpath -Wl,$(SANITIZER_DYLIB_PATH)\n\nifeq ($(Embedded),NO)\ntsan: CFLAGS := $(filter-out $(ARCH_FLAGS),$(CFLAGS)) -arch x86_64 -fsanitize=thread\ntsan: OTHER_LDFLAGS += -Wl,-rpath -Wl,$(SANITIZER_DYLIB_PATH)\nelse\nEXCLUDED_SOURCES += tsan.c\nendif\n\nmadvise: OTHER_CFLAGS += -I../src\nstack_logging_test: OTHER_CFLAGS += -I../private\nradix_tree_test: OTHER_CFLAGS += -I../src -framework Foundation\n\n.DEFAULT_GOAL := all\n\ninclude $(DEVELOPER_DIR)/AppleInternal/Makefiles/darwintest/Makefile.targets\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/Benchmark.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"Benchmark.h\"\n#include \"CPUCount.h\"\n#include \"balloon.h\"\n#include \"big.h\"\n#include \"churn.h\"\n#include \"fragment.h\"\n#include \"list.h\"\n#include \"medium.h\"\n#include \"memalign.h\"\n#include \"message.h\"\n#include \"realloc.h\"\n#include \"stress.h\"\n#include \"stress_aligned.h\"\n#include \"tree.h\"\n#include <dispatch/dispatch.h>\n#include <iostream>\n#include <fstream>\n#include <mach/mach.h>\n#include <mach/task_info.h>\n#include <map>\n#include <string>\n#include <sys/time.h>\n#include <thread>\n#include <unistd.h>\n\n#include \"mbmalloc.h\"\n\nusing namespace std;\n\nstruct BenchmarkPair {\n    const char* const name;\n    const BenchmarkFunction function;\n};\n\nstatic const BenchmarkPair benchmarkPairs[] = {\n    { \"balloon\", benchmark_balloon },\n    { \"big\", benchmark_big },\n    { \"churn\", benchmark_churn },\n    { \"fragment\", benchmark_fragment },\n    { \"fragment_iterate\", benchmark_fragment_iterate },\n    { \"list_allocate\", benchmark_list_allocate },\n    { \"list_traverse\", benchmark_list_traverse },\n    { \"medium\", benchmark_medium },\n    { \"memalign\", benchmark_memalign },\n    { \"message_many\", benchmark_message_many },\n    { \"message_one\", benchmark_message_one },\n    { \"realloc\", benchmark_realloc },\n    { \"stress\", benchmark_stress },\n    { \"stress_aligned\", benchmark_stress_aligned },\n    { \"tree_allocate\", benchmark_tree_allocate },\n    { \"tree_churn\", benchmark_tree_churn },\n    { \"tree_traverse\", benchmark_tree_traverse },\n};\n\nstatic const size_t benchmarksPairsCount = sizeof(benchmarkPairs) / sizeof(BenchmarkPair);\n\nstatic inline bool operator==(const BenchmarkPair& benchmarkPair, const string& string)\n{\n    return string == benchmarkPair.name;\n}\n\nstatic void*** allocateHeap(size_t heapSize, size_t chunkSize, size_t objectSize)\n{\n    if (!heapSize)\n        return 0;\n\n    size_t chunkCount = heapSize / chunkSize;\n    size_t objectCount = chunkSize / objectSize;\n    void*** chunks = (void***)mbmalloc(chunkCount * sizeof(void**));\n    for (size_t i = 0; i < chunkCount; ++i) {\n        chunks[i] = (void**)mbmalloc(objectCount * sizeof(void*));\n        for (size_t j = 0; j < objectCount; ++j) {\n            chunks[i][j] = (void*)mbmalloc(objectSize);\n            bzero(chunks[i][j], objectSize);\n        }\n    }\n    return chunks;\n}\n\nstatic void deallocateHeap(void*** chunks, size_t heapSize, size_t chunkSize, size_t objectSize)\n{\n    if (!heapSize)\n        return;\n\n    size_t chunkCount = heapSize / chunkSize;\n    size_t objectCount = chunkSize / objectSize;\n    for (size_t i = 0; i < chunkCount; ++i) {\n        for (size_t j = 0; j < objectCount; ++j)\n            mbfree(chunks[i][j], objectSize);\n        mbfree(chunks[i], objectCount * sizeof(void*));\n    }\n    mbfree(chunks, chunkCount * sizeof(void**));\n}\n\nBenchmark::Benchmark(const string& benchmarkName, bool isParallel, size_t runs, size_t heapSize)\n    : m_benchmarkPair()\n    , m_elapsedTime()\n    , m_isParallel(isParallel)\n    , m_heapSize(heapSize)\n    , m_runs(runs)\n{\n    const BenchmarkPair* benchmarkPair = std::find(\n        benchmarkPairs, benchmarkPairs + benchmarksPairsCount, benchmarkName);\n    if (benchmarkPair == benchmarkPairs + benchmarksPairsCount)\n        return;\n    \n    m_benchmarkPair = benchmarkPair;\n}\n    \nvoid Benchmark::printBenchmarks()\n{\n    cout << \"Benchmarks: \" << endl;\n    for (size_t i = 0; i < benchmarksPairsCount; ++i)\n        cout << \"\\t\" << benchmarkPairs[i].name << endl;\n}\n\nvoid Benchmark::runOnce()\n{\n    if (!m_isParallel) {\n        m_benchmarkPair->function(m_isParallel);\n        return;\n    }\n\n    dispatch_group_t group = dispatch_group_create();\n\n    for (size_t i = 0; i < cpuCount(); ++i) {\n        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{\n            m_benchmarkPair->function(m_isParallel);\n        });\n    }\n\n    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);\n\n    dispatch_release(group);\n}\n\nvoid Benchmark::run()\n{\n    static const size_t objectSize = 32;\n    static const size_t chunkSize = 1024 * 1024;\n    \n    void*** heap = allocateHeap(m_heapSize, chunkSize, objectSize);\n\n    runOnce(); // Warmup run.\n\n    for (size_t i = 0; i < m_runs; ++i) {\n        double start = currentTimeMS();\n        runOnce();\n        double end = currentTimeMS();\n        double elapsed = end - start;\n        m_elapsedTime += elapsed;\n    }\n    m_elapsedTime /= m_runs;\n\n    deallocateHeap(heap, m_heapSize, chunkSize, objectSize);\n    \n    mbscavenge();\n    m_memory = currentMemoryBytes();\n}\n\nvoid Benchmark::printReport()\n{\n    size_t kB = 1024;\n\tconst char *env = getenv(\"BATS_TMP_DIR\") ?: \"/tmp\";\n\tstd::string name(m_isParallel ? \"parallel-\" : \"single-\");\n\tname += m_benchmarkPair->name;\n\n\t/*\n\t * Must prepend files with dtres_ to get them picked up by BATS until\n\t * <rdar://problem/28389212>\n\t */\n\tstd::string perfDataPath = std::string(env) + \"/dtres_\" + name + \".perfdata\";\n\tstd::ofstream ofs(perfDataPath, std::ofstream::out);\n\tcout << \"Writing perf data to: \" << perfDataPath << endl;\n\n\tofs << \"{\" << endl;\n    ofs << \"\\t\\\"version\\\": \\\"1.0\\\",\" << endl;\n    ofs << \"\\t\\\"bats_test_name\\\": \\\"\" << name << \"\\\",\" << endl;\n    ofs << \"\\t\\\"measurements\\\": {\" << endl;\n\tofs << \"\\t\\t\\\"\" << name << \"\\\": {\" << endl;\n\tofs << \"\\t\\t\\t\\\"names\\\": [\\\"time\\\", \\\"memory\\\", \\\"peakmem\\\", \\\"phys_footprint\\\"],\" << endl;\n\tofs << \"\\t\\t\\t\\\"units\\\": [\\\"us\\\", \\\"B\\\", \\\"B\\\", \\\"B\\\"],\" << endl;\n\tofs << \"\\t\\t\\t\\\"data\\\": [[\";\n\tofs << m_elapsedTime << \"], [\";\n\tofs << m_memory.resident << \"], [\";\n\tofs << m_memory.residentMax << \"], [\";\n\tofs << m_memory.physicalFootprint;\n\tofs << \"]]\" << endl;\n\tofs << \"\\t\\t}\" << endl;\n\tofs << \"\\t}\" << endl;\n\tofs << \"}\" << endl;\n}\n\ndouble Benchmark::currentTimeMS()\n{\n    struct timeval now;\n    gettimeofday(&now, 0);\n    return (now.tv_sec * 1000.0) + now.tv_usec / 1000.0;\n}\n\nBenchmark::Memory Benchmark::currentMemoryBytes()\n{\n    Memory memory;\n\n    task_vm_info_data_t vm_info;\n    mach_msg_type_number_t vm_size = TASK_VM_INFO_COUNT;\n    if (KERN_SUCCESS != task_info(mach_task_self(), TASK_VM_INFO_PURGEABLE, (task_info_t)(&vm_info), &vm_size)) {\n        cout << \"Failed to get mach task info\" << endl;\n        exit(1);\n    }\n\n    memory.resident = vm_info.internal - vm_info.purgeable_volatile_pmap;\n    memory.residentMax = vm_info.resident_size_peak;\n    memory.physicalFootprint = vm_info.phys_footprint;\n    return memory;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/Benchmark.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef Benchmark_h\n#define Benchmark_h\n\n#include <map>\n#include <string>\n\ntypedef void (*BenchmarkFunction)(bool isParallel);\nstruct BenchmarkPair;\n\nclass Benchmark {\npublic:\n    struct Memory {\n        Memory()\n            : resident()\n            , residentMax()\n            , physicalFootprint()\n        {\n        }\n        \n        Memory(size_t resident, size_t residentMax, size_t physicalFootprint)\n            : resident(resident)\n            , residentMax(residentMax)\n            , physicalFootprint(physicalFootprint)\n        {\n        }\n\n        Memory operator-(const Memory& other)\n        {\n            return Memory(resident - other.resident, residentMax - other.residentMax, physicalFootprint - other.physicalFootprint);\n        }\n    \n        size_t resident;\n        size_t residentMax;\n        size_t physicalFootprint;\n    };\n\n    static double currentTimeMS();\n    static Memory currentMemoryBytes();\n\n    Benchmark(const std::string&, bool isParallel, size_t runs, size_t heapSize);\n    \n    bool isValid() { return m_benchmarkPair; }\n    \n    void printBenchmarks();\n    void run();\n    void printReport();\n\nprivate:\n    typedef std::map<std::string, BenchmarkFunction> MapType;\n    \n    void runOnce();\n\n    MapType m_map;\n\n    const BenchmarkPair* m_benchmarkPair;\n    bool m_isParallel;\n    size_t m_runs;\n    size_t m_heapSize;\n\n    Memory m_memory;\n    double m_elapsedTime;\n};\n\n#endif // Benchmark_h\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/CPUCount.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"CPUCount.h\"\n#include <stdlib.h>\n#include <sys/param.h>\n#include <sys/sysctl.h>\n#include <sys/types.h>\n\nstatic size_t count;\n\nsize_t cpuCount()\n{\n    if (count)\n        return count;\n\n    size_t length = sizeof(count);\n    int name[] = {\n            CTL_HW,\n            HW_NCPU\n    };\n    int sysctlResult = sysctl(name, sizeof(name) / sizeof(int), &count, &length, 0, 0);\n    if (sysctlResult < 0)\n        abort();\n\n    return count;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/CPUCount.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef CPUCount_h\n#define CPUCount_h\n\n#include <stddef.h>\n\nsize_t cpuCount();\n\n#endif // CPUCount_h\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/CommandLine.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"CommandLine.h\"\n#include <getopt.h>\n#include <iostream>\n\nstruct option CommandLine::longOptions[] =\n{\n    {\"benchmark\", required_argument, 0, 'b'},\n    {\"parallel\", no_argument, 0, 'p'},\n    {\"heap\", required_argument, 0, 'h'},\n    {\"runs\", required_argument, 0, 'r'},\n    {0, 0, 0, 0}\n};\n\nCommandLine::CommandLine(std::string name, bool parallel)\n\t: m_benchmarkName(name)\n    , m_isParallel(parallel)\n    , m_heapSize(0)\n    , m_runs(4)\n{\n}\n\nvoid CommandLine::printUsage()\n{\n    std::string fullPath(m_argv[0]);\n    size_t pos = fullPath.find_last_of(\"/\") + 1;\n    std::string program = fullPath.substr(pos);\n    std::cout << \"Usage: \" << program << \" --benchmark benchmark_name [ --parallel ] [ --heap MB ]\" << std::endl;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/CommandLine.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include <string>\n\nclass CommandLine {\npublic:\n\tCommandLine(std::string name, bool parallel);\n\n    bool isValid() { return m_benchmarkName.size(); }\n    const std::string& benchmarkName() { return m_benchmarkName; }\n    bool isParallel() { return m_isParallel; }\n    size_t heapSize() { return m_heapSize; }\n    size_t runs() { return m_runs; }\n\n    void printUsage();\n\nprivate:\n    static struct option longOptions[];\n\n    int m_argc;\n    char** m_argv;\n    std::string m_benchmarkName;\n    bool m_isParallel;\n    size_t m_heapSize;\n    size_t m_runs;\n};\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/Interpreter.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"CPUCount.h\"\n#include \"Interpreter.h\"\n#include <assert.h>\n#include <cstddef>\n#include <cstdlib>\n#include <errno.h>\n#include <fcntl.h>\n#include <string>\n#include <sys/mman.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <sys/uio.h>\n#include <unistd.h>\n#include <vector>\n\n#include \"mbmalloc.h\"\n\nInterpreter::Interpreter(const char* fileName, bool shouldFreeAllObjects)\n    : m_shouldFreeAllObjects(shouldFreeAllObjects)\n{\n    m_fd = open(fileName, O_RDWR, S_IRUSR | S_IWUSR);\n    if (m_fd == -1)\n        fprintf(stderr, \"failed to open\\n\");\n\n    struct stat buf;\n    fstat(m_fd, &buf);\n\n    m_opCount = buf.st_size / sizeof(Op);\n    assert(m_opCount * sizeof(Op) == buf.st_size);\n\n    size_t maxSlot = 0;\n\n    std::vector<Op> ops(1024);\n    size_t remaining = m_opCount * sizeof(Op);\n    while (remaining) {\n        size_t bytes = std::min(remaining, ops.size() * sizeof(Op));\n        remaining -= bytes;\n        read(m_fd, ops.data(), bytes);\n\n        size_t opCount = bytes / sizeof(Op);\n        for (size_t i = 0; i < opCount; ++i) {\n            Op op = ops[i];\n            if (op.slot > maxSlot)\n                maxSlot = op.slot;\n        }\n    }\n\n    m_objects.resize(maxSlot + 1);\n}\n\nInterpreter::~Interpreter()\n{\n    int result = close(m_fd);\n    if (result == -1)\n        fprintf(stderr, \"failed to close\\n\");\n}\n\nvoid Interpreter::run()\n{\n    std::vector<Op> ops(1024);\n    lseek(m_fd, 0, SEEK_SET);\n    size_t remaining = m_opCount * sizeof(Op);\n    while (remaining) {\n        size_t bytes = std::min(remaining, ops.size() * sizeof(Op));\n        remaining -= bytes;\n        read(m_fd, ops.data(), bytes);\n\n        size_t opCount = bytes / sizeof(Op);\n        for (size_t i = 0; i < opCount; ++i) {\n            Op op = ops[i];\n            switch (op.opcode) {\n            case op_malloc: {\n                m_objects[op.slot] = { mbmalloc(op.size), op.size };\n                assert(m_objects[op.slot].object);\n                bzero(m_objects[op.slot].object, op.size);\n                break;\n            }\n            case op_free: {\n                if (!m_objects[op.slot].object)\n                    continue;\n                mbfree(m_objects[op.slot].object, m_objects[op.slot].size);\n                m_objects[op.slot] = { 0, 0 };\n                break;\n            }\n            case op_realloc: {\n                if (!m_objects[op.slot].object)\n                    continue;\n                m_objects[op.slot] = { mbrealloc(m_objects[op.slot].object, m_objects[op.slot].size, op.size), op.size };\n                break;\n            }\n            default: {\n                fprintf(stderr, \"bad opcode: %d\\n\", op.opcode);\n                abort();\n                break;\n            }\n            }\n        }\n    }\n\n    // A recording might not free all of its allocations.\n    if (!m_shouldFreeAllObjects)\n        return;\n\n    for (size_t i = 0; i < m_objects.size(); ++i) {\n        if (!m_objects[i].object)\n            continue;\n        mbfree(m_objects[i].object, m_objects[i].size);\n        m_objects[i] = { 0, 0 };\n    }\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/Interpreter.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef Interpreter_h\n#define Interpreter_h\n\n#include <vector>\n\nclass Interpreter {\npublic:\n    Interpreter(const char* fileName, bool shouldFreeAllObjects = true);\n    ~Interpreter();\n\n    void run();\n\nprivate:\n    enum Opcode { op_malloc, op_free, op_realloc };\n    struct Op { Opcode opcode; size_t slot; size_t size; };\n    struct Record { void* object; size_t size; };\n\n    bool m_shouldFreeAllObjects;\n    int m_fd;\n    size_t m_opCount;\n    std::vector<Record> m_objects;\n};\n\n#endif // Interpreter_h\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/balloon.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"Benchmark.h\"\n#include \"CPUCount.h\"\n#include \"balloon.h\"\n#include <array>\n#include <chrono>\n#include <memory>\n#include <stddef.h>\n\n#include \"mbmalloc.h\"\n\nvoid benchmark_balloon(bool isParallel)\n{\n    const size_t chunkSize = 1 * 1024;\n    const size_t balloonSize = 100 * 1024 * 1024;\n    const size_t steadySize = 10 * 1024 * 1024;\n    \n    std::array<void*, balloonSize / chunkSize> balloon;\n    std::array<void*, balloonSize / chunkSize> steady;\n\n    auto start = std::chrono::steady_clock::now();\n\n    for (size_t i = 0; i < balloon.size(); ++i) {\n        balloon[i] = mbmalloc(chunkSize);\n        bzero(balloon[i], chunkSize);\n    }\n\n    for (size_t i = 0; i < balloon.size(); ++i)\n        mbfree(balloon[i], chunkSize);\n\n    auto stop = std::chrono::steady_clock::now();\n    \n    auto benchmarkTime = stop - start;\n\n    start = std::chrono::steady_clock::now();\n\n    // Converts bytes to time -- for reporting's sake -- by waiting a while until\n    // the heap shrinks back down. This isn't great for pooling with other\n    // benchmarks in a geometric mean of throughput, but it's OK for basic testing.\n    while (Benchmark::currentMemoryBytes().resident > 2 * steadySize\n        && std::chrono::steady_clock::now() - start < 8 * benchmarkTime) {\n        for (size_t i = 0; i < steady.size(); ++i) {\n            steady[i] = mbmalloc(chunkSize);\n            bzero(steady[i], chunkSize);\n        }\n\n        for (size_t i = 0; i < steady.size(); ++i)\n            mbfree(steady[i], chunkSize);\n    }\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/balloon.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef balloon_h\n#define balloon_h\n\nvoid benchmark_balloon(bool isParallel);\n\n#endif // balloon_h\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/big.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"CPUCount.h\"\n#include \"big.h\"\n#include <algorithm>\n#include <cstddef>\n#include <cstdlib>\n#include <strings.h>\n\n#include \"mbmalloc.h\"\n\nusing namespace std;\n\nstruct Object {\n    double* p;\n    size_t size;\n};\n\nvoid benchmark_big(bool isParallel)\n{\n    size_t times = 1;\n\n    size_t vmSize = 1ul * 1024 * 1024 * 1024;\n    size_t objectSizeMin = 4 * 1024;\n    size_t objectSizeMax = 64 * 1024;\n    if (isParallel)\n        vmSize /= cpuCount();\n\n    size_t objectCount = vmSize / objectSizeMin;\n\n    srandom(0); // For consistency between runs.\n\n    for (size_t i = 0; i < times; ++i) {\n        Object* objects = (Object*)mbmalloc(objectCount * sizeof(Object));\n        bzero(objects, objectCount * sizeof(Object));\n\n        for (size_t i = 0, remaining = vmSize; remaining > objectSizeMin; ++i) {\n            size_t size = min(remaining, max(objectSizeMin, random() % objectSizeMax));\n            objects[i] = { (double*)mbmalloc(size), size };\n            bzero(objects[i].p, size);\n            remaining -= size;\n        }\n\n        for (size_t i = 0; i < objectCount && objects[i].p; ++i)\n            mbfree(objects[i].p, objects[i].size);\n\n        mbfree(objects, objectCount * sizeof(Object));\n    }\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/big.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef big_h\n#define big_h\n\nvoid benchmark_big(bool isParallel);\n\n#endif // big_h\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/churn.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"CPUCount.h\"\n#include \"churn.h\"\n#include <memory>\n#include <stddef.h>\n\n#include \"mbmalloc.h\"\n\nstruct HeapDouble {\n    void* operator new(size_t size) { return mbmalloc(size); }\n    void operator delete(void* p, size_t size) { mbfree(p, size); }\n\n    HeapDouble(double d) : value(d) { }\n    const HeapDouble& operator+=(const HeapDouble& other) { value += other.value; return *this; }\n    double value;\n};\n\nvoid benchmark_churn(bool isParallel)\n{\n    size_t times = 7000000;\n    if (isParallel)\n        times /= cpuCount();\n\n    auto total = std::unique_ptr<HeapDouble>(new HeapDouble(0.0));\n    for (size_t i = 0; i < times; ++i) {\n        auto heapDouble = std::unique_ptr<HeapDouble>(new HeapDouble(i));\n        *total += *heapDouble;\n    }\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/churn.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef churn_h\n#define churn_h\n\nvoid benchmark_churn(bool isParallel);\n\n#endif // churn_h\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/fragment.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"CPUCount.h\"\n#include \"fragment.h\"\n#include <stdlib.h>\n#include <strings.h>\n\n#include \"mbmalloc.h\"\n\nnamespace {\n\nclass Node {\npublic:\n    void* operator new(size_t size)\n    {\n        return mbmalloc(size);\n    }\n\n    void operator delete(void* p, size_t size)\n    {\n        mbfree(p, size);\n    }\n\n    Node()\n        : m_next(0)\n        , m_payload()\n    {\n    }\n\n    Node(Node* next)\n        : m_next(next)\n        , m_payload()\n    {\n    }\n    \n    Node* next() { return m_next; }\n    \n    void validate()\n    {\n        for (size_t i = 0; i < sizeof(m_payload); ++i) {\n            if (m_payload[i])\n                abort();\n        }\n    }\n\nprivate:\n    Node* m_next;\n    char m_payload[32 - sizeof(Node*)];\n};\n\n} // namespace\n\nvoid validate(Node* head)\n{\n    for (Node* node = head; node; node = node->next())\n        node->validate();\n}\n\nvoid benchmark_fragment(bool isParallel)\n{\n    size_t nodeCount = 128 * 1024;\n    if (isParallel)\n        nodeCount /= cpuCount();\n    size_t replaceCount = nodeCount / 4;\n    size_t times = 25;\n\n    srandom(0); // For consistency between runs.\n\n    for (size_t i = 0; i < times; ++i) {\n        Node** nodes = static_cast<Node**>(mbmalloc(nodeCount * sizeof(Node*)));\n        for (size_t i = 0; i < nodeCount; ++i)\n            nodes[i] = new Node;\n\n        for (size_t i = 0; i < replaceCount; ++i) {\n            size_t node = random() % nodeCount;\n\n            delete nodes[node];\n            nodes[node] = new Node;\n        }\n\n        for (size_t node = 0; node < nodeCount; ++node)\n            delete nodes[node];\n        mbfree(nodes, nodeCount * sizeof(Node*));\n    }\n}\n\nvoid benchmark_fragment_iterate(bool isParallel)\n{\n    size_t nodeCount = 512 * 1024;\n    size_t times = 20;\n    if (isParallel)\n        nodeCount /= cpuCount();\n    size_t replaceCount = nodeCount / 4;\n\n    srandom(0); // For consistency between runs.\n\n    Node** nodes = static_cast<Node**>(mbmalloc(nodeCount * sizeof(Node*)));\n    for (size_t i = 0; i < nodeCount; ++i)\n        nodes[i] = new Node;\n\n    Node* head = 0;\n    for (size_t i = 0; i < replaceCount; ++i) {\n        size_t node = random() % nodeCount;\n\n        delete nodes[node];\n        nodes[node] = 0;\n        head = new Node(head);\n    }\n    \n    for (size_t i = 0; i < times; ++i)\n        validate(head);\n\n    for (Node* next ; head; head = next) {\n        next = head->next();\n        delete head;\n    }\n\n    for (size_t node = 0; node < nodeCount; ++node) {\n        if (!nodes[node])\n            continue;\n        delete nodes[node];\n    }\n    mbfree(nodes, nodeCount * sizeof(Node*));\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/fragment.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef fragment_h\n#define fragment_h\n\nvoid benchmark_fragment(bool isParallel);\nvoid benchmark_fragment_iterate(bool isParallel);\n\n#endif // fragment_h\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/list.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"CPUCount.h\"\n#include \"list.h\"\n#include <stdlib.h>\n#include <strings.h>\n\n#include \"mbmalloc.h\"\n\nnamespace {\n\nstruct Node {\n    void* operator new(size_t size)\n    {\n        return mbmalloc(size);\n    }\n\n    void operator delete(void* p, size_t size)\n    {\n        mbfree(p, size);\n    }\n\n    Node(Node* next, size_t payloadSize)\n        : m_refCount(1)\n        , m_next(next)\n        , m_payload(static_cast<char*>(mbmalloc(payloadSize)))\n        , m_payloadSize(payloadSize)\n    {\n        if (m_next)\n            m_next->ref();\n        bzero(m_payload, payloadSize);\n    }\n\n    ~Node()\n    {\n        if (m_next)\n            m_next->deref();\n        mbfree(m_payload, m_payloadSize);\n    }\n\n    void ref()\n    {\n        ++m_refCount;\n    }\n\n    void deref()\n    {\n        if (m_refCount == 1)\n            delete this;\n        else\n            --m_refCount;\n    }\n\n    Node* takeNext()\n    {\n        Node* tmp = m_next;\n        m_next = 0;\n        return tmp;\n    }\n    \n    bool validate()\n    {\n        if (m_payload[0])\n            return false;\n        return true;\n    }\n\n    unsigned m_refCount;\n    Node* m_next;\n    char* m_payload;\n    size_t m_payloadSize;\n};\n\n} // namespace\n\nvoid benchmark_list_allocate(bool isParallel)\n{\n    Node* head = 0;\n    size_t times = 70;\n    size_t nodes = 32 * 1024;\n    if (isParallel) {\n        nodes /= cpuCount();\n        times *= 2;\n    }\n    \n    for (size_t time = 0; time < times; ++time) {\n        // Construct a list of nodes.\n        for (size_t node = 0; node < nodes; ++node) {\n            Node* oldHead = head;\n            head = new Node(oldHead, (nodes & (64 - 1)) | 1);\n            if (oldHead)\n                oldHead->deref();\n        }\n\n        // Tear down the list.\n        while (head) {\n            Node* tmp = head->takeNext();\n            head->deref();\n            head = tmp;\n        }\n    }\n}\n\nvoid benchmark_list_traverse(bool isParallel)\n{\n    Node* head = 0;\n    size_t times = 1 * 1024;\n    size_t nodes = 32 * 1024;\n    if (isParallel) {\n        nodes /= cpuCount();\n        times *= 4;\n    }\n\n    // Construct a list of nodes.\n    for (size_t node = 0; node < nodes; ++node) {\n        Node* oldHead = head;\n        head = new Node(oldHead, (nodes & (64 - 1)) | 1);\n        if (oldHead)\n            oldHead->deref();\n    }\n\n    // Validate the list.\n    for (size_t time = 0; time < times; ++time) {\n        for (Node* node = head; node; node = node->m_next) {\n            if (!node->validate())\n                abort();\n        }\n    }\n\n    // Tear down the list.\n    while (head) {\n        Node* tmp = head->takeNext();\n        head->deref();\n        head = tmp;\n    }\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/list.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef list_h\n#define list_h\n\nvoid benchmark_list_allocate(bool isParallel);\nvoid benchmark_list_traverse(bool isParallel);\n\n#endif // list_h\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/mbmalloc.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include <limits>\n#include <stdio.h>\n#include <stdlib.h>\n#import <malloc/malloc.h>\n\nextern \"C\" {\n\nvoid* mbmalloc(size_t size)\n{\n    return malloc(size);\n}\n\nvoid* mbmemalign(size_t alignment, size_t size)\n{\n    void* result;\n    posix_memalign(&result, alignment, size);\n    return result;\n}\n\nvoid mbfree(void* p, size_t)\n{\n    return free(p);\n}\n\nvoid* mbrealloc(void* p, size_t, size_t newSize)\n{\n    return realloc(p, newSize);\n}\n\nvoid mbscavenge()\n{\n    malloc_zone_pressure_relief(nullptr, 0);\n}\n\n} // extern \"C\"\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/mbmalloc.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef mbmalloc_h\n#define mbmalloc_h\n\n#include <stddef.h>\n\n// This file defines a default implementation of the mbmalloc API, using system\n// malloc. To test with another malloc, supply an override .dylib that exports\n// these symbols.\n\nextern \"C\" {\n\nvoid* mbmalloc(size_t);\nvoid* mbmemalign(size_t, size_t);\nvoid mbfree(void*, size_t);\nvoid* mbrealloc(void*, size_t, size_t);\nvoid mbscavenge();\n    \n}\n\n// Catch accidental benchmark allocation through malloc and free. All benchmark\n// code should use mbmalloc / mbfree, to call the instrumented malloc we're\n// benchmarking against.\n\n#define malloc error\n#define free error\n#define realloc error\n\n#endif // mbmalloc_h\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/medium.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"CPUCount.h\"\n#include \"medium.h\"\n#include <algorithm>\n#include <cstddef>\n#include <cstdlib>\n#include <strings.h>\n\n#include \"mbmalloc.h\"\n\nusing namespace std;\n\nstruct Object {\n    double* p;\n    size_t size;\n};\n\nvoid benchmark_medium(bool isParallel)\n{\n    size_t times = 1;\n\n    size_t vmSize = 1ul * 1024 * 1024 * 1024;\n    size_t objectSizeMin = 2 * 1024;\n    size_t objectSizeMax = 8 * 1024;\n    if (isParallel)\n        vmSize /= cpuCount();\n\n    size_t objectCount = vmSize / objectSizeMin;\n\n    srandom(0); // For consistency between runs.\n\n    for (size_t i = 0; i < times; ++i) {\n        Object* objects = (Object*)mbmalloc(objectCount * sizeof(Object));\n        bzero(objects, objectCount * sizeof(Object));\n\n        for (size_t i = 0, remaining = vmSize; remaining > objectSizeMin; ++i) {\n            size_t size = min(remaining, max(objectSizeMin, random() % objectSizeMax));\n            objects[i] = { (double*)mbmalloc(size), size };\n            bzero(objects[i].p, size);\n            remaining -= size;\n        }\n\n        for (size_t i = 0; i < objectCount && objects[i].p; ++i)\n            mbfree(objects[i].p, objects[i].size);\n\n        mbfree(objects, objectCount * sizeof(Object));\n    }\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/medium.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef medium_h\n#define medium_h\n\nvoid benchmark_medium(bool isParallel);\n\n#endif // medium_h\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/memalign.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include <assert.h>\n#include \"memalign.h\"\n#include <memory>\n#include <stddef.h>\n\n#include \"mbmalloc.h\"\n\nvoid test(size_t alignment, size_t size)\n{\n    void* result = mbmemalign(alignment, size);\n\n    assert(result);\n    assert(!((uintptr_t)result & (alignment - 1)));\n    \n    mbfree(result, size);\n}\n\nvoid benchmark_memalign(bool isParallel)\n{\n    for (size_t alignment = 2; alignment < 4096; alignment *= 2) {\n        for (size_t size = 0; size < 4096; ++size)\n            test(alignment, size);\n    }\n\n    test(1 * 1024 * 1024, 8);\n    test(8 * 1024 * 1024, 8);\n    test(32 * 1024 * 1024, 8);\n    test(64 * 1024 * 1024, 8);\n    test(1 * 1024 * 1024, 8 * 1024 * 1024);\n    test(1 * 1024 * 1024, 16 * 1024 * 1024);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/memalign.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef memalign_h\n#define memalign_h\n\nvoid benchmark_memalign(bool isParallel);\n\n#endif // memalign_h\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/message.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"CPUCount.h\"\n#include \"message.h\"\n#include <dispatch/dispatch.h>\n#include <stdlib.h>\n#include <strings.h>\n\n#include \"mbmalloc.h\"\n\nnamespace {\n\nsize_t hash(size_t hash, unsigned short a, unsigned short b)\n{\n    hash += a ^ b;\n    return hash;\n}\n\nclass Node {\n    static const size_t payloadCount = 128;\npublic:\n    void* operator new(size_t size)\n    {\n        return mbmalloc(size);\n    }\n\n    void operator delete(void* p, size_t size)\n    {\n        mbfree(p, size);\n    }\n\n    Node()\n        : m_payload()\n    {\n    }\n\n    size_t hash(size_t hash)\n    {\n        for (size_t i = 0; i < payloadCount; i += 2)\n            hash = ::hash(hash, m_payload[i], m_payload[i + 1]);\n        return hash;\n    }\n\nprivate:\n    unsigned short m_payload[payloadCount];\n};\n\nclass Message {\n    static const size_t nodeCount = 1 * 1024;\n\npublic:\n    void* operator new(size_t size)\n    {\n        return mbmalloc(size);\n    }\n\n    void operator delete(void* p, size_t size)\n    {\n        mbfree(p, size);\n    }\n\n    Message()\n        : m_buffer(static_cast<Node**>(mbmalloc(nodeCount * sizeof(Node**))))\n    {\n        for (size_t i = 0; i < nodeCount; ++i)\n            m_buffer[i] = new Node;\n    }\n    \n    ~Message()\n    {\n        for (size_t i = 0; i < nodeCount; ++i)\n            delete m_buffer[i];\n        mbfree(m_buffer, nodeCount * sizeof(Node**));\n    }\n\n    size_t hash()\n    {\n        size_t hash = 0;\n        for (size_t i = 0; i < nodeCount; ++i)\n            hash = m_buffer[i]->hash(hash);\n        return hash;\n    }\n\nprivate:\n    Node** m_buffer;\n};\n\n} // namespace\n\nvoid benchmark_message_one(bool isParallel)\n{\n    if (isParallel)\n        abort();\n\n    const size_t times = 2048;\n    const size_t quantum = 16;\n\n    dispatch_queue_t queue = dispatch_queue_create(\"message\", 0);\n\n    for (size_t i = 0; i < times; i += quantum) {\n        for (size_t j = 0; j < quantum; ++j) {\n            Message* message = new Message;\n            dispatch_async(queue, ^{\n                size_t hash = message->hash();\n                if (hash)\n                    abort();\n                delete message;\n            });\n        }\n        dispatch_sync(queue, ^{ });\n    }\n\n    dispatch_sync(queue, ^{ });\n\n    dispatch_release(queue);\n}\n\nvoid benchmark_message_many(bool isParallel)\n{\n    if (isParallel)\n        abort();\n\n    const size_t times = 768;\n    const size_t quantum = 16;\n\n    const size_t queueCount = cpuCount() - 1;\n    dispatch_queue_t queues[queueCount];\n    for (size_t i = 0; i < queueCount; ++i)\n        queues[i] = dispatch_queue_create(\"message\", 0);\n\n    for (size_t i = 0; i < times; i += quantum) {\n        for (size_t j = 0; j < quantum; ++j) {\n            for (size_t k = 0; k < queueCount; ++k) {\n                Message* message = new Message;\n                dispatch_async(queues[k], ^{\n                    size_t hash = message->hash();\n                    if (hash)\n                        abort();\n                    delete message;\n                });\n            }\n        }\n\n        for (size_t i = 0; i < queueCount; ++i)\n            dispatch_sync(queues[i], ^{ });\n    }\n\n    for (size_t i = 0; i < queueCount; ++i)\n        dispatch_sync(queues[i], ^{ });\n\n    for (size_t i = 0; i < queueCount; ++i)\n        dispatch_release(queues[i]);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/message.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef message_h\n#define message_h\n\nvoid benchmark_message_one(bool isParallel);\nvoid benchmark_message_many(bool isParallel);\n\n#endif // message_h\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/realloc.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"realloc.h\"\n#include <memory>\n#include <stddef.h>\n\n#include \"mbmalloc.h\"\n\nvoid benchmark_realloc(bool isParallel)\n{\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/realloc.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef realloc_h\n#define realloc_h\n\nvoid benchmark_realloc(bool isParallel);\n\n#endif // realloc_h\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/stress.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"Benchmark.h\"\n#include \"CPUCount.h\"\n#include \"stress.h\"\n#include <array>\n#include <chrono>\n#include <cstdlib>\n#include <memory>\n#include <stddef.h>\n#include <vector>\n\n#include \"mbmalloc.h\"\n\nstatic const size_t kB = 1024;\nstatic const size_t MB = kB * kB;\n\nstruct Object {\n    Object(void* pointer, size_t size, long uuid)\n        : pointer(pointer)\n        , size(size)\n        , uuid(uuid)\n    {\n    }\n\n    void* pointer;\n    size_t size;\n    long uuid;\n};\n\nclass SizeStream {\npublic:\n    SizeStream()\n        : m_state(Small)\n        , m_count(0)\n    {\n    }\n\n    size_t next()\n    {\n        switch (m_state) {\n        case Small: {\n            if (++m_count == smallCount) {\n                m_state = Medium;\n                m_count = 0;\n            }\n            return random() % smallMax;\n        }\n                \n        case Medium: {\n            if (++m_count == mediumCount) {\n                m_state = Large;\n                m_count = 0;\n            }\n            return random() % mediumMax;\n        }\n                \n        case Large: {\n            if (++m_count == largeCount) {\n                m_state = Small;\n                m_count = 0;\n            }\n            return random() % largeMax;\n        }\n        }\n    }\n\nprivate:\n    static const size_t smallCount = 1000;\n    static const size_t smallMax = 16 * kB;\n\n    static const size_t mediumCount = 100;\n    static const size_t mediumMax = 512 * kB;\n    \n    static const size_t largeCount = 10;\n    static const size_t largeMax = 4 * MB;\n\n    enum { Small, Medium, Large } m_state;\n    size_t m_count;\n};\n\nObject allocate(size_t size)\n{\n    Object object(mbmalloc(size), size, random());\n    for (size_t i = 0; i < size / sizeof(long); ++i)\n        (static_cast<long*>(object.pointer))[i] = object.uuid;\n    return object;\n}\n\nvoid deallocate(const Object& object)\n{\n    for (size_t i = 0; i < object.size / sizeof(long); ++i) {\n        if ((static_cast<long*>(object.pointer))[i] != object.uuid)\n            abort();\n    }\n\n    mbfree(object.pointer, object.size);\n}\n\nvoid benchmark_stress(bool isParallel)\n{\n    const size_t heapSize = 100 * MB;\n    const size_t churnSize = .05 * heapSize;\n    const size_t churnCount = 10000;\n    \n    srandom(1); // For consistency between runs.\n\n    std::vector<Object> objects;\n    \n    SizeStream sizeStream;\n    \n    size_t size = 0;\n    for (size_t remaining = heapSize; remaining; remaining -= std::min(remaining, size)) {\n        size = sizeStream.next();\n        objects.push_back(allocate(size));\n    }\n    \n    for (size_t i = 0; i < churnCount; ++i) {\n        std::vector<Object> objectsToFree;\n        for (size_t remaining = churnSize; remaining; remaining -= std::min(remaining, size)) {\n            size = sizeStream.next();\n            Object object = allocate(size);\n\n            size_t index = random() % objects.size();\n            objectsToFree.push_back(objects[index]);\n            objects[index] = object;\n        }\n\n        for (auto& object : objectsToFree)\n            deallocate(object);\n        \n        mbscavenge();\n    }\n    \n    for (auto& object : objects)\n        mbfree(object.pointer, object.size);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/stress.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef stress_h\n#define stress_h\n\nvoid benchmark_stress(bool isParallel);\n\n#endif // stress_h\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/stress_aligned.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"Benchmark.h\"\n#include \"CPUCount.h\"\n#include \"stress_aligned.h\"\n#include <array>\n#include <chrono>\n#include <cmath>\n#include <cstdlib>\n#include <memory>\n#include <stddef.h>\n#include <vector>\n\n#include \"mbmalloc.h\"\n\nnamespace {\n\nstatic const size_t kB = 1024;\nstatic const size_t MB = kB * kB;\n\nstruct Object {\n    Object(void* pointer, size_t size, long uuid)\n        : pointer(pointer)\n        , size(size)\n        , uuid(uuid)\n    {\n    }\n\n    void* pointer;\n    size_t size;\n    long uuid;\n};\n\nclass SizeStream {\npublic:\n    SizeStream()\n        : m_state(Small)\n        , m_count(0)\n    {\n    }\n\n    size_t next()\n    {\n        switch (m_state) {\n        case Small: {\n            if (++m_count == smallCount) {\n                m_state = Medium;\n                m_count = 0;\n            }\n            return random() % smallMax;\n        }\n\n        case Medium: {\n            if (++m_count == mediumCount) {\n                m_state = Large;\n                m_count = 0;\n            }\n            return random() % mediumMax;\n        }\n\n        case Large: {\n            if (++m_count == largeCount) {\n                m_state = Small;\n                m_count = 0;\n            }\n            return random() % largeMax;\n        }\n        }\n    }\n\nprivate:\n    static const size_t smallCount = 1000;\n    static const size_t smallMax = 16 * kB;\n\n    static const size_t mediumCount = 100;\n    static const size_t mediumMax = 512 * kB;\n    \n    static const size_t largeCount = 10;\n    static const size_t largeMax = 4 * MB;\n\n    enum { Small, Medium, Large } m_state;\n    size_t m_count;\n};\n\nObject allocate(size_t alignment, size_t size)\n{\n    Object object(mbmemalign(alignment, size), size, random());\n    if ((uintptr_t)object.pointer & (alignment - 1))\n        abort();\n    for (size_t i = 0; i < size / sizeof(long); ++i)\n        (static_cast<long*>(object.pointer))[i] = object.uuid;\n    return object;\n}\n\nvoid deallocate(const Object& object)\n{\n    for (size_t i = 0; i < object.size / sizeof(long); ++i) {\n        if ((static_cast<long*>(object.pointer))[i] != object.uuid)\n            abort();\n    }\n\n    mbfree(object.pointer, object.size);\n}\n\nsize_t randomAlignment()\n{\n    switch (random() % 32) {\n    case 0:\n        return pow(2, random() % 26);\n    default:\n        return pow(2, random() % 14);\n    }\n}\n\n}\n\nvoid benchmark_stress_aligned(bool isParallel)\n{\n    const size_t heapSize = 100 * MB;\n    const size_t churnSize = .05 * heapSize;\n    const size_t churnCount = 100;\n    \n    srandom(1); // For consistency between runs.\n\n    std::vector<Object> objects;\n    \n    SizeStream sizeStream;\n    \n    size_t size = 0;\n    for (size_t remaining = heapSize; remaining; remaining -= std::min(remaining, size)) {\n        size = sizeStream.next();\n        objects.push_back(allocate(randomAlignment(), size));\n    }\n    \n    for (size_t i = 0; i < churnCount; ++i) {\n        std::vector<Object> objectsToFree;\n        for (size_t remaining = churnSize; remaining; remaining -= std::min(remaining, size)) {\n            size = sizeStream.next();\n            Object object = allocate(randomAlignment(), size);\n\n            size_t index = random() % objects.size();\n            objectsToFree.push_back(objects[index]);\n            objects[index] = object;\n        }\n\n        for (auto& object : objectsToFree)\n            deallocate(object);\n        \n        mbscavenge();\n    }\n    \n    for (auto& object : objects)\n        mbfree(object.pointer, object.size);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/stress_aligned.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef stress_aligned_h\n#define stress_aligned_h\n\nvoid benchmark_stress_aligned(bool isParallel);\n\n#endif // stress_aligned_h\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/tree.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"tree.h\"\n#include <limits>\n#include <stdlib.h>\n#include <strings.h>\n\n#include \"mbmalloc.h\"\n\nnamespace {\n\nstruct Node {\n    void* operator new(size_t size)\n    {\n        return mbmalloc(size);\n    }\n\n    void operator delete(void* p, size_t size)\n    {\n        mbfree(p, size);\n    }\n\n    Node(Node* left, Node* right, size_t payloadSize, size_t id)\n        : m_refCount(1)\n        , m_left(left)\n        , m_right(right)\n        , m_payload(static_cast<char*>(mbmalloc(payloadSize)))\n        , m_payloadSize(payloadSize)\n        , m_id(id)\n    {\n        if (m_left)\n            m_left->ref();\n        if (m_right)\n            m_right->ref();\n        bzero(m_payload, payloadSize);\n    }\n\n    ~Node()\n    {\n        if (m_left)\n            m_left->deref();\n        if (m_right)\n            m_right->deref();\n        mbfree(m_payload, m_payloadSize);\n    }\n\n    void ref()\n    {\n        ++m_refCount;\n    }\n\n    void deref()\n    {\n        if (m_refCount == 1)\n            delete this;\n        else\n            --m_refCount;\n    }\n    \n    size_t id() { return m_id; }\n    Node* left() { return m_left; }\n    Node* right() { return m_right; }\n\n    void setLeft(Node* left)\n    {\n        left->ref();\n        if (m_left)\n            m_left->deref();\n        \n        m_left = left;\n    }\n\n    void setRight(Node* right)\n    {\n        right->ref();\n        if (m_right)\n            m_right->deref();\n        \n        m_right = right;\n    }\n\n    unsigned m_refCount;\n    Node* m_left;\n    Node* m_right;\n    char* m_payload;\n    size_t m_payloadSize;\n    size_t m_id;\n};\n\nvoid verify(Node* node, Node* left, Node* right)\n{\n    if (left && left->id() >= node->id())\n        abort();\n\n    if (right && right->id() <= node->id())\n        abort();\n}\n\nNode* createTree(size_t depth, size_t& counter)\n{\n    if (!depth)\n        return 0;\n\n    Node* left = createTree(depth - 1, counter);\n    size_t id = counter++;\n    Node* right = createTree(depth - 1, counter);\n\n    Node* result = new Node(left, right, ((depth * 8) & (64 - 1)) | 1, id);\n\n    verify(result, left, right);\n\n    if (left)\n        left->deref();\n    if (right)\n        right->deref();\n    return result;\n}\n\nNode* createTree(size_t depth)\n{\n    size_t counter = 0;\n    return createTree(depth, counter);\n}\n\nvoid churnTree(Node* node, size_t stride, size_t& counter)\n{\n    if (!node)\n        return;\n    \n    churnTree(node->left(), stride, counter);\n\n    if (node->left() && !(counter % stride)) {\n        Node* left = new Node(node->left()->left(), node->left()->right(), (counter & (64 - 1)) | 1, node->left()->id());\n        Node* right = new Node(node->right()->left(), node->right()->right(), (counter & (64 - 1)) | 1, node->right()->id());\n        node->setLeft(left);\n        node->setRight(right);\n        left->deref();\n        right->deref();\n    }\n    ++counter;\n\n    churnTree(node->right(), stride, counter);\n\n    verify(node, node->left(), node->right());\n}\n\nvoid churnTree(Node* tree, size_t stride)\n{\n    size_t counter;\n    churnTree(tree, stride, counter);\n}\n\n} // namespace\n\nvoid benchmark_tree_allocate(bool isParallel)\n{\n    size_t times = 24;\n    size_t depth = 16;\n    if (isParallel) {\n        times *= 4;\n        depth = 13;\n    }\n\n    for (size_t time = 0; time < times; ++time) {\n        Node* tree = createTree(depth);\n        tree->deref();\n    }\n}\n\nvoid benchmark_tree_traverse(bool isParallel)\n{\n    size_t times = 256;\n    size_t depth = 15;\n    if (isParallel) {\n        times = 512;\n        depth = 13;\n    }\n\n    Node* tree = createTree(depth);\n    for (size_t time = 0; time < times; ++time)\n        churnTree(tree, std::numeric_limits<size_t>::max()); // Reuse this to iterate and validate.\n    tree->deref();\n}\n\nvoid benchmark_tree_churn(bool isParallel)\n{\n    size_t times = 130;\n    size_t depth = 15;\n    if (isParallel) {\n        times *= 4;\n        depth = 12;\n    }\n\n    Node* tree = createTree(depth);\n    for (size_t time = 0; time < times; ++time)\n        churnTree(tree, 8);\n    tree->deref();\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench/tree.h",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#ifndef tree_h\n#define tree_h\n\nvoid benchmark_tree_allocate(bool isParallel);\nvoid benchmark_tree_traverse(bool isParallel);\nvoid benchmark_tree_churn(bool isParallel);\n\n#endif // tree_h\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/MallocBench.cpp",
    "content": "/*\n * Copyright (C) 2014 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n */\n\n#include \"Benchmark.h\"\n#include \"CommandLine.h\"\n#include <iostream>\n#include <map>\n#include <sstream>\n#include <string>\n\nusing namespace std;\n\nint main(int argc, char** argv)\n{\n    CommandLine commandLine(BENCHMARK_NAME, PARALLEL);\n    if (!commandLine.isValid()) {\n        commandLine.printUsage();\n        exit(1);\n    }\n\n    Benchmark benchmark(commandLine.benchmarkName(), commandLine.isParallel(), commandLine.runs(), commandLine.heapSize());\n    if (!benchmark.isValid()) {\n        cout << \"Invalid benchmark: \" << commandLine.benchmarkName() << endl << endl;\n        benchmark.printBenchmarks();\n        exit(1);\n    }\n\n    benchmark.run();\n    benchmark.printReport();\n    cout << \"TEST PASS: \" << commandLine.benchmarkName() << endl;\n        \n    return 0;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/asan.c",
    "content": "#include <TargetConditionals.h>\n#include <darwintest.h>\n#include <dlfcn.h>\n#include <setjmp.h>\n#include <stdlib.h>\n#include \"sanitizer/asan_interface.h\"\n\nT_DECL(asan_sanity, \"ASan Sanity Check\", T_META_CHECK_LEAKS(NO))\n{\n\tconst char *dylib_path =\n\t\tTARGET_OS_OSX    ? \"@rpath/libclang_rt.asan_osx_dynamic.dylib\" :\n\t\tTARGET_OS_IOS    ? \"@rpath/libclang_rt.asan_ios_dynamic.dylib\" :\n\t\tTARGET_OS_TV     ? \"@rpath/libclang_rt.asan_tvos_dynamic.dylib\" :\n\t\tTARGET_OS_WATCH  ? \"@rpath/libclang_rt.asan_watchos_dynamic.dylib\" :\n\t\tTARGET_OS_BRIDGE ? \"@rpath/libclang_rt.asan_bridgeos_dynamic.dylib\" :\n\t\tNULL;\n\n\tvoid *asan_dylib = dlopen(dylib_path, RTLD_NOLOAD);\n\tT_ASSERT_NOTNULL(asan_dylib, \"ASan dylib loaded\");\n\n\tvoid *ptr = malloc(16);\n\tfree(ptr);\n\t\n\tT_PASS(\"I didn't crash!\");\n}\n\njmp_buf longjmp_env = {0};\nbool asan_report_hit = false;\nchar *asan_report = NULL;\n\nvoid asan_report_handler(const char *report) {\n\tasan_report_hit = true;\n\tasan_report = strdup(report);\n\tlongjmp(longjmp_env, 1);\n}\n\n__attribute__((optnone, noinline))\nvoid write_byte(void *ptr, size_t offset) {\n\t((char *)ptr)[offset] = 'x';\n}\n\nT_DECL(asan_use_after_free, \"ASan Detects use-after-free\", T_META_CHECK_LEAKS(NO))\n{\n\tasan_report = NULL;\n\tasan_report_hit = false;\n\t__asan_set_error_report_callback(asan_report_handler);\n\n\tif (setjmp(longjmp_env) == 0) {\n\t\tchar *ptr = malloc(16);\n\t\tfree(ptr);\n\t\twrite_byte(ptr, 10);\n\n\t\tT_FAIL(\"use-after-free not detected\");\n\t}\n\n\tT_EXPECT_EQ(asan_report_hit, true, \"asan finds use-after-free\");\n\tT_EXPECT_NOTNULL(strstr(asan_report, \"AddressSanitizer: heap-use-after-free\"), \"asan header\");\n}\n\nT_DECL(asan_heap_buffer_overflow, \"ASan Detects heap-buffer-overflow\", T_META_CHECK_LEAKS(NO))\n{\n\tasan_report = NULL;\n\tasan_report_hit = false;\n\t__asan_set_error_report_callback(asan_report_handler);\n\n\tif (setjmp(longjmp_env) == 0) {\n\t\tchar *ptr = malloc(16);\n\t\twrite_byte(ptr, 17);\n\t\tfree(ptr);\n\n\t\tT_FAIL(\"heap-buffer-overflow not detected\");\n\t}\n\n\tT_EXPECT_EQ(asan_report_hit, true, \"asan finds heap-buffer-overflow\");\n\tT_EXPECT_NOTNULL(strstr(asan_report, \"AddressSanitizer: heap-buffer-overflow\"), \"asan header\");\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/basic_malloc_free_perf.c",
    "content": "//\n//  basic_malloc_free_perf.c\n//  libmalloc\n//\n//  Simple and repeatable performance tests for malloc/free, running tests\n// \ton the regular, Nanov1 and Nanov2 allocators.\n//\n#include <darwintest.h>\n#include <dispatch/dispatch.h>\n#include <../src/internal.h>\n#include <perfcheck_keys.h>\n\n// This value is a guess that will be refined over time.\n#define PERFCHECK_THRESHOLD_PCT\t10.0\n\nstatic uint32_t\nncpu(void)\n{\n\tstatic uint32_t activecpu, physicalcpu;\n\tif (!activecpu) {\n\t\tuint32_t n;\n\t\tsize_t s = sizeof(n);\n\t\tsysctlbyname(\"hw.activecpu\", &n, &s, NULL, 0);\n\t\tactivecpu = n;\n\t\ts = sizeof(n);\n\t\tsysctlbyname(\"hw.physicalcpu\", &n, &s, NULL, 0);\n\t\tphysicalcpu = n;\n\t}\n\treturn MIN(activecpu, physicalcpu);\n}\n\n// Code to run a single test and save the converged sample time as the DPS\n// metric. The code also measures the time taken in dispatch_apply(), but that\n// should be more or less constant in all cases. We are only interested in\n// whether the overall sampled time regresses, not in the absolute time value.\n\nstatic void\nrun_test(void (^test)(size_t), bool singlethreaded)\n{\n\tuint32_t nthreads = 0;\n\tif (singlethreaded) {\n\t\tnthreads = 1;\n\t} else {\n\t\tconst char *e;\n\t\tif ((e = getenv(\"DT_STAT_NTHREADS\"))) {\n\t\t\tnthreads = strtoul(e, NULL, 0);\n\t\t}\n\t\tif (nthreads < 2) {\n\t\t\tnthreads = ncpu();\n\t\t}\n\t}\n\tdt_stat_time_t s = dt_stat_time_create(\n\t\t\tnthreads > 1 ? \"basic_malloc_free_perf multithreaded\" :\n\t\t\t\t\t\"basic_malloc_free_perf singlethreaded\");\n\tdt_stat_set_variable((dt_stat_t)s, \"threads\", nthreads);\n\tdo {\n\t\tint batch_size = dt_stat_batch_size(s);\n\t\tdt_stat_token t = dt_stat_begin(s);\n\t\t// rdar://problem/40417821: disable thresholds for now.\n\t\t//dt_stat_set_variable((dt_stat_t)s, kPCFailureThresholdPctVar,\n\t\t//\t\tPERFCHECK_THRESHOLD_PCT);\n\n\t\tdispatch_apply(nthreads,\n\t\t\t\tdispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), test);\n\n\t\tdt_stat_end_batch(s, batch_size, t);\n\t} while (!dt_stat_stable(s));\n\tdt_stat_finalize(s);\n}\n\n// Test content. Each of the functions is called from six different test cases,\n// with singlethreaded true and false and MallocNanoZone set to 0, V1 and V2.\n// The test content is biased towards the implementation of Nanov2.\n\nstatic void\nbasic_perf_malloc_free_8_bytes(bool singlethreaded)\n{\n#define NUM_ALLOCS 512\n\trun_test(^(size_t iteration __unused) {\n\t\tvoid *ptrs[NUM_ALLOCS];\n\t\tfor (int i = 0; i < NUM_ALLOCS; i++) {\n\t\t\tptrs[i] = malloc(8);\n\t\t}\n\n\t\tfor (int i = 0; i < NUM_ALLOCS; i++) {\n\t\t\tfree(ptrs[i]);\n\t\t}\n\t}, singlethreaded);\n#undef NUM_ALLOCS\n}\n\nstatic void\nbasic_perf_malloc_free_8_bytes_multi_block(bool singlethreaded)\n{\n\t// Use a large number of allocations to amortize the cost of scanning\n\t// for a new block.\n#define NUM_ALLOCS 65535\n\trun_test(^(size_t iteration __unused) {\n\t\tvoid **ptrs = calloc(NUM_ALLOCS, sizeof(void *));\n\t\tfor (int i = 0; i < NUM_ALLOCS; i++) {\n\t\t\tptrs[i] = malloc(8);\n\t\t}\n\n\t\tfor (int i = 0; i < NUM_ALLOCS; i++) {\n\t\t\tfree(ptrs[i]);\n\t\t}\n\t\tfree(ptrs);\n\t}, singlethreaded);\n#undef NUM_ALLOCS\n}\n\nstatic void\nbasic_perf_malloc_free_different_size_classes(bool singlethreaded)\n{\n#define NUM_ALLOCS 512\n\trun_test(^(size_t iteration __unused) {\n\t\tvoid *ptrs[NUM_ALLOCS];\n\t\tsize_t sz = (iteration + 1) * 16;\n\t\tif (sz > 256) {\n\t\t\t// Too big for Nano.\n\t\t\treturn;\n\t\t}\n\t\tfor (int i = 0; i < NUM_ALLOCS; i++) {\n\t\t\tptrs[i] = malloc(sz);\n\t\t}\n\n\t\tfor (int i = 0; i < NUM_ALLOCS; i++) {\n\t\t\tfree(ptrs[i]);\n\t\t}\n\t}, singlethreaded);\n#undef NUM_ALLOCS\n}\n\nstatic void\nbasic_perf_malloc_free_by_size_class(bool singlethreaded)\n{\n#define NUM_LOOPS 16\n\trun_test(^(size_t iteration __unused) {\n\t\tvoid *ptrs[NUM_LOOPS * 16];\n\t\tint k = 0;\n\t\tfor (int i = 0; i < NUM_LOOPS; i++) {\n\t\t\tfor (int j = 0; j < 16; j++) {\n\t\t\t\tptrs[k++] = malloc(16 * j + 8);\n\t\t\t}\n\t\t}\n\n\t\tfor (int i = 0; i < k; i++) {\n\t\t\tfree(ptrs[i]);\n\t\t}\n\t}, singlethreaded);\n#undef NUM_LOOPS\n}\n\nstatic void\nbasic_perf_malloc_free_by_size_class_offset(bool singlethreaded)\n{\n#define NUM_LOOPS 16\n\tint cpu_number = _os_cpu_number();\n\trun_test(^(size_t iteration __unused) {\n\t\tvoid *ptrs[NUM_LOOPS * 16];\n\t\tint k = 0;\n\t\tfor (int i = 0; i < NUM_LOOPS; i++) {\n\t\t\tfor (int j = 0; j < 16; j++) {\n\t\t\t\tptrs[k++] = malloc(16 * ((j + cpu_number) % 16) + 8);\n\t\t\t}\n\t\t}\n\n\t\tfor (int i = 0; i < k; i++) {\n\t\t\tfree(ptrs[i]);\n\t\t}\n\t}, singlethreaded);\n#undef NUM_LOOPS\n}\n\n// The tests that follow are grouped as follows:\n// \t- single-thread non-Nano version\n//  - single-threaded NanoV1 version\n//\t- single-threaded NanoV2 version\n// \t- parallel non-Nano version\n//  - parallel NanoV1 version\n//\t- parallel NanoV2 version\n// Each group probably could be built with a macro, but that would be harder\n// to debug when there is a problem.\n\n#pragma mark -\n#pragma mark 8-byte allocation/free\n\nT_DECL(basic_perf_serial_8_bytes, \"Malloc/Free 8 bytes single-threaded\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\tbasic_perf_malloc_free_8_bytes(true);\n}\n\nT_DECL(basic_perf_serial_8_bytes_V1, \"Malloc/Free 8 bytes single-threaded on V1\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t   T_META_ENVVAR(\"MallocNanoZone=V1\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_8_bytes(true);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_serial_8_bytes_V2, \"Malloc/Free 8 bytes single-threaded on V2\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_8_bytes(true);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_parallel_8_bytes, \"Malloc/Free 8 bytes parallel\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\tbasic_perf_malloc_free_8_bytes(false);\n}\n\nT_DECL(basic_perf_parallel_8_bytes_V1, \"Malloc/Free 8 bytes parallel on V1\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t   T_META_ENVVAR(\"MallocNanoZone=V1\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_8_bytes(false);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_parallel_8_bytes_V2, \"Malloc/Free 8 bytes single-threaded on V2\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_8_bytes(false);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\n#pragma mark -\n#pragma mark 8-byte allocation/free forcing block overflow with default scan policy\n\nT_DECL(basic_perf_serial_8_bytes_multi_block_default_scan_policy,\n\t   \"Malloc/Free 8 bytes single-threaded with block overflow, default scan policy\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\tbasic_perf_malloc_free_8_bytes_multi_block(true);\n}\n\nT_DECL(basic_perf_serial_8_bytes_multi_block_default_scan_policy_V1,\n\t   \t\"Malloc/Free 8 bytes single-threaded with block overflow, default scan policy on V1\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t   T_META_ENVVAR(\"MallocNanoZone=V1\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_8_bytes_multi_block(true);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_serial_8_bytes_multi_block_default_scan_policy_V2,\n\t   \t\"Malloc/Free 8 bytes single-threaded with block overflow, default scan policy on V2\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_8_bytes_multi_block(true);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_parallel_8_bytes_multi_block_default_scan_policy,\n\t   \"Malloc/Free 8 bytes parallel with block overflow, default scan policy\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\tbasic_perf_malloc_free_8_bytes_multi_block(false);\n}\n\nT_DECL(basic_perf_parallel_8_bytes_multi_block_default_scan_policy_V1,\n\t   \t\"Malloc/Free 8 bytes parallel with block overflow, default scan policy on V1\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t   T_META_ENVVAR(\"MallocNanoZone=V1\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_8_bytes_multi_block(false);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_parallel_8_bytes_multi_block_default_scan_policy_V2,\n\t   \t\"Malloc/Free 8 bytes parallel with block overflow, default scan policy on V2\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_8_bytes_multi_block(false);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\n#pragma mark -\n#pragma mark 8-byte allocation/free forcing block overflow with first-fit\n\n// This test only makes sense on Nanov2\nT_DECL(basic_perf_serial_8_bytes_multi_block_first_fit_V2,\n\t   \"Malloc/Free 8 bytes single-threaded with block overflow, first-fit on V2\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"),\n\t   T_META_ENVVAR(\"MallocNanoScanPolicy=firstfit\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_8_bytes_multi_block(true);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_parallel_8_bytes_multi_block_first_fit_V2,\n\t   \"Malloc/Free 8 bytes parallel with block overflow, first-fit on V2\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"),\n\t   T_META_ENVVAR(\"MallocNanoScanPolicy=firstfit\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_8_bytes_multi_block(false);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\n#pragma mark -\n#pragma mark Repeated allocation/free where each thread uses a different size class\n\nT_DECL(basic_perf_serial_different_size_classes,\n\t   \"Malloc/Free in different size classes single-threaded\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\tbasic_perf_malloc_free_different_size_classes(false);\n}\n\nT_DECL(basic_perf_serial_different_size_classes_V1,\n\t   \"Malloc/Free in different size classes single-threaded on V1\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=V1\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_different_size_classes(false);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_serial_different_size_classes_V2,\n\t   \"Malloc/Free in different size classes single-threaded on V2\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_different_size_classes(true);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_parallel_different_size_classes,\n\t   \"Malloc/Free in different size classes parallel\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\tbasic_perf_malloc_free_different_size_classes(false);\n}\n\nT_DECL(basic_perf_parallel_different_size_classes_V1,\n\t   \"Malloc/Free in different size classes parallel on V1\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=V1\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_different_size_classes(false);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_parallel_different_size_classes_V2,\n\t   \"Malloc/Free in different size classes single-threaded on V2\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_different_size_classes(false);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\n#pragma mark -\n#pragma mark Repeated allocation/free for each size class\n\nT_DECL(basic_perf_serial_by_size_class,\n\t   \"Malloc/Free by size class single-threaded\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\tbasic_perf_malloc_free_by_size_class(true);\n}\n\nT_DECL(basic_perf_serial_by_size_class_V1,\n\t   \"Malloc/Free by size class single-threaded on V1\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=V1\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_by_size_class(true);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_serial_by_size_class_V2,\n\t   \"Malloc/Free by size class single-threaded on V2\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_by_size_class(true);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_parallel_by_size_class,\n\t   \"Malloc/Free by size class parallel\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\tbasic_perf_malloc_free_by_size_class(false);\n}\n\nT_DECL(basic_perf_parallel_by_size_class_V1,\n\t   \"Malloc/Free by size class parallel on V1\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=V1\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_by_size_class(false);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_parallel_by_size_class_V2,\n\t   \"Malloc/Free by size class single-threaded on V2\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_by_size_class(false);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\n#pragma mark -\n#pragma mark Repeated allocation/free for each size class, offset by CPU\n\nT_DECL(basic_perf_serial_by_size_class_offset,\n\t   \"Malloc/Free by size class with offset single-threaded\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\tbasic_perf_malloc_free_by_size_class_offset(true);\n}\n\nT_DECL(basic_perf_serial_by_size_class_offset_V1,\n\t   \t\"Malloc/Free by size class with offset single-threaded on V1\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=V1\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_by_size_class_offset(true);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_serial_by_size_class_offset_V2,\n\t   \t\"Malloc/Free by size class with offset single-threaded on V2\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_by_size_class_offset(true);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_parallel_by_size_class_offset,\n\t   \"Malloc/Free by size class with offset parallel\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone\"))\n{\n\tbasic_perf_malloc_free_by_size_class_offset(false);\n}\n\nT_DECL(basic_perf_parallel_by_size_class_offset_V1,\n\t   \t\"Malloc/Free by size class with offset parallel on V1\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=V1\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_by_size_class_offset(false);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(basic_perf_parallel_by_size_class_offset_V2,\n\t   \t\"Malloc/Free by size class with offset single-threaded on V2\",\n\t   T_META_TAG_PERF, T_META_ALL_VALID_ARCHS(NO),\n\t   T_META_LTEPHASE(LTE_POSTINIT),\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n#if CONFIG_NANOZONE\n\tbasic_perf_malloc_free_by_size_class_offset(false);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/calloc_test.c",
    "content": "//\n//  malloc_calloc_test.c\n//  libmalloc\n//\n//  test calloc for various sizes\n//\n#include <TargetConditionals.h>\n#include <darwintest.h>\n#include <limits.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <malloc/malloc.h>\n\nstatic inline void*\nt_calloc(size_t count, size_t s)\n{\n\tvoid *ptr = calloc(count, s);\n\tT_QUIET; T_ASSERT_NOTNULL(ptr, \"allocation\");\n\tsize_t sz = malloc_size(ptr);\n\tT_QUIET; T_EXPECT_GE(sz, s * count, \"allocation size\");\n\tchar *p = ptr;\n\tfor (int i = 0; i < s * count; i++, p++) {\n\t\tT_QUIET; T_ASSERT_EQ(*p, '\\0', \"nonzero byte at offset %d\\n\", i);\n\t}\n\treturn ptr;\n}\n\nstatic void\ntest_calloc(size_t count, size_t min, size_t max, size_t incr)\n{\n\tfor (size_t s =  min; s <= max; s += incr) {\n\t\tvoid *ptr = t_calloc(count, s);\n\t\tfree(ptr);\n\t}\n}\n\nstatic void\ntest_calloc_random(size_t count, size_t min, size_t max, size_t incr, size_t n)\n{\n\tconst size_t r = (max - min) / incr, P = 100;\n\tvoid *ptrs[P] = {};\n\tfor (size_t i = 0, j = 0, k = 0; i < n + P; i++, j = k, k = (k + 1) % P) {\n\t\tvoid *ptr = NULL;\n\t\tif (i < n) ptr = t_calloc(count, min + arc4random_uniform(r) * incr);\n\t\tfree(ptrs[j]);\n\t\tptrs[k] = ptr;\n\t}\n}\n\nT_DECL(calloc_overflow_nano, \"calloc with overflow (nano)\",\n\tT_META_ENVVAR(\"MallocNanoZone=1\"))\n{\n\tvoid *ptr = calloc(LONG_MAX, 256);\n\tT_ASSERT_EQ(ptr, NULL, \"calloc overflow check #1\");\n\tfree(ptr);\n\n\tptr = calloc(256, LONG_MAX);\n\tT_ASSERT_EQ(ptr, NULL, \"calloc overflow check #2\");\n\tfree(ptr);\n}\n\nT_DECL(calloc_overflow, \"calloc with overflow\",\n\tT_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\tvoid *ptr = calloc(LONG_MAX, 1000);\n\tT_ASSERT_EQ(ptr, NULL, \"calloc overflow check #1\");\n\tfree(ptr);\n\n\tptr = calloc(1000, LONG_MAX);\n\tT_ASSERT_EQ(ptr, NULL, \"calloc overflow check #2\");\n\tfree(ptr);\n}\n\nT_DECL(calloc_nano, \"nano calloc all sizes <= 256\",\n\t   T_META_ENVVAR(\"MallocNanoZone=1\"))\n{\n\ttest_calloc(1, 0, 256, 1);\t\t// NANO_MAX_SIZE\n\ttest_calloc_random(1, 0, 256, 1, 100);\n\n\ttest_calloc(16, 0, 256/16, 1);\t// NANO_MAX_SIZE\n\ttest_calloc_random(16, 0, 256/16, 1, 100);\n\n\ttest_calloc(32, 0, 256/32, 1);\t// NANO_MAX_SIZE\n\ttest_calloc_random(32, 0, 256/32, 1, 100);\n}\n\nT_DECL(calloc_tiny, \"tiny calloc 16b increments <= 1008\",\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\ttest_calloc(1, 0, 1008, 16); \t\t// SMALL_THRESHOLD\n\ttest_calloc_random(1, 0, 1008, 16, 100);\n\n\ttest_calloc(4, 0, 1008/4, 16);\t\t// SMALL_THRESHOLD\n\ttest_calloc_random(4, 0, 1008/4, 16, 100);\n\n\ttest_calloc(16, 0, 1008/16, 16);\t// SMALL_THRESHOLD\n\ttest_calloc_random(16, 0, 1008/16, 16, 100);\n}\n\n// The next test is too demanding for some watches (taking over 15 minutes to\n// run) and for some AppleTVs, so use a cut-down version.\n#if TARGET_OS_WATCH || TARGET_OS_TV\nT_DECL(calloc, \"calloc all 2048b increments <= 130kb\",\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\ttest_calloc(1, 1024, 130 * 1024, 2048);\t\t// > LARGE_THRESHOLD_LARGEMEM\n\ttest_calloc_random(1, 1024, 130 * 1024, 2048, 50);\n\n\ttest_calloc(16, 1024/16, 130 * 1024/16, 2048);\n\ttest_calloc_random(16, 1024/16, 130 * 1024/16, 2048, 50);\n\n\ttest_calloc(64, 1024/64, 130 * 1024/64, 2048);\n\ttest_calloc_random(64, 1024/64, 130 * 1024/64, 2048, 50);\n}\n#else // !TARGET_OS_WATCH && !TARGET_OS_TV\nT_DECL(calloc, \"calloc all 512b increments <= 256kb\",\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\ttest_calloc(1, 1024, 256 * 1024, 512);\t\t// > LARGE_THRESHOLD_LARGEMEM\n\ttest_calloc_random(1, 1024, 256 * 1024, 512, 100);\n\n\ttest_calloc(16, 1024/16, 256 * 1024/16, 512);\n\ttest_calloc_random(16, 1024/16, 256 * 1024/16, 512, 100);\n\n\ttest_calloc(64, 1024/64, 256 * 1024/64, 512);\n\ttest_calloc_random(64, 1024/64, 256 * 1024/64, 512, 100);\n}\n#endif // !TARGET_OS_WATCH && !TARGET_OS_TV\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/libmalloc_tests.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXFileReference section */\n\t\t92D71A2B1B99355C00108CA1 /* stress_test.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = stress_test.c; path = ../tests/stress_test.c; sourceTree = \"<group>\"; };\n\t\t92D71A321B99364200108CA1 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXGroup section */\n\t\t92D71A1C1B99354500108CA1 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t92D71A321B99364200108CA1 /* Makefile */,\n\t\t\t\t92D71A2B1B99355C00108CA1 /* stress_test.c */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXLegacyTarget section */\n\t\t92D71A211B99354500108CA1 /* libmalloc_tests */ = {\n\t\t\tisa = PBXLegacyTarget;\n\t\t\tbuildArgumentsString = \"$(ACTION)\";\n\t\t\tbuildConfigurationList = 92D71A241B99354500108CA1 /* Build configuration list for PBXLegacyTarget \"libmalloc_tests\" */;\n\t\t\tbuildPhases = (\n\t\t\t);\n\t\t\tbuildToolPath = /usr/bin/make;\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = libmalloc_tests;\n\t\t\tpassBuildSettingsInEnvironment = 1;\n\t\t\tproductName = libmalloc_tests;\n\t\t};\n/* End PBXLegacyTarget section */\n\n/* Begin PBXProject section */\n\t\t92D71A1D1B99354500108CA1 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 0700;\n\t\t\t\tORGANIZATIONNAME = \"Apple Inc\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t92D71A211B99354500108CA1 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.0;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 92D71A201B99354500108CA1 /* Build configuration list for PBXProject \"libmalloc_tests\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t);\n\t\t\tmainGroup = 92D71A1C1B99354500108CA1;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t92D71A211B99354500108CA1 /* libmalloc_tests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin XCBuildConfiguration section */\n\t\t92D71A221B99354500108CA1 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t92D71A231B99354500108CA1 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t92D71A251B99354500108CA1 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx.internal;\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos appletvos watchos\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t92D71A261B99354500108CA1 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx.internal;\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos appletvos watchos\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t92D71A201B99354500108CA1 /* Build configuration list for PBXProject \"libmalloc_tests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t92D71A221B99354500108CA1 /* Debug */,\n\t\t\t\t92D71A231B99354500108CA1 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t92D71A241B99354500108CA1 /* Build configuration list for PBXLegacyTarget \"libmalloc_tests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t92D71A251B99354500108CA1 /* Debug */,\n\t\t\t\t92D71A261B99354500108CA1 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 92D71A1D1B99354500108CA1 /* Project object */;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/madvise.c",
    "content": "#include <TargetConditionals.h>\n#include <darwintest.h>\n#include <sys/mman.h>\n#include <stdio.h>\n#include <malloc/malloc.h>\n#include <mach/vm_page_size.h>\n#include <stdlib.h>\n\n#include \"base.h\"\n#include \"platform.h\"\n#include \"nano_zone_common.h\"\n#include \"nano_zone.h\"\n\nextern int\nmalloc_engaged_nano(void);\n\n#define T_EXPECT_BYTES(p, len, byte, msg, ...) do { \\\n\tchar *_p = (char *)(p); \\\n\tbool bytes = true; \\\n\tfor (int i=0; i<len; i++) { \\\n\t\tT_QUIET; T_EXPECT_EQ_CHAR(*(_p+i), byte, \"*(%p+0x%x)\", _p, i); \\\n\t\tif (*(_p+i) != byte) { bytes = false; break; } \\\n\t} \\\n\tT_EXPECT_TRUE(bytes, msg, ## __VA_ARGS__); \\\n} while(0)\n\n// vm.madvise_free_debug should cause the kernel to forcibly discard\n// pages that are madvised when the call is made. Making testing\n// madvise behaviour predictable under test.\nT_DECL(madvise_free_debug, \"test vm.madvise_free_debug\",\n\t   T_META_SYSCTL_INT(\"vm.madvise_free_debug=1\"),\n\t   T_META_ASROOT(YES))\n{\n\t// Map 32k of memory.\n\tsize_t memsz = 32 * vm_page_size;\n\tvoid *mem = mmap(NULL, memsz, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, 0);\n\tT_EXPECT_NE_PTR(mem, MAP_FAILED, \"mapped pages should not be MAP_FAILED\");\n\n\t// Fill it with scribble.\n\tmemset(mem, 0xa, 32 * vm_page_size);\n\n\t// Madvise a specfic page.\n\tT_EXPECT_POSIX_ZERO(\n\t\t\tmadvise(mem + (4 * vm_page_size), vm_page_size, MADV_FREE_REUSABLE),\n\t\t\t\"madvise (mem + 4 pages)\");\n\n\t// Check the entire page is empty.\n\tT_EXPECT_BYTES(mem + (4 * vm_page_size), vm_page_size, 0x0, \"madvise'd memory is all zeros\");\n\tT_EXPECT_POSIX_SUCCESS(munmap(mem, memsz), \"munmap\");\n}\n\nT_DECL(subpage_madvise_free_debug, \"test vm.madvise_free_debug\",\n\t   T_META_SYSCTL_INT(\"vm.madvise_free_debug=1\"),\n\t   T_META_ASROOT(YES))\n{\n\t// Skip if we dont' have vm_kernel_page_size < vm_page_size\n\tif (vm_kernel_page_size >= vm_page_size) {\n\t\tT_SKIP(\"vm_kernel_page_size >= vm_page_size, skipping subpage tests\");\n\t\treturn;\n\t}\n\n\t// Map 32k of memory.\n\tsize_t memsz = 32 * vm_page_size;\n\tvoid *mem = mmap(NULL, memsz, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, 0);\n\tT_EXPECT_NE_PTR(mem, MAP_FAILED, \"mapped pages should not be MAP_FAILED\");\n\n\t// Fill it with scribble.\n\tmemset(mem, 0xa, 32 * vm_page_size);\n\n\t// Madvise a specfic page.\n\tT_EXPECT_POSIX_ZERO(\n\t\t\tmadvise(mem + (4 * vm_kernel_page_size), vm_kernel_page_size, MADV_FREE_REUSABLE),\n\t\t\t\"madvise (mem + 4 pages)\");\n\n\t// Check the entire page is empty.\n\tT_EXPECT_BYTES(mem + (4 * vm_kernel_page_size), vm_kernel_page_size, 0x0, \"madvise'd memory is all zeros\");\n\n\t// Check that the subsequent page is 0xaa.\n\tT_EXPECT_BYTES(mem + (5 * vm_kernel_page_size), vm_kernel_page_size, 0xa, \"un-madvise'd memory is all 0xaa\");\n\n\tT_EXPECT_POSIX_SUCCESS(munmap(mem, memsz), \"munmap\");\n}\n\n// <rdar://problem/31844360> disable nano_subpage_madvise due to consistent\n// failures.\n#if 0\n\nT_DECL(nano_subpage_madvise, \"nano allocator madvise\",\n\t   T_META_SYSCTL_INT(\"vm.madvise_free_debug=1\"),\n\t   T_META_ENVVAR(\"MallocNanoZone=1\"),\n\t   T_META_CHECK_LEAKS(NO),\n\t   T_META_ASROOT(YES))\n{\n\tT_EXPECT_TRUE(malloc_engaged_nano(), \"nano zone enabled\");\n\n\tvoid *ptr = malloc(128);\n\tT_EXPECT_EQ_PTR(\n\t\t\t(void *)(((uintptr_t)ptr) >> (64-NANO_SIGNATURE_BITS)),\n\t\t\t(void *)NANOZONE_SIGNATURE,\n\t\t\t\"malloc == nano allocation\");\n\tfree(ptr);\n\n\tconst size_t granularity = 128;\n\tconst size_t allocations = 128 * 1024;\n\n\tvoid *bank[allocations / granularity];\n\tfor (int i=0; i<(sizeof(bank)/sizeof(*bank)); i++) {\n\t\t// allocate 128k of memory, scribble them\n\t\tbank[i] = malloc(granularity);\n\t\tmemset(bank[i], 'A', granularity);\n\t}\n\n\tptr = NULL;\n\tsize_t limit = vm_kernel_page_size;\n\tfor (int i=0; i<256; i++) {\n\t\t// find the first entry that lies on the user page\n\t\t// boundary, rather than kernel, to try and find\n\t\t// bugs where we accidentally round up to other page\n\t\t// sizes.\n\t\tif (!ptr && trunc_page((uintptr_t)bank[i]) != (uintptr_t)bank[i]) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// mark active, free the entry, then decrement the\n\t\t// limit until we get to a full page.\n\t\tif (!ptr) {\n\t\t\tptr = bank[i];\n\t\t}\n\n\t\tfree(bank[i]);\n\t\tbank[i] = NULL;\n\t\tlimit -= 128;\n\n\t\tif (limit == 0) {\n\t\t\t// finished, break.\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// force the nano alloc to madvise things\n\tmalloc_zone_pressure_relief(malloc_default_zone(), 0);\n\n\t// we should be able to test for the entire range that's\n\t// madvised being zeros now.\n\tT_EXPECT_BYTES(ptr, vm_kernel_page_size, 0x0,\n\t\t\t\"madvised region was cleared\");\n\n\t// and that the page immediately after the kernel page is\n\t// stil intacted.\n\tT_EXPECT_BYTES(ptr + vm_kernel_page_size, vm_kernel_page_size, 'A',\n\t\t\t\"non-madvised page check\");\n\n\tfor (int i=0; i<(sizeof(bank)/sizeof(*bank)); i++) {\n\t\tfree(bank[i]);\n\t}\n}\n\n#endif\n\n#if 0\n// OS X has the recirc depot enabled, so more has to be done to reliably test\n// madvise on that platform.\n\nT_DECL(tiny_subpage_madvise, \"tiny allocator madvise\",\n\t   T_META_SYSCTL_INT(\"vm.madvise_free_debug=1\"),\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"),\n\t   T_META_ASROOT(YES))\n{\n\tT_EXPECT_TRUE(!malloc_engaged_nano(), \"nano zone disabled\");\n\n\tmalloc_zone_t *zone = malloc_create_zone(0, 0);\n\n\tconst size_t granularity = 16;\n\tconst size_t allocations = 128 * 1024;\n\n\tvoid *bank[allocations / granularity];\n\tfor (int i=0; i<(sizeof(bank)/sizeof(*bank)); i++) {\n\t\t// allocate 128k of memory, scribble them\n\t\tbank[i] = malloc_zone_malloc(zone, granularity);\n\t\tmemset(bank[i], 'A', granularity);\n\t\tprintf(\"%p\\n\", bank[i]);\n\n\t\tif (i>0) {\n\t\t\tT_QUIET;\n\t\t\tT_ASSERT_EQ_PTR(((uintptr_t)bank[i-1]) + granularity,\n\t\t\t\t\t\t\t(uintptr_t)bank[i],\n\t\t\t\t\t\t\t\"contiguous allocations required\");\n\t\t}\n\t}\n\n\tvoid *ptr = NULL;\n\tsize_t num_needed = vm_kernel_page_size / granularity + 1;\n\n\tfor (int i=1; i<(sizeof(bank)/sizeof(*bank)); i++) {\n\t\t// find the first page aligned entry\n\t\tif (!ptr &&\n\t\t\t((uintptr_t)bank[i] > round_page_kernel((uintptr_t)bank[i]) ||\n\t\t\t (uintptr_t)bank[i] + granularity - 1 < round_page_kernel((uintptr_t)bank[i])))\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n\t\t// when we find the entry, take this pointer and\n\t\t// also free the entry before.\n\t\tif (!ptr) {\n\t\t\tptr = (void *)round_page_kernel((uintptr_t)bank[i]);\n\t\t}\n\n\t\tmalloc_zone_free(zone, bank[i]);\n\t\tbank[i] = NULL;\n\t\tnum_needed--;\n\n\t\tif (num_needed == 0) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tT_ASSERT_NOTNULL(ptr, \"expected pointer\");\n\n\t// we should be able to test for the entire range that's\n\t// madvised being zeros now.\n\tT_EXPECT_BYTES(ptr, vm_kernel_page_size, 0x0,\n\t\t\t\t   \"madvised region was cleared\");\n\n\t// and that the page immediately after the kernel page is\n\t// stil intacted.\n\tT_EXPECT_BYTES(ptr + vm_kernel_page_size + granularity, vm_kernel_page_size, 'A',\n\t\t\t\t   \"non-madvised page check\");\n\n\tfor (int i=0; i<(sizeof(bank)/sizeof(*bank)); i++) {\n\t\tmalloc_zone_free(zone, bank[i]);\n\t}\n}\n\nT_DECL(small_subpage_madvise, \"small allocator madvise\",\n\t   T_META_SYSCTL_INT(\"vm.madvise_free_debug=1\"),\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\tT_EXPECT_TRUE(!malloc_engaged_nano(), \"nano zone disabled\");\n\n\tconst size_t granularity = 512;\n\tconst size_t allocations = 128 * 1024;\n\n\tvoid *bank[allocations / granularity];\n\tfor (int i=0; i<(sizeof(bank)/sizeof(*bank)); i++) {\n\t\t// allocate 128k of memory, scribble them\n\t\tbank[i] = malloc(granularity);\n\t\tmemset(bank[i], 'A', granularity);\n\t}\n\n\tvoid *ptr = NULL;\n\tsize_t num_needed = vm_kernel_page_size / granularity + 1;\n\n\tfor (int i=1; i<(sizeof(bank)/sizeof(*bank)); i++) {\n\t\t// find the first page aligned entry\n\t\tif (!ptr &&\n\t\t\t((uintptr_t)bank[i] > round_page_kernel((uintptr_t)bank[i]) ||\n\t\t\t (uintptr_t)bank[i] + granularity - 1 < round_page_kernel((uintptr_t)bank[i])))\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n\t\t// when we find the entry, take this pointer and\n\t\t// also free the entry before.\n\t\tif (!ptr) {\n\t\t\tptr = (void *)round_page_kernel((uintptr_t)bank[i]);\n\t\t}\n\n\t\tfree(bank[i]);\n\t\tbank[i] = NULL;\n\t\tnum_needed--;\n\n\t\tif (num_needed == 0) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tT_ASSERT_NOTNULL(ptr, \"expected pointer\");\n\n\t// we should be able to test for the entire range that's\n\t// madvised being zeros now.\n\tT_EXPECT_BYTES(ptr, vm_kernel_page_size, 0x0,\n\t\t\t\t   \"madvised region was cleared\");\n\n\t// and that the page immediately after the kernel page is\n\t// stil intacted.\n\tT_EXPECT_BYTES(ptr + vm_kernel_page_size + granularity, vm_kernel_page_size, 'A',\n\t\t\t\t   \"non-madvised page check\");\n\n\tfor (int i=0; i<(sizeof(bank)/sizeof(*bank)); i++) {\n\t\tfree(bank[i]);\n\t}\n}\n#endif // #if 0\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/magazine_malloc.c",
    "content": "//\n//  magazine_malloc.c\n//  libmalloc\n//\n//  Created by Kim Topley on 11/8/17.\n//\n#include <darwintest.h>\n#include <stdlib.h>\n#include <malloc/malloc.h>\n\nT_DECL(malloc_zone_batch, \"malloc_zone_batch_malloc and malloc_zone_batch_free\")\n{\n\tconst unsigned count = 10;\n\tvoid **results;\n\tunsigned number;\n\n\t// Use malloc_zone_batch_malloc() with a size that maps to the tiny\n\t// allocator. This should succeed.\n\tresults = calloc(count, sizeof(void *));\n\tnumber = malloc_zone_batch_malloc(malloc_default_zone(), 32, results, count);\n\tT_ASSERT_EQ(number, count, \"allocated from tiny zone\");\n\tfor (int i = 0; i < count; i++) {\n\t\tT_QUIET; T_ASSERT_NOTNULL(results[i], \"pointer %d is NULL\", i);\n\t}\n\tmalloc_zone_batch_free(malloc_default_zone(), results, count);\n\tfree(results);\n\n\t// Use malloc_zone_batch_malloc() with a size that maps to the small\n\t// allocator. This should fail.\n\tresults = calloc(count, sizeof(void *));\n\tnumber = malloc_zone_batch_malloc(malloc_default_zone(), 2048, results, count);\n\tT_ASSERT_EQ(0, number, \"could not allocat from small zone\");\n\tfor (int i = 0; i < count; i++) {\n\t\tT_QUIET; T_ASSERT_NULL(results[i], \"pointer %d is not NULL\", i);\n\t}\n\tmalloc_zone_batch_free(malloc_default_zone(), results, count);\n\tfree(results);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/magazine_rack.c",
    "content": "//\n//  magazine_rack.c\n//  libmalloc\n//\n//  Created by Matt Wright on 8/29/16.\n//\n//\n\n#include <darwintest.h>\n#include \"magazine_testing.h\"\n\nT_DECL(basic_magazine_init, \"allocate magazine counts\")\n{\n\tstruct rack_s rack;\n\n\tfor (int i=1; i < 64; i++) {\n\t\tmemset(&rack, 'a', sizeof(rack));\n\t\track_init(&rack, RACK_TYPE_NONE, i, 0);\n\t\tT_ASSERT_NOTNULL(rack.magazines, \"%d magazine initialisation\", i);\n\t}\n}\n\nT_DECL(basic_magazine_deinit, \"allocate deallocate magazines\")\n{\n\tstruct rack_s rack;\n\tmemset(&rack, 'a', sizeof(rack));\n\n\track_init(&rack, RACK_TYPE_NONE, 1, 0);\n\tT_ASSERT_NOTNULL(rack.magazines, \"magazine init\");\n\n\track_destroy(&rack);\n\tT_ASSERT_NULL(rack.magazines, \"magazine deinit\");\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/magazine_small_test.c",
    "content": "//\n//  magazine_small_test.c\n//  libmalloc\n//\n//  Created by Matt Wright on 8/22/16.\n//\n//\n\n#include <darwintest.h>\n\n#include \"../src/magazine_small.c\"\n#include \"magazine_testing.h\"\n\nstatic inline void\ntest_rack_setup(rack_t *rack)\n{\n\tmemset(rack, 'a', sizeof(rack));\n\track_init(rack, RACK_TYPE_SMALL, 1, 0);\n\tT_QUIET; T_ASSERT_NOTNULL(rack->magazines, \"magazine initialisation\");\n}\n\nT_DECL(basic_small_alloc, \"small rack init and alloc\")\n{\n\tstruct rack_s rack;\n\ttest_rack_setup(&rack);\n\n\tvoid *ptr = small_malloc_should_clear(&rack, SMALL_MSIZE_FOR_BYTES(512), false);\n\tT_ASSERT_NOTNULL(ptr, \"allocation\");\n\n\tregion_t *rgn = small_region_for_ptr_no_lock(&rack, ptr);\n\tT_ASSERT_NOTNULL(rgn, \"allocation region found in rack\");\n\n\tsize_t sz = small_size(&rack, ptr);\n\tT_ASSERT_EQ((int)sz, 512, \"size == 32\");\n}\n\nT_DECL(basic_small_teardown, \"small rack init, alloc, teardown\")\n{\n\tstruct rack_s rack;\n\ttest_rack_setup(&rack);\n\n\tvoid *ptr = small_malloc_should_clear(&rack, TINY_MSIZE_FOR_BYTES(512), false);\n\tT_ASSERT_NOTNULL(ptr, \"allocation\");\n\n\track_destroy_regions(&rack, SMALL_REGION_SIZE);\n\tfor (int i=0; i < rack.region_generation->num_regions_allocated; i++) {\n\t\tT_QUIET;\n\t\tT_ASSERT_TRUE(rack.region_generation->hashed_regions[i] == HASHRING_OPEN_ENTRY ||\n\t\t\t\t\t  rack.region_generation->hashed_regions[i] == HASHRING_REGION_DEALLOCATED,\n\t\t\t\t\t  \"all regions destroyed\");\n\t}\n\n\track_destroy(&rack);\n\tT_ASSERT_NULL(rack.magazines, \"magazines destroyed\");\n}\n\nT_DECL(basic_small_free, \"small free\")\n{\n\tstruct rack_s rack;\n\ttest_rack_setup(&rack);\n\n\tvoid *ptr = small_malloc_should_clear(&rack, SMALL_MSIZE_FOR_BYTES(512), false);\n\tT_ASSERT_NOTNULL(ptr, \"allocation\");\n\n\t// free doesn't return an error (unless we assert here)\n\tfree_small(&rack, ptr, SMALL_REGION_FOR_PTR(ptr), 0);\n\n\tsize_t sz = small_size(&rack, ptr);\n\tT_ASSERT_EQ((int)sz, 0, \"allocation freed (sz == 0)\");\n}\n\nT_DECL(basic_small_shrink, \"small rack shrink\")\n{\n\tstruct rack_s rack;\n\ttest_rack_setup(&rack);\n\n\tvoid *ptr = small_malloc_should_clear(&rack, SMALL_MSIZE_FOR_BYTES(1024), false);\n\tT_ASSERT_NOTNULL(ptr, \"allocation\");\n\n\tsize_t sz = small_size(&rack, ptr);\n\tT_ASSERT_EQ((int)sz, 1024, \"size == 1024\");\n\n\tvoid *nptr = small_try_shrink_in_place(&rack, ptr, sz, 512);\n\tsize_t nsz = small_size(&rack, nptr);\n\tT_ASSERT_EQ_PTR(ptr, nptr, \"ptr == nptr\");\n\tT_ASSERT_EQ((int)nsz, 512, \"nsz == 512\");\n}\n\nT_DECL(basic_small_realloc_in_place, \"small rack realloc in place\")\n{\n\tstruct rack_s rack;\n\ttest_rack_setup(&rack);\n\n\t// Allocate two blocks and free the second, then try to realloc() the first.\n\t// This should extend in-place using the one-level death row cache that's\n\t// occupied by the second block.\n\tvoid *ptr = small_malloc_should_clear(&rack, SMALL_MSIZE_FOR_BYTES(512), false);\n\tT_ASSERT_NOTNULL(ptr, \"allocation\");\n\n\tsize_t sz = small_size(&rack, ptr);\n\tT_ASSERT_EQ((int)sz, 512, \"size == 512\");\n\n\tvoid *ptr2 = small_malloc_should_clear(&rack, SMALL_MSIZE_FOR_BYTES(512), false);\n\tT_ASSERT_NOTNULL(ptr2, \"allocation 2\");\n\tT_ASSERT_EQ_PTR(ptr2, (void *)((uintptr_t)ptr + 512), \"sequential allocations\");\n\n\tfree_small(&rack, ptr2, SMALL_REGION_FOR_PTR(ptr2), 0);\n\n\t// Attempt to realloc up to 1024 bytes, this should happen in place\n\t// because of the death-row cache.\n\tboolean_t reallocd = small_try_realloc_in_place(&rack, ptr, sz, 1024);\n\tT_ASSERT_TRUE(reallocd, \"realloced\");\n\n\tsize_t nsz = small_size(&rack, ptr);\n\tT_ASSERT_EQ((int)nsz, 1024, \"realloc size == 1024\");\n\n\t// Try another realloc(). This should extend in place because the rest of\n\t// the rack is empty.\n\treallocd = small_try_realloc_in_place(&rack, ptr, nsz, 2048);\n\tT_ASSERT_TRUE(reallocd, \"realloced #2\");\n\tnsz = small_size(&rack, ptr);\n\tT_ASSERT_EQ((int)nsz, 2048, \"realloc size == 2048\");\n\n\tfree_small(&rack, ptr, SMALL_REGION_FOR_PTR(ptr), 0);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/magazine_testing.h",
    "content": "/*\n * Copyright (c) 2016 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __MAGAZINE_TESTING\n#define __MAGAZINE_TESTING\n\n// Import the mvm_* functions for magazines to use\n#import \"../src/vm.c\"\n\n#import \"../src/magazine_rack.c\"\n\nboolean_t\nmalloc_tracing_enabled = 0;\n\nint\nrecirc_retained_regions = DEFAULT_RECIRC_RETAINED_REGIONS;\n\n// Stub out cross-file dependencies so that they just assert.\nvoid malloc_report(uint32_t flags, const char *fmt, ...)\n{\n\t__builtin_trap();\n}\n\nvoid\nmalloc_zone_error(uint32_t flags, bool is_corruption, const char *fmt, ...)\n{\n\t__builtin_trap();\n}\nvoid\nmalloc_zone_check_fail(const char *msg, const char *fmt, ...)\n{\n\t__builtin_trap();\n}\n\nvoid\nszone_free(szone_t *szone, void *ptr)\n{\n\t__builtin_trap();\n}\n\nvoid *\nszone_malloc(szone_t *szone, size_t size)\n{\n\t__builtin_trap();\n}\n\n#endif // __MAGAZINE_TESTING\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/magazine_tiny_test.c",
    "content": "//\n//  magazine_tiny_test.c\n//  libmalloc\n//\n//  Created by Matt Wright on 8/22/16.\n//\n//\n\n#include <darwintest.h>\n\n#include \"../src/magazine_tiny.c\"\n#include \"magazine_testing.h\"\n\nstatic inline void\ntest_rack_setup(rack_t *rack)\n{\n\tmemset(rack, 'a', sizeof(rack));\n\track_init(rack, RACK_TYPE_TINY, 1, 0);\n\tT_QUIET; T_ASSERT_NOTNULL(rack->magazines, \"magazine initialisation\");\n}\n\nT_DECL(basic_tiny_alloc, \"tiny rack init and alloc\")\n{\n\tstruct rack_s rack;\n\ttest_rack_setup(&rack);\n\n\tvoid *ptr = tiny_malloc_should_clear(&rack, TINY_MSIZE_FOR_BYTES(32), false);\n\tT_ASSERT_NOTNULL(ptr, \"allocation\");\n\n\tregion_t *rgn = tiny_region_for_ptr_no_lock(&rack, ptr);\n\tT_ASSERT_NOTNULL(rgn, \"allocation region found in rack\");\n\n\tsize_t sz = tiny_size(&rack, ptr);\n\tT_ASSERT_EQ((int)sz, 32, \"size == 32\");\n}\n\nT_DECL(basic_tiny_teardown, \"tiny rack init, alloc, teardown\")\n{\n\tstruct rack_s rack;\n\ttest_rack_setup(&rack);\n\n\tvoid *ptr = tiny_malloc_should_clear(&rack, TINY_MSIZE_FOR_BYTES(32), false);\n\tT_ASSERT_NOTNULL(ptr, \"allocation\");\n\n\track_destroy_regions(&rack, TINY_REGION_SIZE);\n\tfor (int i=0; i < rack.region_generation->num_regions_allocated; i++) {\n\t\tT_QUIET;\n\t\tT_ASSERT_TRUE(rack.region_generation->hashed_regions[i] == HASHRING_OPEN_ENTRY ||\n\t\t\t\t\t  rack.region_generation->hashed_regions[i] == HASHRING_REGION_DEALLOCATED,\n\t\t\t\t\t  \"all regions destroyed\");\n\t}\n\n\track_destroy(&rack);\n\tT_ASSERT_NULL(rack.magazines, \"magazines destroyed\");\n}\n\nT_DECL(basic_tiny_free, \"tiny free\")\n{\n\tstruct rack_s rack;\n\ttest_rack_setup(&rack);\n\n\tvoid *ptr = tiny_malloc_should_clear(&rack, TINY_MSIZE_FOR_BYTES(32), false);\n\tT_ASSERT_NOTNULL(ptr, \"allocation\");\n\n\t// free doesn't return an error (unless we assert here)\n\tfree_tiny(&rack, ptr, TINY_REGION_FOR_PTR(ptr), 0);\n\n\tsize_t sz = tiny_size(&rack, ptr);\n\tT_ASSERT_EQ((int)sz, 0, \"allocation freed (sz == 0)\");\n}\n\nT_DECL(basic_tiny_shrink, \"tiny rack shrink\")\n{\n\tstruct rack_s rack;\n\ttest_rack_setup(&rack);\n\n\tvoid *ptr = tiny_malloc_should_clear(&rack, TINY_MSIZE_FOR_BYTES(64), false);\n\tT_ASSERT_NOTNULL(ptr, \"allocation\");\n\n\tsize_t sz = tiny_size(&rack, ptr);\n\tT_ASSERT_EQ((int)sz, 64, \"size == 64\");\n\n\tvoid *nptr = tiny_try_shrink_in_place(&rack, ptr, sz, 16);\n\tsize_t nsz = tiny_size(&rack, nptr);\n\tT_ASSERT_EQ_PTR(ptr, nptr, \"ptr == nptr\");\n\tT_ASSERT_EQ((int)nsz, 16, \"nsz == 16\");\n}\n\nT_DECL(basic_tiny_realloc_in_place, \"tiny rack realloc in place\")\n{\n\tstruct rack_s rack;\n\ttest_rack_setup(&rack);\n\n\t// Allocate two blocks and free the second, then try to realloc() the first.\n\t// This should extend in-place using the one-level death row cache that's\n\t// occupied by the second block.\n\tvoid *ptr = tiny_malloc_should_clear(&rack, TINY_MSIZE_FOR_BYTES(16), false);\n\tT_ASSERT_NOTNULL(ptr, \"allocation\");\n\n\tsize_t sz = tiny_size(&rack, ptr);\n\tT_ASSERT_EQ((int)sz, 16, \"size == 16\");\n\n\tvoid *ptr2 = tiny_malloc_should_clear(&rack, TINY_MSIZE_FOR_BYTES(16), false);\n\tT_ASSERT_NOTNULL(ptr2, \"allocation 2\");\n\tT_ASSERT_EQ_PTR(ptr2, (void *)((uintptr_t)ptr + 16), \"sequential allocations\");\n\tfree_tiny(&rack, ptr2, TINY_REGION_FOR_PTR(ptr2), 0);\n\n\t// Attempt to realloc up to 32 bytes, this should happen in place\n\t// because of the death-row cache.\n\tboolean_t reallocd = tiny_try_realloc_in_place(&rack, ptr, sz, 32);\n\tT_ASSERT_TRUE(reallocd, \"realloced #1\");\n\n\tsize_t nsz = tiny_size(&rack, ptr);\n\tT_ASSERT_EQ((int)nsz, 32, \"realloc size == 32\");\n\n\t// Try another realloc(). This should extend in place because the rest of\n\t// the rack is empty.\n\treallocd = tiny_try_realloc_in_place(&rack, ptr, nsz, 64);\n\tT_ASSERT_TRUE(reallocd, \"realloced #2\");\n\tnsz = tiny_size(&rack, ptr);\n\tT_ASSERT_EQ((int)nsz, 64, \"realloc size == 64\");\n\n\tfree_tiny(&rack, ptr, TINY_REGION_FOR_PTR(ptr), 0);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/malloc_claimed_address_tests.c",
    "content": "//\n//  malloc_claimed_address_tests.c\n//  libmalloc\n//\n//  Tests for malloc_claimed_address() and malloc_zone_claimed_address().\n//\n\n#include <darwintest.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <mach/mach.h>\n#include <mach/mach_vm.h>\n#include <malloc.h>\n#include <malloc/malloc.h>\n#include <malloc_private.h>\n#include <sys/mman.h>\n\nT_DECL(malloc_claimed_address_default_zone_test,\n\t\t\"Tests for malloc_claimed_address, default zone only\",\n\t\tT_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\t// NULL is never a possible pointer.\n\tboolean_t result = malloc_claimed_address(NULL);\n\tT_EXPECT_FALSE(result, \"NULL is never a valid pointer\");\n\n\t// Allocate from tiny, check that it's claimed.\n\tvoid *ptr = malloc(16);\n\tresult = malloc_claimed_address(ptr);\n\tT_EXPECT_TRUE(result, \"allocation from tiny\");\n\n\t// Offset from the pointer, check that it's still claimed.\n\tresult = malloc_claimed_address(ptr + 8);\n\tT_EXPECT_TRUE(result, \"allocation from tiny with offset\");\n\tfree(ptr);\n\n\t// Allocate from small, check that it's claimed.\n\tptr =  malloc(2048);\n\tresult = malloc_claimed_address(ptr);\n\tT_EXPECT_TRUE(result, \"allocation from small\");\n\n\t// Offset from the pointer, check that it's still claimed.\n\tresult = malloc_claimed_address(ptr + 1000);\n\tT_EXPECT_TRUE(result, \"allocation from small with offset\");\n\tfree(ptr);\n\n\t// Allocate from large, check that it's claimed.\n\tptr =  malloc(140000);\n\tresult = malloc_claimed_address(ptr);\n\tT_EXPECT_TRUE(result, \"allocation from large\");\n\n\t// Offset from the pointer, check that it's still claimed.\n\tresult = malloc_claimed_address(ptr + 1000);\n\tT_EXPECT_TRUE(result, \"allocation from large with offset\");\n\tfree(ptr);\n\n\t// Allocate some memory with vm_allocate() and make sure it's not claimed.\n\tmach_vm_address_t addr;\n\tkern_return_t kr = mach_vm_allocate(mach_task_self(), &addr, 1024, VM_FLAGS_ANYWHERE);\n\tT_ASSERT_TRUE(kr == KERN_SUCCESS, \"allocate vm space\");\n\tresult = malloc_claimed_address((void *)addr);\n\tT_EXPECT_FALSE(result, \"address in VM allocated memory\");\n\tmach_vm_deallocate(mach_task_self(), addr, 1024);\n}\n\n\nT_DECL(malloc_zone_claimed_address_test,\n\t\t\"Tests for malloc_zone_claimed_address\",\n\t\tT_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\tmalloc_zone_t *zone = malloc_create_zone(0, 0);\n\n\t// NULL is never a possible pointer.\n\tboolean_t result = malloc_zone_claimed_address(zone, NULL);\n\tT_EXPECT_FALSE(result, \"NULL is never a valid pointer\");\n\n\t// Allocate from tiny, check that it's claimed.\n\tvoid *ptr = malloc_zone_malloc(zone, 16);\n\tresult = malloc_zone_claimed_address(zone, ptr);\n\tT_EXPECT_TRUE(result, \"allocation from tiny\");\n\n\t// Offset from the pointer, check that it's still claimed.\n\tresult = malloc_zone_claimed_address(zone, ptr + 8);\n\tT_EXPECT_TRUE(result, \"allocation from tiny with offset\");\n\tfree(ptr);\n\n\t// Allocate with tiny from the default zone, check that it's not claimed.\n\tptr = malloc(16);\n\tresult = malloc_zone_claimed_address(zone, ptr);\n\tT_EXPECT_FALSE(result, \"allocation from tiny in default zone\");\n\tresult = malloc_zone_claimed_address(zone, ptr + 8);\n\tT_EXPECT_FALSE(result, \"allocation from tiny in default zone with offset\");\n\tfree(ptr);\n\n\t// Allocate from small, check that it's claimed.\n\tptr =  malloc_zone_malloc(zone, 2048);\n\tresult = malloc_zone_claimed_address(zone, ptr);\n\tT_EXPECT_TRUE(result, \"allocation from small\");\n\n\t// Offset from the pointer, check that it's still claimed.\n\tresult = malloc_zone_claimed_address(zone, ptr + 1000);\n\tT_EXPECT_TRUE(result, \"allocation from small with offset\");\n\tfree(ptr);\n\n\t// Allocate with small from the default zone, check that it's not claimed.\n\tptr = malloc(2048);\n\tresult = malloc_zone_claimed_address(zone, ptr);\n\tT_EXPECT_FALSE(result, \"allocation from small in default zone\");\n\tresult = malloc_zone_claimed_address(zone, ptr + 8);\n\tT_EXPECT_FALSE(result, \"allocation from small in default zone with offset\");\n\tfree(ptr);\n\n\t// Allocate from large, check that it's claimed.\n\tptr =  malloc_zone_malloc(zone, 140000);\n\tresult = malloc_zone_claimed_address(zone, ptr);\n\tT_EXPECT_TRUE(result, \"allocation from large\");\n\n\t// Offset from the pointer, check that it's still claimed.\n\tresult = malloc_zone_claimed_address(zone, ptr + 1000);\n\tT_EXPECT_TRUE(result, \"allocation from large with offset\");\n\tfree(ptr);\n\n\t// Allocate with large from the default zone, check that it's not claimed.\n\tptr = malloc(140000);\n\tresult = malloc_zone_claimed_address(zone, ptr);\n\tT_EXPECT_FALSE(result, \"allocation from large in default zone\");\n\tresult = malloc_zone_claimed_address(zone, ptr + 8);\n\tT_EXPECT_FALSE(result, \"allocation from large in default zone with offset\");\n\tfree(ptr);\n\n\t// Allocate some memory with vm_allocate() and make sure it's not claimed.\n\tmach_vm_address_t addr;\n\tkern_return_t kr = mach_vm_allocate(mach_task_self(), &addr, 1024, VM_FLAGS_ANYWHERE);\n\tT_ASSERT_TRUE(kr == KERN_SUCCESS, \"allocate vm space\");\n\tresult = malloc_zone_claimed_address(zone, (void *)addr);\n\tT_EXPECT_FALSE(result, \"address in VM allocated memory\");\n\tmach_vm_deallocate(mach_task_self(), addr, 1024);\n\n\tmalloc_destroy_zone(zone);\n}\n\nT_DECL(malloc_claimed_address_zone_test,\n\t\t\"Tests for malloc_claimed_address with another zone\",\n\t\tT_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\t// Allocate in a custom zone, check that we can still use\n\t// malloc_claimed_address() to check whether an address is claimed.\n\tmalloc_zone_t *zone = malloc_create_zone(0, 0);\n\n\t// Allocate from tiny, check that it's claimed.\n\tvoid *ptr = malloc_zone_malloc(zone, 16);\n\tboolean_t result = malloc_claimed_address(ptr);\n\tT_EXPECT_TRUE(result, \"allocation from tiny\");\n\n\t// Offset from the pointer, check that it's still claimed.\n\tresult = malloc_claimed_address(ptr + 8);\n\tT_EXPECT_TRUE(result, \"allocation from tiny with offset\");\n\tfree(ptr);\n\n\t// Allocate from small, check that it's claimed.\n\tptr =  malloc_zone_malloc(zone, 2048);\n\tresult = malloc_claimed_address(ptr);\n\tT_EXPECT_TRUE(result, \"allocation from small\");\n\n\t// Offset from the pointer, check that it's still claimed.\n\tresult = malloc_claimed_address(ptr + 1000);\n\tT_EXPECT_TRUE(result, \"allocation from small with offset\");\n\tfree(ptr);\n\n\t// Allocate from large, check that it's claimed.\n\tptr =  malloc_zone_malloc(zone, 140000);\n\tresult = malloc_claimed_address(ptr);\n\tT_EXPECT_TRUE(result, \"allocation from large\");\n\n\t// Offset from the pointer, check that it's still claimed.\n\tresult = malloc_claimed_address(ptr + 1000);\n\tT_EXPECT_TRUE(result, \"allocation from large with offset\");\n\tfree(ptr);\n\n\tmalloc_destroy_zone(zone);\n}\n\nT_DECL(malloc_claimed_address_nanozone_test,\n\t\t\"Tests for malloc_claimed_address with nano\",\n\t\tT_META_ENVVAR(\"MallocNanoZone=1\"))\n{\n\t// NULL is never a possible pointer.\n\tboolean_t result = malloc_claimed_address(NULL);\n\tT_EXPECT_FALSE(result, \"NULL is never a valid pointer\");\n\n\t// Allocate various sizes, check that they are claimed and that offset\n\t// pointers are also claimed.\n\tfor (size_t sz = 16; sz <= 256; sz += 16) {\n\t\tvoid *ptr = malloc(sz);\n\t\tresult = malloc_claimed_address(ptr);\n\t\tT_EXPECT_TRUE(result, \"nano allocation size %d\", (int)sz);\n\t\tresult = malloc_claimed_address(ptr + sz/2);\n\t\tT_EXPECT_TRUE(result, \"nano allocation size %d offset %d\", (int)sz, (int)sz/2);\n\t\tfree(ptr);\n\t}\n\n\t// Allocate some memory with vm_allocate() and make sure it's not claimed.\n\tmach_vm_address_t addr;\n\tkern_return_t kr = mach_vm_allocate(mach_task_self(), &addr, 1024, VM_FLAGS_ANYWHERE);\n\tT_ASSERT_TRUE(kr == KERN_SUCCESS, \"allocate vm space\");\n\tresult = malloc_claimed_address((void *)addr);\n\tT_EXPECT_FALSE(result, \"address in VM allocated memory\");\n\tmach_vm_deallocate(mach_task_self(), addr, 1024);\n}\n\n\nT_DECL(malloc_claimed_address_custom_zone_test,\n\t\t\"Tests for malloc_claimed_address in a zone that does not implement it\",\n\t\tT_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\t// Custom zones that do not support claimed_address must always appear\n\t// to return true.\n\tmalloc_zone_t *zone = malloc_create_zone(0, 0);\n\tmprotect(zone, sizeof(*zone), PROT_READ | PROT_WRITE);\n\tzone->version = 9;\n\tzone->claimed_address = NULL;\n\tmprotect(zone, sizeof(*zone), PROT_READ);\n\n\t// NULL must still be disclaimed.\n\tboolean_t result = malloc_zone_claimed_address(zone, NULL);\n\tT_EXPECT_FALSE(result, \"NULL is never a valid pointer\");\n\n\t// Allocate from tiny, check that it's claimed.\n\tvoid *ptr = malloc_zone_malloc(zone, 16);\n\tresult = malloc_claimed_address(ptr);\n\tT_EXPECT_TRUE(result, \"allocation from tiny\");\n\n\t// Offset from the pointer, check that it's still claimed.\n\tresult = malloc_claimed_address(ptr + 8);\n\tT_EXPECT_TRUE(result, \"allocation from tiny with offset\");\n\tfree(ptr);\n\n\t// Allocate from small, check that it's claimed.\n\tptr =  malloc_zone_malloc(zone, 2048);\n\tresult = malloc_claimed_address(ptr);\n\tT_EXPECT_TRUE(result, \"allocation from small\");\n\n\t// Offset from the pointer, check that it's still claimed.\n\tresult = malloc_claimed_address(ptr + 1000);\n\tT_EXPECT_TRUE(result, \"allocation from small with offset\");\n\tfree(ptr);\n\n\t// Allocate from large, check that it's claimed.\n\tptr =  malloc_zone_malloc(zone, 140000);\n\tresult = malloc_claimed_address(ptr);\n\tT_EXPECT_TRUE(result, \"allocation from large\");\n\n\t// Offset from the pointer, check that it's still claimed.\n\tresult = malloc_claimed_address(ptr + 1000);\n\tT_EXPECT_TRUE(result, \"allocation from large with offset\");\n\tfree(ptr);\n\n\tmalloc_destroy_zone(zone);\n}\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/malloc_free_test.c",
    "content": "//\n//  malloc_free_test.c\n//  libmalloc\n//\n//  test allocating and freeing all sizes\n//\n\n#include <darwintest.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <malloc/malloc.h>\n\nstatic inline void*\nt_malloc(size_t s)\n{\n\tvoid *ptr = malloc(s);\n\tT_QUIET; T_ASSERT_NOTNULL(ptr, \"allocation\");\n\tsize_t sz = malloc_size(ptr);\n\tT_QUIET; T_EXPECT_LE(s, sz, \"allocation size\");\n\tconst uint64_t pat = 0xdeadbeefcafebabeull;\n\tmemset_pattern8(ptr, &pat, s);\n\treturn ptr;\n}\n\nstatic void\ntest_malloc_free(size_t min, size_t max, size_t incr)\n{\n\tfor (size_t s =  min; s <= max; s += incr) {\n\t\tvoid *ptr = t_malloc(s);\n\t\tfree(ptr); // try to go through mag_last_free SMALL_CACHE\n\t}\n\tfor (size_t s = min, t = max; s <= max; s += incr, t -= incr) {\n\t\tvoid *ptr1 = t_malloc(s);\n\t\tvoid *ptr2 = t_malloc(t);\n\t\tfree(ptr1); // try to defeat mag_last_free SMALL_CACHE\n\t\tfree(ptr2);\n\t}\n}\n\nstatic void\ntest_malloc_free_random(size_t min, size_t max, size_t incr, size_t n)\n{\n\tconst size_t r = (max - min) / incr, P = 100;\n\tvoid *ptrs[P] = {};\n\tfor (size_t i = 0, j = 0, k = 0; i < n + P; i++, j = k, k = (k + 1) % P) {\n\t\tvoid *ptr = NULL;\n\t\tif (i < n) ptr = t_malloc(min + arc4random_uniform(r) * incr);\n\t\tfree(ptrs[j]);\n\t\tptrs[k] = ptr;\n\t}\n}\n\nT_DECL(malloc_free_nano, \"nanomalloc and free all sizes <= 256\",\n\t   T_META_ENVVAR(\"MallocNanoZone=1\"))\n{\n\ttest_malloc_free(0, 256, 1); // NANO_MAX_SIZE\n\ttest_malloc_free_random(0, 256, 1, 10000);\n}\n\nT_DECL(malloc_free_tiny, \"tiny malloc and free 16b increments <= 1008\",\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\ttest_malloc_free(0, 1008, 16); // SMALL_THRESHOLD\n\ttest_malloc_free_random(0, 1008, 16, 10000);\n}\n\nT_DECL(malloc_free, \"malloc and free all 512b increments <= 256kb\",\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\ttest_malloc_free(1024, 256 * 1024, 512); // > LARGE_THRESHOLD_LARGEMEM\n\ttest_malloc_free_random(1024, 256 * 1024, 512, 100000);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/malloc_size_test.c",
    "content": "//\n//  malloc_size_test.c\n//  libmalloc\n//\n//  Tests for malloc_size() on both good and bad pointers.\n//\n\n#include <darwintest.h>\n#include <stdlib.h>\n#include <malloc/malloc.h>\n\nstatic void\ntest_malloc_size_valid(size_t min, size_t max, size_t incr)\n{\n\tfor (size_t sz = min; sz <= max; sz += incr) {\n\t\tvoid *ptr = malloc(sz);\n\t\tT_ASSERT_NOTNULL(ptr, \"Allocate size %llu\\n\", (uint64_t)sz);\n\t\tT_ASSERT_EQ(malloc_size(ptr), malloc_good_size(sz), \"Check size value\");\n\t\tfree(ptr);\n\t}\n}\n\nstatic void\ntest_malloc_size_invalid(size_t min, size_t max, size_t incr)\n{\n\tfor (size_t sz = min; sz <= max; sz += incr) {\n\t\tvoid *ptr = malloc(sz);\n\t\tT_ASSERT_NOTNULL(ptr, \"Allocate size %llu\\n\", (uint64_t)sz);\n\t\tT_ASSERT_EQ(malloc_size(ptr + 1), 0UL, \"Check offset by 1 size value\");\n\t\tT_ASSERT_EQ(malloc_size(ptr + sz/2), 0UL, \"Check offset by half size value\");\n\t\tfree(ptr);\n\t}\n}\n\nT_DECL(malloc_size_valid, \"Test malloc_size() on valid pointers, non-Nano\",\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\t// Test various sizes, roughly targetting each allocator range.\n\ttest_malloc_size_valid(2, 256, 16);\n\ttest_malloc_size_valid(512, 8192, 256);\n\ttest_malloc_size_valid(8192, 65536, 1024);\n}\n\nT_DECL(malloc_size_valid_nanov1, \"Test malloc_size() on valid pointers for Nanov1\",\n\t   T_META_ENVVAR(\"MallocNanoZone=V1\"))\n{\n\ttest_malloc_size_valid(2, 256, 16);\n}\n\nT_DECL(malloc_size_valid_nanov2, \"Test malloc_size() on valid pointers for Nanov2\",\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n\ttest_malloc_size_valid(2, 256, 16);\n}\n\nT_DECL(malloc_size_invalid, \"Test malloc_size() on invalid pointers, non-Nano\",\n\t   T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\t// Test various sizes, roughly targetting each allocator range.\n\ttest_malloc_size_invalid(2, 256, 16);\n\ttest_malloc_size_invalid(512, 8192, 256);\n\ttest_malloc_size_invalid(8192, 32768, 1024);\n}\n\nT_DECL(malloc_size_invalid_nanov1, \"Test malloc_size() on valid pointers for Nanov1\",\n\t   T_META_ENVVAR(\"MallocNanoZone=V1\"))\n{\n\ttest_malloc_size_invalid(2, 256, 16);\n}\n\nT_DECL(malloc_size_invalid_nanov2, \"Test malloc_size() on valid pointers for Nanov2\",\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n\ttest_malloc_size_invalid(2, 256, 16);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/nano_tests.c",
    "content": "//\n//  nano_tests.c\n//  libmalloc\n//\n//  Tests that are specific to the implementation details of Nanov2.\n//\n#include <TargetConditionals.h>\n#include <darwintest.h>\n#include <darwintest_utils.h>\n#include <spawn.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/wait.h>\n#include <malloc/malloc.h>\n#include <../private/malloc_private.h>\n#include <../src/internal.h>\n\n#if CONFIG_NANOZONE\n\n#pragma mark -\n#pragma mark Enumerator access\n\nstatic int range_count;\t\t\t\t\t// Total number of allocated ranges\nstatic int ptr_count;\t\t\t\t\t// Total number of allocated pointers\nstatic size_t total_ranges_size;\t\t// Size of all allocated ranges\nstatic size_t total_in_use_ptr_size;\t// Size of all allocated pointers\n\nstatic void\nrange_recorder(task_t task, void *context, unsigned type, vm_range_t *ranges,\n\t\t\t   unsigned count)\n{\n\tfor (int i = 0; i < count; i++) {\n\t\ttotal_ranges_size += ranges[i].size;\n\t}\n\trange_count += count;\n}\n\nstatic void\npointer_recorder(task_t task, void *context, unsigned type, vm_range_t *ranges,\n\t\t\t unsigned count)\n{\n\tfor (int i = 0; i < count; i++) {\n\t\ttotal_in_use_ptr_size += ranges[i].size;\n\t}\n\tptr_count += count;\n}\n\nstatic kern_return_t\nmemory_reader(task_t remote_task, vm_address_t remote_address, vm_size_t size,\n\t\t\t  void **local_memory)\n{\n\tif (local_memory) {\n\t\t*local_memory = (void*)remote_address;\n\t\treturn KERN_SUCCESS;\n\t}\n\treturn KERN_FAILURE;\n}\n\nstatic void\nrun_enumerator()\n{\n\ttotal_ranges_size = 0;\n\ttotal_in_use_ptr_size = 0;\n\trange_count = 0;\n\tptr_count = 0;\n\tmalloc_zone_t *zone = malloc_default_zone();\n\tzone->introspect->enumerator(mach_task_self(), NULL,\n\t\t\tMALLOC_PTR_REGION_RANGE_TYPE, (vm_address_t)zone, memory_reader,\n\t\t\trange_recorder);\n\tzone->introspect->enumerator(mach_task_self(), NULL,\n\t\t\tMALLOC_PTR_IN_USE_RANGE_TYPE, (vm_address_t)zone, memory_reader,\n\t\t\tpointer_recorder);\n}\n\n#endif // CONFIG_NANOZONE\n\n#pragma mark -\n#pragma mark Enumerator tests\n\n#if TARGET_OS_WATCH\n#define ALLOCATION_COUNT 10000\n#else // TARGET_OS_WATCH\n#define ALLOCATION_COUNT 100000\n#endif // TARGET_OS_WATCH\n\nstatic void *allocations[ALLOCATION_COUNT];\n\nT_DECL(nano_active_test, \"Test that Nano is activated\",\n\t   T_META_ENVVAR(\"MallocNanoZone=1\"))\n{\n#if CONFIG_NANOZONE\n\tvoid *ptr = malloc(16);\n\tT_LOG(\"Nano ptr is %p\\n\", ptr);\n\tT_ASSERT_EQ(NANOZONE_SIGNATURE, (uint64_t)((uintptr_t)ptr) >> SHIFT_NANO_SIGNATURE,\n\t\t\t\"Nanozone is active\");\n\tT_ASSERT_NE(malloc_engaged_nano(), 0, \"Nanozone engaged\");\n\tfree(ptr);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(nano_enumerator_test, \"Test the Nanov2 enumerator\",\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n#if CONFIG_NANOZONE\n\tT_ASSERT_EQ(malloc_engaged_nano(), 2, \"Nanozone V2 engaged\");\n\n\t// This test is problematic because the allocator is used before the test\n\t// starts, so we can't start everything from zero.\n\t// Grab a baseline\n\tmalloc_statistics_t stats;\n\tmalloc_zone_statistics(malloc_default_zone(), &stats);\n\tconst unsigned int initial_blocks_in_use = stats.blocks_in_use;\n\tconst size_t initial_size_in_use = stats.size_in_use;\n\tconst size_t initial_size_allocated = stats.size_allocated;\n\n\trun_enumerator();\n\tconst int initial_ptrs = ptr_count;\n\tconst size_t initial_ranges_size = total_ranges_size;\n\tconst size_t initial_in_use_ptr_size = total_in_use_ptr_size;\n\n\t// Allocate memory of random sizes, all less than the max Nano size.\n\tsize_t total_requested_size = 0;\n\tfor (int i = 0; i < ALLOCATION_COUNT; i++) {\n\t\tsize_t sz = malloc_good_size(arc4random_uniform(257));\n\t\tallocations[i] = malloc(sz);\n\t\ttotal_requested_size += sz;\n\t}\n\n\t// Get the stats and enumerator values again and check whether the result is consistent.\n\tmalloc_zone_statistics(malloc_default_zone(), &stats);\n\trun_enumerator();\n\n\tT_ASSERT_EQ(stats.blocks_in_use, initial_blocks_in_use + ALLOCATION_COUNT,\n\t\t\t\"Incorrect blocks_in_use\");\n\tT_ASSERT_EQ(stats.size_in_use, initial_size_in_use + total_requested_size,\n\t\t\t\"Incorrect size_in_use\");\n\tT_ASSERT_TRUE(stats.size_allocated - initial_size_allocated >= total_requested_size,\n\t\t\t\"Size allocated must be >= size requested\");\n\n\tT_ASSERT_EQ(ptr_count, initial_ptrs + ALLOCATION_COUNT,\n\t\t\t\"Incorrect number of pointers\");\n\tT_ASSERT_EQ(total_in_use_ptr_size, initial_in_use_ptr_size + total_requested_size,\n\t\t\t\"Incorrect in-use pointer size\");\n\n\t// Free half of the memory and recheck the statistics\n\tsize_t size_freed = 0;\n\tfor (int i = 0; i < ALLOCATION_COUNT / 2; i++) {\n\t\tsize_freed += malloc_size(allocations[i]);\n\t\tfree(allocations[i]);\n\t}\n\n\t// Check the stats and enumerator values.\n\tmalloc_zone_statistics(malloc_default_zone(), &stats);\n\trun_enumerator();\n\tT_ASSERT_EQ(stats.blocks_in_use, initial_blocks_in_use + ALLOCATION_COUNT/2,\n\t\t\t\"Incorrect blocks_in_use after half free\");\n\tT_ASSERT_EQ(stats.size_in_use,\n\t\t\tinitial_size_in_use + total_requested_size - size_freed,\n\t\t\t\"Incorrect size_in_use after half free\");\n\tT_ASSERT_TRUE(stats.size_allocated >= initial_size_allocated ,\n\t\t\t\"Size allocated must be >= size requested\");\n\n\tT_ASSERT_EQ(ptr_count, initial_ptrs + ALLOCATION_COUNT / 2,\n\t\t\t\"Incorrect number of pointers after half free\");\n\tT_ASSERT_EQ(total_in_use_ptr_size,\n\t\t\tinitial_in_use_ptr_size + total_requested_size - size_freed,\n\t\t\t\"Incorrect in-use pointer size after half free\");\n\n\t// Free the rest the memory and recheck the statistics\n\tfor (int i = ALLOCATION_COUNT / 2; i < ALLOCATION_COUNT; i++) {\n\t\tfree(allocations[i]);\n\t}\n\t\n\t// Check the stats and enumerator values one more time.\n\tmalloc_zone_statistics(malloc_default_zone(), &stats);\n\trun_enumerator();\n\n\tT_ASSERT_EQ(stats.blocks_in_use, initial_blocks_in_use,\n\t\t\t\"Incorrect blocks_in_use after full free\");\n\tT_ASSERT_EQ(stats.size_in_use, initial_size_in_use,\n\t\t\t\"Incorrect size_in_use after full free\");\n\tT_ASSERT_TRUE(stats.size_allocated >= initial_size_allocated ,\n\t\t\t\"Size allocated must be >= size requested\");\n\t\n\tT_ASSERT_EQ(ptr_count, initial_ptrs, \"Incorrect number of pointers after free\");\n\tT_ASSERT_EQ(total_in_use_ptr_size, initial_in_use_ptr_size,\n\t\t\t\"Incorrect in-use pointer size after free\");\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\n#pragma mark -\n#pragma mark Nano realloc tests\n\n// These tests are specific to the Nano implementation of realloc(). They\n// don't necessarily work with other allocators, since the behavior tested is\n// not part of the documented behavior of realloc().\n\nconst char * const data = \"abcdefghijklm\";\n\nT_DECL(realloc_nano_size_class_change, \"realloc with size class change\",\n\t   T_META_ENVVAR(\"MallocNanoZone=1\"))\n{\n#if CONFIG_NANOZONE\n\tvoid *ptr = malloc(16);\n\tstrcpy(ptr, data);\n\tvoid *new_ptr;\n\n\t// Each pass of the loop realloc's to the next size class up. We must\n\t// get a new pointer each time and the content must have been copied.\n\tfor (int i = 32; i <= 256; i += 16) {\n\t\tnew_ptr = realloc(ptr, i);\n\t\tT_QUIET; T_ASSERT_TRUE(ptr != new_ptr, \"realloc pointer should change\");\n\t\tT_QUIET; T_ASSERT_EQ(i, (int)malloc_size(new_ptr), \"Check size for new allocation\");\n\t\tT_QUIET; T_ASSERT_TRUE(!strncmp(new_ptr, data, strlen(data)), \"Content must be copied\");\n\t\tT_QUIET; T_ASSERT_EQ(0, (int)malloc_size(ptr), \"Old allocation not freed\");\n\t\tptr = new_ptr;\n\t}\n\tfree(new_ptr);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(realloc_nano_ptr_change, \"realloc with pointer change\",\n\t   T_META_ENVVAR(\"MallocNanoZone=1\"))\n{\n#if CONFIG_NANOZONE\n\tvoid *ptr = malloc(32);\n\tstrcpy(ptr, data);\n\n\tvoid *new_ptr = realloc(ptr, 128);\n\tT_ASSERT_TRUE(ptr != new_ptr, \"realloc pointer should change\");\n\tT_ASSERT_EQ(128, (int)malloc_size(new_ptr), \"Wrong size for new allocation\");\n\tT_ASSERT_TRUE(!strncmp(new_ptr, data, strlen(data)), \"Content must be copied\");\n\tT_ASSERT_EQ(0, (int)malloc_size(ptr), \"Old allocation not freed\");\n\t\n\tfree(new_ptr);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(realloc_nano_to_other, \"realloc with allocator change (nano)\",\n\t   T_META_ENVVAR(\"MallocNanoZone=1\"))\n{\n#if CONFIG_NANOZONE\n\tvoid *ptr = malloc(32);\t\t\t\t\t// From Nano\n\tstrcpy(ptr, data);\n\n\tvoid *new_ptr = realloc(ptr, 1024);\t\t// Cannot be Nano.\n\n\tT_ASSERT_TRUE(ptr != new_ptr, \"realloc pointer should change\");\n\tT_ASSERT_EQ(1024, (int)malloc_size(new_ptr), \"Wrong size for new allocation\");\n\tT_ASSERT_TRUE(!strncmp(new_ptr, data, strlen(data)), \"Content must be copied\");\n\tT_ASSERT_EQ(0, (int)malloc_size(ptr), \"Old allocation not freed\");\n\n\tfree(new_ptr);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(realloc_nano_to_zero_size, \"realloc with target size zero\",\n\t   T_META_ENVVAR(\"MallocNanoZone=1\"))\n{\n#if CONFIG_NANOZONE\n\tvoid *ptr = malloc(16);\n\n\t// Realloc to 0 frees the old memory and returns a valid pointer.\n\tvoid *new_ptr = realloc(ptr, 0);\n\tT_ASSERT_EQ(0, (int)malloc_size(ptr), \"Old allocation not freed\");\n\tT_ASSERT_NOTNULL(new_ptr, \"New allocation must be non-NULL\");\n\tT_ASSERT_TRUE(malloc_size(new_ptr) > 0, \"New allocation not known\");\n\n\tfree(new_ptr);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(realloc_nano_shrink, \"realloc to smaller size\",\n\t   T_META_ENVVAR(\"MallocNanoZone=1\"))\n{\n#if CONFIG_NANOZONE\n\tvoid *ptr = malloc(64);\n\tstrcpy(ptr, data);\n\n\t// Reallocate to greater than half the current size - should remain\n\t// in-place.\n\tvoid *new_ptr = realloc(ptr, 40);\n\tT_ASSERT_TRUE(ptr == new_ptr, \"realloc pointer should not change\");\n\tT_ASSERT_TRUE(!strncmp(new_ptr, data, strlen(data)), \"Content changed\");\n\n\t// Reallocate to less than half the current size - should get a new pointer\n\t// Realloc to 0 frees the old memory and returns a valid pointer.\n\tptr = new_ptr;\n\tnew_ptr = realloc(ptr, 16);\n\tT_ASSERT_TRUE(ptr != new_ptr, \"realloc pointer should change\");\n\tT_ASSERT_TRUE(!strncmp(new_ptr, data, strlen(data)), \"Content must be copied\");\n\n\tfree(new_ptr);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\n#pragma mark -\n#pragma mark Nanov2 tests\n\n// These tests are specific to the implementation of the Nanov2 allocator.\n\n// Guaranteed number of 256-byte allocations to be sure we fill an arena.\n#define ALLOCS_PER_ARENA ((NANOV2_ARENA_SIZE)/256)\n\nT_DECL(overspill_arena, \"force overspill of an arena\",\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n#if CONFIG_NANOZONE\n\tvoid **ptrs = calloc(ALLOCS_PER_ARENA, sizeof(void *));\n\tT_QUIET; T_ASSERT_NOTNULL(ptrs, \"Unable to allocate pointers\");\n\tint index;\n\n\tnanov2_addr_t first_ptr;\n\tptrs[0] = malloc(256);\n\tT_QUIET; T_ASSERT_NOTNULL(ptrs[index], \"Failed to allocate\");\n\tfirst_ptr.addr = ptrs[0];\n\n\tfor (index = 1; index < ALLOCS_PER_ARENA; index++) {\n\t\tptrs[index] = malloc(256);\n\t\tT_QUIET; T_ASSERT_NOTNULL(ptrs[index], \"Failed to allocate\");\n\n\t\t// Stop allocating once we have crossed into a new arena.\n\t\tnanov2_addr_t current_ptr;\n\t\tcurrent_ptr.addr = ptrs[index];\n\t\tif (current_ptr.fields.nano_arena != first_ptr.fields.nano_arena) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Free everything, which is a check that the book-keeping works across\n\t// arenas.\n\tfor (int i = 0; i <= index; i++) {\n\t\tfree(ptrs[i]);\n\t}\n\tfree(ptrs);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\n#if TARGET_OS_OSX\n\n// Guaranteed number of 256-byte allocations to be sure we fill a region.\n#define ALLOCS_PER_REGION ((NANOV2_REGION_SIZE)/256)\n\n// This test is required only on macOS because iOS only uses one region.\nT_DECL(overspill_region, \"force overspill of a region\",\n\t   T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n#if CONFIG_NANOZONE\n\tvoid **ptrs = calloc(ALLOCS_PER_REGION, sizeof(void *));\n\tT_QUIET; T_ASSERT_NOTNULL(ptrs, \"Unable to allocate pointers\");\n\tint index;\n\n\tnanov2_addr_t first_ptr;\n\tptrs[0] = malloc(256);\n\tT_QUIET; T_ASSERT_NOTNULL(ptrs[index], \"Failed to allocate\");\n\tfirst_ptr.addr = ptrs[0];\n\n\tfor (index = 1; index < ALLOCS_PER_REGION; index++) {\n\t\tptrs[index] = malloc(256);\n\t\tT_QUIET; T_ASSERT_NOTNULL(ptrs[index], \"Failed to allocate\");\n\n\t\t// Stop allocating once we have crossed into a new region.\n\t\tnanov2_addr_t current_ptr;\n\t\tcurrent_ptr.addr = ptrs[index];\n\t\tif (current_ptr.fields.nano_region != first_ptr.fields.nano_region) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Free everything, which is a check that the book-keeping works across\n\t// regions.\n\tfor (int i = 0; i <= index; i++) {\n\t\tfree(ptrs[i]);\n\t}\n\tfree(ptrs);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n#endif // TARGET_OS_OSX\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/perf_contended_malloc_free.c",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <stdatomic.h>\n#include <math.h>\n#include <unistd.h>\n#include <sys/sysctl.h>\n#include <mach/mach.h>\n#include <perfcheck_keys.h>\n#include <pthread.h>\n#include <malloc/malloc.h>\n#include <darwintest.h>\n\n// number of times malloc & free are called per dt_stat batch\n#define ITERATIONS_PER_DT_STAT_BATCH 10000ull\n// number of times large malloc is called per dt_stat  batch\n#define ITERATIONS_PER_DT_STAT_BATCH_LARGE_MALLOC 1000ull\n// max number of allocations kept live during the benchmark (< iterations above)\n#define LIVE_ALLOCATIONS 256\n// maintain and print progress counters in between measurement batches\n#define COUNTERS 0\n\n// move the darwintest assertion code out of the straight line execution path\n// since it is has non-trivial overhead and codegen impact even if the assertion\n// is never triggered.\n#define iferr(_e) if(__builtin_expect(!!(_e), 0))\n\n#pragma mark -\n\nuint64_t\nrandom_busy_counts(unsigned int *seed, uint64_t *first, uint64_t *second)\n{\n\tuint64_t random = rand_r(seed);\n\t*first = 0x4 + (random & (0x10 - 1));\n\trandom >>= 4;\n\t*second = 0x4 + (random & (0x10 - 1));\n\trandom >>= 4;\n\treturn random;\n}\n\n// By default busy() does no cpu busy work in the malloc bench\nenum {\n\tbusy_is_nothing = 0,\n\tbusy_is_cpu_busy,\n\tbusy_is_cpu_yield,\n};\nstatic int busy_select = busy_is_nothing;\n\nstatic double\ncpu_busy(uint64_t n)\n{\n\tdouble d = M_PI;\n\tuint64_t i;\n\tfor (i = 0; i < n; i++) d *= M_PI;\n\treturn d;\n}\n\nstatic double\ncpu_yield(uint64_t n)\n{\n\tuint64_t i;\n\tfor (i = 0; i < n; i++) {\n#if defined(__arm__) || defined(__arm64__)\n\tasm volatile(\"yield\");\n#elif defined(__x86_64__) || defined(__i386__)\n\tasm volatile(\"pause\");\n#else\n#error Unrecognized architecture\n#endif\n\t}\n\treturn 0;\n}\n\n__attribute__((noinline))\nstatic double\nbusy(uint64_t n)\n{\n\tswitch(busy_select) {\n\tcase busy_is_cpu_busy:\n\t\treturn cpu_busy(n);\n\tcase busy_is_cpu_yield:\n\t\treturn cpu_yield(n);\n\tdefault:\n\t\treturn 0;\n\t}\n}\n\n#pragma mark -\n\nstatic semaphore_t ready_sem, start_sem, end_sem;\nstatic uint32_t nthreads;\nstatic _Atomic uint32_t active_thr;\nstatic _Atomic int64_t todo;\nuint64_t iterations_per_dt_stat_batch = ITERATIONS_PER_DT_STAT_BATCH;\n\n#if COUNTERS\nstatic _Atomic uint64_t total_mallocs;\n#define ctr_inc(_t) atomic_fetch_add_explicit(&(_t), 1, memory_order_relaxed)\n#else\n#define ctr_inc(_t)\n#endif\n\nstatic uint32_t\nncpu(void)\n{\n\tstatic uint32_t activecpu, physicalcpu;\n\tif (!activecpu) {\n\t\tuint32_t n;\n\t\tsize_t s = sizeof(n);\n\t\tsysctlbyname(\"hw.activecpu\", &n, &s, NULL, 0);\n\t\tactivecpu = n;\n\t\ts = sizeof(n);\n\t\tsysctlbyname(\"hw.physicalcpu\", &n, &s, NULL, 0);\n\t\tphysicalcpu = n;\n\t}\n\treturn MIN(activecpu, physicalcpu);\n}\n\n__attribute__((noinline))\nstatic void\nthreaded_bench(dt_stat_time_t s, int batch_size)\n{\n\tkern_return_t kr;\n\tfor (int i = 0; i < nthreads; i++) {\n\t\tkr = semaphore_wait(ready_sem);\n\t\tiferr (kr) {T_QUIET; T_ASSERT_MACH_SUCCESS(kr, \"semaphore_wait\");}\n\t}\n\tatomic_init(&active_thr, nthreads);\n\tatomic_init(&todo, batch_size * iterations_per_dt_stat_batch);\n\tdt_stat_token t = dt_stat_begin(s);\n\tkr = semaphore_signal_all(start_sem);\n\tiferr (kr) {T_QUIET; T_ASSERT_MACH_SUCCESS(kr, \"semaphore_signal_all\");}\n\tkr = semaphore_wait(end_sem);\n\tiferr (kr) {T_QUIET; T_ASSERT_MACH_SUCCESS(kr, \"semaphore_wait\");}\n\tdt_stat_end_batch(s, batch_size, t);\n}\n\nstatic void\nsetup_threaded_bench(void* (*thread_fn)(void*), bool singlethreaded)\n{\n\tkern_return_t kr;\n\tint r;\n\tchar *e;\n\n\tif (singlethreaded) {\n\t\tnthreads = 1;\n\t} else {\n\t\tif ((e = getenv(\"DT_STAT_NTHREADS\"))) nthreads = strtoul(e, NULL, 0);\n\t\tif (nthreads < 2) nthreads = ncpu();\n\t}\n\tif ((e = getenv(\"DT_STAT_CPU_BUSY\"))) busy_select = strtoul(e, NULL, 0);\n\n\tkr = semaphore_create(mach_task_self(), &ready_sem, SYNC_POLICY_FIFO, 0);\n\tT_QUIET; T_ASSERT_MACH_SUCCESS(kr, \"semaphore_create\");\n\tkr = semaphore_create(mach_task_self(), &start_sem, SYNC_POLICY_FIFO, 0);\n\tT_QUIET; T_ASSERT_MACH_SUCCESS(kr, \"semaphore_create\");\n\tkr = semaphore_create(mach_task_self(), &end_sem, SYNC_POLICY_FIFO, 0);\n\tT_QUIET; T_ASSERT_MACH_SUCCESS(kr, \"semaphore_create\");\n\n\tpthread_attr_t attr;\n\tr = pthread_attr_init(&attr);\n\tT_QUIET; T_ASSERT_POSIX_ZERO(r, \"pthread_attr_init\");\n\tr = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);\n\tT_QUIET; T_ASSERT_POSIX_ZERO(r, \"pthread_attr_setdetachstate\");\n\n\tfor (int i = 0; i < nthreads; i++) {\n\t\tpthread_t th;\n\t\tr = pthread_create(&th, &attr, thread_fn, (void *)(uintptr_t)(i+1));\n\t\tT_QUIET; T_ASSERT_POSIX_ZERO(r, \"pthread_create\");\n\t}\n}\n\n#pragma mark -\n\nstatic _Atomic(void*) allocations[LIVE_ALLOCATIONS];\nstatic size_t max_rand, min_size, incr_size;\n\nstatic void *\nmalloc_bench_thread(void * arg)\n{\n\tkern_return_t kr;\n\tint r;\n\tunsigned int seed;\n\tvolatile double dummy;\n\tuint64_t pos, remaining_frees;\n\tvoid *alloc;\n\nrestart:\n\tseed = (uintptr_t)arg; // each thread repeats its own sequence\n\t// start threads off in different positions in allocations array\n\tpos = (seed - 1) * (LIVE_ALLOCATIONS / nthreads);\n\tremaining_frees = LIVE_ALLOCATIONS;\n\tkr = semaphore_wait_signal(start_sem, ready_sem);\n\tT_QUIET; T_ASSERT_MACH_SUCCESS(kr, \"semaphore_wait_signal\");\n\n\twhile (1) {\n\t\tuint64_t first, second;\n\t\tuint64_t random = random_busy_counts(&seed, &first, &second);\n\t\tif (atomic_fetch_sub_explicit(&todo, 1, memory_order_relaxed) > 0) {\n\t\t\tdummy = busy(first);\n\t\t\talloc = malloc(min_size + (random % (max_rand + 1)) * incr_size);\n\t\t\tiferr (!alloc) { T_ASSERT_POSIX_ZERO(errno, \"malloc\"); }\n\t\t\tctr_inc(total_mallocs);\n\t\t} else {\n\t\t\tif (!remaining_frees--) break;\n\t\t\talloc = NULL;\n\t\t}\n\t\talloc = atomic_exchange(&allocations[(pos++)%LIVE_ALLOCATIONS], alloc);\n\t\tif (alloc) {\n\t\t\tdummy = busy(second);\n\t\t\tfree(alloc);\n\t\t}\n\t}\n\n\tif (atomic_fetch_sub_explicit(&active_thr, 1, memory_order_relaxed) == 1) {\n\t\tkr = semaphore_signal(end_sem);\n\t\tT_QUIET; T_ASSERT_MACH_SUCCESS(kr, \"semaphore_signal\");\n\t}\n\tgoto restart;\n}\n\nstatic void\nmalloc_bench(bool singlethreaded, size_t from, size_t to, size_t incr)\n{\n\tint r;\n\tint batch_size;\n#if COUNTERS\n\tuint64_t batch = 0;\n#endif\n\n\tsetup_threaded_bench(malloc_bench_thread, singlethreaded);\n\n\tincr_size = incr;\n\tmin_size = from;\n\tmax_rand = (to - from) / incr;\n\tassert((to - from) % incr == 0);\n\n\tdt_stat_time_t s = dt_stat_time_create(\n\t\t\tnthreads > 1 ? \"%llu malloc & free multithreaded\" :\n\t\t\t\t\t\"%llu malloc & free singlethreaded\",\n\t\t\titerations_per_dt_stat_batch);\n\tdt_stat_set_variable((dt_stat_t)s, \"threads\", nthreads);\n\n\t// For now, set the A/B failure threshold to 50% of baseline.\n\t// 40292129 tracks removing noise and setting a more useful threshold.\n\tdt_stat_set_variable((dt_stat_t) s, kPCFailureThresholdPctVar, 50.0);\n\tdo {\n\t\tbatch_size = dt_stat_batch_size(s);\n\t\tthreaded_bench(s, batch_size);\n#if COUNTERS\n\t\tfprintf(stderr, \"\\rbatch: %4llu\\t size: %4d\\tmallocs: %8llu\",\n\t\t\t\t++batch, batch_size,\n\t\t\t\tatomic_load_explicit(&total_mallocs, memory_order_relaxed));\n#endif\n\t} while (!dt_stat_stable(s));\n#if COUNTERS\n\tfprintf(stderr, \"\\n\");\n#endif\n\tdt_stat_finalize(s);\n}\n\nT_DECL(perf_uncontended_nano_bench, \"Uncontended nano malloc\",\n\t\tT_META_ALL_VALID_ARCHS(NO),\n\t\tT_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t\tT_META_ENVVAR(\"MallocNanoZone=1\"), T_META_TAG_PERF)\n{\n\tmalloc_bench(true, 16, 256, 16); // NANO_MAX_SIZE\n}\n\nT_DECL(perf_contended_nano_bench, \"Contended nano malloc\",\n\t\tT_META_ALL_VALID_ARCHS(NO),\n\t\tT_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t\tT_META_ENVVAR(\"MallocNanoZone=1\"), T_META_TAG_PERF)\n{\n\tmalloc_bench(false, 16, 256, 16); // NANO_MAX_SIZE\n}\n\nT_DECL(perf_uncontended_tiny_bench, \"Uncontended tiny malloc\",\n\t\tT_META_ALL_VALID_ARCHS(NO),\n\t\tT_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t\tT_META_ENVVAR(\"MallocNanoZone=0\"), T_META_TAG_PERF)\n{\n\tmalloc_bench(true, 16, 1008, 16); // SMALL_THRESHOLD\n}\n\nT_DECL(perf_contended_tiny_bench, \"Contended tiny malloc\",\n\t\tT_META_ALL_VALID_ARCHS(NO),\n\t\tT_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t\tT_META_ENVVAR(\"MallocNanoZone=0\"), T_META_TAG_PERF)\n{\n\tmalloc_bench(false, 16, 1008, 16); // SMALL_THRESHOLD\n}\n\nT_DECL(perf_uncontended_small_bench, \"Uncontended small malloc\",\n\t\tT_META_ALL_VALID_ARCHS(NO),\n\t\tT_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t\tT_META_TAG_PERF)\n{\n\tmalloc_bench(true, 1024, 15 * 1024, 512); // LARGE_THRESHOLD\n}\n\nT_DECL(perf_contended_small_bench, \"Contended small malloc\",\n\t\tT_META_ALL_VALID_ARCHS(NO),\n\t\tT_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t\tT_META_TAG_PERF)\n{\n\tmalloc_bench(false, 1024, 15 * 1024, 512); // LARGE_THRESHOLD\n}\n\nT_DECL(perf_uncontended_large_bench, \"Uncontended large malloc\",\n\t\tT_META_ALL_VALID_ARCHS(NO),\n\t\tT_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t\tT_META_TAG_PERF)\n{\n\titerations_per_dt_stat_batch = ITERATIONS_PER_DT_STAT_BATCH_LARGE_MALLOC;\n\tmalloc_bench(true, 16 * 1024, 256 * 1024, 16 * 1024);\n}\n\nT_DECL(perf_contended_large_bench, \"Contended large malloc\",\n\t\tT_META_ALL_VALID_ARCHS(NO),\n\t\tT_META_LTEPHASE(LTE_POSTINIT), T_META_CHECK_LEAKS(false),\n\t\tT_META_TAG_PERF)\n{\n\titerations_per_dt_stat_batch = ITERATIONS_PER_DT_STAT_BATCH_LARGE_MALLOC;\n\tmalloc_bench(false, 16 * 1024, 256 * 1024, 16 * 1024);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/perf_realloc.c",
    "content": "#include <stdlib.h>\n#include <mach/vm_page_size.h>\n#include <../src/internal.h>\n#include <darwintest.h>\n#include <perfcheck_keys.h>\n\n#pragma mark -\n#pragma mark Helper code\n\n#define PAGE_SPREAD 8\n#define MAX_NAME_SIZE 256\n#define OUTLIER_TIME 20000\n\n// This value is a guess that will be refined over time.\n#define PERFCHECK_THRESHOLD_PCT\t10.0\n\nstatic char name[MAX_NAME_SIZE];\n#define NUMBER_OF_SAMPLES_FOR_BATCH(s) _dt_stat_batch_size((dt_stat_t)s)\n\n// Measures the time required to realloc a block of memory of given size\n// by a specified amount.\nstatic void\nrealloc_by_amount(const char *base_metric_name, size_t size, ssize_t amount,\n\t\tbool amount_is_random)\n{\n\tif (amount_is_random) {\n\t\tsnprintf(name, MAX_NAME_SIZE, amount >= 0 ?\n\t\t\t \"%s_from_%llu_up_random\" : \"%s_from_%llu_down_random\",\n\t\t\t base_metric_name, (uint64_t)size);\n\t} else {\n\t\tsnprintf(name, MAX_NAME_SIZE, amount >= 0 ?\n\t\t\t\t \"%s_from_%llu_up_%ld\" : \"%s_from_%llu_down_%ld\",\n\t\t\t\t base_metric_name, (uint64_t)size, labs(amount));\n\t}\n\n\tuint64_t total_time = 0;\n\tint count = 0;\n\tdt_stat_time_t s = dt_stat_time_create(name);\n\tdt_stat_set_variable((dt_stat_t)s, \"size (bytes)\", (unsigned int)size);\n\tdt_stat_set_variable((dt_stat_t)s, \"amount (bytes)\", (int)amount);\n\t// rdar://problem/40417821: disable thresholds for now.\n\t//dt_stat_set_variable((dt_stat_t)s, kPCFailureThresholdPctVar,\n\t//\t\tPERFCHECK_THRESHOLD_PCT);\n\tdt_stat_token now = dt_stat_time_begin(s);\n\n\tfor (;;) {\n\t\tvoid *ptr = malloc(size);\n\t\tT_QUIET; T_ASSERT_NOTNULL(ptr, \"malloc for size %llu failed\", (uint64_t)size);\n\n\t\tdt_stat_token start = dt_stat_time_begin(s);\n\t\tptr = realloc(ptr, size + amount);\n\t\tdt_stat_token end = dt_stat_time_begin(s);\n\t\tT_QUIET; T_ASSERT_NOTNULL(ptr,\n\t\t\t\t\"realloc from size %llu to size %llu failed\", (uint64_t)size,\n\t\t\t\t(uint64_t)(size + amount));\n\t\ttotal_time += end - start;\n\t\tfree(ptr);\n\n\t\tif (++count >= NUMBER_OF_SAMPLES_FOR_BATCH(s)) {\n\t\t\t// Discard outliers or the test won't converge -- this should\n\t\t\t// be done in libdarwintest\n\t\t\tif (total_time/count < OUTLIER_TIME) {\n\t\t\t\tdt_stat_mach_time_add_batch(s, count, total_time);\n\t\t\t}\n\t\t\ttotal_time = 0;\n\t\t\tcount = 0;\n\t\t\tif (dt_stat_stable(s)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tdt_stat_finalize(s);\n}\n\n// Times a set of size adjustments from a given base.\nstatic void\nrealloc_test_set(const char *base_name, size_t start_size)\n{\n\tssize_t adj = 1;\n\trealloc_by_amount(base_name, start_size, adj, false);\n\trealloc_by_amount(base_name, start_size + adj, -adj, false);\n\n\tadj = 8;\n\trealloc_by_amount(base_name, start_size, adj, false);\n\trealloc_by_amount(base_name, start_size + adj, -adj, false);\n\n\tadj = 16;\n\trealloc_by_amount(base_name, start_size, adj, false);\n\trealloc_by_amount(base_name, start_size + adj, -adj, false);\n\n#if INCLUDE_RANDOM_SIZE_TESTS\n\tadj = 1 + arc4random_uniform(vm_page_size - 1);\n\trealloc_by_amount(base_name, start_size, adj, true);\n\trealloc_by_amount(base_name, start_size + adj, -adj, true);\n\n\tuint32_t pages = 1 + arc4random_uniform(PAGE_SPREAD);\n\tadj = pages * vm_page_size;\n\trealloc_by_amount(base_name, start_size, adj, true);\n\trealloc_by_amount(base_name, start_size + adj, -adj, true);\n#else // INCLUDE_RANDOM_SIZE_TESTS\n\tT_LOG(\"Skipping random size tests\");\n#endif // INCLUDE_RANDOM_SIZE_TESTS\n\n\tadj = vm_page_size;\n\trealloc_by_amount(base_name, start_size, adj, false);\n\trealloc_by_amount(base_name, start_size + adj, -adj, false);\n\n\tadj = 4 * vm_page_size;\n\trealloc_by_amount(base_name, start_size, adj, false);\n\trealloc_by_amount(base_name, start_size + adj, -adj, false);\n\n\t// Adjust up and then down by over half the size of the allocation --\n\t// this skips the fast path in some allocators.\n\tadj = 4 * vm_page_size;\n\trealloc_by_amount(base_name, start_size, adj, false);\n\trealloc_by_amount(base_name, start_size + adj, -(((ssize_t)start_size) + adj)/2 - 1, false);\n\n\tadj = 32;\n\trealloc_by_amount(base_name, start_size, adj, false);\n\trealloc_by_amount(base_name, start_size + adj, -(((ssize_t)start_size) + adj)/2 - 1, false);\n}\n\nstatic void\nrealloc_tests(const char *base_name, boolean_t using_nano)\n{\n\t// tiny or nano\n\trealloc_test_set(using_nano ? base_name : \"Tiny\", 8);\n\n\tif (!using_nano) {\n\t\t// No point in running these tests three times.\n\n\t\t// tiny\n\t\trealloc_test_set(\"Tiny\", 512);\n\n\t\t// small\n\t\trealloc_test_set(\"Small\", 2048);\n\n\t\t// large\n\t\trealloc_test_set(\"Large\", 128 * 1024);\n\t}\n\n\tT_END;\n}\n\n#pragma mark -\n#pragma mark Tests for realloc()\n\nT_DECL(realloc_perf_base, \"realloc without nano\",\n\t   T_META_TAG_PERF, T_META_ENVVAR(\"MallocNanoZone=0\"))\n{\n\trealloc_tests(\"NoNano\", false);\n}\n\nT_DECL(realloc_perf_nanov1, \"realloc with nanoV1\",\n\t   T_META_TAG_PERF, T_META_ENVVAR(\"MallocNanoZone=V1\"))\n{\n#if CONFIG_NANOZONE\n\trealloc_tests(\"Nanov1\", true);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n\nT_DECL(realloc_perf_nanov2, \"realloc with nanoV2\",\n\t   T_META_TAG_PERF, T_META_ENVVAR(\"MallocNanoZone=V2\"))\n{\n#if CONFIG_NANOZONE\n\trealloc_tests(\"Nanov2\", true);\n#else // CONFIG_NANOZONE\n\tT_SKIP(\"Nano allocator not configured\");\n#endif // CONFIG_NANOZONE\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/radix_tree_test.m",
    "content": "\n\n#import <Foundation/Foundation.h>\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#include <assert.h>\n#include <stdbool.h>\n#include <string.h>\n\n#include <radix_tree.h>\n#include <radix_tree_internal.h>\n\n#include <darwintest.h>\n\n#include \"../src/radix_tree_debug.c\"\n\nbool failed = false;\n\n#if 0\n\n#define ASSERT(x) \\\n\tif (!(x)) {   \\\n\t\tabort();  \\\n\t}\n#define ASSERT_EQ(x, y) \\\n\tif ((x) != (y)) {   \\\n\t\tabort();        \\\n\t}\n\n#else\n\n#define ASSERT(x)      \\\n\tif (!(x)) {        \\\n\t\tfailed = true; \\\n\t}\n#define ASSERT_EQ(x, y) \\\n\tif ((x) != (y)) {   \\\n\t\tfailed = true;  \\\n\t}\n\n#endif\n\nstatic int\nlog2i(uint64_t x)\n{\n\tif (x == 1) {\n\t\treturn 0;\n\t}\n\tif (x & 1) {\n\t\tabort();\n\t}\n\treturn 1 + log2(x >> 1);\n}\n\nT_DECL(radix_tree_test, \"radix_tree_test\")\n{\n\tbool ok;\n\n\t// size_t size = 100 * 4096;\n\t// void *buf = malloc(size);\n\t// memset(buf, 0xde, size);\n\t// struct radix_tree *tree = radix_tree_init(buf, size);\n\n\tstruct radix_tree *tree = radix_tree_create();\n\tASSERT(tree);\n\n\tconst int n = 999;\n\n\tuint64_t minsize = 4096;\n\n\tfor (uint64_t i = 0; i < n * minsize; i += minsize) {\n\t\tok = radix_tree_insert(&tree, i, minsize, 3 * i);\n\t\tASSERT(ok);\n\n\t\t/* printf(\"@@@@@@@@@@@--------\\n\"); */\n\t\t/* radix_tree_print(tree); */\n\t\t/* printf(\"@@@@@@@@@@---------\\n\"); */\n\n\t\tfor (uint64_t j = 0; j < n * minsize; j += minsize) {\n\t\t\t// printf (\"testing %lld %lld\\n\", i, j);\n\t\t\tif (j <= i) {\n\t\t\t\tASSERT(radix_tree_lookup(tree, j) == 3 * j);\n\t\t\t} else {\n\t\t\t\tASSERT(radix_tree_lookup(tree, j) == radix_tree_invalid_value);\n\t\t\t}\n\t\t}\n\t}\n\n\tT_EXPECT_FALSE(failed, \"insert 1 to n\");\n\n\tfor (uint64_t i = 0; i < n * minsize; i += minsize) {\n\t\tok = radix_tree_delete(&tree, i, minsize);\n\t\tASSERT(ok);\n\t\tfor (uint64_t j = 0; j < n * minsize; j += minsize) {\n\t\t\tif (j > i) {\n\t\t\t\tASSERT(radix_tree_lookup(tree, j) == 3 * j);\n\t\t\t} else {\n\t\t\t\tASSERT(radix_tree_lookup(tree, j) == radix_tree_invalid_value);\n\t\t\t}\n\t\t}\n\t}\n\n\tT_EXPECT_FALSE(failed, \"delete 1 to n\");\n\n\tfor (uint64_t i = 0; i < n * minsize; i += minsize) {\n\t\tok = radix_tree_insert(&tree, i, minsize, 3 * i);\n\t\tASSERT(ok);\n\t}\n\n\tfor (uint64_t i = n * minsize; i > 0;) {\n\t\ti -= minsize;\n\n\t\t//\t\t printf(\"@@@@@@@@@@@--------\\n\");\n\t\t//\t\t radix_tree_print(tree);\n\t\t//\t\t printf(\"@@@@@@@@@@---------\\n\");\n\n\t\tok = radix_tree_delete(&tree, i, minsize);\n\n\t\tASSERT(ok);\n\t\tfor (uint64_t j = 0; j < n * minsize; j += minsize) {\n\t\t\tif (j < i) {\n\t\t\t\tASSERT_EQ(radix_tree_lookup(tree, j), 3 * j);\n\t\t\t} else {\n\t\t\t\tASSERT_EQ(radix_tree_lookup(tree, j), radix_tree_invalid_value);\n\t\t\t}\n\t\t}\n\t}\n\n\tT_EXPECT_FALSE(failed, \"delete n to 1\");\n\n\tsrand(12345);\n\n\tNSMutableDictionary *d = [[NSMutableDictionary alloc] init];\n\n\tfor (uint64_t i = 0; i < n; i++) {\n\t\t@autoreleasepool {\n\t\t\tfor (int j = 0; j < 3; j++) {\n\t\t\t\tuint64_t key = minsize * (rand() + ((uint64_t)rand() << 32));\n\t\t\t\tuint64_t value = rand();\n\n\t\t\t\t//\t\t\t\tprintf(\"@@@@@@@@@@@--------\\n\");\n\t\t\t\t//\t\t\t\tradix_tree_print(tree);\n\t\t\t\t//\t\t\t\tprintf(\"@@@@@@@@@@---------inserting %llx\\n\", key);\n\n\t\t\t\tok = radix_tree_insert(&tree, key, minsize, value);\n\n\t\t\t\t//\t\t\t\tprintf(\"@@@@@@@@@@---------ok\\n\");\n\n\t\t\t\tASSERT(ok);\n\n\t\t\t\td[@(key)] = @(value);\n\t\t\t}\n\n\t\t\tNSArray *array = [d allKeys];\n\t\t\tid k = [array objectAtIndex:rand() % [array count]];\n\n\t\t\tok = radix_tree_delete(&tree, [k unsignedLongLongValue], minsize);\n\t\t\tASSERT(ok);\n\t\t\t[d removeObjectForKey:k];\n\n\t\t\tfor (id k in d) {\n\t\t\t\tASSERT_EQ(radix_tree_lookup(tree, [k unsignedLongLongValue]), [d[k] unsignedLongLongValue]);\n\t\t\t}\n\n\t\t\tuint64_t count = radix_tree_count(tree);\n\n\t\t\t//\t\t\tfor (id k in d) {\n\t\t\t//\t\t\t\tprintf(\"key %llx -> %llx\\n\", [k unsignedLongLongValue], [d[k] unsignedLongLongValue]);\n\t\t\t//\t\t\t}\n\t\t\t//\t\t\tradix_tree_print(tree);\n\n\t\t\tASSERT_EQ((long)(count % minsize), 0l);\n\t\t\tASSERT_EQ([[d allKeys] count], (long)(count / minsize));\n\t\t}\n\t}\n\n\tT_EXPECT_FALSE(failed, \"random\");\n\n\tfor (id k in d) {\n\t\tradix_tree_delete(&tree, [k unsignedLongLongValue], minsize);\n\t}\n\tT_EXPECT_EQ_ULLONG(0ull, radix_tree_count(tree), \"delete randoms\");\n\n\tASSERT_EQ(radix_tree_lookup(tree, 0), -1);\n\tASSERT_EQ(radix_tree_lookup(tree, minsize - 1), -1);\n\tASSERT_EQ(radix_tree_lookup(tree, minsize), -1);\n\n\tok = radix_tree_insert(&tree, 0, minsize, 0xf00);\n\tASSERT(ok);\n\tASSERT_EQ(radix_tree_lookup(tree, 0), 0xf00);\n\tASSERT_EQ(radix_tree_lookup(tree, minsize - 1), 0xf00);\n\tASSERT_EQ(radix_tree_lookup(tree, minsize), -1);\n\n\t// this would abort:\n\t//\tok = radix_tree_insert(&tree, -minsize, minsize, 0xb00);\n\t//\tASSERT(!ok);\n\n\tok = radix_tree_insert(&tree, -2 * minsize, minsize, 0xb00);\n\tASSERT(ok);\n\n\tASSERT_EQ(radix_tree_lookup(tree, -2 * minsize), 0xb00);\n\tASSERT_EQ(radix_tree_lookup(tree, -2 * minsize - 1), -1);\n\tASSERT_EQ(radix_tree_lookup(tree, -2 * minsize + 1), 0xb00);\n\tASSERT_EQ(radix_tree_lookup(tree, -2 * minsize + minsize - 1), 0xb00);\n\tASSERT_EQ(radix_tree_lookup(tree, -1 * minsize), -1);\n\tASSERT_EQ(radix_tree_lookup(tree, minsize), -1);\n\n\tradix_tree_delete(&tree, -2 * minsize, minsize);\n\tradix_tree_delete(&tree, 0, minsize);\n\tASSERT_EQ(radix_tree_count(tree), 0);\n\n\tT_EXPECT_FALSE(failed, \"off by 1\");\n\n\tint modelsize = 1024;\n\tuint32_t model[modelsize];\n\n\twhile (log2i(modelsize) + log2i(minsize) <= 64) {\n\t\tmemset(model, 0xff, sizeof(model));\n\n\t\tfor (int i = 0; i < n; i++) {\n\t\t\tuint64_t start = rand() % modelsize;\n\t\t\tif (start == modelsize - 1 && log2i(modelsize) + log2i(minsize) == 64) {\n\t\t\t\tstart = modelsize - 2;\n\t\t\t}\n\t\t\tuint64_t maxsize = modelsize - start;\n\t\t\tuint64_t size;\n\t\t\tif (maxsize / 4 > 1) {\n\t\t\t\tsize = (rand() % (maxsize / 4)) + (rand() % (maxsize / 4)) + (rand() % (maxsize / 4)) + (rand() % (maxsize / 4));\n\t\t\t} else if (maxsize > 1) {\n\t\t\t\tsize = rand() % maxsize;\n\t\t\t} else {\n\t\t\t\tsize = 1;\n\t\t\t}\n\t\t\tif (size == 0) {\n\t\t\t\tsize = 1;\n\t\t\t}\n\t\t\tif (minsize * start + minsize * size < minsize * start) {\n\t\t\t\tsize--;\n\t\t\t}\n\t\t\tif (minsize * start + minsize * size < minsize * start) {\n\t\t\t\tabort();\n\t\t\t}\n\t\t\tif (size == 0) {\n\t\t\t\tabort();\n\t\t\t}\n\t\t\tuint32_t value = rand();\n\n\t\t\t// printf(\"inserting %llx, %llx\\n\", start*minsize, size*minsize);\n\t\t\t// radix_tree_print(tree);\n\n\t\t\tok = radix_tree_insert(&tree, start * minsize, size * minsize, value);\n\t\t\tASSERT(ok);\n\n\t\t\t// radix_tree_print(tree);\n\t\t\tASSERT(radix_tree_fsck(tree));\n\n\t\t\tfor (uint64_t i = start; i < start + size; i++) {\n\t\t\t\tmodel[i] = value;\n\t\t\t}\n\n\t\t\tfor (uint64_t j = 0; j < modelsize; j++) {\n\t\t\t\tuint64_t expected;\n\t\t\t\tif (model[j] == (uint32_t)-1) {\n\t\t\t\t\texpected = (uint64_t)-1;\n\t\t\t\t} else {\n\t\t\t\t\texpected = model[j];\n\t\t\t\t}\n\n\t\t\t\t// radix_tree_print(tree);\n\t\t\t\tuint64_t ans = radix_tree_lookup(tree, j * minsize);\n\t\t\t\t// printf(\"j*minsize=%llx expected=%llx ans=%llx\\n\", j*minsize, expected, ans);\n\t\t\t\tASSERT_EQ(expected, ans);\n\t\t\t}\n\t\t}\n\n\t\tT_EXPECT_FALSE(failed, \"model %d\", log2i(minsize) + log2i(modelsize));\n\n\t\tradix_tree_delete(&tree, 0, -1);\n\t\tT_EXPECT_EQ_ULLONG(0ull, radix_tree_count(tree), \"delete model\");\n\n\t\tminsize *= 2;\n\t\ttree->leaf_size_shift++;\n\t}\n}\n\nT_DECL(radix_tree_holes, \"radix_tree_holes_test\")\n{\n\tbool ok;\n\tstruct radix_tree *tree = radix_tree_create();\n\tT_ASSERT_NOTNULL(tree, \"radix_tree_create()\");\n\n\tuint64_t size = 0xff00000;\n\tuint64_t minsize = 0x1000;\n\tuint64_t start = 0x10303c000;\n\n\tok = radix_tree_insert(&tree, start, size, 0xf00ba);\n\n\tT_ASSERT_TRUE(ok, \"created region\");\n\n\tok = radix_tree_fsck(tree);\n\tT_QUIET;\n\tT_ASSERT_TRUE(ok, \"fsck\");\n\n\tfor (uint64_t addr = start; addr < start + size; addr += minsize) {\n\t\tT_QUIET;\n\t\tT_ASSERT_EQ_ULLONG(radix_tree_lookup(tree, addr), 0xf00ball, \"stackid\");\n\t\tuint64_t index = (addr - start) / minsize;\n\t\tif (index % 2) {\n\t\t\tok = radix_tree_delete(&tree, addr, minsize);\n\t\t\tT_QUIET;\n\t\t\tT_ASSERT_TRUE(ok, \"deleted odd %lld\", index);\n\t\t}\n\t}\n\n\tfor (uint64_t addr = start; addr < start + size; addr += minsize) {\n\t\tuint64_t index = (addr - start) / minsize;\n\t\tT_QUIET;\n\t\tT_ASSERT_EQ_ULLONG(radix_tree_lookup(tree, addr), index % 2 ? -1 : 0xf00ball, \"stackid\");\n\t\tif (!(index % 2)) {\n\t\t\tok = radix_tree_delete(&tree, addr, minsize);\n\t\t\tT_QUIET;\n\t\t\tT_ASSERT_TRUE(ok, \"deleted even, %lld\", index);\n\t\t}\n\t}\n\n\tok = radix_tree_fsck(tree);\n\tT_ASSERT_TRUE(ok, \"fsck\");\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/reallocarray.c",
    "content": "#include <stdlib.h>\n\n#include <malloc_private.h>\n\n#include <darwintest.h>\n\nT_DECL(reallorarray, \"reallocarray(3)\",\n\t   T_META_CHECK_LEAKS(NO)){\n\tvoid *ptr;\n\tT_WITH_ERRNO; T_EXPECT_NOTNULL((ptr = reallocarray(NULL, 8, 8)), NULL);\n\tT_WITH_ERRNO; T_EXPECT_NOTNULL(reallocarray(ptr, 8, 8), NULL);\n\tT_EXPECT_NULL(reallocarray(NULL, SIZE_MAX >> 3, 1 << 5), NULL);\n\tT_EXPECT_EQ(errno, ENOMEM, NULL);\n\tT_EXPECT_NULL(reallocarray(ptr, SIZE_MAX >> 3, 1 << 5), NULL);\n\tT_EXPECT_EQ(errno, ENOMEM, NULL);\n}\n\nT_DECL(reallorarrayf, \"reallocarrayf(3)\",\n\t   T_META_CHECK_LEAKS(NO)){\n\tvoid *ptr;\n\tT_WITH_ERRNO; T_EXPECT_NOTNULL((ptr = reallocarrayf(NULL, 8, 8)), NULL);\n\tT_WITH_ERRNO; T_EXPECT_NOTNULL(reallocarrayf(ptr, 8, 8), NULL);\n\tT_EXPECT_NULL(reallocarrayf(NULL, SIZE_MAX >> 3, 1 << 5), NULL);\n\tT_EXPECT_EQ(errno, ENOMEM, NULL);\n\tT_EXPECT_NULL(reallocarrayf(ptr, SIZE_MAX >> 3, 1 << 5), NULL);\n\tT_EXPECT_EQ(errno, ENOMEM, NULL);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/stack_logging_test.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <stdbool.h>\n#include <malloc/malloc.h>\n#include <mach/mach.h>\n#include <mach/mach_vm.h>\n#include <stack_logging.h>\n#include <sys/stat.h>\n#include <sys/event.h>\n#include <malloc_private.h>\n#include <TargetConditionals.h>\n\n#if DARWINTEST\n#include <darwintest.h>\n\n#define FAIL(msg, ...) \\\nT_QUIET; \\\nT_FAIL(msg, ## __VA_ARGS__)\n\n#define EXPECT_TRUE(expr, msg, ...) \\\nT_QUIET; \\\nT_EXPECT_TRUE(expr, msg,  ## __VA_ARGS__)\n\n#define EXPECT_EQ(val1, val2, msg, ...) \\\nT_QUIET; \\\nT_EXPECT_EQ(val1, val2, msg,  ## __VA_ARGS__)\n\n#define PAUSE(msg)\n\n#else\n\n#define FAIL(msg, ...) \\\n{ \\\nprintf(\"test failure:\"); \\\nprintf(msg, ## __VA_ARGS__); \\\nprintf(\"\\n\"); \\\ngetchar(); \\\n}\n\n#define EXPECT_TRUE(expr, msg, ...) \\\nif (!(expr)) \\\nFAIL(msg,  ## __VA_ARGS__);\n\n#define EXPECT_EQ(val1, val2, msg, ...) \\\nif (val1 != val2) \\\nFAIL(msg,  ## __VA_ARGS__);\n\n\n// change this to actually pause if you want to examine the stacks using SamplingTools\n#define PAUSE(msg) \\\nprintf(msg); \\\nprintf(\"\\n\"); \\\n//getchar();\n\n#endif\n\n\nconst int max_size = 100;\nconst int allocation_count = 10;\nconst int item_count = 20;\n#define MAX_FRAMES\t512\n\nstatic void\nfree_ptrs(malloc_zone_t *zone, char *ptrs[], int num_ptrs, boolean_t use_zone_free)\n{\n\tfor (int i = 0; i < num_ptrs; i++) {\n\t\tsize_t len = malloc_size(ptrs[i]);\n\t\t\n\t\t// set the memory to different values for possible diagnostics later on\n\t\tif (use_zone_free) {\n\t\t\tmemset(ptrs[i], '!', len);\n\t\t\tzone->free(zone, ptrs[i]);\n\t\t} else if (zone) {\n\t\t\tmemset(ptrs[i], '@', len);\n\t\t\tmalloc_zone_free(zone, ptrs[i]);\n\t\t} else {\n\t\t\tmemset(ptrs[i], '%', len);\n\t\t\tfree(ptrs[i]);\n\t\t}\n\t}\n}\n\nstatic uint64_t\nget_stack_id_from_ptr(void *ptr)\n{\n\tsize_t ptr_size = malloc_size(ptr) + 8;\n\tvoid *idptr = ptr + ptr_size - sizeof(uint64_t);\n\t\n\treturn * (uint64_t *) idptr;\n}\n\nextern uint64_t __mach_stack_logging_shared_memory_address;\n\nstatic void\ncheck_stacks(char *ptrs[], int num_ptrs, boolean_t lite_mode)\n{\n\tmach_vm_address_t frames[MAX_FRAMES];\n\tuint32_t frames_count;\n\t\n\tfor (int i = 0; i < num_ptrs; i++) {\n\t\tkern_return_t ret = (lite_mode) ?\n\t\t__mach_stack_logging_get_frames_for_stackid(mach_task_self(), get_stack_id_from_ptr(ptrs[i]), frames, MAX_FRAMES, &frames_count, NULL) :\n\t\t__mach_stack_logging_get_frames(mach_task_self(), (mach_vm_address_t) ptrs[i], frames, MAX_FRAMES, &frames_count);\n\t\t\n\t\tEXPECT_TRUE(ret == KERN_SUCCESS, \"return from __mach_stack_logging_get_frames = %d\\n\", (int) ret);\n\t\tEXPECT_TRUE(frames_count > 0, \"number of frames returned from __mach_stack_logging_get_frames = %u\\n\", frames_count);\n\t}\n}\n\nstatic void\ntest_malloc(malloc_zone_t *zone, boolean_t lite_mode, boolean_t validate_stacks, boolean_t use_zone_functions, boolean_t use_zone_free)\n{\n\tchar *ptrs[allocation_count];\n\t\n\tfor (int i = 0; i < allocation_count; i++) {\n\t\tsize_t size = rand() % max_size;\n\t\t\n\t\tif (use_zone_functions) {\n\t\t\tptrs[i] = zone->malloc(zone, size);\n\t\t} else {\n\t\t\tptrs[i] = zone ? malloc_zone_malloc(zone, size) : malloc(size);\n\t\t}\n\t\t\n\t\t// fill ptr with numbers in case a leak shows up\n\t\tfor (int j = 0; j < size; j++) {\n\t\t\tptrs[i][j] = '0' + i;\n\t\t}\n\t}\n\t\n\tif (validate_stacks) {\n\t\tcheck_stacks(ptrs, allocation_count, lite_mode);\n\t}\n\t\n\tPAUSE(zone ? \"malloc_zone_malloc\" : \"malloc\");\n\t\n\tfree_ptrs(zone, ptrs, allocation_count, use_zone_free);\n}\n\nstatic void\ntest_calloc(malloc_zone_t *zone, boolean_t lite_mode, boolean_t validate_stacks, boolean_t use_zone_functions, boolean_t use_zone_free)\n{\n\tchar *ptrs[allocation_count];\n\t\n\tfor (int i = 0; i < allocation_count; i++) {\n\t\tsize_t size = rand() % max_size;\n\t\t\n\t\tif (use_zone_functions) {\n\t\t\tptrs[i] = zone->calloc(zone, item_count, size);\n\t\t} else {\n\t\t\tptrs[i] = zone ? malloc_zone_calloc(zone, item_count, size) : calloc(item_count, size);\n\t\t}\n\t\t\n\t\t// fill ptr with numbers in case a leak shows up\n\t\tfor (int j = 0; j < size; j++) {\n\t\t\tptrs[i][j] = 'A' + i;\n\t\t}\n\t}\n\t\n\tif (validate_stacks) {\n\t\tcheck_stacks(ptrs, allocation_count, lite_mode);\n\t}\n\t\n\tPAUSE(zone ? \"malloc_zone_calloc\" : \"calloc\");\n\t\n\tfree_ptrs(zone, ptrs, allocation_count, use_zone_free);\n}\n\nstatic void\ntest_valloc(malloc_zone_t *zone, boolean_t lite_mode, boolean_t validate_stacks, boolean_t use_zone_functions, boolean_t use_zone_free)\n{\n\tchar *ptrs[allocation_count];\n\t\n\tfor (int i = 0; i < allocation_count; i++) {\n\t\tsize_t size = rand() % max_size;\n\t\t\n\t\tif (use_zone_functions) {\n\t\t\tptrs[i] = zone->valloc(zone, size);\n\t\t} else {\n\t\t\tptrs[i] = zone ? malloc_zone_valloc(zone, size) : valloc(size);\n\t\t}\n\t\t\n\t\t// fill ptr with numbers in case a leak shows up\n\t\tfor (int j = 0; j < size; j++) {\n\t\t\tptrs[i][j] = 'a' + i;\n\t\t}\n\t}\n\t\n\tif (validate_stacks) {\n\t\tcheck_stacks(ptrs, allocation_count, lite_mode);\n\t}\n\t\n\tPAUSE(zone ? \"malloc_zone_valloc\" : \"valloc\");\n\t\n\tfree_ptrs(zone, ptrs, allocation_count, use_zone_free);\n}\n\nstatic void\ntest_realloc(malloc_zone_t *zone, boolean_t lite_mode, boolean_t validate_stacks, boolean_t use_zone_functions, boolean_t use_zone_free)\n{\n\tchar *ptrs[allocation_count];\n\t\n\tfor (int i = 0; i < allocation_count; i++) {\n\t\tsize_t size = rand() % max_size;\n\t\tptrs[i] = zone ? malloc_zone_malloc(zone, size) : malloc(size);\n\t}\n\t\n\tfor (int i = 0; i < allocation_count; i++) {\n\t\tsize_t size = rand() % max_size;\n\t\t\n\t\tif (use_zone_functions) {\n\t\t\tptrs[i] = zone->realloc(zone, ptrs[i], size);\n\t\t} else {\n\t\t\tptrs[i] = zone ? malloc_zone_realloc(zone, ptrs[i], size) : realloc(ptrs[i], size);\n\t\t}\n\t\t\n\t\t// fill ptr with numbers in case a leak shows up\n\t\tfor (int j = 0; j < size; j++) {\n\t\t\tptrs[i][j] = 'r' + i;\n\t\t}\n\t}\n\t\n\tif (validate_stacks) {\n\t\tcheck_stacks(ptrs, allocation_count, lite_mode);\n\t}\n\t\n\tPAUSE(zone ? \"malloc_zone_realloc\" : \"realloc\");\n\t\n\tfree_ptrs(zone, ptrs, allocation_count, use_zone_free);\n}\n\nstatic void\ntest_batch_malloc(malloc_zone_t *zone, boolean_t lite_mode, boolean_t validate_stacks, boolean_t use_zone_functions, boolean_t use_zone_free)\n{\n\tsize_t size = rand() % max_size;\n\tvoid *results[allocation_count];\n\tunsigned num_allocated;\n\t\n\tif (use_zone_functions) {\n\t\tnum_allocated = zone->batch_malloc(zone, size, results, allocation_count);\n\t} else {\n\t\tnum_allocated = malloc_zone_batch_malloc(zone, size, results, allocation_count);\n\t}\n\t\n\tif (validate_stacks && num_allocated > 0) {\n\t\tcheck_stacks((char**) results, num_allocated, lite_mode);\n\t}\n\t\n\tPAUSE(\"malloc_zone_batch_malloc\");\n\t\n\tfor (int i = 0; i < num_allocated; i++) {\n\t\tsize_t len = malloc_size(results[i]);\n\t\tmemset(results[i], '$', len);\n\t}\n\t\n\tif (use_zone_free) {\n\t\tzone->batch_free(zone, results, num_allocated);\n\t} else {\n\t\tmalloc_zone_batch_free(zone, results, num_allocated);\n\t}\n}\n\nstatic void\ntest_memalign(malloc_zone_t *zone, boolean_t lite_mode, boolean_t validate_stacks, boolean_t use_zone_functions, boolean_t use_zone_free)\n{\n\tchar *ptrs[allocation_count];\n\t\n\tfor (int i = 0; i < allocation_count; i++) {\n\t\tsize_t size = rand() % max_size;\n\t\t\n\t\tif (use_zone_functions) {\n\t\t\tptrs[i] = zone->memalign(zone, 1024, size);\n\t\t} else {\n\t\t\tptrs[i] = malloc_zone_memalign(zone, 1024, size);\n\t\t}\n\t}\n\t\n\tif (validate_stacks) {\n\t\tcheck_stacks(ptrs, allocation_count, lite_mode);\n\t}\n\t\n\tPAUSE(\"malloc_zone_memalign\");\n\t\n\tfree_ptrs(zone, ptrs, allocation_count, use_zone_free);\n}\n\n// tests calling zone->size and zone->free\nstatic void\ntest_malloc_zone_functions(malloc_zone_t *zone)\n{\n\tvoid *ptrs[allocation_count];\n\t\n\tfor (int i = 0; i < allocation_count; i++) {\n\t\tsize_t size = rand() % max_size;\n\t\tptrs[i] = malloc(size);\n\t\t\n\t\tsize_t allocated_size = malloc_size(ptrs[i]);\n\t\tEXPECT_TRUE(allocated_size >= size, \"allocated size=%lu requested size=%lu\", allocated_size, size);\n\t\t\n\t\tsize_t zone_size = zone->size(zone, ptrs[i]);\n\t\tEXPECT_EQ(allocated_size, zone_size, \"allocated size=%lu zone size=%lu\", allocated_size, zone_size);\n\t}\n\t\n\tfor (int i = 0; i < allocation_count; i++) {\n\t\tsize_t len = malloc_size(ptrs[i]);\n\t\tmemset(ptrs[i], '&', len);\n\t\tzone->free(zone, ptrs[i]);\n\t}\n}\n\ntypedef struct {\n\tvoid *ptr1;\n\tsize_t ptr1_size;\n\tvoid *ptr2;\n\tsize_t ptr2_size;\n\tint num_ptrs_found;\n} zone_enumerator_info;\n\n\nstatic void zone_enumerator(task_t task, void *context, unsigned type, vm_range_t *ranges, unsigned count)\n{\n\tzone_enumerator_info *info = (zone_enumerator_info *) context;\n\t\n\tfor (unsigned int i = 0; i < count; i++) {\n\t\tvoid *ptr = (void*) ranges[i].address;\n\t\tsize_t size = ranges[i].size;\n\t\t\n\t\tif (ptr == info->ptr1 && size == info->ptr1_size) {\n\t\t\tinfo->num_ptrs_found++;\n\t\t} else if (ptr == info->ptr2 && size == info->ptr2_size) {\n\t\t\tinfo->num_ptrs_found++;\n\t\t}\n\t}\n}\n\nstatic void test_zone_enumeration(malloc_zone_t *zone, boolean_t lite_mode_enabled)\n{\n\t// allocate some ptrs with msl\n\tchar *new_ptr_1 = malloc(10);\n\tchar *new_ptr_2 = malloc(10);\n\t\n\t// now check to see if enumerating the default zone finds both ptrs\n\t\n\tzone_enumerator_info info;\n\t\n\tinfo.ptr1 = new_ptr_1;\n\tinfo.ptr1_size = malloc_size(info.ptr1);\n\tif (lite_mode_enabled) {\n\t\t// need to add 8 bytes to get raw size\n\t\tinfo.ptr1_size += 8;\n\t}\n\t\n\tinfo.ptr2 = new_ptr_2;\n\tinfo.ptr2_size = malloc_size(info.ptr2);\n\tif (lite_mode_enabled) {\n\t\t// need to add 8 bytes to get raw size\n\t\tinfo.ptr2_size += 8;\n\t}\n\t\n\tinfo.num_ptrs_found = 0;\n\t\n\tint expected_ptrs_found = 2;\n\t\n\tkern_return_t err = zone->introspect->enumerator(mach_task_self(), &info, MALLOC_PTR_IN_USE_RANGE_TYPE, (vm_address_t) zone, NULL, zone_enumerator);\n\t\n\tEXPECT_EQ(err, KERN_SUCCESS, \"return from default_zone->introspect->enumerator: %d\", err);\n\tEXPECT_EQ(info.num_ptrs_found, expected_ptrs_found, \"info.num_ptrs_found:%d expected:%d\", info.num_ptrs_found, expected_ptrs_found);\n\t\n\tfree(new_ptr_1);\n\tfree(new_ptr_2);\n}\n\nstatic void\ntest_virtual_default_zone(malloc_zone_t *zone, boolean_t nano_allocator_enabled, boolean_t lite_mode_enabled)\n{\n\t// <rdar://problem/26335503> leak in nano zone enumerator\n\tif (!nano_allocator_enabled)\n\t\ttest_zone_enumeration(zone, lite_mode_enabled);\n}\n\nstatic void\ntest_introspection_functions(malloc_zone_t *zone, boolean_t nano_allocator_enabled)\n{\n\tmalloc_introspection_t *introspect = zone->introspect;\n\t\n\tsize_t size = introspect->good_size(zone, 16);\n\tsize_t expected_size = 16;\n\tEXPECT_EQ(size, expected_size, \"introspect->good_size=%lu expected_size=%lu\", size, expected_size);\n\t\n\t// <rdar://problem/24680189> malloc heap checking still crashes\n\t//\tboolean_t ret = introspect->check(zone);\n\t//\tEXPECT_EQ(ret, true, \"introspect->check=%d\", (int) ret);\n\t\n\tintrospect->force_lock(zone);\n\tintrospect->force_unlock(zone);\n\t\n\tboolean_t locked = introspect->zone_locked(zone);\n\t// can't check return value for nano allocator\n\t// <rdar://problem/26391117> nano_locked checks both the nano zone and helper zone, but nano force lock and force unlock only operate on the nano zone\n\tif (!nano_allocator_enabled) {\n\t\tEXPECT_EQ(locked, false, \"introspect->zone_locked=%d\", (int) locked);\n\t}\n\t\n\tmalloc_statistics_t stats;\n\tchar *p = zone->malloc(zone, 10);\n\t\n\tintrospect->statistics(zone, &stats);\n\t// don't check the valus in status because of <rdar://problem/26391877> bug in szone_statistics?\n\t// also I imagine they could change over time so best not to rely on checing these internals\n\t\n\tzone->free(zone, p);\n}\n\nstatic void\ntest_pressure_relief(malloc_zone_t *default_zone)\n{\n\t// call both the single zone and all zone versions\n\t// can't rely on return value to be consistent, so just make sure we don't crash\n\t// or corrupt memory\n\tmalloc_zone_pressure_relief(default_zone, 0);\n\tmalloc_zone_pressure_relief(NULL, 0);\n}\n\nstatic void\ntest_realloc_non_lite_ptr(char *ptr)\n{\n\t// the ptr was malloc'd before lite mode was turned on, therefore not in the lite zone.\n\t// make sure realloc succeeds, and that the new ptr has a valid stack associated with it\n\n\tchar *new_ptr = realloc(ptr, 200);\n\t\n\tmach_vm_address_t frames[MAX_FRAMES];\n\tuint32_t frames_count;\n\t\n\tkern_return_t ret =  __mach_stack_logging_get_frames_for_stackid(mach_task_self(), get_stack_id_from_ptr(new_ptr), frames, MAX_FRAMES, &frames_count, NULL);\n\t\t\n\tEXPECT_TRUE(ret == KERN_SUCCESS, \"return from __mach_stack_logging_get_frames = %d\\n\", (int) ret);\n\tEXPECT_TRUE(frames_count > 0, \"number of frames returned from __mach_stack_logging_get_frames = %u\\n\", frames_count);\n\t\n\t// test that we can realloc the ptr now that it's in the lite zone\n\tnew_ptr =  realloc(new_ptr, 100);\n\t\n\tret =  __mach_stack_logging_get_frames_for_stackid(mach_task_self(), get_stack_id_from_ptr(new_ptr), frames, MAX_FRAMES, &frames_count, NULL);\n\t\n\tEXPECT_TRUE(ret == KERN_SUCCESS, \"return from __mach_stack_logging_get_frames = %d\\n\", (int) ret);\n\tEXPECT_TRUE(frames_count > 0, \"number of frames returned from __mach_stack_logging_get_frames = %u\\n\", frames_count);\n\n\tfree(new_ptr);\n}\n\nstatic void\ntest_realloc_after_lite_mode_turned_off(char *lite_ptr, char *non_lite_ptr)\n{\n\t// make sure realloc works for both ptrs - do twice to test after ptr gets out of the lite zone\n\tchar *new_lite_ptr = realloc(lite_ptr, 100);\n\tEXPECT_TRUE(new_lite_ptr != NULL, \"realloc of new_lite_ptr\");\n\tnew_lite_ptr = realloc(new_lite_ptr, 200);\n\tEXPECT_TRUE(new_lite_ptr != NULL, \"realloc of new_lite_ptr\");\n\t\n\tchar *new_non_lite_ptr = realloc(non_lite_ptr, 100);\n\tEXPECT_TRUE(new_non_lite_ptr != NULL, \"realloc of new_non_lite_ptr\");\n\tnew_non_lite_ptr = realloc(new_non_lite_ptr, 100);\n\tEXPECT_TRUE(new_non_lite_ptr != NULL, \"realloc of new_non_lite_ptr\");\n\t\n\tfree(new_lite_ptr);\n\tfree(new_non_lite_ptr);\n}\n\nstatic void\ndo_test(stack_logging_mode_type mode, boolean_t validate_stacks, boolean_t nano_allocator_enabled, boolean_t lite_mode_enabled)\n{\n\tprintf(\"do_test. stack_logging_mode_type=%d validate_stacks=%d nano_allocator_enabled=%d\\n\", (int) mode, (int) validate_stacks, (int) nano_allocator_enabled);\n\t\n\tmalloc_zone_t *default_zone = malloc_default_zone();\n\tmalloc_zone_t *default_purgeable_zone = malloc_default_purgeable_zone();\n\t\n\tchar *ptr = malloc(10);\n\tchar *non_lite_ptr = malloc(10);\t// used in the realloc test later for lite mode\n\t\n\tmalloc_zone_t *zone_from_ptr = malloc_zone_from_ptr(ptr);\n\tEXPECT_EQ(zone_from_ptr, default_zone, \"malloc_zone_from_ptr:%p default_zone:%p\\n\", zone_from_ptr, default_zone);\n\t\t\n\tif (mode != stack_logging_mode_none) {\n\t\ttest_introspection_functions(default_zone, nano_allocator_enabled);\n\t\ttest_pressure_relief(default_zone);\n\t\t\n\t\tprintf(\"turning on stack logging mode %d\\n\", (int) mode);\n\t\tturn_on_stack_logging(mode);\n\t\t\n\t\t// check to make sure returned default zone hasn't changed\n\t\tEXPECT_EQ(default_zone, malloc_default_zone(), \"cached default zone:%p  malloc_default_zone():%p\", default_zone, malloc_default_zone());\n\t\tEXPECT_EQ(default_purgeable_zone, malloc_default_purgeable_zone(), \"cached default purgeable zone:%p  malloc_default_purgeable_zone():%p\", default_purgeable_zone, malloc_default_purgeable_zone());\n\t\t\n\t\tmalloc_zone_t *zone_from_ptr = malloc_zone_from_ptr(ptr);\n\t\tEXPECT_EQ(zone_from_ptr, default_zone, \"malloc_zone_from_ptr:%p default_zone:%p\\n\", zone_from_ptr, default_zone);\n\t\t\n\t\ttest_pressure_relief(default_zone);\n\t}\n\t\n\ttest_introspection_functions(default_zone, nano_allocator_enabled);\n\ttest_virtual_default_zone(default_zone, nano_allocator_enabled, lite_mode_enabled);\n\t\n\t// test to see if zone->size works on the ptr allocated at the beginning\n\tsize_t ptr_size = default_zone->size(default_zone, ptr);\n\tEXPECT_TRUE(ptr_size > 0, \"ptr_size=%d\\n\", (int) ptr_size);\n\t\n\tboolean_t lite_mode = lite_mode_enabled;\n\t\n\tif (validate_stacks) {\n\t\tkern_return_t ret = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_mode);\n\t\tEXPECT_TRUE(ret == KERN_SUCCESS, \"return from __mach_stack_logging_start_reading = %d\", ret);\n\t}\n\t\n\t// lite mode test: check realloc on a ptr that was created pre-enabling lite mode\n\tif (mode == stack_logging_mode_lite) {\n\t\t// this will free the ptr\n\t\ttest_realloc_non_lite_ptr(ptr);\n\t} else {\n\t\tfree(ptr);\n\t}\n\t\n\t// test regular versions\n\ttest_malloc(NULL, lite_mode, validate_stacks, false, false);\n\ttest_calloc(NULL, lite_mode, validate_stacks, false, false);\n\ttest_valloc(NULL, lite_mode, validate_stacks, false, false);\n\ttest_realloc(NULL, lite_mode, validate_stacks, false, false);\n\t\n\t// test malloc_zone versions\n\ttest_malloc(default_zone, lite_mode, validate_stacks, false, false);\n\ttest_calloc(default_zone, lite_mode, validate_stacks, false, false);\n\ttest_valloc(default_zone, lite_mode, validate_stacks, false, false);\n\ttest_realloc(default_zone, lite_mode, validate_stacks, false, false);\n\ttest_batch_malloc(default_zone, lite_mode, validate_stacks, false, false);\n\ttest_memalign(default_zone, lite_mode, validate_stacks, false, false);\n\t\n\t// test zone-> versions\n\t// if not lite mode then don't validate stacks, as this goes behind the back of the standard recorder\n\tif (!lite_mode) {\n\t\tvalidate_stacks = false;\n\t}\n\t\n\ttest_malloc(default_zone, lite_mode, validate_stacks, true, false);\n\ttest_calloc(default_zone, lite_mode, validate_stacks, true, false);\n\ttest_valloc(default_zone, lite_mode, validate_stacks, true, false);\n\ttest_realloc(default_zone, lite_mode, validate_stacks, true, false);\n\ttest_batch_malloc(default_zone, lite_mode, validate_stacks, true, false);\n\ttest_memalign(default_zone, lite_mode, validate_stacks, true, false);\n\t\n\ttest_malloc(default_zone, lite_mode, validate_stacks, false, true);\n\ttest_calloc(default_zone, lite_mode, validate_stacks, false, true);\n\ttest_valloc(default_zone, lite_mode, validate_stacks, false, true);\n\ttest_realloc(default_zone, lite_mode, validate_stacks, false, true);\n\ttest_batch_malloc(default_zone, lite_mode, validate_stacks, false, true);\n\ttest_memalign(default_zone, lite_mode, validate_stacks, false, true);\n\t\n\ttest_malloc(default_zone, lite_mode, validate_stacks, true, true);\n\ttest_calloc(default_zone, lite_mode, validate_stacks, true, true);\n\ttest_valloc(default_zone, lite_mode, validate_stacks, true, true);\n\ttest_realloc(default_zone, lite_mode, validate_stacks, true, true);\n\ttest_batch_malloc(default_zone, lite_mode, validate_stacks, true, true);\n\ttest_memalign(default_zone, lite_mode, validate_stacks, true, true);\n\t\n\ttest_malloc_zone_functions(default_zone);\n\t\n\tchar *lite_ptr = malloc(10);\n\tzone_from_ptr = malloc_zone_from_ptr(lite_ptr);\n\tEXPECT_EQ(zone_from_ptr, default_zone, \"malloc_zone_from_ptr:%p default_zone:%p\\n\", zone_from_ptr, default_zone);\n\n\tif (mode != stack_logging_mode_none) {\n\t\tturn_off_stack_logging();\n\t}\n\t\n\tzone_from_ptr = malloc_zone_from_ptr(lite_ptr);\n\tEXPECT_EQ(zone_from_ptr, default_zone, \"malloc_zone_from_ptr:%p default_zone:%p\\n\", zone_from_ptr, default_zone);\n\t\n\tif (mode == stack_logging_mode_lite) {\n\t\t// this will free the ptrs\n\t\ttest_realloc_after_lite_mode_turned_off(lite_ptr, non_lite_ptr);\n\t} else {\n\t\tfree(lite_ptr);\n\t\tfree(non_lite_ptr);\n\t}\n\t\n\ttest_pressure_relief(default_zone);\n\t\n\t// check that the default zone hasn't changed after turning off stack logging\n\tEXPECT_EQ(default_zone, malloc_default_zone(), \"cached default zone:%p  malloc_default_zone():%p\", default_zone, malloc_default_zone());\n\tEXPECT_EQ(default_purgeable_zone, malloc_default_purgeable_zone(), \"cached default purgeable zone:%p  malloc_default_purgeable_zone():%p\", default_purgeable_zone, malloc_default_purgeable_zone());\n\n\tif (mode != stack_logging_mode_lite) {\n\t\t// if lite mode was turned on and then turned off, the zone is still around but allocations will not be done in the lite zone\n\t\t// so the enumerator will not find them - that's expected. This is similar to the situation where the nano zone is the default allocator\n\t\t// but some of the allocations occur in the helper zone, and calling the nano zone enumerator won't find these either.\n\t\t// This test uses small enough allocations that the nano zone always handles the allocations so we can test in that case.\n\t\ttest_virtual_default_zone(default_zone, nano_allocator_enabled, lite_mode_enabled);\n\t}\n}\n\nstatic void \ntest_enable_disable_enable_msl(unsigned long enable_value_1, unsigned long enable_value_2, boolean_t vm_only)\n{\n\tunsigned long event = enable_value_1;\n\t// Turn on MSL malloc mode\n\tmalloc_memory_event_handler(event);\n\t\n\tchar *ptrs[1];\n\tptrs[0] = malloc(10);\n\t\n\tboolean_t lite_or_vmlite_mode;\n\tboolean_t expected_lite_mode = (enable_value_1 & MEMORYSTATUS_ENABLE_MSL_LITE) != 0;\n\tkern_return_t ret = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_or_vmlite_mode);\n\tEXPECT_TRUE(ret == KERN_SUCCESS, \"return from __mach_stack_logging_start_reading = %d\", ret);\n\tEXPECT_TRUE(lite_or_vmlite_mode == expected_lite_mode, \"return from __mach_stack_logging_start_reading - lite_or_vmlite_mode = %d\", lite_or_vmlite_mode);\n\t\n\t// check to see if malloc stacks are present\n\tif (!vm_only) {\n\t\tcheck_stacks(ptrs, 1, lite_or_vmlite_mode);\n\t}\n\t\n\t// Turn off malloc mode\n\tevent = MEMORYSTATUS_DISABLE_MSL;\n\tmalloc_memory_event_handler(event);\n\t\n\t// verify that the stacks are still there\n\t// First have to clear any cached uniquing table, then check again\n\t__mach_stack_logging_stop_reading(mach_task_self());\n\tret = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_or_vmlite_mode);\n\tEXPECT_TRUE(ret == KERN_SUCCESS, \"return from __mach_stack_logging_start_reading = %d\", ret);\n\tEXPECT_TRUE(lite_or_vmlite_mode == expected_lite_mode, \"return from __mach_stack_logging_start_reading - lite_or_vmlite_mode = %d\", lite_or_vmlite_mode);\n\t\n\tif (!vm_only) {\n\t\tcheck_stacks(ptrs, 1, lite_or_vmlite_mode);\n\t}\n\t\n\t// now see if we can turn on malloc stack logging again\n\tevent = enable_value_2;\n\tmalloc_memory_event_handler(event);\n\t\n\t__mach_stack_logging_stop_reading(mach_task_self());\n\tret = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_or_vmlite_mode);\n\tEXPECT_TRUE(ret == KERN_SUCCESS, \"return from __mach_stack_logging_start_reading = %d\", ret);\n\tEXPECT_TRUE(lite_or_vmlite_mode == expected_lite_mode, \"return from __mach_stack_logging_start_reading - lite_or_vmlite_mode = %d\", lite_or_vmlite_mode);\n\t\n\textern int stack_logging_enable_logging;\n\textern boolean_t is_stack_logging_lite_enabled(void);\n\t\n\tif (lite_or_vmlite_mode && enable_value_1 == enable_value_2 && enable_value_1 != MEMORYSTATUS_ENABLE_MSL_LITE_VM) {\n\t\tEXPECT_TRUE(is_stack_logging_lite_enabled(), \"is_stack_logging_lite_enabled() = %d\", is_stack_logging_lite_enabled());\n\t} else {\n\t\tint expected_stack_logging_enable_logging = (enable_value_1 == enable_value_2);\n\t\tEXPECT_TRUE(expected_stack_logging_enable_logging == stack_logging_enable_logging, \"stack_logging_enable_logging = %d\", stack_logging_enable_logging);\n\t}\n\t\n\tif (!vm_only) {\n\t\tcheck_stacks(ptrs, 1, lite_or_vmlite_mode);\n\t}\n\t\n\tfree(ptrs[0]);\n}\n\n#if DARWINTEST\n\nT_DECL(msl_test_full_runtime_no_nano, \"Test full mode of malloc stack logging enabled during runtime - not using nano allocator\", T_META_ENVVAR(\"MallocNanoZone=0\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = true;\n\tboolean_t nano_allocator_enabled = false;\n\tboolean_t lite_mode_enabled = false;\n\t\n\tdo_test(stack_logging_mode_all, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_malloc_runtime_no_nano, \"Test malloc mode of malloc stack logging enabled during runtime - not using nano allocator\", T_META_ENVVAR(\"MallocNanoZone=0\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = true;\n\tboolean_t nano_allocator_enabled = false;\n\tboolean_t lite_mode_enabled = false;\n\t\n\tdo_test(stack_logging_mode_malloc, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_vm_runtime_no_nano, \"Test vm mode of malloc stack logging enabled during runtime - not using nano allocator\", T_META_ENVVAR(\"MallocNanoZone=0\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = false;\n\tboolean_t nano_allocator_enabled = false;\n\tboolean_t lite_mode_enabled = false;\n\t\n\tdo_test(stack_logging_mode_vm, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_lite_runtime_no_nano, \"Test lite mode of malloc stack logging enabled during runtime - not using nano allocator\", T_META_ENVVAR(\"MallocNanoZone=0\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = true;\n\tboolean_t nano_allocator_enabled = false;\n\tboolean_t lite_mode_enabled = true;\n\t\n\tdo_test(stack_logging_mode_lite, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_full_atstart_no_nano, \"Test full mode of malloc stack logging enabled at start - not using nano allocator\", T_META_ENVVAR(\"MallocStackLogging=1\"), T_META_ENVVAR(\"MallocNanoZone=0\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = true;\n\tboolean_t nano_allocator_enabled = false;\n\tboolean_t lite_mode_enabled = false;\n\t\n\tdo_test(stack_logging_mode_none, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_malloc_atstart_no_nano, \"Test malloc mode of malloc stack logging enabled at start - not using nano allocator\", T_META_ENVVAR(\"MallocStackLogging=malloc\"), T_META_ENVVAR(\"MallocNanoZone=0\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = true;\n\tboolean_t nano_allocator_enabled = false;\n\tboolean_t lite_mode_enabled = false;\n\t\n\tdo_test(stack_logging_mode_none, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_vm_atstart_no_nano, \"Test vm mode of malloc stack logging enabled at start - not using nano allocator\", T_META_ENVVAR(\"MallocStackLogging=vm\"), T_META_ENVVAR(\"MallocNanoZone=0\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = false;\n\tboolean_t nano_allocator_enabled = false;\n\tboolean_t lite_mode_enabled = false;\n\t\n\tdo_test(stack_logging_mode_none, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_lite_atstart_no_nano, \"Test lite mode of malloc stack logging enabled at start - not using nano allocator\", T_META_ENVVAR(\"MallocStackLogging=lite\"), T_META_ENVVAR(\"MallocNanoZone=0\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = true;\n\tboolean_t nano_allocator_enabled = false;\n\tboolean_t lite_mode_enabled = true;\n\t\n\tdo_test(stack_logging_mode_none, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_full_runtime_with_nano, \"Test full mode of malloc stack logging enabled during runtime - using nano allocator\", T_META_ENVVAR(\"MallocNanoZone=1\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = true;\n\tboolean_t nano_allocator_enabled = true;\n\tboolean_t lite_mode_enabled = false;\n\t\n\tdo_test(stack_logging_mode_all, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_malloc_runtime_with_nano, \"Test malloc mode of malloc stack logging enabled during runtime - using nano allocator\", T_META_ENVVAR(\"MallocNanoZone=1\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = true;\n\tboolean_t nano_allocator_enabled = true;\n\tboolean_t lite_mode_enabled = false;\n\t\n\tdo_test(stack_logging_mode_malloc, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_vm_runtime_with_nano, \"Test vm mode of malloc stack logging enabled during runtime - using nano allocator\", T_META_ENVVAR(\"MallocNanoZone=1\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = false;\n\tboolean_t nano_allocator_enabled = true;\n\tboolean_t lite_mode_enabled = false;\n\t\n\tdo_test(stack_logging_mode_vm, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_lite_runtime_with_nano, \"Test lite mode of malloc stack logging enabled during runtime - using nano allocator\", T_META_ENVVAR(\"MallocNanoZone=1\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = true;\n\tboolean_t nano_allocator_enabled = true;\n\tboolean_t lite_mode_enabled = true;\n\t\n\tdo_test(stack_logging_mode_lite, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_full_atstart_with_nano, \"Test full mode of malloc stack logging enabled at start - using nano allocator\", T_META_ENVVAR(\"MallocStackLogging=1\"), T_META_ENVVAR(\"MallocNanoZone=1\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = true;\n\tboolean_t nano_allocator_enabled = true;\n\tboolean_t lite_mode_enabled = false;\n\t\n\tdo_test(stack_logging_mode_none, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_malloc_atstart_with_nano, \"Test malloc mode of malloc stack logging enabled at start - using nano allocator\", T_META_ENVVAR(\"MallocStackLogging=malloc\"), T_META_ENVVAR(\"MallocNanoZone=1\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = true;\n\tboolean_t nano_allocator_enabled = true;\n\tboolean_t lite_mode_enabled = false;\n\t\n\tdo_test(stack_logging_mode_none, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_vm_atstart_with_nano, \"Test vm mode of malloc stack logging enabled at start - using nano allocator\", T_META_ENVVAR(\"MallocStackLogging=vm\"), T_META_ENVVAR(\"MallocNanoZone=1\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = false;\n\tboolean_t nano_allocator_enabled = true;\n\tboolean_t lite_mode_enabled = false;\n\t\n\tdo_test(stack_logging_mode_none, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_lite_atstart_with_nano, \"Test lite mode of malloc stack logging enabled at start - using nano allocator\", T_META_ENVVAR(\"MallocStackLogging=lite\"), T_META_ENVVAR(\"MallocNanoZone=1\"), T_META_CHECK_LEAKS(NO))\n{\n\tboolean_t validate_stacks = true;\n\tboolean_t nano_allocator_enabled = true;\n\tboolean_t lite_mode_enabled = true;\n\t\n\tdo_test(stack_logging_mode_none, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n}\n\nT_DECL(msl_test_serialize_uniquing_table, \"Test that that stack uniquing table can be serialized, deserialized and read\", T_META_ENVVAR(\"MallocStackLogging=lite\"))\n{\n\tuintptr_t *foo = malloc(sizeof(uintptr_t));\n\tT_ASSERT_NOTNULL(foo, \"malloc\");\n\n\tuint64_t stackid = foo[1];\n\n\tmach_vm_address_t frames1[STACK_LOGGING_MAX_STACK_SIZE];\n\tuint32_t count1;\n\n\tkern_return_t kr;\n\n\tboolean_t lite_mode;\n\tkr  = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_mode);\n\tT_ASSERT_MACH_SUCCESS(kr, \"start reading\");\n\n\tkr = __mach_stack_logging_get_frames_for_stackid(mach_task_self(), stackid, frames1, STACK_LOGGING_MAX_STACK_SIZE, &count1, NULL);\n\tT_ASSERT_MACH_SUCCESS(kr, \"get frames\");\n\tT_ASSERT_TRUE(count1 > 0, \"frames not empty\");\n\n\tstruct backtrace_uniquing_table *table = __mach_stack_logging_copy_uniquing_table(mach_task_self());\n\tT_ASSERT_NOTNULL(table, \"get a copy of the uniquing table\");\n\n\tmach_vm_size_t size = 0;\n\tvoid *serialized = __mach_stack_logging_uniquing_table_serialize(table, &size);\n\tT_ASSERT_NOTNULL(serialized, \"serialize the table\");\n\n\t__mach_stack_logging_uniquing_table_release(table);\n\ttable = NULL;\n\n\ttable = __mach_stack_logging_uniquing_table_copy_from_serialized(serialized, size);\n\tT_ASSERT_NOTNULL(table, \"deserialize the table\");\n\n\tkr = mach_vm_deallocate(mach_task_self(), (mach_vm_address_t)serialized, size);\n\tT_ASSERT_MACH_SUCCESS(kr, \"deallocate buffer\");\n\n\tmach_vm_address_t frames2[STACK_LOGGING_MAX_STACK_SIZE];\n\tuint32_t count2;\n\n\tkr = __mach_stack_logging_uniquing_table_read_stack(table, stackid, frames2, &count2, STACK_LOGGING_MAX_STACK_SIZE);\n\tT_ASSERT_MACH_SUCCESS(kr, \"get frames gain\");\n\n\n\tT_ASSERT_EQ(count1, count2, \"frame counts match\");\n\tT_ASSERT_EQ(0, memcmp(frames1, frames2, sizeof(mach_vm_address_t) * count1), \"frames match\");\n\n\t__mach_stack_logging_uniquing_table_release(table);\n\tfree(foo);\n\t__mach_stack_logging_stop_reading(mach_task_self());\n}\n\nstatic vm_address_t\n__attribute__((noinline))\nallocate() {\n\tvm_address_t region = 0;\n\tvm_allocate(mach_task_self(), &region, 0x1000, VM_FLAGS_ANYWHERE);\n\treturn region;\n}\n\nstatic void\n__attribute__((noinline))\nallocate_end() {\n}\n\nstatic\nvoid\ndo_test_msl_vm_stacks()\n{\n\tvm_address_t region = allocate();\n\n\tT_ASSERT_NOTNULL((void *)region, \"allocated region\");\n\n\tboolean_t lite_mode;\n\tkern_return_t kr  = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_mode);\n\tT_ASSERT_MACH_SUCCESS(kr, \"start reading\");\n\n\tT_ASSERT_TRUE(lite_mode, \"check lite mode\");\n\n\tuint64_t stackid = __mach_stack_logging_stackid_for_vm_region(mach_task_self(), region);\n\n\tT_EXPECT_FALSE(stackid == -1, \"check that stackid is valid\");\n\n\tmach_vm_address_t frames[512];\n\tuint32_t count =0;\n\tbool last_frame_is_threadid;\n\tkr = __mach_stack_logging_get_frames_for_stackid(mach_task_self(), stackid, frames, sizeof(frames)/sizeof(frames[0]), &count, &last_frame_is_threadid);\n\tT_ASSERT_MACH_SUCCESS(kr, \"get frames\");\n\n\tvoid *allocate_ptr = allocate;\n\tvoid *allocate_end_ptr = allocate_end;\n#if __has_feature(ptrauth_calls)\n\tallocate_ptr = ptrauth_strip(allocate_ptr, ptrauth_key_function_pointer);\n\tallocate_end_ptr = ptrauth_strip(allocate_end_ptr, ptrauth_key_function_pointer);\n#endif /* __has_feature(ptrauth_calls) */\n\n\tT_LOG(\"allocate = %p\", allocate_ptr);\n\tT_LOG(\"allocate_end = %p\", allocate_end_ptr);\n\n\tbool found = false;\n\tfor (uint32_t i = 0; i < count; i++)  {\n\t\tT_LOG(\"frames[%d] = %llx\", (int)i, frames[i]);\n\t\tif (frames[i] >= (uintptr_t)allocate_ptr && frames[i] < (uintptr_t)allocate_end_ptr) {\n\t\t\tT_LOG(\"found!\");\n\t\t\tfound = true;\n\t\t}\n\t}\n\n\tT_EXPECT_TRUE(found, \"found allocate() in the frames\");\n\n\tvm_deallocate(mach_task_self(), region, 0x1000);\n\n\t__mach_stack_logging_stop_reading(mach_task_self());\n\n}\n\nstatic\nvoid\ndo_test_msl_no_vm_stacks()\n{\n\tvm_address_t region = allocate();\n\t\n\tT_ASSERT_NOTNULL((void *)region, \"allocated region\");\n\t\n\tboolean_t lite_mode = false;\n\tkern_return_t kr  = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_mode);\n\tif (__mach_stack_logging_shared_memory_address) {\n\t\tT_ASSERT_MACH_SUCCESS(kr, \"start_reading return code with initialized __mach_stack_logging_shared_memory_address\");\n\t\tT_ASSERT_TRUE(lite_mode, \"check lite mode with initialized __mach_stack_logging_shared_memory_address\");\n\t} else {\n\t\tT_ASSERT_MACH_ERROR_(kr, KERN_FAILURE, \"start_reading return code with uninitialized __mach_stack_logging_shared_memory_address\");\n\t\tT_ASSERT_FALSE(lite_mode, \"check lite mode with uninitialized __mach_stack_logging_shared_memory_address\");\n\t}\n\t\n\tuint64_t stackid = __mach_stack_logging_stackid_for_vm_region(mach_task_self(), region);\n\tT_EXPECT_TRUE(stackid == -1, \"check that no stackid is available for VM region\");\n\t\n\t__mach_stack_logging_stop_reading(mach_task_self());\n}\n\nT_DECL(msl_lite_vm_stacks, \"test that we can read stack logs for VM region in lite mode\", T_META_ENVVAR(\"MallocStackLogging=lite\"))\n{\n\tdo_test_msl_vm_stacks();\n}\n\nT_DECL(msl_lite_vm_stacks_no_env, \"like msl_vmlite but we turn on stack logging with a function call \")\n{\n\tturn_on_stack_logging(stack_logging_mode_lite);\n\tdo_test_msl_vm_stacks();\n}\n\nT_DECL(msl_vmlite_vm_stacks, \"test that we can read stack logs for VM region in vmlite mode\", T_META_ENVVAR(\"MallocStackLogging=vmlite\"))\n{\n\tdo_test_msl_vm_stacks();\n}\n\nT_DECL(msl_vmlite_no_malloc_stacks, \"test that no malloc stacks are logged in vmlite mode\", T_META_ENVVAR(\"MallocStackLogging=vmlite\"))\n{\n\textern boolean_t is_stack_logging_lite_enabled(void);\n\tT_EXPECT_FALSE(is_stack_logging_lite_enabled(), \"is_stack_logging_lite_enabled() = %d\", is_stack_logging_lite_enabled());\n}\n\nT_DECL(msl_vmlite_vm_stacks_no_env, \"test absence/presence of vm stacks in vmlite mode, controlled with function calls\")\n{\n\tdo_test_msl_no_vm_stacks();\n\tturn_on_stack_logging(stack_logging_mode_vmlite);\n\tdo_test_msl_vm_stacks();\n\tturn_off_stack_logging();\n\tdo_test_msl_no_vm_stacks();\n}\n\nT_DECL(msl_vmlite_stress, \"stress test for VM region in lite mode\", T_META_ENVVAR(\"MallocStackLogging=lite\"))\n{\n\tvm_size_t size = 0xff00000;\n\tvm_size_t minsize = 0x1000;\n\tvm_address_t region;\n\tvm_allocate(mach_task_self(), &region, size, VM_FLAGS_ANYWHERE);\n\tT_EXPECT_TRUE(region != 0, \"allocated region %llx\", (long long) region);\n\tfor (vm_address_t addr = region; addr < region + size; addr += minsize) {\n\t\tvm_size_t index = (addr - region) / minsize;\n\t\tif (index % 2) {\n\t\t\t//T_LOG(\"deallocate %llx\", (long long)addr);\n\t\t\tvm_deallocate(mach_task_self(), addr, minsize);\n\t\t}\n\t}\n\tfor (vm_address_t addr = region; addr < region + size; addr += minsize) {\n\t\tvm_size_t index = (addr - region) / minsize;\n\t\tif (!(index % 2)) {\n\t\t\t//T_LOG(\"deallocate %llx\", (long long)addr);\n\t\t\tvm_deallocate(mach_task_self(), addr, minsize);\n\t\t}\n\t}\n\n\t;\n\n\tvm_address_t regions[5000];\n\tfor (int i = 0; i < sizeof(regions)/sizeof(regions[0]); i++) {\n\t\tvm_allocate(mach_task_self(), &regions[i], minsize, VM_FLAGS_ANYWHERE);\n\t\tT_QUIET;\n\t\tT_EXPECT_TRUE(regions[i] != 0, \"allocation succeeded %llx\", (long long) regions[i]);\n\t}\n\tfor (int i = 0; i < sizeof(regions)/sizeof(regions[0]); i++) {\n\t\tvm_deallocate(mach_task_self(), regions[i], minsize);\n\t}\n\n\tT_END;\n}\n\nT_DECL(msl_test_malloc_memory_event_handler, \"Test the memory event handler\")\n{\n#if !TARGET_OS_OSX\n\tT_SKIP(\"Skipping for non-OSX platform\")\n#endif\n\n\tunsigned long event = NOTE_MEMORYSTATUS_PROC_LIMIT_WARN;\n\t// Trigger a memory resource exception warning\n\tmalloc_memory_event_handler(event);\n\t\n\tchar *ptrs[1];\n\tptrs[0] = malloc(10);\n\t\n\tboolean_t lite_mode;\n\tkern_return_t ret = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_mode);\n\tEXPECT_TRUE(ret == KERN_SUCCESS, \"return from __mach_stack_logging_start_reading = %d\", ret);\n\tEXPECT_TRUE(lite_mode, \"return from __mach_stack_logging_start_reading - lite_mode = %d\", lite_mode);\n\t\n\t// check to see if malloc stacks are present\n\tcheck_stacks(ptrs, 1, true);\n\t\n\t// enter critical, should turn off stack logging and delete stack table\n\tevent = NOTE_MEMORYSTATUS_PROC_LIMIT_CRITICAL;\n\tmalloc_memory_event_handler(event);\n\t\n\t// verify that there are no stacks\n\t// First have to clear any cached uniquing table, then check again\n\t__mach_stack_logging_stop_reading(mach_task_self());\n\tret = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_mode);\n\tEXPECT_TRUE(ret != KERN_SUCCESS, \"return from __mach_stack_logging_start_reading = %d\", ret);\n\t__mach_stack_logging_stop_reading(mach_task_self());\n\t\n\t// now see if we can turn on malloc stack logging via the MSL commands - this should fail\n\tevent = MEMORYSTATUS_ENABLE_MSL_MALLOC;\n\tmalloc_memory_event_handler(event);\n\tret = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_mode);\n\tEXPECT_TRUE(ret != KERN_SUCCESS, \"return from __mach_stack_logging_start_reading = %d\", ret);\n\t\n\tfree(ptrs[0]);\n}\n\nT_DECL(msl_test_enable_disable_msl_malloc_malloc, \"Test enabling and disabling msl. malloc:malloc\")\n{\n\ttest_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_MALLOC, MEMORYSTATUS_ENABLE_MSL_MALLOC, false);\n}\n\nT_DECL(msl_test_enable_disable_msl_vm_vm, \"Test enabling and disabling msl. vm:vm\")\n{\n\ttest_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_VM, MEMORYSTATUS_ENABLE_MSL_VM, true);\n}\n\nT_DECL(msl_test_enable_disable_msl_all, \"Test enabling and disabling msl. all:all\")\n{\n\ttest_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_MALLOC | MEMORYSTATUS_ENABLE_MSL_VM, MEMORYSTATUS_ENABLE_MSL_MALLOC | MEMORYSTATUS_ENABLE_MSL_VM, false);\n}\n\nT_DECL(msl_test_enable_disable_msl_litefull_litefull, \"Test enabling and disabling msl. litefull:litefull\")\n{\n\ttest_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_LITE_FULL, MEMORYSTATUS_ENABLE_MSL_LITE_FULL, false);\n}\n\nT_DECL(msl_test_enable_disable_msl_litefull_malloc, \"Test enabling and disabling msl. litefull:malloc\")\n{\n\ttest_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_LITE_FULL, MEMORYSTATUS_ENABLE_MSL_MALLOC, false);\n}\n\nT_DECL(msl_test_enable_disable_msl_malloc_litefull, \"Test enabling and disabling msl. malloc:litefull\")\n{\n\ttest_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_MALLOC, MEMORYSTATUS_ENABLE_MSL_LITE_FULL, false);\n}\n\nT_DECL(msl_test_enable_disable_msl_litevm_malloc, \"Test enabling and disabling msl. litevm:malloc\")\n{\n\ttest_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_LITE_VM, MEMORYSTATUS_ENABLE_MSL_MALLOC, true);\n}\n\nT_DECL(msl_test_enable_disable_msl_malloc_litevm, \"Test enabling and disabling msl. malloc:litevm\")\n{\n\ttest_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_MALLOC, MEMORYSTATUS_ENABLE_MSL_LITE_VM, false);\n}\n\nT_DECL(msl_test_enable_disable_msl_litevm_litevm, \"Test enabling and disabling msl. litevm:litevm\")\n{\n\ttest_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_LITE_VM, MEMORYSTATUS_ENABLE_MSL_LITE_VM, true);\n}\n\nT_DECL(msl_test_enable_disable_msl_litefull_litevm, \"Test enabling and disabling msl. litefull:litevm\")\n{\n\ttest_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_LITE_FULL, MEMORYSTATUS_ENABLE_MSL_LITE_VM, false);\n}\n\nT_DECL(msl_test_enable_disable_msl_litevm_litefull, \"Test enabling and disabling msl. litevm:litefull\")\n{\n\ttest_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_LITE_VM, MEMORYSTATUS_ENABLE_MSL_LITE_FULL, true);\n}\n\n#else\n\nint\nmain(int argc, const char * argv[])\n{\n\tboolean_t nano_allocator_enabled = true;\n\tboolean_t validate_stacks = false;\n\tboolean_t lite_mode_enabled = false;\n\t\n\tchar *nano_zone = getenv(\"MallocNanoZone\");\n\tif (nano_zone) {\n\t\tif (strcmp(nano_zone, \"0\") == 0) {\n\t\t\tnano_allocator_enabled = false;\n\t\t}\n\t}\n\t\n\t// get the mode from the environment\n\tchar *mode = getenv(\"MallocStackLogging\");\n\t\n\tif (!mode) {\n\t\tstack_logging_mode_type mode_type = stack_logging_mode_none;\n\t\t\n\t\tmode = getenv(\"MallocStackLoggingMode\");\n\t\t\n\t\tif (mode) {\n\t\t\tif (strcmp(mode, \"all\") == 0) {\n\t\t\t\tmode_type = stack_logging_mode_all;\n\t\t\t\tvalidate_stacks = true;\n\t\t\t} else if (strcmp(mode, \"vm\") == 0) {\n\t\t\t\tmode_type = stack_logging_mode_vm;\n\t\t\t\tvalidate_stacks = false;\n\t\t\t} else if (strcmp(mode, \"malloc\") == 0) {\n\t\t\t\tmode_type = stack_logging_mode_malloc;\n\t\t\t\tvalidate_stacks = true;\n\t\t\t} else if (strcmp(mode, \"lite\") == 0) {\n\t\t\t\tmode_type = stack_logging_mode_lite;\n\t\t\t\tvalidate_stacks = true;\n\t\t\t\tlite_mode_enabled = true;\n\t\t\t} else if (strcmp(mode, \"none\") == 0) {\n\t\t\t\tmode_type = stack_logging_mode_none;\n\t\t\t\tvalidate_stacks = false;\n\t\t\t}\n\t\t}\n\t\tdo_test(mode_type, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n\t} else {\n\t\t// stack logging already turned on, so don't pass in a mode to dynamically enable\n\t\tif (strcmp(mode, \"lite\") == 0) {\n\t\t\tlite_mode_enabled = true;\n\t\t\tvalidate_stacks = true;\n\t\t} else if (strcmp(mode, \"vm\") == 0) {\n\t\t\tlite_mode_enabled = false;\n\t\t\tvalidate_stacks = false;\n\t\t} else {\n\t\t\tlite_mode_enabled = false;\n\t\t\tvalidate_stacks = true;\n\t\t}\n\t\t\n\t\tdo_test(stack_logging_mode_none, validate_stacks, nano_allocator_enabled, lite_mode_enabled);\n\t}\n\t\n\tPAUSE(\"At end of test. Run leaks now if desired.\\n\");\n\t\n\treturn 0;\n}\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/stress_test.c",
    "content": "/*\n * malloc_stress:  Stress the heck out of malloc(), and do a lot of\n *                 sanity checks that the malloc()'ed buffers are legit.\n *\n * usage:  malloc_stress [options...]\n *\n * Default:  Do random-sized malloc() calls until malloc() returns NULL\n *           or some signal kills the process.\n *           Randomly do a free() 10% of the time.\n *\n * Options:\n *    -min #bytes   malloc() at least #bytes per malloc() call.\n *    -max #bytes   malloc() no more than #byte per malloc() call.\n *    -mem #bytes   Stop when #bytes has been allocated.\n *    -calls #      Stop when #calls to malloc() have been executed.\n *    -time #sec    Stop if the number of seconds has elapsed.\n *    -seed #       Set the random seed to #.\n *    -free %       Randomly free() some % of the time.\n *    -dbg          Dump internal structures (could be voluminous!)\n *\n * Exits with status code:\n *    0    PASS\n *    1    FAIL (plus lots of stdout output)\n *    99   Illegal arguments or internal error.\n */\n\n#include <stdio.h>\n#include <unistd.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <errno.h>\n#include <err.h>\n\n#if DARWINTEST\n#include <darwintest.h>\n#endif\n\n/* globals */\nint rseed;\t /* initial random seed value */\nint min_bytes; /* minimum bytes to malloc */\nint max_bytes; /* maximum bytes to malloc */\n\nlong long max_mem;\t\t /* maximum total memory to allocate */\nlong long mem_allocated; /* memory allocated so far */\n\nint free_pct; /* call free() this pct of the time */\n\nint max_malloc_calls;  /* Maximum number of malloc() calls to make */\nint malloc_calls_made; /* Actual count of malloc()'s done */\nint malloc_bufs;\t   /* # of active malloc()'ed buffers (calls - freed) */\n\nint time_limit; /* How many seconds should this program run? */\n\nint debug_dump; /* Set to 1 to dump internal structures */\n\n/* Array size for remembering malloc info */\n#define MAX_MALLOC_INFO 10000000 /* 10 million */\n\n/* Remember significant info of each malloc() done. */\nstruct malloc_info {\n\tvoid *buf_ptr;\t\t   /* the ptr returned by malloc() */\n\tint buf_size;\t\t   /* count of bytes allocated */\n\tint set_val;\t\t   /* the value the buffer was set to */\n\tint this_buffer_freed; /* has this buffer been free()'d? */\n} minfo_array[MAX_MALLOC_INFO];\n\n/* Generate a random percentage (1-100) */\n#define D100 (1 + (rand() % 100))\n\nint signal_happened = 0; /* gets set to signal# if one happens */\n\nvoid\nsig_handler(int signo)\n{\n\tsignal_happened = signo;\n\treturn;\n}\n\nvoid\ntrap_signals()\n{\n\tint signum;\n\tfor (signum = 1; signum < NSIG; signum++) {\n\t\tif (signal(signum, sig_handler) == SIG_ERR && (signum != SIGKILL && signum != SIGSTOP)) {\n#if DARWINTEST\n\t\t\tT_FAIL(\"Could not trap signal %d (OK)\\n\", signum);\n#else\n\t\t\tprintf(\"INFO:  Could not trap signal %d (OK)\\n\", signum);\n#endif\n\t\t};\n\t}\n}\n\n/* Display a brief usage message and exit with status 99 */\nvoid\nusage()\n{\n\tprintf(\"\\nusage: malloc_stress [options...]\\n\");\n\tprintf(\"Default: Allocate up to %d buffers, with a %d percent free() chance.\\n\", MAX_MALLOC_INFO, free_pct);\n\tprintf(\"         Buffer sizes range from %d to %d bytes.\\n\", min_bytes, max_bytes);\n\tprintf(\"\\nOptions:\\n\");\n\tprintf(\"   -min #bytes    Minimum buffer size to allocate (at least 1).\\n\");\n\tprintf(\"   -max #bytes    Maximum buffer size (up to 2gb allowed).\\n\");\n\tprintf(\"   -mem #bytes    Stop when total allocations surpasses this.\\n\");\n\tprintf(\"   -free #        Percent chance to free a buffer.\\n\");\n\tprintf(\"   -calls #       Maximum allocations to do, then stop.\\n\");\n\tprintf(\"   -seed #        Set the random seed to this number.\\n\");\n\tprintf(\"   -dbg           Produce some debugging outputs.\\n\");\n\texit(99);\n}\n\n/*\n * summarize():  Give a brief synopsis of the number of malloc() calls made,\n *               free() calls made, total memory allocated.\n */\nvoid\nsummarize()\n{\n\tint mx;\n\n\tprintf(\"INFO: %d total malloc() calls made.\\n\", malloc_calls_made);\n\tprintf(\"INFO: %d total free() calls made during testing.\\n\", malloc_calls_made - malloc_bufs);\n\tprintf(\"INFO: Total memory allocated: %lld bytes\\n\", mem_allocated);\n\n\tif (debug_dump) {\n\t\tfor (mx = 0; mx < malloc_calls_made; mx++) {\n\t\t\tprintf(\"Buffer index %d: Address = 0x%llx, Size=%d, Fill=%d \", mx, (unsigned long long)(minfo_array[mx].buf_ptr),\n\t\t\t\t\tminfo_array[mx].buf_size, minfo_array[mx].set_val);\n\t\t\tif (minfo_array[mx].this_buffer_freed) {\n\t\t\t\tprintf(\"[freed]\");\n\t\t\t}\n\t\t\tprintf(\"\\n\");\n\t\t}\n\t}\n\tprintf(\"INFO: Random seed value = %d\\n\", rseed);\n\n\treturn;\n}\n\n/*\n * When we hit an end condition, every allocated buffer should be free()-able.\n */\nvoid\ncleanup()\n{\n\tint mx;\n#ifndef DARWINTEST\n\tprintf(\"Cleanup:  Started.\\n\");\n\n\tprintf(\"Cleanup:  Every allocated buffer should be free-able.\\n\");\n#endif\n\tfor (mx = 0; mx < malloc_calls_made; mx++) {\n\t\tif (!(minfo_array[mx].this_buffer_freed)) {\n\t\t\tfree(minfo_array[mx].buf_ptr);\n\t\t\tif (signal_happened) {\n#if DARWINTEST\n\t\t\t\tT_FAIL(\"Signal %d occurred during free(0x%llx)\", signal_happened, (unsigned long long)(minfo_array[mx].buf_ptr));\n#else\n\t\t\t\tprintf(\"FAIL:  Signal %d occurred during free(0x%llx)\\n\", signal_happened,\n\t\t\t\t\t\t(unsigned long long)(minfo_array[mx].buf_ptr));\n\t\t\t\texit(1);\n#endif\n\t\t\t}\n\t\t}\n\t}\n\treturn;\n}\n\n/*\n * Take a ptr and size, and another ptr and size, and verify they do not\n * overlap.  Return 0 if they are disjoint, or 1 if they overlap.\n */\nint\ncheck_overlap(void *p1, int len1, void *p2, int len2)\n{\n\tunsigned long long bob1, eob1, bob2, eob2;\n\n\t/* make begin and end ptrs in an integer form for easier comparison */\n\tbob1 = (unsigned long long)p1;\n\teob1 = bob1 + (unsigned long long)len1 - 1LL;\n\n\tbob2 = (unsigned long long)p2;\n\teob2 = bob2 + (unsigned long long)len2 - 1LL;\n\n\t/*\n\t * The begin and end points of one buffer should not be contained\n\t * between the begin and end points of the other buffer.\n\t */\n\tif ((bob1 >= bob2 && bob1 <= eob2) || (eob1 >= bob2 && eob1 <= eob2) || (bob2 >= bob1 && bob2 <= eob1) ||\n\t\t\t(eob2 >= bob1 && eob2 <= eob1)) {\n#ifdef DARWINTEST\n\t\tT_FAIL(\"Buffers overlap:  Buffer 1 (0x%llx, %d bytes), Buffer 2 (0x%llx, %d bytes)\", bob1, len1, bob2, len2);\n#else\n\t\tprintf(\"FAIL:  Buffers overlap:  Buffer 1 (0x%llx, %d bytes), Buffer 2 (0x%llx, %d bytes)\\n\", bob1, len1, bob2, len2);\n#endif\n\t\treturn 1; /* Indicate buffers overlap */\n\t}\n\n\treturn 0; /* buffers do not overlap */\n}\n\nvoid do_test(void);\n\n#ifndef DARWINTEST\nint\nmain(int argc, char *argv[])\n{\n\tint argx;\n\n\tmalloc_calls_made = malloc_bufs = 0;\n\tmem_allocated = 0;\n\n\t/* Set defaults */\n\trseed = (int)time(0);\n\tmin_bytes = 1;\n\tmax_bytes = (1024 * 1024);\t\t\t/* 1mb */\n\tmax_mem = 0;\t\t\t\t\t\t/* Continue until malloc() returns NULL */\n\tfree_pct = 10;\t\t\t\t\t\t/* Do a free() 10% of the time */\n\tmax_malloc_calls = MAX_MALLOC_INFO; /* no larger than our array */\n\n\ttime_limit = 0;\n\n\tdebug_dump = 0;\n\n\t/*\n\t * Process arguments.\n\t */\n\tfor (argx = 1; argx < argc; argx++) {\n\t\tif (strcmp(\"-min\", argv[argx]) == 0) {\n\t\t\tmin_bytes = atoi(argv[++argx]);\n\n\t\t} else if (strcmp(\"-max\", argv[argx]) == 0) {\n\t\t\tmax_bytes = atoi(argv[++argx]);\n\n\t\t} else if (strcmp(\"-mem\", argv[argx]) == 0) {\n\t\t\tmax_mem = atoll(argv[++argx]);\n\n\t\t} else if (strcmp(\"-seed\", argv[argx]) == 0) {\n\t\t\trseed = atoi(argv[++argx]);\n\n\t\t} else if (strcmp(\"-free\", argv[argx]) == 0) {\n\t\t\tfree_pct = atoi(argv[++argx]);\n\n\t\t} else if (strcmp(\"-calls\", argv[argx]) == 0) {\n\t\t\tmax_malloc_calls = atoi(argv[++argx]);\n\n\t\t} else if (strcmp(\"-time\", argv[argx]) == 0) {\n\t\t\ttime_limit = atoi(argv[++argx]);\n\n\t\t} else if (strcmp(\"-dbg\", argv[argx]) == 0) {\n\t\t\tdebug_dump = 1;\n\n\t\t} else if (strcmp(\"-h\", argv[argx]) == 0) {\n\t\t\tusage();\n\n\t\t} else {\n\t\t\tprintf(\"Unknown argument: '%s'\\n\", argv[argx]);\n\t\t\tusage();\n\t\t}\n\t}\n\n\t/* Sanity check the arguments */\n\n\tif (min_bytes < 1) {\n\t\tprintf(\"Minimum bytes (-min %d) must be at least 1.\\n\", min_bytes);\n\t\tusage();\n\t}\n\n\tif (max_bytes < 1) {\n\t\tprintf(\"Maximum bytes (-max %d) must be at least 1.\\n\", max_bytes);\n\t\tusage();\n\t}\n\n\tif (min_bytes > max_bytes) {\n\t\tprintf(\"Minimum bytes (-min %d) must not exceed max bytes (-max %d)\\n\", min_bytes, max_bytes);\n\t\tusage();\n\t}\n\n\tif (free_pct < 0 || free_pct > 100) {\n\t\tprintf(\"Percentage to free (-free %d) must be between 0 and 100.\\n\", free_pct);\n\t\tusage();\n\t}\n\n\tif (max_malloc_calls < 1) {\n\t\tprintf(\"Maximum malloc calls (-calls %d) must be at least 1.\\n\", max_malloc_calls);\n\t\tusage();\n\t}\n\n\tif (max_malloc_calls > MAX_MALLOC_INFO) {\n\t\tprintf(\"This program has been compiled for %d max allocations.\\n\", MAX_MALLOC_INFO);\n\t\tprintf(\"To support more, re-compile malloc_stress.c with a larger MAX_MALLOC_INFO\\n\");\n\t\tusage();\n\t}\n\n\tif (time_limit < 0) {\n\t\tprintf(\"The maximum execution time specified (%d seconds) must be 0 or positive.\\n\", time_limit);\n\t\tusage();\n\t}\n\n\t/* Describe our inputs and actions to be taken */\n\tif (max_malloc_calls) {\n\t\tprintf(\"Will call malloc() up to %d times.\\n\", max_malloc_calls);\n\t} else {\n\t\tprintf(\"Will call malloc() repeatedly until it returns NULL.\\n\");\n\t}\n\n\tif (min_bytes == max_bytes) {\n\t\tprintf(\"Will allocate buffers all of size %d bytes.\\n\", min_bytes);\n\t} else {\n\t\tprintf(\"Will allocate buffers between %d and %d bytes.\\n\", min_bytes, max_bytes);\n\t}\n\n\tif (free_pct) {\n\t\tprintf(\"Will free() a malloc'ed buffer %d%% of the time.\\n\", free_pct);\n\t} else {\n\t\tprintf(\"free() will NOT be called between malloc's.\\n\");\n\t}\n\n\tif (time_limit > 0) {\n\t\tprintf(\"Will stop after %d elapsed seconds.\\n\", time_limit);\n\t}\n\n\tsrand(rseed);\n\tprintf(\"Random seed value = %d\\n\", rseed);\n\tfflush(stdout);\n\n\tdo_test();\n\n\treturn 0;\n}\n#endif\n\nvoid\ndo_test(void)\n{\n\ttime_t start_time = time(0);\n\n\t/* Trap all signals that are possible to trap */\n\ttrap_signals();\n\n\t/*\n\t * Loop until we have some reason to quit.\n\t */\n\tfor (;;) {\n\t\tint buf_size;\n\t\tint bx;\n\t\tchar *malloc_buf;\n\t\tint set_buf_val;\n\t\tint save_errno;\n\n\t\t/* Have we exceeded our execution time limit? */\n\t\tif (time_limit > 0 && (time(0) - start_time >= time_limit)) {\n#if DARWINTEST\n\t\t\tcleanup();\n\t\t\tT_PASS(\"Ran until time limit without incident.\");\n\t\t\treturn;\n#else\n\t\t\tprintf(\"INFO: Execution time limit has been reached.\\n\");\n\t\t\tsummarize();\n\t\t\tcleanup();\n\t\t\tprintf(\"PASS\\n\");\n\t\t\texit(0);\n#endif\n\t\t}\n\n\t\t/* Is this a good time to free() a buffer? */\n\t\tif (malloc_bufs > 0 && (D100 < free_pct)) {\n\t\t\t/* Choose a random malloc'd buffer to free up */\n\t\t\tint random_buf;\n\n\t\t\t/* Find a currently allocated buffer to free */\n\t\t\tfor (;;) {\n\t\t\t\trandom_buf = rand() % malloc_calls_made;\n\t\t\t\tif (!(minfo_array[random_buf].this_buffer_freed)) {\n\t\t\t\t\tfree(minfo_array[random_buf].buf_ptr);\n\t\t\t\t\t/* If a signal happened, Fail */\n\t\t\t\t\tif (signal_happened) {\n#if DARWINTEST\n\t\t\t\t\t\tT_FAIL(\"Signal %d caught during free() of buffer 0x%llx\\n\", signal_happened,\n\t\t\t\t\t\t\t\t(unsigned long long)(minfo_array[random_buf].buf_ptr));\n\t\t\t\t\t\treturn;\n#else\n\t\t\t\t\t\tsummarize();\n\t\t\t\t\t\tprintf(\"FAIL:  Signal %d caught during free() of buffer 0x%llx\\n\", signal_happened,\n\t\t\t\t\t\t\t\t(unsigned long long)(minfo_array[random_buf].buf_ptr));\n\t\t\t\t\t\texit(1);\n#endif\n\t\t\t\t\t}\n\n\t\t\t\t\tminfo_array[random_buf].this_buffer_freed = 1;\n\t\t\t\t\tmalloc_bufs--; /* decrease the count of allocated bufs */\n\n\t\t\t\t\tif (debug_dump) {\n\t\t\t\t\t\tprintf(\"INFO: Freed buffer index %d, (%d bytes) at address 0x%llx\\n\", random_buf,\n\t\t\t\t\t\t\t\tminfo_array[random_buf].buf_size, (unsigned long long)(minfo_array[random_buf].buf_ptr));\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t/* Else it is a good time to malloc() a buffer */\n\t\tbuf_size = min_bytes + (rand() % (max_bytes - min_bytes + 1));\n\t\terrno = 0;\n\t\tmalloc_buf = malloc(buf_size);\n\t\tsave_errno = errno;\n\n\t\t/* If a signal was caught, summarize and FAIL */\n\t\tif (signal_happened) {\n#if DARWINTEST\n\t\t\tT_FAIL(\"Signal %d caught during malloc(%d).\", signal_happened, buf_size);\n\t\t\treturn;\n#else\n\t\t\tsummarize();\n\t\t\tprintf(\"FAIL:  Signal %d caught during malloc()!\\n\", signal_happened);\n\t\t\tprintf(\"Buffer size being allocated was %d bytes.\\n\", buf_size);\n\t\t\texit(1);\n#endif\n\t\t}\n\n\t\tif (debug_dump) {\n\t\t\tprintf(\"INFO: Allocated buffer (%d bytes) at address 0x%llx\\n\", buf_size, (unsigned long long)malloc_buf);\n\t\t}\n\n\t\t/* Did the malloc() succeed? */\n\t\tif (malloc_buf == NULL) {\n/* malloc() returned NULL;  make sure it was due to ENOMEM */\n#if DARWINTEST\n\t\t\tT_ASSERT_EQ_INT(save_errno, ENOMEM, \"malloc failed, but with errno = %d instead of ENOMEM.\", save_errno);\n\t\t\tcleanup();\n\t\t\tT_PASS(\"Ran out of memory without incident.\");\n\t\t\treturn;\n#else\n\t\t\tif (save_errno != ENOMEM) {\n\t\t\t\tprintf(\"FAIL:  malloc failed, but with errno = %d instead of ENOMEM.\\n\", save_errno);\n\t\t\t\tsummarize();\n\t\t\t\texit(1);\n\t\t\t}\n\t\t\tsummarize();\n\t\t\tcleanup(); /* Every malloc()'d buffer should be free()-able */\n\t\t\tprintf(\"PASS\\n\");\n\t\t\texit(0);\n#endif\n\t\t}\n\n\t\t/*\n\t\t * Sanity check that this buffer does not overlap with any other\n\t\t * buffer we have previously allocated.   NOTE:  Be sure to\n\t\t * skip minfo_array elements which have been free()'d previously.\n\t\t */\n\t\tfor (bx = 0; bx < malloc_calls_made; bx++) {\n\t\t\t/* Skip to the next if this buffer was free()'d before */\n\t\t\tif (minfo_array[bx].this_buffer_freed) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * The new buffer should not overlap with any other buffer.\n\t\t\t */\n\t\t\tif (check_overlap(malloc_buf, buf_size, minfo_array[bx].buf_ptr, minfo_array[bx].buf_size)) {\n#if DARWINTEST\n\t\t\t\treturn;\n#else\n\t\t\t\tsummarize();\n\t\t\t\tprintf(\"FAIL: Allocated buffer overlaps with buffer index %d\\n\", bx);\n\t\t\t\texit(1);\n#endif\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t * Verify that we can read the bytes of the buffer.\n\t\t * Note that malloc() does not (have to) initialize the buffer.\n\t\t * If any signal occurs while reading, FAIL.\n\t\t */\n\t\tfor (bx = 0; bx < buf_size; bx++) {\n\t\t\tchar byte;\n\t\t\t*((volatile char *)&byte) = *((volatile char *)malloc_buf + bx);\n\n\t\t\tif (signal_happened) {\n#if DARWINTEST\n\t\t\t\tT_FAIL(\"Signal %d caught reading buffer!\", signal_happened);\n\t\t\t\treturn;\n#else\n\t\t\t\tsummarize();\n\t\t\t\tprintf(\"FAIL:  Signal %d caught reading buffer!\\n\", signal_happened);\n\t\t\t\texit(1);\n#endif\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t * One malloc() requirement is that the buffer should be aligned\n\t\t * such that any numeric type can be stored using the base address,\n\t\t * assuming the buffer is large enough to hold that numeric type.\n\t\t * If the buffer is not well-aligned we might get a signal like\n\t\t * SIGSEGV (segmentation violation) or SIGBUS.\n\t\t * Be sure to do this test BEFORE the memset() operation below.\n\t\t */\n\t\tif (sizeof(short) <= buf_size) {\n\t\t\t*((short *)malloc_buf) = 1;\n\t\t}\n\n\t\tif (sizeof(int) <= buf_size) {\n\t\t\t*((int *)malloc_buf) = 2;\n\t\t}\n\n\t\tif (sizeof(long) <= buf_size) {\n\t\t\t*((long *)malloc_buf) = 3L;\n\t\t}\n\n\t\tif (sizeof(long long) <= buf_size) {\n\t\t\t*((long long *)malloc_buf) = 4LL;\n\t\t}\n\n\t\tif (sizeof(float) <= buf_size) {\n\t\t\t*((float *)malloc_buf) = 5.0;\n\t\t}\n\n\t\tif (sizeof(double) <= buf_size) {\n\t\t\t*((double *)malloc_buf) = 6.1;\n\t\t}\n\n\t\tif (sizeof(long double) <= buf_size) {\n\t\t\t*((long double *)malloc_buf) = 7.2;\n\t\t}\n\n\t\tif (signal_happened) {\n#if DARWINTEST\n\t\t\tT_FAIL(\"Signal %d occurred storing numeric types at address 0x%llx (%d bytes)\", signal_happened,\n\t\t\t\t\t(unsigned long long)malloc_buf, buf_size);\n\t\t\treturn;\n#else\n\t\t\tprintf(\"\\nFAIL:  Signal %d occurred storing numeric types at address 0x%llx (%d bytes)\\n\", signal_happened,\n\t\t\t\t\t(unsigned long long)malloc_buf, buf_size);\n\t\t\tsummarize();\n\t\t\texit(1);\n#endif\n\t\t}\n\n\t\t/* Pick a random byte value to set the bytes of the buffer to */\n\t\tset_buf_val = rand() & 0xFF;\n\t\tmemset(malloc_buf, set_buf_val, buf_size);\n\t\tif (signal_happened) {\n#if DARWINTEST\n\t\t\tT_FAIL(\"Signal %d caught initializing buffer to byte value %d!\", signal_happened, set_buf_val);\n\t\t\treturn;\n#else\n\t\t\tsummarize();\n\t\t\tprintf(\"FAIL:  Signal %d caught initializing buffer to byte value %d!\\n\", signal_happened, set_buf_val);\n\t\t\texit(1);\n#endif\n\t\t}\n\n\t\t/* Save the new malloc info */\n\n\t\tminfo_array[malloc_calls_made].buf_ptr = malloc_buf;\n\t\tminfo_array[malloc_calls_made].buf_size = buf_size;\n\t\tminfo_array[malloc_calls_made].set_val = set_buf_val;\n\t\tminfo_array[malloc_calls_made].this_buffer_freed = 0;\n\n\t\t/*\n\t\t * Update counts and sums.  Break out if we hit a requested limit.\n\t\t */\n\t\tmalloc_calls_made++;\n\t\tmalloc_bufs++;\n\t\tmem_allocated += buf_size;\n\n\t\tif (malloc_calls_made >= max_malloc_calls) {\n#if DARWINTEST\n\t\t\tcleanup();\n\t\t\tT_PASS(\"Maximum malloc calls reached: %d\", malloc_calls_made);\n\t\t\treturn;\n#else\n\t\t\tprintf(\"Maximum malloc calls reached: %d\\n\", malloc_calls_made);\n\t\t\tsummarize();\n\t\t\tcleanup();\n\t\t\tprintf(\"PASS\\n\");\n\t\t\texit(0);\n#endif\n\t\t}\n\n\t\tif (max_mem > 0 && mem_allocated >= max_mem) {\n#if DARWINTEST\n\t\t\tcleanup();\n\t\t\tT_PASS(\"Maximum memory allocation reached: %lld\", mem_allocated);\n\t\t\treturn;\n#else\n\t\t\tprintf(\"Maximum memory allocation reached: %lld\\n\", mem_allocated);\n\t\t\tcleanup();\n\t\t\tprintf(\"PASS\\n\");\n\t\t\texit(0);\n#endif\n\t\t}\n\n\t\t/* Now verify that no existing buffer has been stepped on */\n\t\tfor (bx = 0; bx < malloc_calls_made; bx++) {\n\t\t\tint cx;\n\t\t\tunsigned char *bptr = minfo_array[bx].buf_ptr;\n\t\t\tint expected_val = minfo_array[bx].set_val;\n\n\t\t\t/* A previously free()'d buffer might get re-used */\n\t\t\tif (minfo_array[bx].this_buffer_freed) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (cx = 0; cx < minfo_array[bx].buf_size; cx++) {\n\t\t\t\tif (bptr[cx] != expected_val) {\n#if DARWINTEST\n\t\t\t\t\tT_FAIL(\"Allocated buffer [%d] appears to have been stepped on.\", bx);\n\t\t\t\t\treturn;\n#else\n\t\t\t\t\tsummarize();\n\t\t\t\t\tprintf(\"FAIL: Allocated buffer [%d] appears to have been stepped on.\\n\", bx);\n\t\t\t\t\tprintf(\"Buffer address: 0x%llx, bad byte index %d\\n\", (unsigned long long)bptr, cx);\n\t\t\t\t\tprintf(\"Expected byte value %d, but found %d\\n\", expected_val, (int)(bptr[cx]));\n\t\t\t\t\texit(1);\n#endif\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* If any signal occurred, that's a FAIL too. */\n\t\t\tif (signal_happened) {\n#if DARWINTEST\n\t\t\t\tT_FAIL(\"Signal %d caught validating buffer contents.\\n\", signal_happened);\n\t\t\t\treturn;\n#else\n\t\t\t\tsummarize();\n\t\t\t\tprintf(\"FAIL:  Signal %d caught validating buffer contents.\\n\", signal_happened);\n\t\t\t\texit(1);\n#endif\n\t\t\t}\n\n\t\t} /* end then malloc succeeded */\n\n\t} /* end forever loop, until some end-point is reached  */\n}\n\n#if DARWINTEST\n\nstatic void\nsetup_and_test(void)\n{\n\t/* Set defaults */\n\trseed = 42;\n\tmin_bytes = 1;\n\tmax_bytes = (1024 * 1024);\t\t\t/* 1mb */\n\tmax_mem = (512 * 1024 * 1024);\t\t/* Continue until malloc() returns NULL */\n\tfree_pct = 10;\t\t\t\t\t\t/* Do a free() 10% of the time */\n\tmax_malloc_calls = MAX_MALLOC_INFO; /* no larger than our array */\n\t\n\ttime_limit = 15;\n\t\n\tdebug_dump = 0;\n\t\n\tdo_test();\n}\n\nT_DECL(malloc_stress, \"Stress the heck out of malloc()\")\n{\n\tsetup_and_test();\n}\n\nT_DECL(malloc_stress_msl_full, \"Stress the heck out of malloc() - enable malloc stack logging, full mode\", T_META_ENVVAR(\"MallocStackLogging=1\"))\n{\n\tsetup_and_test();\n}\n\nT_DECL(malloc_stress_msl_malloc, \"Stress the heck out of malloc() - enable malloc stack logging, malloc mode\", T_META_ENVVAR(\"MallocStackLogging=malloc\"))\n{\n\tsetup_and_test();\n}\n\nT_DECL(malloc_stress_msl_vm, \"Stress the heck out of malloc() - enable malloc stack logging, vm mode\", T_META_ENVVAR(\"MallocStackLogging=vm\"))\n{\n\tsetup_and_test();\n}\n\nT_DECL(malloc_stress_msl_lite, \"Stress the heck out of malloc() - enable malloc stack logging, lite mode\", T_META_ENVVAR(\"MallocStackLogging=lite\"))\n{\n\tsetup_and_test();\n}\n\n\n#endif"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tests/tsan.c",
    "content": "#include <darwintest.h>\n#include <dlfcn.h>\n#include <pthread.h>\n#include <stdlib.h>\n\nT_DECL(tsan_sanity, \"TSan Sanity Check\", T_META_CHECK_LEAKS(NO))\n{\n\tvoid *tsan_dylib = dlopen(\"@rpath/libclang_rt.tsan_osx_dynamic.dylib\", RTLD_NOLOAD);\n\tT_ASSERT_NOTNULL(tsan_dylib, \"TSan dylib loaded\");\n\n\tvoid *ptr = malloc(16);\n\tfree(ptr);\n\t\t\n\tT_PASS(\"I didn't crash!\");\n}\n\ntypedef unsigned long long invisible_barrier_t;\nvoid __tsan_testonly_barrier_init(invisible_barrier_t *barrier, unsigned count);\nvoid __tsan_testonly_barrier_wait(invisible_barrier_t *barrier);\nint __tsan_get_report_data(void *report, const char **description, int *count,\n\t\t\t\t\t\t   int *stack_count, int *mop_count, int *loc_count,\n\t\t\t\t\t\t   int *mutex_count, int *thread_count,\n\t\t\t\t\t\t   int *unique_tid_count, void **sleep_trace,\n\t\t\t\t\t\t   unsigned long trace_size);\n\nbool tsan_report_hit = false;\nchar *tsan_description = NULL;\ninvisible_barrier_t barrier;\n\nconst char *__tsan_default_options() {\n\treturn \"abort_on_error=0:exitcode=0\";\n}\n\nvoid __tsan_on_report(void *report) {\n\ttsan_report_hit = true;\n\n\tconst char *description;\n\tint count;\n\tint stack_count, mop_count, loc_count, mutex_count, thread_count,\n\tunique_tid_count;\n\tvoid *sleep_trace[16] = {0};\n\t__tsan_get_report_data(report, &description, &count, &stack_count, &mop_count,\n\t\t\t\t\t\t   &loc_count, &mutex_count, &thread_count,\n\t\t\t\t\t\t   &unique_tid_count, sleep_trace, 16);\n\ttsan_description = strdup(description);\n}\n\nvoid *thread1(void *arg) {\n\t__tsan_testonly_barrier_wait(&barrier);\n\t*((long *)arg) = 42;\n\treturn NULL;\n}\n\nvoid *thread2(void *arg) {\n\t*((long *)arg) = 43;\n\t__tsan_testonly_barrier_wait(&barrier);\n\treturn NULL;\n}\n\nT_DECL(tsan_data_race_stack, \"TSan Detects data-race on stack\", T_META_CHECK_LEAKS(NO))\n{\n\ttsan_description = NULL;\n\ttsan_report_hit = false;\n\t__tsan_testonly_barrier_init(&barrier, 2);\n\n\tlong racy_stack_value = 0;\n\tpthread_t t1;\n\tpthread_create(&t1, NULL, thread1, &racy_stack_value);\n\tpthread_t t2;\n\tpthread_create(&t2, NULL, thread2, &racy_stack_value);\n\tpthread_join(t2, NULL);\n\tpthread_join(t1, NULL);\n\n\tT_EXPECT_EQ(tsan_report_hit, true, \"tsan finds data-race\");\n\tT_EXPECT_NOTNULL(strstr(tsan_description, \"data-race\"), \"tsan header\");\n}\n\nT_DECL(tsan_data_race_heap, \"TSan Detects data-race on heap\", T_META_CHECK_LEAKS(NO))\n{\n\ttsan_description = NULL;\n\ttsan_report_hit = false;\n\t__tsan_testonly_barrier_init(&barrier, 2);\n\n\tlong *racy_heap_value = malloc(sizeof(long));\n\tpthread_t t1;\n\tpthread_create(&t1, NULL, thread1, racy_heap_value);\n\tpthread_t t2;\n\tpthread_create(&t2, NULL, thread2, racy_heap_value);\n\tpthread_join(t2, NULL);\n\tpthread_join(t1, NULL);\n\n\tT_EXPECT_EQ(tsan_report_hit, true, \"tsan finds data-race\");\n\tT_EXPECT_NOTNULL(strstr(tsan_description, \"data-race\"), \"tsan header\");\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tools/malloc_replay.cpp",
    "content": "/*\n * Copyright (c) 2016 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include <mach/mach_vm.h>\n#include <malloc/malloc.h>\n#include <ktrace/ktrace.h>\n#include <os/assumes.h>\n#include <sys/event.h>\n#include <numeric>\n#include <notify.h>\n#include <dlfcn.h>\n#include \"malloc_replay.h\"\n#include <map>\n#include <string>\n#include <sysexits.h>\n#include <perfdata/perfdata.h>\n#include <perfcheck_keys.h>\n\n#define capture_thread_counters(x, c) \\\n    if (c & (CONFIG_REC_COUNTERS | CONFIG_REC_STATS)) { \\\n        x = thread_instruction_count(); \\\n    }\n\n#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\n// Maximum size to map when reading replay file chunks\n#define MAX_REPLAY_FILE_CHUNK_SIZE (100 * 1024 * 1024)\n\n#endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\nstatic void (*s_funcMagSetThreadIndex)(unsigned int index);\n\nextern \"C\" int thread_selfcounts(int type, void *buf, size_t nbytes);\n\n//\n//Store counter values for each (call, size) tuple.\n//\ntypedef std::pair<int, uint32_t> CallSizePair;\ntypedef std::vector<uint16_t, ReplayAllocator<uint16_t>> ReplayVector;\nstatic std::map<CallSizePair, ReplayVector, std::less<CallSizePair>, ReplayAllocator<std::pair<const CallSizePair, ReplayVector>>> s_counterDistributions;\nstatic std::map<uint64_t, uint64_t, std::less<uint64_t>, ReplayAllocator<std::pair<const uint64_t, uint64_t> > > s_addressMap;\n\nstatic uint64_t s_totalEvents = 0;\nstatic uint64_t s_totalLibMallocEvents = 0;\nstatic uint64_t s_totalMallocEvents = 0;\nstatic uint64_t s_totalMalignEvents = 0;\nstatic uint64_t s_totalCallocEvents = 0;\nstatic uint64_t s_totalReallocEvents = 0;\nstatic uint64_t s_totalFreeEvents = 0;\nstatic uint64_t s_totalVallocEvents = 0;\nstatic uint64_t s_totalFailedFreeEvents = 0;\nstatic uint64_t s_totalFailedReallocEvents = 0;\n\nuint64_t call_ins_retired[operation_count] = {0};\nuint64_t call_count[operation_count] = {0};\n\nstatic const char *_DefaultFragMetricName = \"DefaultZoneFragmentation\";\nstatic const char *_DefaultNanoZone = \"DefaultMallocZone\";\n\nenum {\n\tCONFIG_REC_COUNTERS  = 1 << 0,\n\tCONFIG_REC_STATS     = 1 << 1,\n\tCONFIG_RUN_REPLAY    = 1 << 2,\n\tCONFIG_CONVERT_FILE  = 1 << 3,\n\tCONFIG_PAUSE         = 1 << 4,\n};\ntypedef uint8_t replay_config_t;\n\n//\n//Our allocator to allocate from a specific zone.\n//\nmalloc_zone_t* s_zone = NULL;\n\nstatic void\nconfigure_ktrace_session(ktrace_session_t s)\n{\n\tktrace_set_execnames_enabled(s, KTRACE_FEATURE_DISABLED);\n\tktrace_set_walltimes_enabled(s, KTRACE_FEATURE_DISABLED);\n\tktrace_set_uuid_map_enabled(s, KTRACE_FEATURE_DISABLED);\n\tktrace_set_thread_groups_enabled(s, KTRACE_FEATURE_DISABLED);\n}\n\nstatic uint64_t\nthread_instruction_count(void)\n{\n    uint64_t instrCounts[2] = {};\n    int err;\n    err = thread_selfcounts(1, &instrCounts, sizeof(instrCounts));\n    return instrCounts[0];\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//\n// run_ktrace - Takes a nullable input ktrace file path and an output file path.\n//              If the input file is NULL, this will setup a ktrace recording\n//              session targeted at a file in the output file path. If an input\n//              ktrace file path is provided, this will convert the ktrace file\n//              to the compressed mtrace format, targeted at the output file\n//              path.\n//\n////////////////////////////////////////////////////////////////////////////////\n\nconst int chunk_buffer_size = 16 * 1024 * 1024;\n\ntypedef union {\n\tstruct compressed_alloc alloc;\n\tstruct compressed_calloc calloc;\n\tstruct compressed_realloc realloc;\n\tstruct compressed_free free;\n\tstruct compressed_memalign memalign;\n} compressed_op_params;\n\nstatic bool\nrun_ktrace(const char* inputFile, const char* outputFile)\n{\n    __block uint32_t blockBytesWritten = 0;\n\n\tktrace_file_t output_file = ktrace_file_create(NULL, outputFile);\n\tif (!output_file) {\n\t\tprintf(\"Couldn't create output file: %s\\n\", outputFile);\n\t\treturn false;\n\t}\n\n\tktrace_session_t s = ktrace_session_create();\n\tif (inputFile) {\n\t\tif (ktrace_set_file(s, inputFile)) {\n\t\t\tprintf(\"Couldn't open file: %s\\n\", inputFile);\n\t\t\tktrace_file_close(output_file);\n\t\t\tktrace_session_destroy(s);\n\t\t\treturn false;\n\t\t}\n\t} else {\n\t\tassert(outputFile);\n\t\tktrace_set_signal_handler(s);\n\t}\n\n\tconfigure_ktrace_session(s);\n\n\tktrace_chunk_t events_chunk = ktrace_file_append_start(output_file,\n\t\t\tMALLOC_EVENTS_TAG, MALLOC_EVENTS_V_MAJOR, MALLOC_EVENTS_V_MINOR);\n\tif (!events_chunk) {\n\t\tktrace_file_close(output_file);\n\t\tktrace_session_destroy(s);\n\t\treturn false;\n\t}\n\n\tvoid *buffer = malloc(chunk_buffer_size);\n\tif (!buffer) {\n\t\tprintf(\"Could not allocate buffer for events\\n\");\n\t\tktrace_file_close(output_file);\n\t\tktrace_session_destroy(s);\n\t\treturn false;\n\t}\n\n\t__block void *next_ptr = buffer;\n\t__block size_t space_left = chunk_buffer_size;\n\n\tdispatch_group_t g = dispatch_group_create();\n\tdispatch_queue_t q = dispatch_queue_create(\"Read Source File\", DISPATCH_QUEUE_SERIAL);\n\n\tktrace_events_subclass(s, DBG_UMALLOC, DBG_UMALLOC_EXTERNAL, (^(ktrace_event_t event) {\n\t\ts_totalEvents++;\n\t\tif (space_left < sizeof(compressed_operation) + sizeof(compressed_op_params)) {\n\t\t\tktrace_file_append_data(output_file, events_chunk, buffer,\n\t\t\t\t\tchunk_buffer_size - space_left);\n\t\t\tblockBytesWritten += chunk_buffer_size - space_left;\n\t\t\tnext_ptr = buffer;\n\t\t\tspace_left = chunk_buffer_size;\n\t\t}\n\t\tunsigned int debugid = event->debugid;\n\t\tsize_t entry_size = 0;\n\n\t\tstruct compressed_operation *operation = (struct compressed_operation *)next_ptr;\n\t\toperation->core = (uint8_t)event->cpuid;\n\t\toperation->opcode = (uint8_t)KDBG_EXTRACT_CODE(debugid);\n\n\t\tswitch (debugid) {\n\t\tcase TRACE_malloc|DBG_FUNC_END:\n\t\tcase TRACE_valloc|DBG_FUNC_END: {\n\t\t\ts_totalLibMallocEvents++;\n\t\t\ts_totalMallocEvents++;\n\n\t\t\tstruct compressed_alloc *allocp = (struct compressed_alloc *)operation->body;\n\t\t\tallocp->size = (uint32_t)event->arg2;\n\t\t\tallocp->address = event->arg3;\n\t\t\tentry_size = sizeof(compressed_operation) + sizeof(struct compressed_alloc);\n\t\t\tbreak;\n\t\t}\n\t\tcase TRACE_calloc|DBG_FUNC_END: {\n\t\t\ts_totalLibMallocEvents++;\n\t\t\ts_totalCallocEvents++;\n\n\t\t\tstruct compressed_calloc *callocp = (struct compressed_calloc *)operation->body;\n\t\t\tcallocp->count = (uint32_t)event->arg2;\n\t\t\tcallocp->size = (uint32_t)event->arg3;\n\t\t\tcallocp->address = event->arg4;\n\t\t\tentry_size = sizeof(compressed_operation) + sizeof(struct compressed_calloc);\n\t\t\tbreak;\n\t\t}\n\t\tcase TRACE_memalign|DBG_FUNC_END: {\n\t\t\ts_totalLibMallocEvents++;\n\t\t\ts_totalMalignEvents++;\n\n\t\t\tstruct compressed_memalign *malignp = (struct compressed_memalign *)operation->body;\n\t\t\tmalignp->alignment = (uint32_t)event->arg2;\n\t\t\tmalignp->size = (uint32_t)event->arg3;\n\t\t\tmalignp->address = event->arg4;\n\t\t\tentry_size = sizeof(compressed_operation) + sizeof(struct compressed_memalign);\n\t\t\tbreak;\n\t\t}\n\t\tcase TRACE_realloc|DBG_FUNC_END: {\n\t\t\ts_totalLibMallocEvents++;\n\t\t\ts_totalReallocEvents++;\n\n\t\t\tstruct compressed_realloc *reallocp = (struct compressed_realloc *)operation->body;\n\t\t\treallocp->oldAddress = event->arg2;\n\t\t\treallocp->size = (uint32_t)event->arg3;\n\t\t\treallocp->newAddress = event->arg4;\n\t\t\tentry_size = sizeof(compressed_operation) + sizeof(struct compressed_realloc);\n\t\t\tbreak;\n\t\t}\n\t\tcase TRACE_free: {\n\t\t\ts_totalLibMallocEvents++;\n\t\t\ts_totalFreeEvents++;\n\n\t\t\tstruct compressed_free *freep = (struct compressed_free *)operation->body;\n\t\t\tfreep->address = event->arg2;\n\t\t\tentry_size = sizeof(compressed_operation) + sizeof(struct compressed_free);\n\t\t\tbreak;\n\t\t}\n\t\t}\n\t\tif (entry_size) {\n\t\t\tnext_ptr = (char *)next_ptr + entry_size;\n\t\t\tspace_left -= entry_size;\n\t\t}\n\t}));\n\tktrace_set_completion_handler(s, ^{\n\t\tdispatch_group_leave(g);\n\t});\n\tdispatch_group_enter(g);\n\n\tif (!ktrace_start(s, q)) {\n\t\tdispatch_group_wait(g, DISPATCH_TIME_FOREVER);\n\t} else {\n\t\tdispatch_group_leave(g);\n\t}\n\tdispatch_release(g);\n\tdispatch_release(q);\n\n\t// Write out any remaining data\n\tif (space_left < chunk_buffer_size) {\n\t\tktrace_file_append_data(output_file, events_chunk, buffer,\n\t\t\t\tchunk_buffer_size - space_left);\n\t\tblockBytesWritten += chunk_buffer_size - space_left;\n\t}\n\tfree(buffer);\n\n\tif (ktrace_file_append_finish(output_file, events_chunk)) {\n\t\tprintf(\"Failed to write events to %s\\n\", outputFile);\n\t}\n\tktrace_file_close(output_file);\n\tktrace_session_destroy(s);\n\n    //\n    //Dump out data about how many events we saw.\n    //\n    printf(\"TotalMalloc:        %16llu\\n\"\n           \"TotalCalloc:        %16llu\\n\"\n           \"TotalRealloc:       %16llu\\n\"\n           \"TotalMalign:        %16llu\\n\"\n           \"TotalFree:          %16llu\\n\"\n           \"\\n\"\n           \"TotalEvents:        %16llu\\n\"\n           \"TotalLibMalloc:     %16llu\\n\"\n           \"\\n\"\n           \"TotalBytesWritten:  %16u\\n\",\n           s_totalMallocEvents,\n           s_totalCallocEvents,\n           s_totalReallocEvents,\n           s_totalMalignEvents,\n           s_totalFreeEvents,\n           s_totalEvents,\n           s_totalLibMallocEvents,\n           blockBytesWritten\n\t);\n\n    return true;\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n//\n// dirty_memory - Writes the minimum number of bytes to dirty a range of memory.\n//\n////////////////////////////////////////////////////////////////////////////////\n\nstatic void\ndirty_memory(uint8_t* memory, size_t size)\n{\n\t*memory = 0xFF;\n\n\tuint8_t* current = (uint8_t*)round_page_kernel((uint64_t)memory);\n\tsize_t good_size = malloc_good_size(size);\n\twhile (current < (memory + good_size)) {\n\t\t*current = 0xFF;\n\t\tcurrent += vm_kernel_page_size;\n\t}\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n//\n// run_event - Decodes an operation into its actual event type and then calls the\n//            proper libmalloc function.  Returns the size of the event type so\n//            so the caller can move to the next compressed_operation.\n//\n////////////////////////////////////////////////////////////////////////////////\n\nstatic size_t\nrun_event(const struct compressed_operation* currentOperation,\n\t\tsize_t remainingMapping, replay_config_t config)\n{\n    void* event = (void *)currentOperation->body;\n    size_t bytesRead = sizeof(compressed_operation);\n    remainingMapping -= sizeof(compressed_operation);\n\n    if (s_funcMagSetThreadIndex){\n        s_funcMagSetThreadIndex(currentOperation->core);\n    }\n\n\tuint64_t preICount = 0;\n\tuint64_t postICount = 0;\n\tuint32_t reqAllocSize = 0;\n\n    //printf(\"EVENT : %llx\\n\", event);\n    switch (currentOperation->opcode) {\n\tcase op_malloc: {\n\t\tif (remainingMapping < sizeof(struct compressed_alloc)) {\n\t\t\treturn 0;\n\t\t}\n\t\tstruct compressed_alloc* alloc = (struct compressed_alloc*)event;\n\t\treqAllocSize = alloc->size;\n\t\tcapture_thread_counters(preICount, config);\n\t\tuint64_t* allocation = (uint64_t*)malloc(alloc->size);\n\t\tcapture_thread_counters(postICount, config);\n\t\tos_assert(allocation);\n\t\tdirty_memory((uint8_t*)allocation, alloc->size);\n\t\ts_addressMap.insert(std::make_pair(alloc->address, (uint64_t)allocation));\n\t\ts_totalMallocEvents++;\n\n\t\tbytesRead += sizeof(struct compressed_alloc);\n\t\tbreak;\n\t}\n\tcase op_calloc: {\n\t\tif (remainingMapping < sizeof(struct compressed_calloc)) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tstruct compressed_calloc* alloc = (struct compressed_calloc*)event;\n\t\treqAllocSize = alloc->size * alloc->count;\n\t\tcapture_thread_counters(preICount, config);\n\t\tuint64_t allocation = (uint64_t)calloc(alloc->count, alloc->size);\n\t\tcapture_thread_counters(postICount, config);\n\t\tos_assert(allocation);\n\t\tdirty_memory((uint8_t*)allocation, alloc->size * alloc->count);\n\t\ts_addressMap.insert(std::make_pair(alloc->address, allocation));\n\t\ts_totalCallocEvents++;\n\n\t\tbytesRead += sizeof(struct compressed_calloc);\n\t\tbreak;\n\t}\n\tcase op_memalign: {\n\t\tif (remainingMapping < sizeof(struct compressed_memalign)) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tstruct compressed_memalign* alloc = (struct compressed_memalign*)event;\n\t\treqAllocSize = alloc->size;\n\t\tuint64_t allocation = 0;\n\t\tcapture_thread_counters(preICount, config);\n\t\tposix_memalign((void**)&allocation, alloc->alignment, alloc->size);\n\t\tcapture_thread_counters(postICount, config);\n\t\tos_assert(allocation);\n\t\tdirty_memory((uint8_t*)allocation, alloc->size);\n\t\ts_addressMap.insert(std::make_pair(alloc->address, allocation));\n\t\ts_totalMalignEvents++;\n\n\t\tbytesRead += sizeof(struct compressed_memalign);\n\t\tbreak;\n\t}\n\tcase op_valloc: {\n\t\tif (remainingMapping < sizeof(struct compressed_alloc)) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tstruct compressed_alloc* alloc = (struct compressed_alloc*)event;\n\t\treqAllocSize = alloc->size;\n\t\tcapture_thread_counters(preICount, config);\n\t\tuint64_t allocation = (uint64_t)valloc(alloc->size);\n\t\tcapture_thread_counters(postICount, config);\n\t\tos_assert(allocation);\n\t\tdirty_memory((uint8_t*)allocation, alloc->size);\n\t\ts_addressMap.insert(std::make_pair(alloc->address, allocation));\n\t\ts_totalVallocEvents++;\n\n\t\tbytesRead += sizeof(struct compressed_alloc);\n\t\tbreak;\n\t}\n\tcase op_free: {\n\t\tif (remainingMapping < sizeof(struct compressed_free)) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tbytesRead += sizeof(struct compressed_free);\n\n\t\tstruct compressed_free* freed = (struct compressed_free*)event;\n\t\tauto iter = s_addressMap.find(freed->address);\n\t\tif (iter == s_addressMap.end()) {\n\t\t\ts_totalFailedFreeEvents++;\n\t\t\tbreak;\n\t\t}\n\t\tcapture_thread_counters(preICount, config);\n\t\tfree((void*)iter->second);\n\t\tcapture_thread_counters(postICount, config);\n\t\ts_addressMap.erase(iter);\n\t\ts_totalFreeEvents++;\n\t\tbreak;\n\t}\n\tcase op_realloc: {\n\t\tif (remainingMapping < sizeof(struct compressed_realloc)) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tbytesRead += sizeof(struct compressed_realloc);\n\n\t\tstruct compressed_realloc* alloc = (struct compressed_realloc*)event;\n\t\treqAllocSize = alloc->size;\n\t\tauto iter = s_addressMap.find(alloc->oldAddress);\n\t\tif (iter == s_addressMap.end()) {\n\t\t\ts_totalFailedReallocEvents++;\n\t\t\tbreak;\n\t\t}\n\n\t\tuint64_t oldAddress = iter->second;\n\t\tcapture_thread_counters(preICount, config);\n\t\tuint64_t newAddress = (uint64_t)realloc((void*)oldAddress, alloc->size);\n\t\tcapture_thread_counters(postICount, config);\n\t\tos_assert(newAddress);\n\t\tdirty_memory((uint8_t*)newAddress, alloc->size);\n\t\ts_addressMap.erase(iter);\n\t\ts_addressMap.insert(std::make_pair(alloc->newAddress, newAddress));\n\t\ts_totalReallocEvents++;\n\t\tbreak;\n\t}\n\tdefault:\n\t\t__builtin_trap();\n\t\tbreak;\n    };\n\n\tif (config & (CONFIG_REC_COUNTERS | CONFIG_REC_STATS)) {\n\t\tuint64_t diff = postICount - preICount;\n\t\tuint16_t instrCount = diff <= UINT16_MAX ? diff : UINT16_MAX;\n\t\tif (config & CONFIG_REC_STATS) {\n\t\t\tcall_ins_retired[currentOperation->opcode - 1] += instrCount;\n\t\t\tcall_count[currentOperation->opcode - 1]++;\n\t\t}\n\t\tif ((config & CONFIG_REC_COUNTERS) && reqAllocSize > 0) {\n\t\t\tauto lookup = CallSizePair(currentOperation->opcode, reqAllocSize);\n\t\t\tauto iter = s_counterDistributions.find(lookup);\n\t\t\tif (iter != s_counterDistributions.end()) {\n\t\t\t\titer->second.push_back(instrCount);\n\t\t\t} else {\n\t\t\t\ts_counterDistributions.insert({lookup, ReplayVector(1, instrCount)});\n\t\t\t}\n\t\t}\n\t}\n\n    return bytesRead;\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n//\n// setup_private_malloc_zone - Creates a malloc zone for use during actual replay.\n//                          We need to do so in order to keep the bookkeeping\n//                          separate from the replayed data.  This zone is not\n//                          counted when figuring out fragmentation.\n//\n////////////////////////////////////////////////////////////////////////////////\n\nstatic bool\nsetup_private_malloc_zone()\n{\n    s_zone = malloc_create_zone(0, 0);\n    if (!s_zone) {\n        printf(\"Couldn't create zone\\n\");\n        return false;\n    }\n\n    malloc_set_zone_name(s_zone, \"IGNORE_THIS_ZONE\");\n    return true;\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n//\n// memory_reader - Read from ourselves, instead of a remote process like vmmap\n//                 does.\n//\n////////////////////////////////////////////////////////////////////////////////\n\nstatic kern_return_t\nmemory_reader(task_t remote_task, vm_address_t remote_address, vm_size_t size,\n\t\tvoid **local_memory)\n{\n    if (local_memory) {\n        *local_memory = (void*)remote_address;\n        return KERN_SUCCESS;\n    }\n\n    return KERN_FAILURE;\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n//\n// vm_range_recorder - Enumerate all the malloc vm ranges, looking at each page\n//                     to figure out if it is resident or not, and dirty or not.\n//                     Used to calculate fragmentation.\n//\n////////////////////////////////////////////////////////////////////////////////\n\nstatic void\nvm_range_recorder(task_t task, void* context, unsigned type, vm_range_t *ranges,\n\t\tunsigned count)\n{\n\tfor (unsigned currentRange = 0; currentRange < count; currentRange++ ) {\n\t\treplay_malloc_magazine magazine = {\n\t\t\t.baseAddress = ranges[currentRange].address,\n\t\t\t.extent = ranges[currentRange].address + ranges[currentRange].size\n\t\t};\n\n\t\tfor (uint64_t i = magazine.baseAddress; i < magazine.extent; i += vm_kernel_page_size) {\n\t\t\tkern_return_t err = 0;\n\t\t\tinteger_t disposition = 0;\n\t\t\tinteger_t refCount = 0;\n\n\t\t\terr = mach_vm_page_query(mach_task_self(), i, &disposition, &refCount);\n\t\t\tif (!err) {\n\t\t\t\tif (disposition & VM_PAGE_QUERY_PAGE_PRESENT) {\n\t\t\t\t\tif (disposition & (VM_PAGE_QUERY_PAGE_COPIED|VM_PAGE_QUERY_PAGE_DIRTY)) {\n\t\t\t\t\t\tmagazine.pages_dirty++;\n\t\t\t\t\t}\n\n\t\t\t\t\tmagazine.pages_resident++;\n\t\t\t\t} else if (disposition & VM_PAGE_QUERY_PAGE_PAGED_OUT){\n\t\t\t\t\tmagazine.pages_dirty++;\n\t\t\t\t\tmagazine.pages_resident++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t((replay_malloc_zone_t)context)->magazines.push_back(magazine);\n\t}\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n//\n// run_malloc_replay - Replay a compressed malloc trace.  The idea here is to replay\n//                   the recorded events while forcing a specific CPU.  By doing\n//                   so libmalloc will target a specific magazine.  This way we\n//                   can see how the current allocator would pack an old allocation\n//                   stream.\n//\n////////////////////////////////////////////////////////////////////////////////\n\nstatic bool\nrun_malloc_replay(const char* fileName, pdwriter_t perfDataWriter, replay_config_t config)\n{\n    if (!setup_private_malloc_zone()) {\n        return false;\n    }\n\n\tktrace_session_t s = ktrace_session_create();\n\tif (ktrace_set_file(s, fileName)) {\n\t\tprintf(\"Couldn't open file: %s\\n\", fileName);\n\t\tktrace_session_destroy(s);\n        return false;\n\t}\n\tconfigure_ktrace_session(s);\n\n\tdispatch_group_t g = dispatch_group_create();\n\tdispatch_queue_t q = dispatch_queue_create(\"Read Malloc Trace File\",\n\t\t\tDISPATCH_QUEUE_SERIAL);\n\n\tktrace_chunks(s, MALLOC_EVENTS_TAG, ^(ktrace_chunk_t c) {\n\t\tif (ktrace_chunk_version_major(c) != MALLOC_EVENTS_V_MAJOR\n\t\t\t\t|| ktrace_chunk_version_minor(c) != MALLOC_EVENTS_V_MINOR) {\n\t\t\tprintf(\"Invalid replay file: %s\\n\", fileName);\n\t\t\texit(1);\n\t\t}\n\n\t\tsize_t size = (size_t)ktrace_chunk_size(c);\n\t\toff_t offset = 0;\n\t\twhile (size > sizeof(compressed_operation)) {\n\t\t\tvoid *ptr;\n\t\t\tsize_t mapped_size = size;\n#ifdef MAX_REPLAY_FILE_CHUNK_SIZE\n\t\t\tmapped_size = MIN(mapped_size, MAX_REPLAY_FILE_CHUNK_SIZE);\n#endif // MAX_REPLAY_FILE_CHUNK_SIZE\n\n\t\t\t// Map as much of the chunk as we can. If we can't map everything,\n\t\t\t// keep halving the requested size until we get to something that\n\t\t\t// works. If nothing works, bail.\n\t\t\tdo {\n\t\t\t\tptr = ktrace_chunk_map_data(c, offset, mapped_size);\n\t\t\t\tif (!ptr) {\n\t\t\t\t\tmapped_size /= 2;\n\t\t\t\t}\n\t\t\t} while (!ptr && mapped_size);\n\n\t\t\tif (!mapped_size) {\n\t\t\t\tperror(\"Could not map replay file chunk\");\n\t\t\t\texit(1);\n\t\t\t}\n\n\t\t\tstruct compressed_operation* event = (struct compressed_operation*)ptr;\n\t\t\tsize_t size_left = mapped_size;\n\t\t\tdo {\n\t\t\t\tsize_t read = run_event(event, size_left, config);\n\t\t\t\tif (read == 0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\ts_totalLibMallocEvents++;\n\n\t\t\t\tsize_left -= read;\n\t\t\t\tsize -= read;\n\t\t\t\toffset += read;\n\n\t\t\t\tevent = (struct compressed_operation*)((char *)event + read);\n\t\t\t} while (size_left > sizeof(compressed_operation));\n\n\t\t\tktrace_chunk_unmap_data(c, ptr, mapped_size);\n\t\t}\n\t});\n\n\tktrace_set_completion_handler(s, ^{\n\t\tdispatch_group_leave(g);\n\t});\n\tdispatch_group_enter(g);\n\n\tktrace_events_all(s, ^(ktrace_event_t event) { });\n\tif (!ktrace_start(s, q)) {\n\t\tdispatch_group_wait(g, DISPATCH_TIME_FOREVER);\n\t} else {\n\t\tdispatch_group_leave(g);\n\t}\n\tdispatch_release(g);\n\tdispatch_release(q);\n\n\ts_addressMap.clear();\n\tktrace_session_destroy(s);\n\n    //\n    //If passed a writer, output performance data.\n    //\n    if (perfDataWriter) {\n        pdwriter_new_value(perfDataWriter, \"TotalMalloc\", PDUNIT_CUSTOM(totalmalloc), s_totalMallocEvents);\n        pdwriter_new_value(perfDataWriter, \"TotalCalloc\", PDUNIT_CUSTOM(totalcalloc), s_totalCallocEvents);\n        pdwriter_new_value(perfDataWriter, \"TotalRealloc\", PDUNIT_CUSTOM(totalrealloc), s_totalReallocEvents);\n        pdwriter_new_value(perfDataWriter, \"TotalValloc\", PDUNIT_CUSTOM(totalvalloc), s_totalVallocEvents);\n        pdwriter_new_value(perfDataWriter, \"TotalMalign\", PDUNIT_CUSTOM(totalmalign), s_totalMalignEvents);\n        pdwriter_new_value(perfDataWriter, \"TotalFree\", PDUNIT_CUSTOM(totalfree), s_totalFreeEvents);\n        pdwriter_new_value(perfDataWriter, \"FailedRealloc\", PDUNIT_CUSTOM(failedrealloc), s_totalFailedReallocEvents);\n        pdwriter_new_value(perfDataWriter, \"FailedFree\", PDUNIT_CUSTOM(failedfree), s_totalFailedFreeEvents);\n    }\n\n\tprintf(\"TotalMalloc:    %16llu\\n\"\n           \"TotalCalloc:    %16llu\\n\"\n           \"TotalRealloc:   %16llu\\n\"\n           \"TotalValloc:    %16llu\\n\"\n           \"TotalMalign:    %16llu\\n\"\n           \"TotalFree:      %16llu\\n\"\n           \"\\n\"\n           \"FailedRealloc:  %16llu\\n\"\n           \"FailedFree:     %16llu\\n\",\n           s_totalMallocEvents,\n           s_totalCallocEvents,\n           s_totalReallocEvents,\n           s_totalVallocEvents,\n           s_totalMalignEvents,\n           s_totalFreeEvents,\n           s_totalFailedReallocEvents,\n           s_totalFailedFreeEvents\n           );\n\n    //\n    //Now lets go over the data and find how fragmented we are.\n    //\n    vm_address_t* addresses = NULL;\n    unsigned count = 0;\n\n    printf(\"\\n\\n\\n\");\n    printf(\"Zone:                     BytesDirty      BytesInUse  %%Frag\\n\");\n    printf(\"===========================================================\\n\");\n\n\tdouble defaultFrag = 0;\n\n    malloc_get_all_zones(mach_task_self(), memory_reader, &addresses, &count);\n    for (unsigned i = 0; i < count; i++) {\n        malloc_zone_t* zone = (malloc_zone_t*)addresses[i];\n        replay_malloc_zone zoneInfo = { 0 };\n        if (strcmp(zone->zone_name, \"IGNORE_THIS_ZONE\") != 0) {\n            malloc_statistics_t stats = {0};\n            zone->introspect->enumerator(mach_task_self(), &zoneInfo, MALLOC_PTR_REGION_RANGE_TYPE, (vm_address_t)zone, memory_reader, vm_range_recorder);\n            zone->introspect->statistics(zone, &stats);\n\n            uint64_t bytesDirty = 0;\n\n            for (const auto& magazine : zoneInfo.magazines) {\n                bytesDirty += magazine.pages_dirty * vm_kernel_page_size;\n\t\t\t\t//printf(\"%llx %llx %d\\n\", magazine.baseAddress, magazine.extent, magazine.pages_dirty);\n            }\n\n            double frag = (bytesDirty && (stats.size_in_use < bytesDirty)) ? 100 - (100.0 * stats.size_in_use)/bytesDirty : 0;\n\n            printf(\"%20s  %14llu  %14lu %6.2f\\n\", zone->zone_name, bytesDirty, stats.size_in_use, frag);\n            if (perfDataWriter) {\n                pdwriter_new_value(perfDataWriter, \"BytesDirty\", pdunit_bytes, bytesDirty);\n                pdwriter_record_variable_str(perfDataWriter, \"ZoneName\", zone->zone_name);\n                pdwriter_new_value(perfDataWriter, \"BytesInUse\", pdunit_bytes, stats.size_in_use);\n                pdwriter_record_variable_str(perfDataWriter, \"ZoneName\", zone->zone_name);\n                pdwriter_new_value(perfDataWriter, \"Fragmentation\", PDUNIT_CUSTOM(FragmentedPercent), frag);\n                pdwriter_record_variable_str(perfDataWriter, \"ZoneName\", zone->zone_name);\n\n\t\t\t\tif (strcmp(zone->zone_name, _DefaultNanoZone) == 0) {\n\t\t\t\t\tdefaultFrag = frag;\n\t\t\t\t}\n            }\n        }\n    }\n\n\tif (perfDataWriter) {\n\t\t//\n\t\t//Write out the fragmentation in DefaultMallocZone as a primary metric.\n\t\t//\n\t\tpdwriter_new_value(perfDataWriter, _DefaultFragMetricName, PDUNIT_CUSTOM(FragmentedPercent), defaultFrag);\n\t\tpdwriter_record_variable(perfDataWriter, kPCFailureThresholdPctVar, 10);\n\t} else if (config & CONFIG_REC_STATS){\n\t\tprintf(\"\\n\\n\\n\");\n\t\tprintf(\"Call       Cycles (mean)\\n\");\n\t\tprintf(\"=====================\\n\");\n\t}\n\n\t//\n\t//If we were asked to gather instruction counts, iterate through them and\n\t//either output the mean for the call or the raw counts for each\n\t//call:requested-size pair.\n\t//\n\tif (config & (CONFIG_REC_COUNTERS | CONFIG_REC_STATS)) {\n\t\tjson_t jsonW = NULL;\n\t\tif (perfDataWriter && (config & CONFIG_REC_COUNTERS)) {\n\t\t\t//\n\t\t\t//Write out the instruction count data. We record into an extension\n\t\t\t//since there's typically a large numbers of counts.\n\t\t\t//\n\t\t\tjsonW = pdwriter_start_extension(perfDataWriter, \"libmalloc.instruction_counts\");\n\t\t\tif (jsonW) {\n\t\t\t\tfor (auto const &mCallDistribution : s_counterDistributions) {\n\t\t\t\t\t//\n\t\t\t\t\t//If requested, write the i-counts out to the perfdata.\n\t\t\t\t\t//\n\t\t\t\t\tchar description[16];\n\t\t\t\t\tsnprintf(description, sizeof(description), \"%d:%u\", mCallDistribution.first.first, mCallDistribution.first.second);\n\t\t\t\t\tjson_member_start_object(jsonW, description);\n\t\t\t\t\tjson_member_int(jsonW, \"call\", mCallDistribution.first.first);\n\t\t\t\t\tjson_member_int(jsonW, \"size\", mCallDistribution.first.second);\n\t\t\t\t\tjson_member_uint(jsonW, \"count\", (unsigned int)mCallDistribution.second.size());\n\t\t\t\t\tjson_member_start_array(jsonW, \"values\");\n\t\t\t\t\tfor (uint64_t val : mCallDistribution.second) {\n\t\t\t\t\t\tjson_value_uint(jsonW, (unsigned int)val);\n\t\t\t\t\t}\n\t\t\t\t\tjson_end_array(jsonW); // Inner counts\n\t\t\t\t\tjson_end_object(jsonW);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t//\n\t\t//Output the mean number of instructions retired.\n\t\t//\n\t\tif (config & CONFIG_REC_STATS) {\n\t\t\tfor (int i = 0; i < operation_count; i++) {\n\t\t\t\tif (call_ins_retired[i] > 0 && call_count[i] > 0) {\n\t\t\t\t\tuint64_t mean = call_ins_retired[i] / call_count[i];\n\t\t\t\t\tif (perfDataWriter) {\n\t\t\t\t\t\tchar full_name[16];\n\t\t\t\t\t\t// operation enum is indexed from 1, adjust index for mcall_to_name.\n\t\t\t\t\t\tsnprintf(full_name, sizeof(full_name), \"%s-mean\", mcall_to_name(i + 1));\n\t\t\t\t\t\tpdwriter_new_value(perfDataWriter, full_name, pdunit_instructions, mean);\n\t\t\t\t\t\tpdwriter_record_variable(perfDataWriter, kPCFailureThresholdPctVar, 100);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tprintf(\"%9s  %6llu\\n\", mcall_to_name(i + 1), mean);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (jsonW) {\n\t\t\tpdwriter_end_extension(perfDataWriter, jsonW);\n\t\t}\n\t}\n\treturn true;\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n//\n// usage - Output help.\n//\n////////////////////////////////////////////////////////////////////////////////\n\nstatic void\nusage()\n{\n    printf(\"libmalloc_replay -r <input mtrace file> [-p] [-j filename] [-t testname] [-c | -s]\\n\");\n    printf(\"libmalloc_replay [-i <input artrace file>] -o <output mtrace file> [-p]\\n\");\n    printf(\"\\t-p Pause the replay process before exit\\n\");\n    printf(\"\\t-j  <output file>\\toutput perfdata V2 formatted file\\n\");\n    printf(\"\\t-t  <test name>\\tset the test name for the perfdata V2 formatted output file\\n\");\n    printf(\"\\t-c capture and output instruction counts along with the performance data.\\n\");\n    printf(\"\\t-s capture and output instruction count statistics along with the performance data.\\n\");\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n//\n// main - Yep.\n//\n////////////////////////////////////////////////////////////////////////////////\n\nint\nmain(int argc, char** argv)\n{\n    char * inputMTrace = NULL;\n    char * inputKtrace = NULL;\n    char * outputMTrace = NULL;\n    char * outputPerfData = NULL;\n    char * outputTestName = NULL;\n    replay_config_t config = 0;\n    int c = 0;\n\n    if (argc < 2) {\n        usage();\n        return -1;\n    }\n\n    while ((c = getopt(argc, (char* const*)argv, \"phr:i:o:j:t:cs\")) != -1) {\n      switch (c) {\n\t\tcase 'r':\n\t\t\tinputMTrace = strdup(optarg);\n\t\t\tconfig |= CONFIG_RUN_REPLAY;\n\t\t\tbreak;\n\t\tcase 'i':\n\t\t\tinputKtrace = strdup(optarg);\n\t\t\tif (inputKtrace && outputMTrace) {\n\t\t\t\tconfig |= CONFIG_CONVERT_FILE;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'o':\n\t\t\toutputMTrace = strdup(optarg);\n\t\t\tif (inputKtrace && outputMTrace) {\n\t\t\t\tconfig |= CONFIG_CONVERT_FILE;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'p':\n\t\t\tconfig |= CONFIG_PAUSE;\n\t\t\tbreak;\n\t\tcase 'j':\n\t\t\toutputPerfData = strdup(optarg);\n\t\t\tbreak;\n\t\tcase 't':\n\t\t\toutputTestName = strdup(optarg);\n\t\t\tbreak;\n\t\tcase 'c':\n\t\t\tconfig |= CONFIG_REC_COUNTERS;\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tconfig |= CONFIG_REC_STATS;\n\t\t\tbreak;\n\t\tcase 'h':\n\t\tdefault:\n\t\t\tusage();\n\t\t\treturn EX_USAGE;\n        }\n    }\n\n\tif ((config & CONFIG_REC_COUNTERS) && (config & CONFIG_REC_STATS)) {\n\t\tprintf(\"Invalid usage: -c and -s\\n\");\n\t\tusage();\n\t\treturn EX_USAGE;\n\t}\n\n\ttimespec beginTime = {0};\n\n    pdwriter_t writer = NULL;\n    if (outputPerfData) {\n        char dataPath[MAXPATHLEN];\n\n        //\n        //Ensure the filename is prepended with libmalloc\n        //\n        const char *prepend = \"libmalloc\";\n        auto outputFilePath = std::string(outputPerfData);\n        const auto namePos = outputFilePath.find_last_of('/') + 1;\n        if (outputFilePath.find(prepend, namePos) != namePos) {\n            outputFilePath.insert(namePos, prepend);\n        }\n        int ret = snprintf(dataPath, sizeof(dataPath), \"%s.%d.%llx.\" PD_FILE_EXT,\n                           outputFilePath.c_str(), getpid(), mach_absolute_time());\n        if (ret < 0) {\n            return errno;\n        }\n\t\tauto perfdataName = std::string(\"libmalloc.replay.\");\n\t\tperfdataName += outputTestName ? outputTestName : dataPath;\n\t\twriter = pdwriter_open(dataPath, perfdataName.c_str(), 0, 0);\n\t\tif (!writer) {\n\t\t\tprintf(\"\\n****Couldn't open writer for performance data file. Error: %s\\n\", strerror(errno));\n\t\t} else {\n\t\t\tpdwriter_set_primary_metric(writer, _DefaultFragMetricName);\n\t\t}\n    }\n\n\tif (config & CONFIG_RUN_REPLAY) {\n\t\tvoid *libmalloc = dlopen(\"/usr/lib/system/libsystem_malloc.dylib\", RTLD_NOW);\n\t\tif (libmalloc) {\n\t\t\ts_funcMagSetThreadIndex = (void (*)(unsigned int))dlsym(libmalloc, \"mag_set_thread_index\");\n\t\t}\n\n\t\tif (!s_funcMagSetThreadIndex) {\n\t\t\tprintf(\"\\n****Couldn't load mag_set_thread_index, replay won't honor core****\\n\\n\");\n\t\t}\n\n\t\tclock_gettime(CLOCK_MONOTONIC_RAW, &beginTime);\n\n\n\t\tif (!run_malloc_replay(inputMTrace, writer, config)) {\n\t\t\treturn -1;\n\t\t}\n\t} else if (config & CONFIG_CONVERT_FILE) {\n\t\tclock_gettime(CLOCK_MONOTONIC_RAW, &beginTime);\n\t\tif (!run_ktrace(inputKtrace, outputMTrace)) {\n\t\t\tprintf(\"\\n****Couldn't record mtrace file.\\n\");\n\t\t}\n\t} else if (outputMTrace) {\n\t\tclock_gettime(CLOCK_MONOTONIC_RAW, &beginTime);\n\t\tif (!run_ktrace(NULL, outputMTrace)) {\n\t\t\tprintf(\"\\n****Couldn't record mtrace file.\\n\");\n\t\t}\n\t}\n\n\tif (beginTime.tv_sec) {\n\t\ttimespec endTime;\n\t\tclock_gettime(CLOCK_MONOTONIC_RAW, &endTime);\n\t\tprintf(\"\\n\\nRuntime: %ld ms\\n\", ((endTime.tv_sec - beginTime.tv_sec) * 1000) + (endTime.tv_nsec - beginTime.tv_nsec)/1000000);\n\t}\n\n    if (writer) {\n      pdwriter_close(writer);\n    }\n\n\tif (config & CONFIG_PAUSE) {\n\t\tprintf(\"\\n\\nProcess paused, hit Crtl+C to exit\\n\");\n\t\tpause();\n\t}\n\n    return 0;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tools/malloc_replay.h",
    "content": "/*\n * Copyright (c) 2018 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __MALLOC_REPLAY_H\n#define __MALLOC_REPLAY_H\n\n#include \"trace.h\"\n#include <vector>\n\n//\n//Our file format\n//\n\n// Definitions for the event chunk.\n#define MALLOC_EVENTS_TAG\t(uint32_t)0xe001e001\n#define MALLOC_EVENTS_V_MAJOR\t1\n#define MALLOC_EVENTS_V_MINOR\t1\n\nenum operation {\n    op_malloc = 0x01,\n    op_free = 0x02,\n    op_realloc = 0x03,\n    op_memalign = 0x04,\n    op_calloc = 0x05,\n    op_valloc = 0x06,\n};\n\nstatic const int operation_count = op_valloc;\nstatic const char *mcall_names[] = {\"malloc\", \"free\", \"realloc\", \"memalign\", \"calloc\", \"valloc\"};\n\nstatic inline const char *\nmcall_to_name(int call_num) {\n\tif (call_num > 0 && call_num <= operation_count) {\n\t\treturn mcall_names[call_num - 1];\n\t}\n\treturn NULL;\n}\n\nenum flags {\n    flag_stacks     = 0x00000001,\n    flag_timestamps = 0x00000002\n};\n\nstruct compressed_header {\n    uint16_t version;\n    uint64_t flags;\n} __attribute__((packed));\n\nstruct compressed_operation {\n\tuint8_t opcode;\n\tuint8_t core;\n\tuint32_t body[];\n}__attribute__((packed));\n\nstruct compressed_alloc {\n    uint64_t address;\n    uint32_t size;\n} __attribute__((packed));\n\nstruct compressed_calloc {\n    uint64_t address;\n    uint32_t count;\n    uint32_t size;\n} __attribute__((packed));\n\nstruct compressed_memalign {\n    uint64_t address;\n    uint32_t alignment;\n    uint32_t size;\n} __attribute__((packed));\n\nstruct compressed_free {\n    uint64_t address;\n} __attribute__((packed));\n\nstruct compressed_realloc {\n    uint64_t oldAddress;\n    uint64_t newAddress;\n    uint32_t size;\n} __attribute__((packed));\n\nstruct compressed_stack_key {\n    uint64_t stackKey;\n} __attribute__((packed));\n\nstruct compressed_time {\n    uint64_t timestamp;\n} __attribute__((packed));\n\n\n//\n//Our allocator to allocate from a specific zone.\n//\nextern malloc_zone_t* s_zone;\n\ntemplate <class T>\nclass ReplayAllocator {\npublic:\n    // type definitions\n    typedef T        value_type;\n    typedef T*       pointer;\n    typedef const T* const_pointer;\n    typedef T&       reference;\n    typedef const T& const_reference;\n    typedef std::size_t    size_type;\n    typedef std::ptrdiff_t difference_type;\n\n    // rebind allocator to type U\n    template <class U>\n    struct rebind {\n        typedef ReplayAllocator<U> other;\n    };\n\n    // return address of values\n    pointer address (reference value) const\n\t{\n        return &value;\n    }\n    const_pointer address (const_reference value) const\n\t{\n        return &value;\n    }\n\n    /* constructors and destructor\n     * - nothing to do because the allocator has no state\n     */\n    ReplayAllocator() throw() { }\n    ReplayAllocator(const ReplayAllocator&) throw() { }\n    template <class U>\n    ReplayAllocator (const ReplayAllocator<U>&) throw() { }\n    ~ReplayAllocator() throw() { }\n\n    // return maximum number of elements that can be allocated\n    size_type max_size () const throw()\n\t{\n        return std::numeric_limits<std::size_t>::max() / sizeof(T);\n    }\n\n    // allocate but don't initialize num elements of type T\n    pointer allocate (size_type num, const void* = 0)\n\t{\n        return (pointer)malloc_zone_malloc(s_zone, num * sizeof(T));\n    }\n\n    // initialize elements of allocated storage p with value value\n    void construct (pointer p, const T& value)\n\t{\n        // initialize memory with placement new\n        new((void*)p)T(value);\n    }\n\n    // destroy elements of initialized storage p\n    void destroy (pointer p)\n\t{\n        // destroy objects by calling their destructor\n        p->~T();\n    }\n\n    // deallocate storage p of deleted elements\n    void deallocate (pointer p, size_type num)\n\t{\n        malloc_zone_free(s_zone, p);\n    }\n};\n\ntemplate <class T1, class T2>\nbool operator== (const ReplayAllocator<T1>&,\n                 const ReplayAllocator<T2>&) throw()\n{\n    return true;\n}\ntemplate <class T1, class T2>\nbool operator!= (const ReplayAllocator<T1>&,\n                 const ReplayAllocator<T2>&) throw()\n{\n    return false;\n}\n\ntypedef struct replay_malloc_magazine {\n    uint64_t baseAddress;\n    uint64_t extent;\n    uint32_t pages_resident;\n    uint32_t pages_dirty;\n} *replay_malloc_magazine_t;\n\ntypedef struct replay_malloc_zone {\n    const char* name;\n    std::vector<replay_malloc_magazine, ReplayAllocator<replay_malloc_magazine> > magazines;\n} *replay_malloc_zone_t;\n\n\n#endif // __MALLOC_REPLAY_H\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tools/malloc_replay_plotter.py",
    "content": "#!/usr/bin/env python\n\nfrom __future__ import absolute_import\nfrom __future__ import unicode_literals\nfrom __future__ import division\nfrom __future__ import print_function\n\nimport sys\nimport os\nimport re\nimport argparse\nimport logging\nimport json\nfrom pprint import pprint\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n\nclass ReportConfiguration(object):\n\n    def __init__(self, report_type, call, nano_malloc_cutoff, xfilter, num_bins, merge_calloc, fileV1, fileV2):\n        self.report_type = report_type\n        self.call = call\n        self.nano_malloc_cutoff = nano_malloc_cutoff\n        self.xfilter = xfilter\n        self.num_bins = num_bins\n        self.merge_calloc = merge_calloc\n        self.fileV1 = fileV1\n        self.fileV2 = fileV2\n\n    def plotter_class(self):\n        if self.report_type == \"scatter\":\n            return ScatterPlotter\n        if self.report_type == \"instructions\":\n            return InstructionsPlotter\n        if self.report_type == \"request_sizes\":\n            return RequestSizePlotter\n        if self.report_type == \"nano_request_bins\":\n            return RequestSizePlotter\n        if self.report_type == \"nano_request_bins_ysize\":\n            return RequestSizePlotter\n\n    def call_identifier(self):\n        return self.call_identifier_for_name(self.call)\n\n    @classmethod\n    def call_identifier_for_name(cls, name):\n        mapping = {'malloc': 1, 'realloc': 3, 'memalign': 4, 'calloc': 5, 'valloc': 6}\n        return mapping[name]\n\n    @classmethod\n    def configuration_for_arguments(cls, args):\n        return cls(args.report_type, args.call, args.nano_malloc_cutoff, args.xfilter, args.num_bins, args.merge_calloc, args.fileV1, args.fileV2)\n\n\nclass ReportData(object):\n\n    def __init__(self, fileV1, fileV2):\n        self.fileV1 = fileV1\n        self.fileV2 = fileV2\n\n        self.all_data = []\n        self.frag = []\n        self.paths = [fileV1, fileV2]\n\n        self.parse_input_files()\n\n    def parse_input_files(self):\n        with open(self.fileV1) as f:\n            self.all_data.append(json.load(f))\n        if self.fileV2:\n            with open(self.fileV2) as f:\n                self.all_data.append(json.load(f))\n        self.calculate_fragmentation()\n\n    def enumerate(self):\n        for i, data in enumerate(self.all_data):\n            yield i, data, self.frag[i], self.paths[i]\n\n    def fileV1_data(self):\n        return self.all_data[0]\n\n    def num_plots(self):\n        return 2 if self.fileV1 and self.fileV2 else 1\n\n    def calculate_fragmentation(self):\n        for data in self.all_data:\n            total_frag = 0\n            data = data['data']\n            for obj in data:\n                for i in obj:\n                    if 'variables' in i:\n                        if i['metric'] == 'Fragmentation':\n                            total_frag += i['value']\n            self.frag.append(total_frag)\n\n\nclass Plotter(object):\n\n    def __init__(self, report_configuration):\n        self.configuration = report_configuration\n\n    def plot(self, report_data):\n        pass\n\n    # Returns a list of sizes requested and the frequency at which this request\n    # was made.\n    def size_freq_for_data(self, data, call_identifier):\n        size_filter = self.configuration.nano_malloc_cutoff\n        if not size_filter:\n           size_filter = size.maxint\n\n        size_freq = []\n        for ext, counts in data['extensions']['libmalloc.instruction_counts'].items():\n            if counts['call'] == call_identifier and int(counts['size']) <= size_filter:\n                size_freq.append([counts['size'], counts['count']])\n        return size_freq\n\n    # Returns a list of lists of ([size, [instruction counts]]). Where size is the\n    # requested size and instruction counts are the number of CPU instructions it took (as\n    # recorded by libmalloc_replay. If coalesce is set, this instead returns a\n    # coalesced list of instruction counts ([instruction counts]), flattened across all\n    # request sizes.\n    def times_for_data(self, data, call_identifier, coalesce):\n        size_filter = self.configuration.nano_malloc_cutoff\n        if not size_filter:\n            size_filter = size.maxint\n        times = []\n        for ext, counts in data['extensions']['libmalloc.instruction_counts'].items():\n            if counts['call'] == call_identifier and int(counts['size']) <= size_filter:\n                if coalesce:\n                    times += counts['values']\n                else:\n                    times.append([counts['size'], counts['values']])\n        return times\n\n    def show(self):\n        plt.show()\n\n    def write_to_path(self, path):\n        plt.savefig(path)\n\n\nclass ScatterPlotter(Plotter):\n\n    def plot(self, report_data):\n        plt.figure(figsize=(20,10))\n        labels = [\"V1\", \"V2\"]\n        colours = ['r', 'b']\n        for i, data, _, _ in report_data.enumerate():\n            logging.debug(\"Building data\")\n            sizecounts = self.times_for_data(data, self.configuration.call_identifier(), False)\n            sizes = []\n            counts = []\n            for pair in sizecounts:\n                rsize = pair[0]\n                for icount in pair[1]:\n                    sizes.append(rsize)\n                    counts.append(icount)\n            colmark = colours[i] + 'x'\n            logging.debug(\"Plotting scatter\")\n            scatter, = plt.plot(sizes, counts, colmark)\n            scatter.set_label(labels[i])\n        plt.xlabel(\"Requested Size (Bytes)\")\n        plt.ylabel(\"Instruction Count\")\n        plt.legend()\n\n\nclass InstructionsPlotter(Plotter):\n\n    def plot(self, report_data):\n        num_plots = report_data.num_plots()\n        fig = plt.figure(figsize=(20, num_plots * 5))\n        subplot_config = 221 if num_plots == 2 else 121\n\n        for i, data, fragmentation, path in report_data.enumerate():\n            all_times = self.times_for_data(data, self.configuration.call_identifier(), True)\n\n            # We may want to just filter for a certain range (0, xfilter)\n            if self.configuration.xfilter:\n                filtered = [t for t in all_times if t < self.configuration.xfilter]\n            else:\n                filtered = all_times\n\n            logging.debug(\"Plotting: Histogram\")\n            # Histogram\n            h_ax = plt.subplot(subplot_config)\n            subplot_config += 1\n            self.hist_data(filtered, False, 1)\n            if self.configuration.xfilter > 0:\n                h_ax.set_xlim([0, self.configuration.xfilter.xfilter])\n\n            plt.suptitle('{}: {}'.format(path, self.configuration.call))\n\n            logging.debug(\"Plotting: CDF\")\n            # CDF\n            ax = plt.subplot(subplot_config)\n            subplot_config += 1\n            self.hist_data(all_times, True, 0)\n\n            # Table\n            logging.debug(\"Producing table\")\n            per50 = np.percentile(all_times, 50)\n            per75 = np.percentile(all_times, 75)\n            per95 = np.percentile(all_times, 95)\n\n            tblstr = 'Fragmentation: {}%\\n50th: {}\\n75th: {}\\n95th: {}'.format(fragmentation, per50, per75, per95)\n            ax.text(0, 0.1, tblstr, bbox=dict(facecolor='white'), horizontalalignment='right', verticalalignment='top')\n\n    def hist_data(self, data, cumulative, width):\n        norm = 1 if cumulative else 0\n        plt.hist(data, bins=self.configuration.num_bins, log=False, cumulative=cumulative, linewidth=width, normed=norm)\n        plt.xlabel(\"Instruction Counts\")\n        if cumulative:\n            plt.title(\"Cumulative\")\n\n\nclass RequestSizePlotter(Plotter):\n\n        def sort_split_and_fill_size_freqs(self, size_freq):\n            # Sort by the size. Then split into two lists.\n            size_freq.sort(key=lambda x: x[0])\n            sizes = [i[0] for i in size_freq]\n            counts = [i[1] for i in size_freq]\n\n            # Fill out the arrays where we didn't see events. This helps when we\n            # bin the data later.\n            sparse_sizes = []\n            sparse_counts = []\n            i = 0\n            j = 0\n            while i < max(sizes):\n                if sizes[j] == (i + 1):\n                    sparse_sizes.append(sizes[j])\n                    sparse_counts.append(counts[j])\n                    j = j + 1\n                else:\n                    sparse_sizes.append(i+1)\n                    sparse_counts.append(0)\n                i = i + 1\n            return sparse_sizes, sparse_counts\n\n        def merge_size_counts(self, sizes, counts, sizes_c, counts_c):\n            # Merge the calloc data with malloc. N.b. The lists can be different lengths; merge into sizes.\n            if len(sizes_c) > len(sizes):\n                tmpS = sizes\n                tmpC = counts\n                sizes = sizes_c\n                counts = counts_c\n                sizes_c = tmpS\n                counts_c = tmpC\n            for i in range(len(sizes)):\n                if i >= len(sizes_c):\n                    break\n                assert(sizes[i] == sizes_c[i])\n                counts[i] = counts[i] + counts_c[i]\n            return sizes, counts\n\n        def plot(self, report_data):\n            plt.figure(figsize=(50, 10))\n            plt_config = 211\n            calls = ['malloc']\n            if not self.configuration.merge_calloc:\n                plt_config = 311\n                calls.append('calloc')\n            calls.append('realloc')\n\n            for call_name in calls:\n                logging.debug('Plotting: %s' % call_name)\n                call_identifier = self.configuration.call_identifier_for_name(call_name)\n\n                data = report_data.fileV1_data()\n                size_freq = self.size_freq_for_data(data, call_identifier)\n                sizes, counts = self.sort_split_and_fill_size_freqs(size_freq)\n\n                # calloc merging\n                if self.configuration.merge_calloc and call_name == 'malloc':\n                    size_freq_calloc = self.size_freq_for_data(data, 5)\n                    sizes_c, counts_c = self.sort_split_and_fill_size_freqs(size_freq_calloc)\n                    sizes, counts = self.merge_size_counts(sizes, counts, sizes_c, counts_c)\n\n                # Bin the data\n                num_bins = 16\n                binned_counts = [0] * 16\n                curr_bin = 0\n                bin_num = 0\n                for i in range(max(sizes))[1:]:\n                    if i % num_bins == 0 and i != 0:\n                        logging.debug('Bin end: %d' % i)\n                        binned_counts[bin_num] = curr_bin\n                        # Extra logging. Enable this if you want to output the\n                        # counts in each bin to the console.\n                        #logging.debug('  Count: %d' % curr_bin)\n                        bin_num = bin_num + 1\n                        curr_bin = 0\n                    if self.configuration.report_type == \"nano_request_bins_ysize\":\n                        curr_bin = curr_bin + (counts[i-1] * sizes[i-1])\n                    else:\n                        curr_bin = curr_bin + counts[i-1]\n\n                # Draw the plot\n                ax = plt.subplot(plt_config)\n                plt_config += 1\n                if self.configuration.report_type == \"nano_request_bins\" or self.configuration.report_type == \"nano_request_bins_ysize\":\n                    ax.bar(range(num_bins), binned_counts)\n                    ax.set_xticks(range(num_bins))\n                    x_labels = range(1, 256, 16)\n                    x_labels.append(\"0\")\n                    ax.set_xticklabels(x_labels)\n                    ax.set_xlabel(\"Request size (bytes)\", fontsize=12)\n                    if self.configuration.report_type == \"nano_request_bins_ysize\":\n                        ax.set_ylabel(\"Total Requested (Bytes)\")\n                    else:\n                        ax.set_ylabel(\"Frequency\")\n                    ax.set_title(call_name)\n                else:\n                    plt.bar(sizes, counts)\n\n                plt.suptitle(self.configuration.fileV1)\n                plt.subplots_adjust(hspace=0.5)\n\n\nclass Tool(object):\n\n    def __init__(self, args):\n        self.args = args\n\n    def run(self):\n        logging.debug('Loading JSON')\n        configuration = ReportConfiguration.configuration_for_arguments(self.args)\n        plotter_class = configuration.plotter_class()\n        plotter = plotter_class(configuration)\n        report_data = ReportData(self.args.fileV1, self.args.fileV2)\n        plotter.plot(report_data)\n\n        if self.args.show_plot:\n            plotter.show()\n        else:\n            plotter.write_to_path(self.args.output)\n\n    @classmethod\n    def main(cls):\n        parser = argparse.ArgumentParser(description='Analyze libmalloc_replay perfdata output. This takes as input a .pdj file containing request sizes and instruction counts and outputs various plots.')\n        parser.add_argument('fileV1', help='Path to nano V1 data JSON file')\n        parser.add_argument('fileV2', nargs='?', help='Optional path to nano V2 data JSON file')\n        parser.add_argument('--report', dest='report_type', choices=['instructions', 'scatter', 'request_sizes', 'nano_request_bins', 'nano_request_bins_ysize'], default='instructions', help='The report type to produce (default: %(default)s)')\n        parser.add_argument('--call', dest='call', default='malloc', choices=['malloc', 'calloc', 'realloc', 'memalign', 'valloc'], help=\"The call to analyze (default: %(default)s)\")\n        parser.add_argument('-f', '--xfilter', type=int, default=0, help=\"Filter the histogram to a range from 0 to <%(dest)s)>\")\n        parser.add_argument('-b', '--num_bins', type=int, default=10000, help=\"The number of bins to use for histogrammed data (default: %(default)s)\")\n        parser.add_argument('-n', '--nano_malloc_cutoff', type=int, default=256, help=\"The cutoff size to filter for (default: %(default)s bytes)\")\n        parser.add_argument('--merge_calloc', action='store_true', default=False, help='Merge calloc calls with malloc. For use with the nano_request_bins, nano_request_bins_ysize and request_sizes reports.')\n        parser.add_argument('-v', '--verbose', action='store_true', help='Enable verbose debug logging')\n        output_group = parser.add_mutually_exclusive_group(required=True)\n        output_group.add_argument('-s', '--show_plot', action='store_true')\n        output_group.add_argument('-o', '--output', default='fig.pdf', help=\"The output file path, including type extension (default: %(default)s)\")\n\n        args = parser.parse_args()\n        if args.verbose:\n            logging.basicConfig(level=logging.DEBUG)\n\n        cls(args).run()\n\n\nif __name__ == \"__main__\":\n    Tool.main()\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tools/radix_tree_main.m",
    "content": "/*\n * Copyright (c) 2017 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#import <Foundation/Foundation.h>\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <getopt.h>\n\n#include \"../src/radix_tree_internal.h\"\n\nvoid\nusage() {\n\tprintf (\"usage: radix-tree [-l 0xADDRESS | 0xSTART-0xEND] FILENAME\\n\");\n\tprintf (\"\\n\");\n\tprintf (\"This is a debugging tool for the radix-tree sidetable used to track VM allocations\\n\");\n\tprintf (\"under MallocStackLogging=lite.\\n\");\n\tprintf (\"\\n\");\n\tprintf (\"  radix-tree FILE                # print out radix tree as text\\n\");\n\tprintf (\"  radix-tree -l 0xf00 FILE       # lookup address in radix tree\\n\");\n\tprintf (\"  radix-tree -l 0xf00-0xba FILE  # lookup address range in radix tree\\n\");\n\tprintf (\"\\n\");\n\texit(0);\n}\n\nuint64_t minsize = 4096;\n\nint main(int argc, char **argv) {\n\tint ch;\n\tuint64_t start = 0, end = 0;\n\twhile ((ch = getopt(argc, argv, \"l:\")) != -1) {\n\t\tswitch (ch) {\n\t\t\tcase 'l': {\n\t\t\t\tchar *p = strchr(optarg, '-');\n\t\t\t\tif (p) {\n\t\t\t\t\t*p = 0;\n\t\t\t\t\tend = strtoull(p+1, NULL, 16);\n\t\t\t\t\tstart = strtoull(optarg, NULL, 16);\n\t\t\t\t} else {\n\t\t\t\t\tstart = strtoull(optarg, NULL, 16);\n\t\t\t\t}\n\t\t\t\tif (start%minsize || end%minsize) {\n\t\t\t\t\tusage();\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\tcase '?':\n\t\t\t\tusage();\n\t\t}\n\t}\n\targc -= optind;\n\targv += optind;\n\tif (argc != 1)\n\t\tusage();\n\n\tNSData *data;\n\tif (0==strcmp(argv[0], \"-\")) {\n\t\tdata = [[NSFileHandle fileHandleWithStandardInput] readDataToEndOfFile];\n\t} else {\n\t\tdata = [NSData dataWithContentsOfFile:[NSString stringWithUTF8String:argv[0]]];\n\t}\n\tif (!data) {\n\t\tfprintf(stderr, \"failed to read data\\n\");\n\t\treturn 1;\n\t}\n\n\tstruct radix_tree *tree = (void*) [data bytes];\n\tradix_tree_fsck(tree);\n\n\tif (start != 0 && end != 0) {\n\t\tuint64_t last_stackid = -1;\n\t\tuint64_t last_start = 0;\n\t\tfor (uint64_t a = start; a <= end; a += minsize) {\n\t\t\tuint64_t stackid = a == end ? -1 : radix_tree_lookup(tree, a);\n\t\t\tif (last_stackid != -1) {\n\t\t\t\tif (stackid != last_stackid) {\n\t\t\t\t\tprintf (\"[%llx-%llx] -> %llx\\n\", last_start, a, last_stackid);\n\t\t\t\t\tlast_stackid = stackid;\n\t\t\t\t\tlast_start = a;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (stackid != -1) {\n\t\t\t\t\tlast_stackid = stackid;\n\t\t\t\t\tlast_start = a;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else if (start != 0) {\n\t\tprintf (\"%llx -> %llx\\n\", start, radix_tree_lookup(tree, start));\n\t} else {\n\t\tradix_tree_print(tree);\n\t}\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/tools/read-radix-tree",
    "content": "#!/usr/bin/perl\n\n# read the radix tree out of a process and write it to stdout\n\nmy $proc = shift;\n\nmy @vmmap_out = `vmmap -vw -interleaved -noCoalesce $proc`;\nmy $pid;\n\nfor (@vmmap_out) {\n  if (/^Process:.*\\[(\\d+)\\]\\s*$/) {\n    $pid = $1;\n  }\n  if (/^Performance tool data \\s*([0-9a-fA-F]+)-([0-9a-fA-F]+)/) {\n    my $addr = $1;\n    my $end = $2;\n    if (`memread $pid 0x$addr 7` eq \"radixv2\") {\n      exec sprintf(\"memread $pid 0x$addr 0x%x\", hex($end) - hex($addr));\n    }\n  }\n}\n\nprintf STDERR \"not found\\n\";\nexit 1;\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/xcodeconfig/interposable.list",
    "content": "_realloc\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/xcodeconfig/libmalloc.dirty",
    "content": "_max_magazines\n_malloc_entropy\n_first_block_offset_by_size_class\n_last_block_offset_by_size_class\n_ptr_offset_to_size_class\n_nano_common_max_magazines\n_phys_ncpus\n_logical_ncpus\n_entropic_address\n_entropic_limit\n_nanov2_config_predicate\n_pFRZCounterLive\n_pFRZCounterDrain\n__malloc_engaged_nano\n_malloc_num_zones\n_malloc_num_zones_allocated\n_malloc_zones\n_malloc_debug_flags\n__malloc_no_asl_log\n_stack_logging_dontcompact\n_stack_logging_finished_init\n__malloc_entropy_initialized\n_malloc_default_purgeable_zone.dpz\n__malloc_initialize_pred\n_initial_default_zone\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/xcodeconfig/libmalloc.xcconfig",
    "content": "#include \"<DEVELOPER_DIR>/Makefiles/CoreOS/Xcode/BSD.xcconfig\"\n\nSDKROOT = macosx.internal\nSUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator\nBUILD_VARIANTS = normal debug\n\nPRODUCT_NAME = libsystem_malloc\nINSTALL_PATH = /usr/lib/system\nPUBLIC_HEADERS_FOLDER_PATH = /usr/include/malloc\nPRIVATE_HEADERS_FOLDER_PATH = /usr/local/include\n\nSYSTEM_FRAMEWORK_HEADERS = $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders\nHEADER_SEARCH_PATHS = $(DERIVED_FILES_DIR)/dtrace $(SRCROOT)/include $(SYSTEM_FRAMEWORK_HEADERS) $(SDKROOT)/usr/local/include $(inherited)\n\nGCC_PREPROCESSOR_DEFINITIONS = _FORTIFY_SOURCE=0 NDEBUG $(OSATOMIC_PREPROCESSOR_DEFINITIONS) $(PLATFORM_PREPROCESSOR_DEFINITIONS)\nOSATOMIC_PREPROCESSOR_DEFINITIONS = OSATOMIC_USE_INLINED=1 OS_UNFAIR_LOCK_INLINE=1\nOSATOMIC_PREPROCESSOR_DEFINITIONS_NOINLINE = OSATOMIC_DEPRECATED=0 OSATOMIC_USE_INLINED=0 OS_UNFAIR_LOCK_INLINE=0\n\nGCC_NO_COMMON_BLOCKS = YES\nENABLE_STRICT_OBJC_MSGSEND = YES\n\n// TODO: Add -fno-stack-protector when uplink to Libc is removed\nOTHER_CFLAGS = $(PLATFORM_CFLAGS)\nOTHER_CFLAGS_normal = -momit-leaf-frame-pointer\nOTHER_CFLAGS_debug = -fstack-protector -fno-inline -O0 -DDEBUG=1 -UNDEBUG\n\nGCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES\n//GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES\nGCC_WARN_UNUSED_FUNCTION = YES\nGCC_WARN_UNUSED_LABEL = YES\n//GCC_WARN_UNUSED_PARAMETER = YES\nGCC_WARN_UNUSED_VALUE = YES\nGCC_WARN_UNUSED_VARIABLE = YES\nGCC_WARN_64_TO_32_BIT_CONVERSION = YES\nGCC_WARN_ABOUT_RETURN_TYPE = YES\nGCC_WARN_UNDECLARED_SELECTOR = YES\nGCC_WARN_UNINITIALIZED_AUTOS = YES\nCLANG_WARN_BOOL_CONVERSION = YES\nCLANG_WARN_CONSTANT_CONVERSION = YES\nCLANG_WARN_EMPTY_BODY = YES\nCLANG_WARN_ENUM_CONVERSION = YES\nCLANG_WARN_INFINITE_RECURSION = YES\nCLANG_WARN_INT_CONVERSION = YES\nCLANG_WARN_SUSPICIOUS_MOVE = YES\nCLANG_WARN_UNREACHABLE_CODE = YES\nCLANG_WARN__DUPLICATE_METHOD_MATCH = YES\n\n// clang doesn't understand the simple_printf %y specifier\nWARNING_CFLAGS = -Wno-format-invalid-specifier -Wno-format-extra-args\n\nLLVM_LTO = LLVM_LTO_$(CURRENT_VARIANT)\nLLVM_LTO_normal = YES\nLLVM_LTO_debug = NO\nDEAD_CODE_STRIPPING = NO\n\nIS_ZIPPERED = YES\n\nSIM_SUFFIX[sdk=*simulator*] = _sim\nLINK_WITH_STANDARD_LIBRARIES = NO\nOTHER_LDFLAGS = -all_load -L/usr/lib/system -umbrella System $(CR_LDFLAGS) $(LIBCOMPILER_RT_LDFLAGS) $(LIBDYLD_LDFLAGS) $(LIBSYSCALL_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(PLATFORM_LDFLAGS) $(UPLINK_LDFLAGS) $(INTERPOSE_LDFLAGS) $(DIRTY_LDFLAGS)\nLIBCOMPILER_RT_LDFLAGS = -lcompiler_rt\nLIBPLATFORM_LDFLAGS = -lsystem$(SIM_SUFFIX)_platform\nLIBSYSCALL_LDFLAGS = -lsystem$(SIM_SUFFIX)_kernel\nLIBDYLD_LDFLAGS = -ldyld\n\n// TODO: Eliminate the crosslink between libmalloc and Libc (13046853)\nUPLINK_LDFLAGS = -Wl,-upward-lsystem_c\n\nINTERPOSE_LDFLAGS = -Wl,-interposable_list,$(SRCROOT)/xcodeconfig/interposable.list\n\nORDER_FILE = $(SDKROOT)/$(APPLE_INTERNAL_DIR)/OrderFiles/$(PRODUCT_NAME).order\nORDER_FILE[sdk=*simulator*] =\n\nDIRTY_LDFLAGS = -Wl,-dirty_data_list,$(SRCROOT)/xcodeconfig/libmalloc.dirty\nDIRTY_LDFLAGS[sdk=macosx*] =\n\nDYLIB_CURRENT_VERSION = $(CURRENT_PROJECT_VERSION)\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/xcodeconfig/libmalloc_eos.xcconfig",
    "content": "#include \"libmalloc.xcconfig\"\n\nBUILD_VARIANTS = normal\nEXECUTABLE_PREFIX = lib\nGENERATE_MASTER_OBJECT_FILE = YES\nINSTALL_PATH = /usr/local/lib/eOS\nPRODUCT_NAME = malloc_eOS\nSKIP_INSTALL = YES\nSKIP_INSTALL[sdk=iphoneos*] = NO\nSTRIP_INSTALLED_PRODUCT = NO\nVERSIONING_SYSTEM = apple-generic\nMACH_O_TYPE = staticlib\nOTHER_LDFLAGS =\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/xcodeconfig/libmalloc_resolved.xcconfig",
    "content": "#include \"libmalloc.xcconfig\"\n\nSUPPORTED_PLATFORMS = iphoneos appletvos watchos\nPRODUCT_NAME = malloc_$(RESOLVED_VARIANT)\nOTHER_LDFLAGS =\nSKIP_INSTALL = YES\nVERSIONING_SYSTEM =\nEXCLUDED_SOURCE_FILE_NAMES = *\n\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/xcodeconfig/libmalloc_resolver.xcconfig",
    "content": "#include \"libmalloc.xcconfig\"\n\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/xcodeconfig/libmalloc_static.xcconfig",
    "content": "#include \"libmalloc.xcconfig\"\n\nBUILD_VARIANTS = normal debug\nEXECUTABLE_PREFIX = lib\nGENERATE_MASTER_OBJECT_FILE = YES\nINSTALL_PATH = /usr/local/lib/system\nPRODUCT_NAME = malloc\nSTRIP_INSTALLED_PRODUCT = NO\nVERSIONING_SYSTEM = apple-generic\nMACH_O_TYPE = staticlib\nOTHER_LDFLAGS =\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/xcodescripts/install-codes.sh",
    "content": "#!/bin/bash -e\n# install kdebug trace files based on the input file\nINPUT=${SCRIPT_INPUT_FILE_0}\nOUTPUT=${SCRIPT_OUTPUT_FILE_0}\n\n# pre-process the source and pass through perl it\nxcrun cc -E -I${SDKROOT}/System/Library/Frameworks/System.framework/PrivateHeaders -D_MALLOC_BUILDING_CODES_ \"${INPUT}\" | perl > \"${OUTPUT}\"\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/xcodescripts/manpages.sh",
    "content": "#!/bin/bash -e\n\nif [ \"$ACTION\" = installhdrs ]; then exit 0; fi\nif [[ \"$PLATFORM_NAME\" != \"macosx\" ]]; then exit 0; fi\n\nUNIFDEF_FLAGS=\"\"\n\nMANPAGES_LIST=\"${SRCROOT}/man/manpages.lst\"\nFILES=$(find -E ${SRCROOT} -regex '.*/[^.]+\\.[0-9]' -type f)\n\ncat ${MANPAGES_LIST} | grep -v -E '(^#|^\\s*$)' | while read first solid rest; do\n\tSOURCE=$(grep -E \"/${first}$\"<<EOF\n${FILES}\nEOF\n)\n\n\t# This is a subshell, the real exit is after the loop.\n\tif [ -z \"${SOURCE}\" ]; then\n\t\techo \"Error: ${first} not found\"\n\t\texit 1\n\tfi\n\n\tSECTION=$(echo ${first} | tail -c 2)\n\n\tDESTDIR=${DSTROOT}/usr/share/man/man${SECTION}\n\tDEST=${DESTDIR}/${solid}\n\n\tmkdir -p ${DSTROOT}/usr/share/man/man${SECTION}\n\n\t# cat is used to keep bash happy, unifdef returns non-zero in some success cases\n\tcmd=\"unifdef -t ${UNIFDEF_FLAGS} < ${SOURCE} | cat > ${DEST}\"\n\techo ${cmd}\n\teval ${cmd}\n\n\tfor link in ${rest}; do\n\t\tcmd=\"ln -sf ${first} ${DESTDIR}/${link}\"\n\t\techo ${cmd}\n\t\teval ${cmd}\n\tdone\ndone\n\nif [ $? -ne 0 ]; then\n\techo \"Exiting due to previous error(s).\"\n\texit 1\nfi\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/xcodescripts/reindent.sh",
    "content": "#!/bin/bash\n#\n# Reindent CWD recursively using clang-format (assumed to be in your PATH),\n# and per-component or per-directory .clang-format style specifications.\n#\n\nCPUS=`sysctl -n hw.logicalcpu`\nCLANGFORMAT=${CLANGFORMAT:=`xcrun -find clang-format`}\n\nif [ ! -x \"${CLANGFORMAT}\" ]; then\n    echo \"Could not find clang-format\" 1>&2\n    exit 1\nfi\n\necho \"Using ${CLANGFORMAT} to reindent, using concurrency of ${CPUS}\"\n\nfind -x . \\! \\( \\( -name BUILD -o -name EXTERNAL_HEADERS -o -name libMicro -o -name zlib -o -name .svn -o -name .git -o -name cscope.\\* -o -name \\*~ \\) -prune \\) -type f \\( -name \\*.c -o -name \\*.cpp \\) -print0 | \\\n    xargs -0 -P \"${CPUS}\" -n 10 \"${CLANGFORMAT}\" -style=file -i\nret=$?\n\nif [ $ret -ne 0 ]; then\n    echo \"reindent failed: $ret\" 1>&2\n    exit 1\nfi\n\nexit 0\n\n"
  },
  {
    "path": "InterView-obj-isa-class/libmalloc-166.220.1/xcodescripts/sanitise_headers.sh",
    "content": "#!/bin/bash -e\n#\n# Copyright (c) 2010-2011 Apple Inc. All rights reserved.\n#\n# @APPLE_APACHE_LICENSE_HEADER_START@\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# @APPLE_APACHE_LICENSE_HEADER_END@\n#\n\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/APPLE_LICENSE",
    "content": "APPLE PUBLIC SOURCE LICENSE\nVersion 2.0 - August 6, 2003\n\nPlease read this License carefully before downloading this software.\nBy downloading or using this software, you are agreeing to be bound by\nthe terms of this License. If you do not or cannot agree to the terms\nof this License, please do not download or use the software.\n\n1. General; Definitions. This License applies to any program or other\nwork which Apple Computer, Inc. (\"Apple\") makes publicly available and\nwhich contains a notice placed by Apple identifying such program or\nwork as \"Original Code\" and stating that it is subject to the terms of\nthis Apple Public Source License version 2.0 (\"License\"). As used in\nthis License:\n\n1.1 \"Applicable Patent Rights\" mean: (a) in the case where Apple is\nthe grantor of rights, (i) claims of patents that are now or hereafter\nacquired, owned by or assigned to Apple and (ii) that cover subject\nmatter contained in the Original Code, but only to the extent\nnecessary to use, reproduce and/or distribute the Original Code\nwithout infringement; and (b) in the case where You are the grantor of\nrights, (i) claims of patents that are now or hereafter acquired,\nowned by or assigned to You and (ii) that cover subject matter in Your\nModifications, taken alone or in combination with Original Code.\n\n1.2 \"Contributor\" means any person or entity that creates or\ncontributes to the creation of Modifications.\n\n1.3 \"Covered Code\" means the Original Code, Modifications, the\ncombination of Original Code and any Modifications, and/or any\nrespective portions thereof.\n\n1.4 \"Externally Deploy\" means: (a) to sublicense, distribute or\notherwise make Covered Code available, directly or indirectly, to\nanyone other than You; and/or (b) to use Covered Code, alone or as\npart of a Larger Work, in any way to provide a service, including but\nnot limited to delivery of content, through electronic communication\nwith a client other than You.\n\n1.5 \"Larger Work\" means a work which combines Covered Code or portions\nthereof with code not governed by the terms of this License.\n\n1.6 \"Modifications\" mean any addition to, deletion from, and/or change\nto, the substance and/or structure of the Original Code, any previous\nModifications, the combination of Original Code and any previous\nModifications, and/or any respective portions thereof. When code is\nreleased as a series of files, a Modification is: (a) any addition to\nor deletion from the contents of a file containing Covered Code;\nand/or (b) any new file or other representation of computer program\nstatements that contains any part of Covered Code.\n\n1.7 \"Original Code\" means (a) the Source Code of a program or other\nwork as originally made available by Apple under this License,\nincluding the Source Code of any updates or upgrades to such programs\nor works made available by Apple under this License, and that has been\nexpressly identified by Apple as such in the header file(s) of such\nwork; and (b) the object code compiled from such Source Code and\noriginally made available by Apple under this License.\n\n1.8 \"Source Code\" means the human readable form of a program or other\nwork that is suitable for making modifications to it, including all\nmodules it contains, plus any associated interface definition files,\nscripts used to control compilation and installation of an executable\n(object code).\n\n1.9 \"You\" or \"Your\" means an individual or a legal entity exercising\nrights under this License. For legal entities, \"You\" or \"Your\"\nincludes any entity which controls, is controlled by, or is under\ncommon control with, You, where \"control\" means (a) the power, direct\nor indirect, to cause the direction or management of such entity,\nwhether by contract or otherwise, or (b) ownership of fifty percent\n(50%) or more of the outstanding shares or beneficial ownership of\nsuch entity.\n\n2. Permitted Uses; Conditions & Restrictions. Subject to the terms\nand conditions of this License, Apple hereby grants You, effective on\nthe date You accept this License and download the Original Code, a\nworld-wide, royalty-free, non-exclusive license, to the extent of\nApple's Applicable Patent Rights and copyrights covering the Original\nCode, to do the following:\n\n2.1 Unmodified Code. You may use, reproduce, display, perform,\ninternally distribute within Your organization, and Externally Deploy\nverbatim, unmodified copies of the Original Code, for commercial or\nnon-commercial purposes, provided that in each instance:\n\n(a) You must retain and reproduce in all copies of Original Code the\ncopyright and other proprietary notices and disclaimers of Apple as\nthey appear in the Original Code, and keep intact all notices in the\nOriginal Code that refer to this License; and\n\n(b) You must include a copy of this License with every copy of Source\nCode of Covered Code and documentation You distribute or Externally\nDeploy, and You may not offer or impose any terms on such Source Code\nthat alter or restrict this License or the recipients' rights\nhereunder, except as permitted under Section 6.\n\n2.2 Modified Code. You may modify Covered Code and use, reproduce,\ndisplay, perform, internally distribute within Your organization, and\nExternally Deploy Your Modifications and Covered Code, for commercial\nor non-commercial purposes, provided that in each instance You also\nmeet all of these conditions:\n\n(a) You must satisfy all the conditions of Section 2.1 with respect to\nthe Source Code of the Covered Code;\n\n(b) You must duplicate, to the extent it does not already exist, the\nnotice in Exhibit A in each file of the Source Code of all Your\nModifications, and cause the modified files to carry prominent notices\nstating that You changed the files and the date of any change; and\n\n(c) If You Externally Deploy Your Modifications, You must make\nSource Code of all Your Externally Deployed Modifications either\navailable to those to whom You have Externally Deployed Your\nModifications, or publicly available. Source Code of Your Externally\nDeployed Modifications must be released under the terms set forth in\nthis License, including the license grants set forth in Section 3\nbelow, for as long as you Externally Deploy the Covered Code or twelve\n(12) months from the date of initial External Deployment, whichever is\nlonger. You should preferably distribute the Source Code of Your\nExternally Deployed Modifications electronically (e.g. download from a\nweb site).\n\n2.3 Distribution of Executable Versions. In addition, if You\nExternally Deploy Covered Code (Original Code and/or Modifications) in\nobject code, executable form only, You must include a prominent\nnotice, in the code itself as well as in related documentation,\nstating that Source Code of the Covered Code is available under the\nterms of this License with information on how and where to obtain such\nSource Code.\n\n2.4 Third Party Rights. You expressly acknowledge and agree that\nalthough Apple and each Contributor grants the licenses to their\nrespective portions of the Covered Code set forth herein, no\nassurances are provided by Apple or any Contributor that the Covered\nCode does not infringe the patent or other intellectual property\nrights of any other entity. Apple and each Contributor disclaim any\nliability to You for claims brought by any other entity based on\ninfringement of intellectual property rights or otherwise. As a\ncondition to exercising the rights and licenses granted hereunder, You\nhereby assume sole responsibility to secure any other intellectual\nproperty rights needed, if any. For example, if a third party patent\nlicense is required to allow You to distribute the Covered Code, it is\nYour responsibility to acquire that license before distributing the\nCovered Code.\n\n3. Your Grants. In consideration of, and as a condition to, the\nlicenses granted to You under this License, You hereby grant to any\nperson or entity receiving or distributing Covered Code under this\nLicense a non-exclusive, royalty-free, perpetual, irrevocable license,\nunder Your Applicable Patent Rights and other intellectual property\nrights (other than patent) owned or controlled by You, to use,\nreproduce, display, perform, modify, sublicense, distribute and\nExternally Deploy Your Modifications of the same scope and extent as\nApple's licenses under Sections 2.1 and 2.2 above.\n\n4. Larger Works. You may create a Larger Work by combining Covered\nCode with other code not governed by the terms of this License and\ndistribute the Larger Work as a single product. In each such instance,\nYou must make sure the requirements of this License are fulfilled for\nthe Covered Code or any portion thereof.\n\n5. Limitations on Patent License. Except as expressly stated in\nSection 2, no other patent rights, express or implied, are granted by\nApple herein. Modifications and/or Larger Works may require additional\npatent licenses from Apple which Apple may grant in its sole\ndiscretion.\n\n6. Additional Terms. You may choose to offer, and to charge a fee for,\nwarranty, support, indemnity or liability obligations and/or other\nrights consistent with the scope of the license granted herein\n(\"Additional Terms\") to one or more recipients of Covered Code.\nHowever, You may do so only on Your own behalf and as Your sole\nresponsibility, and not on behalf of Apple or any Contributor. You\nmust obtain the recipient's agreement that any such Additional Terms\nare offered by You alone, and You hereby agree to indemnify, defend\nand hold Apple and every Contributor harmless for any liability\nincurred by or claims asserted against Apple or such Contributor by\nreason of any such Additional Terms.\n\n7. Versions of the License. Apple may publish revised and/or new\nversions of this License from time to time. Each version will be given\na distinguishing version number. Once Original Code has been published\nunder a particular version of this License, You may continue to use it\nunder the terms of that version. You may also choose to use such\nOriginal Code under the terms of any subsequent version of this\nLicense published by Apple. No one other than Apple has the right to\nmodify the terms applicable to Covered Code created under this\nLicense.\n\n8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in\npart pre-release, untested, or not fully tested works. The Covered\nCode may contain errors that could cause failures or loss of data, and\nmay be incomplete or contain inaccuracies. You expressly acknowledge\nand agree that use of the Covered Code, or any portion thereof, is at\nYour sole and entire risk. THE COVERED CODE IS PROVIDED \"AS IS\" AND\nWITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND\nAPPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS \"APPLE\" FOR THE\nPURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM\nALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT\nNOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF\nMERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR\nPURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD\nPARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST\nINTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE\nFUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS,\nTHAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR\nERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO\nORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE\nAUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.\nYou acknowledge that the Covered Code is not intended for use in the\noperation of nuclear facilities, aircraft navigation, communication\nsystems, or air traffic control machines in which case the failure of\nthe Covered Code could lead to death, personal injury, or severe\nphysical or environmental damage.\n\n9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO\nEVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL,\nSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING\nTO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR\nANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY,\nTORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF\nAPPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY\nREMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF\nINCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY\nTO YOU. In no event shall Apple's total liability to You for all\ndamages (other than as may be required by applicable law) under this\nLicense exceed the amount of fifty dollars ($50.00).\n\n10. Trademarks. This License does not grant any rights to use the\ntrademarks or trade names \"Apple\", \"Apple Computer\", \"Mac\", \"Mac OS\",\n\"QuickTime\", \"QuickTime Streaming Server\" or any other trademarks,\nservice marks, logos or trade names belonging to Apple (collectively\n\"Apple Marks\") or to any trademark, service mark, logo or trade name\nbelonging to any Contributor. You agree not to use any Apple Marks in\nor as part of the name of products derived from the Original Code or\nto endorse or promote products derived from the Original Code other\nthan as expressly permitted by and in strict compliance at all times\nwith Apple's third party trademark usage guidelines which are posted\nat http://www.apple.com/legal/guidelinesfor3rdparties.html.\n\n11. Ownership. Subject to the licenses granted under this License,\neach Contributor retains all rights, title and interest in and to any\nModifications made by such Contributor. Apple retains all rights,\ntitle and interest in and to the Original Code and any Modifications\nmade by or on behalf of Apple (\"Apple Modifications\"), and such Apple\nModifications will not be automatically subject to this License. Apple\nmay, at its sole discretion, choose to license such Apple\nModifications under this License, or on different terms from those\ncontained in this License or may choose not to license them at all.\n\n12. Termination.\n\n12.1 Termination. This License and the rights granted hereunder will\nterminate:\n\n(a) automatically without notice from Apple if You fail to comply with\nany term(s) of this License and fail to cure such breach within 30\ndays of becoming aware of such breach;\n\n(b) immediately in the event of the circumstances described in Section\n13.5(b); or\n\n(c) automatically without notice from Apple if You, at any time during\nthe term of this License, commence an action for patent infringement\nagainst Apple; provided that Apple did not first commence\nan action for patent infringement against You in that instance.\n\n12.2 Effect of Termination. Upon termination, You agree to immediately\nstop any further use, reproduction, modification, sublicensing and\ndistribution of the Covered Code. All sublicenses to the Covered Code\nwhich have been properly granted prior to termination shall survive\nany termination of this License. Provisions which, by their nature,\nshould remain in effect beyond the termination of this License shall\nsurvive, including but not limited to Sections 3, 5, 8, 9, 10, 11,\n12.2 and 13. No party will be liable to any other for compensation,\nindemnity or damages of any sort solely as a result of terminating\nthis License in accordance with its terms, and termination of this\nLicense will be without prejudice to any other right or remedy of\nany party.\n\n13. Miscellaneous.\n\n13.1 Government End Users. The Covered Code is a \"commercial item\" as\ndefined in FAR 2.101. Government software and technical data rights in\nthe Covered Code include only those rights customarily provided to the\npublic as defined in this License. This customary commercial license\nin technical data and software is provided in accordance with FAR\n12.211 (Technical Data) and 12.212 (Computer Software) and, for\nDepartment of Defense purchases, DFAR 252.227-7015 (Technical Data --\nCommercial Items) and 227.7202-3 (Rights in Commercial Computer\nSoftware or Computer Software Documentation). Accordingly, all U.S.\nGovernment End Users acquire Covered Code with only those rights set\nforth herein.\n\n13.2 Relationship of Parties. This License will not be construed as\ncreating an agency, partnership, joint venture or any other form of\nlegal association between or among You, Apple or any Contributor, and\nYou will not represent to the contrary, whether expressly, by\nimplication, appearance or otherwise.\n\n13.3 Independent Development. Nothing in this License will impair\nApple's right to acquire, license, develop, have others develop for\nit, market and/or distribute technology or products that perform the\nsame or similar functions as, or otherwise compete with,\nModifications, Larger Works, technology or products that You may\ndevelop, produce, market or distribute.\n\n13.4 Waiver; Construction. Failure by Apple or any Contributor to\nenforce any provision of this License will not be deemed a waiver of\nfuture enforcement of that or any other provision. Any law or\nregulation which provides that the language of a contract shall be\nconstrued against the drafter will not apply to this License.\n\n13.5 Severability. (a) If for any reason a court of competent\njurisdiction finds any provision of this License, or portion thereof,\nto be unenforceable, that provision of the License will be enforced to\nthe maximum extent permissible so as to effect the economic benefits\nand intent of the parties, and the remainder of this License will\ncontinue in full force and effect. (b) Notwithstanding the foregoing,\nif applicable law prohibits or restricts You from fully and/or\nspecifically complying with Sections 2 and/or 3 or prevents the\nenforceability of either of those Sections, this License will\nimmediately terminate and You must immediately discontinue any use of\nthe Covered Code and destroy all copies of it that are in your\npossession or control.\n\n13.6 Dispute Resolution. Any litigation or other dispute resolution\nbetween You and Apple relating to this License shall take place in the\nNorthern District of California, and You and Apple hereby consent to\nthe personal jurisdiction of, and venue in, the state and federal\ncourts within that District with respect to this License. The\napplication of the United Nations Convention on Contracts for the\nInternational Sale of Goods is expressly excluded.\n\n13.7 Entire Agreement; Governing Law. This License constitutes the\nentire agreement between the parties with respect to the subject\nmatter hereof. This License shall be governed by the laws of the\nUnited States and the State of California, except that body of\nCalifornia law concerning conflicts of law.\n\nWhere You are located in the province of Quebec, Canada, the following\nclause applies: The parties hereby confirm that they have requested\nthat this License and all related documents be drafted in English. Les\nparties ont exige que le present contrat et tous les documents\nconnexes soient rediges en anglais.\n\nEXHIBIT A.\n\n\"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights\nReserved.\n\nThis file contains Original Code and/or Modifications of Original Code\nas defined in and that are subject to the Apple Public Source License\nVersion 2.0 (the 'License'). You may not use this file except in\ncompliance with the License. Please obtain a copy of the License at\nhttp://www.opensource.apple.com/apsl/ and read it before using this\nfile.\n\nThe Original Code and all software distributed under the License are\ndistributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\nEXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\nINCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\nPlease see the License for the specific language governing rights and\nlimitations under the License.\"\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/ReleaseNotes.rtf",
    "content": "{\\rtf1\\mac\\ansicpg10000\\cocoartf824\\cocoasubrtf420\n{\\fonttbl\\f0\\fswiss\\fcharset77 Helvetica-Bold;\\f1\\fswiss\\fcharset77 Helvetica;\\f2\\fnil\\fcharset77 Monaco;\n}\n{\\colortbl;\\red255\\green255\\blue255;\\red70\\green130\\blue100;}\n\\vieww11200\\viewh14360\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f0\\b\\fs30 \\cf0 Objective-C Release Notes\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f1\\b0\\fs24 \\cf0 \\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f0\\b\\fs30 \\cf0 Mac OS X 10.5 Leopard\n\\f1\\b0\\fs24 \\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f0\\b \\cf0 Contents\n\\f1\\b0 \\\n\\'a5 Garbage Collection\\\n\\'a5\\'caProperties\\\n\\'a5\\'caLoading and Unloading Bundles\\\n\\'a5 Method and Class Attributes\\\n\\'a5\\'ca@package Instance Variables\\\n\\'a5\\'caRuntime API changes\\\n\\'a5\\'ca64-bit ABI\\\n\\'a5\\'ca64-bit Class and Instance Variable Access Control\\\n\\'a5\\'ca64-bit Non-Fragile Instance Variables\\\n\\'a5\\'ca64-bit Zero-Cost C++-Compatible Exceptions\\\n\\\n\\\n\n\\f0\\b Garbage Collection\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f1\\b0 \\cf0 \\\nThe Objective-C runtime examines on startup the execution image to determine whether to run with garbage collection or not.  Each object file has an info section and they must all agree for execution to proceed.  Standard compilation results in an info section that indicates that no GC capability is present.  Compiling with -fobjc-gc indicates that both GC and retain/release logic is present.  Compiling with -fobjc-gc-only indicates that only GC logic is present.  A non-GC executable that attempts to load a gc-only framework will fail, as will a GC capable executable that attemps to load a GC incapable framework (or bundle).\\\n\\\nThe collector initially runs only on the main thread when requested via objc_collect_if_needed(1), which is called automatically from the autoreleasepool -drain method.  The AppKit arranges to call objc_start_collector_thread() after launch and subsequently collections run on a dedicated thread and are responsive to pure allocation demand.  The objc_set_collection_threshold and objc_set_collection_ratio calls are used to establish the \"need\" for a collection.  Once every ratio times a full (complete) collection will occur; otherwise a generational collection will be done if allocations have exceeded the threshold.\\\n\\\nThe garbage collector minimally pauses those threads which have been registered to it while collecting.        Registration occurs during establishment of an NSThread, not simply a pthread.\\\n\\\nA critical assumption that the collector makes is that one thread never gains access to an object (or more generally any block of garbage collected memory) by way of a pointer to another thread's stack memory.    In other words, the collector does not make provision for cross thread stack references.  This enables the collector to avoid pausing all threads at the same time while it examines recursively all of their references.\\\n\\\nThe compiler uses three \"helper\" functions for assignments of strong pointers to garbage collected memory into global memory (\n\\f2\\fs20 objc_assign_global\n\\f1\\fs24 ), garbage collected heap memory (\n\\f2\\fs20 objc_assign_ivar\n\\f1\\fs24 ), or into unknown memory (\n\\f2\\fs20 objc_assign_strongCast\n\\f1\\fs24 ).  For assignments of weak pointers it uses objc_assign_weak and for reads it uses objc_read_weak.\\\n\\\nWhen copying memory in bulk into a garbage collected block one must use the API \n\\f2\\fs20 objc_memmove_collectable(void *dst, const void *src, size_t size)\n\\f1\\fs24 .\\\n\\\nGarbage Collection Errors\\\n\\\nThe collector itself is found in\n\\f2\\fs20  /usr/lib/libauto.dylib\n\\f1\\fs24 . Its error messages are printed using \n\\f2\\fs20 malloc_printf\n\\f1\\fs24 .  The ObjC runtime is found in \n\\f2\\fs20 /usr/lib/libobjc.dylib\n\\f1\\fs24 .  Its errors are printed using \n\\f2\\fs20 _objc_inform\n\\f1\\fs24 .  Currently we note resurrection and reference count underflow errors by calling the following routines:\\\n\\\n\\pard\\tx960\\pardeftab960\\ql\\qnatural\\pardirnatural\n\n\\f2\\fs20 \\cf2 \\CocoaLigature0 objc_assign_global_error\\\n\\pard\\tx960\\pardeftab960\\ql\\qnatural\\pardirnatural\n\\cf0 objc_assign_ivar_error\\\n\\pard\\tx960\\pardeftab960\\ql\\qnatural\\pardirnatural\n\\cf2 objc_exception_during_finalize_error\\\nauto_zone_resurrection_error\\cf0 \\\n\\cf2 auto_refcount_underflow_error\n\\f1\\fs24 \\cf0 \\CocoaLigature1 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\\cf0 \\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f0\\b \\cf0 Properties\n\\f1\\b0 \\\n\\\nThe syntax for Objective-C properties has been overhauled since WWDC 2006. See the property documentation for details.\\\n\\\nIn summary, @property(attributes) type name introduces an implicit declaration of a \"getter\" and a \"setter\" method (unless a read-only property is requested) for the \"variable\" named. The setter= and getter= attributes allow one to specify the names of the methods, otherwise a \"name\" method and a \"setName:\" method are implicitly declared.  They may also be explicitly named.\\\n\\\nBy default, properties are assigned when set.  For objects under non-GC this is often incorrect and a warning is issued unless the assignment semantic is explicitly named.  There are three choices - assign, for non-retained object references, copy, for objects that are copied and implicitly retained, and simply retain, for objects that require being retained when set.\\\n\\\nAccess to properties is atomic by default.  This is trivial under GC for almost everything and also trivial under non-GC for everything but objects and structures.  In particular atomic access to retained objects under non-GC conditions can be expensive. As such, a nonatomic property attribute is available.\\\n\\\nPointers may be held strongly under GC by declaring them __strong, and they can be zeroing weak by declaring them __weak.\\\n\\\nThe implementations for properties can be provided by the compiler and runtime through the use of the @synthesize statement in the @implementation section of the class (or class extension).  The compiler expects an instance variable of the same name as the property.  If one wishes a different name it can be supplied to the @synthesize statement.\\\n\\\nIn particular the compiler and runtime will implement accessors to retained objects by using atomic compare and swap instructions.  It is extremely dangerous to directly access an atomic object property through its instance variable since another thread might change its value unpredictably.  As such the compiler will warn you about such unprotected accesses.  The runtime, in fact, will temporarily use the least significant bit of the instance variable as a temporary lock while retaining the new value and releasing the old.  Direct use of an atomic instance variable under non-GC is strongly discouraged.\\\n\\\n\\\n\n\\f0\\b Loading and Unloading Bundles\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f1\\b0 \\cf0 \\\nSince Mac OS X Version 10.4 it has been possible to unload bundles containing Objective-C.  No attempt is made to prevent this if objects are still present for classes that are unloaded.  Subclasses of classes loaded in bundles are particularly vulnerable.\\\n\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f0\\b \\cf0 Method and Class Attributes\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f1\\b0 \\cf0 Objective-C now supports some gcc attributes for Objective-C methods. Syntactically, attributes for a method follow the method's declaration, and attributes for a method parameter sit between the parameter type and the parameter name. Supported attributes include:\\\n\\\nDeprecation and availability, including AvailabilityMacros.h\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f2\\fs20 \\cf0 \t- (void)method:(id)param  __attribute__((deprecated));\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f1\\fs24 \\cf0 \\\nUnused parameters\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f2\\fs20 \\cf0 \t- (void)method:(id) __attribute__((unused)) param;\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f1\\fs24 \\cf0 \\\nSentinel parameters, including \n\\f2\\fs20 NS_REQUIRES_NIL_TERMINATION\n\\f1\\fs24 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f2\\fs20 \\cf0 \t- (void)methodWithObjects:(id)obj, ...  NS_REQUIRES_NIL_TERMINATION;\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f1\\fs24 \\cf0 \\\nObjective-C also supports some gcc attributes for Objective-C classes. Syntactically, attributes for a class precede the class's \n\\f2\\fs20 @interface\n\\f1\\fs24  declaration. Supported attributes include:\\\n\\\nDeprecation and availability, including AvailabilityMacros.h\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f2\\fs20 \\cf0 \t__attribute__((deprecated))\\\n\t@interface MyDeprecatedClass : SomeSuperclass\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f1\\fs24 \\cf0 \\\nVisibility\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f2\\fs20 \\cf0 \t__attribute__((visibility(\"hidden\")))\\\n\t@interface MyPrivateClass : SomeSuperclass\n\\f1\\fs24 \\\n\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f0\\b \\cf0 @package Instance Variables\n\\f1\\b0 \\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f2\\fs20 \\cf0 @package\n\\f1\\fs24  is a new ivar protection class, like \n\\f2\\fs20 @public\n\\f1\\fs24  and \n\\f2\\fs20 @protected\n\\f1\\fs24 . \n\\f2\\fs20 @package\n\\f1\\fs24  ivars behave as follows:\\\n\\'a5\\'ca\n\\f2\\fs20 @public\n\\f1\\fs24  in 32-bit; \\\n\\'a5\\'ca\n\\f2\\fs20 @public\n\\f1\\fs24  in 64-bit, inside the framework that defined the class; \\\n\\'a5\\'ca\n\\f2\\fs20 @private\n\\f1\\fs24  in 64-bit, outside the framework that defined the class.\\\n\\\nIn 64-bit, the ivar symbol for an \n\\f2\\fs20 @package\n\\f1\\fs24  ivar is not exported, so any attempt to use the ivar from outside the framework that defined the class will fail with a link error. See \"64-bit Class and Instance Variable Access Control\" for more about ivar symbols.\\\n\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f0\\b \\cf0 Runtime API changes\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f1\\b0 \\cf0 The C interface to the Objective-C runtime (in \n\\f2\\fs20 <objc/*.h>\n\\f1\\fs24 ) has changed significantly. Highlights include:\\\n\\'a5\\'caAlmost all structures are deprecated, including \n\\f2\\fs20 struct objc_class\n\\f1\\fs24 . Functional replacements for most of these are provided.\\\n\\'a5\\'ca\n\\f2\\fs20 class_poseAs\n\\f1\\fs24  is deprecated. Use method list manipulation functions instead.\\\n\\'a5\\'ca\n\\f2\\fs20 class_nextMethodList\n\\f1\\fs24  is deprecated. Use \n\\f2\\fs20 class_copyMethodList\n\\f1\\fs24  instead.\\\n\\'a5\\'ca\n\\f2\\fs20 class_addMethods\n\\f1\\fs24  is deprecated. Use \n\\f2\\fs20 class_addMethod\n\\f1\\fs24  instead.\\\n\\'a5\\'ca\n\\f2\\fs20 objc_addClass\n\\f1\\fs24  is deprecated. Use \n\\f2\\fs20 objc_allocateClassPair\n\\f1\\fs24  and \n\\f2\\fs20 objc_registerClassPair\n\\f1\\fs24  instead.\\\n\\'a5\\'caIn general, all deprecated declarations are absent in 64-bit.\\\n\\'a5\\'caThe API in objc/objc-runtime.h and objc/objc-class.h is now in objc/runtime.h and objc/message.h. The old header files simply #include the new ones.\\\n\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f0\\b \\cf0 64-bit ABI\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f1\\b0 \\cf0 The 64-bit Objective-C ABI is generally unlike the 32-bit ABI. The new ABI provides new features, better performance, and improved future adaptability. All aspects of the 64-bit ABI are private and subject to future change. Forthcoming documentation will describe the ABI for the use of compilers and developer tools only.\\\n\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f0\\b \\cf0 64-bit Class and Instance Variable Access Control\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f1\\b0 \\cf0 In 64-bit Objective-C, access control for classes and each class and instance variable has a symbol associated with it. All uses of a class or instance variable reference this symbol. These symbols are subject to access control by the linker.\\\n\\\nThe upshot is that access to private classes and ivars is more strictly enforced. Illegal use of a private ivar may fail with a link error. Frameworks that provide classes and ivars must correctly export their symbols. In particular, frameworks built with \n\\f2\\fs20 -fvisibility=hidden\n\\f1\\fs24  or a linker export list may need to be changed.\\\n\\\nClass symbols have names of the form \n\\f2\\fs20 _OBJC_CLASS_$_ClassName\n\\f1\\fs24  and \n\\f2\\fs20 _OBJC_METACLASS_$_ClassName\n\\f1\\fs24  . The class symbol is used by clients who send messages to the class (i.e. \n\\f2\\fs20 [ClassName someMessage]\n\\f1\\fs24 ). The metaclass symbol is used by clients who subclass the class.\\\n\\\nBy default, class symbols are exported. They are affected by gcc's symbol visibility flags, so \n\\f2\\fs20 -fvisibility=hidden\n\\f1\\fs24  will make the class symbols non-exported. The linker recognizes the old symbol name \n\\f2\\fs20 .objc_class_name_ClassName\n\\f1\\fs24  in linker export lists and translates it to these symbols. \\\n\\\nVisibility of a single class can be changed using an attribute.\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f2\\fs20 \\cf0 \t__attribute__((visibility(\"hidden\")))\\\n\t@interface ClassName : SomeSuperclass\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f1\\fs24 \\cf0 For classes with \n\\f2\\fs20 \"default\"\n\\f1\\fs24  visibility, the class symbols are exported, and the ivar symbols are handled as described below. For classes with \n\\f2\\fs20 \"hidden\"\n\\f1\\fs24  visibility, the class symbols and ivar symbols are all not exported.\\\n\\\nIvar symbols have the form \n\\f2\\fs20 _OBJC_IVAR_$_ClassName.IvarName\n\\f1\\fs24  . The ivar symbol is used by clients who read or write the ivar.\\\n\\\nBy default, ivar symbols for \n\\f2\\fs20 @private\n\\f1\\fs24  and \n\\f2\\fs20 @package\n\\f1\\fs24  ivars are not exported, and ivar symbols for \n\\f2\\fs20 @public\n\\f1\\fs24  and \n\\f2\\fs20 @protected\n\\f1\\fs24  ivars are exported. This can be changed by export lists, \n\\f2\\fs20 -fvisibility\n\\f1\\fs24 , or a visibility attribute on the class. Visibility attributes on individual ivars are currently not supported.\\\n\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f0\\b \\cf0 64-bit Non-Fragile Instance Variables\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f1\\b0 \\cf0 All instance variables in 64-bit Objective-C are non-fragile. That is, existing compiled code that uses a class's ivars will not break when the class or a superclass changes its own ivar layout. In particular, framework classes may add new ivars without breaking subclasses compiled against a previous version of the framework.\\\n\\\nIvars may be added or reordered freely; existing users of a reordered ivar will adapt transparently. Other ivar changes are safe except that they will break any existing users of the ivar: deleting an ivar, renaming an ivar, moving an ivar to a different class, and changing the type of an ivar. \\\n\\\nDo not use \n\\f2\\fs20 @defs\n\\f1\\fs24 . The ivar layout it presents cannot adapt to superclass changes.\\\n\\\nDo not use \n\\f2\\fs20 sizeof(SomeClass)\n\\f1\\fs24 . Use \n\\f2\\fs20 class_getInstanceSize([SomeClass class])\n\\f1\\fs24  instead.\\\n\\\nDo not use \n\\f2\\fs20 offsetof(SomeClass, SomeIvar)\n\\f1\\fs24 . Use \n\\f2\\fs20 ivar_getOffset(class_getInstanceVariable([SomeClass class], \"SomeIvar\"))\n\\f1\\fs24  instead.\\\n\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f0\\b \\cf0 64-bit Zero-Cost C++-Compatible Exceptions\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\ql\\qnatural\\pardirnatural\n\n\\f1\\b0 \\cf0 In 64-bit, the implementation of Objective-C exceptions has been rewritten. The new system provides \"zero-cost\" try blocks and interoperability with C++. \\\n\\\n\"Zero-cost\" try blocks incur no time penalty when entering an \n\\f2\\fs20 @try\n\\f1\\fs24  block, unlike 32-bit which must call \n\\f2\\fs20 setjmp()\n\\f1\\fs24  and other additional bookkeeping. On the other hand, actually throwing an exception is much more expensive. For best performance in 64-bit, exceptions should be thrown only in exceptional cases.\\\n\\\nThe Cocoa frameworks require that all exceptions be instances of NSException or its subclasses. Do not throw objects of other types.\\\n\\\nThe Cocoa frameworks are generally not exception-safe. Their general pattern is that exceptions are reserved for programmer error only, and the program should quit soon after catching such an exception. Be careful when throwing exceptions across the Cocoa frameworks.\\\n\\\nIn 64-bit, C++ exceptions and Objective-C exceptions are interoperable. In particular, C++ destructors and Objective-C \n\\f2\\fs20 @finally\n\\f1\\fs24  blocks are honored when unwinding any exception, and default catch clauses - \n\\f2\\fs20 catch (...)\n\\f1\\fs24  and \n\\f2\\fs20 @catch (...)\n\\f1\\fs24  - are able to catch and re-throw any exception.\\\n\\\nObjective-C \n\\f2\\fs20 @catch (id e)\n\\f1\\fs24  catches any Objective-C exception, but no C++ exceptions. Use \n\\f2\\fs20 @catch (...)\n\\f1\\fs24  to catch everything, and \n\\f2\\fs20 @throw;\n\\f1\\fs24  to re-throw caught exceptions. \n\\f2\\fs20 @catch (...)\n\\f1\\fs24  is allowed in 32-bit, and has the same effect there as \n\\f2\\fs20 @catch (id e)\n\\f1\\fs24 . \\\n}"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/interposable.txt",
    "content": "_objc_release\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/libobjc.order",
    "content": "__objc_init\n_environ_init\n_tls_init\n_lock_init\n_recursive_mutex_init\n_exception_init\n_map_images\n_map_images_nolock\n__getObjcImageInfo\n__hasObjcContents\n__objc_appendHeader\n_verify_gc_readiness\n_gc_init\n__objc_inform_on_crash\n__objc_crashlog\n_rtp_init\n_gc_fixup_barrier_stubs\n__objc_update_stubs_in_mach_header\n_sel_init\n___sel_registerName\n__objc_search_builtins\n__ZNK8objc_opt13objc_selopt_t3getEPKc\n__ZNK8objc_opt13objc_selopt_t4hashEPKc\n_sel_registerName\n_arr_init\n__ZN4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE4initEj\n__read_images\n__Z11initVtablesv\n__Z17appendTrampolinesP22objc_trampoline_header\n_gdb_objc_trampolines_changed\n_crashlog_header_name\n__getObjc2ClassList\n_NXCreateMapTableFromZone\n_NXCreateHashTable\n_NXCreateHashTableFromZone\n_NXHashGet\n_NXHashInsert\n__NXHashRehashToCapacity\n_NXNextHashState\n_freeBuckets\n_NXNoEffectFree\n_hashPrototype\n_NXPtrHash\n_isEqualPrototype\n__Z13futureClassesv\n_NXCountMapTable\n__Z13addNamedClassP7class_tPKc\n_NXMapGet\n__mapStrHash\n_NXMapInsert\n__mapPtrHash\n__Z10remapClassP7class_t\n__Z15remappedClassesa\n_NXMapMember\n__NXMapMember\n__mapStrIsEqual\n__mapPtrIsEqual\n__getObjc2ClassRefs\n__getObjc2SuperRefs\n_sel_preoptimizationValid\n__getObjc2SelectorRefs\n_sel_registerNameNoLock\n___objc_sel_set_create\n___objc_sel_set_add\n___objc_sel_set_findBuckets\n___objc_sel_set_get\n__Z9protocolsv\n__getObjc2ProtocolList\n_NXMapKeyCopyingInsert\n__NXMapRehash\n__getObjc2ProtocolRefs\n__Z13remapProtocolm\n__getObjc2NonlazyClassList\n__Z12realizeClassP7class_t\n__Z11addSubclassP7class_tS0_\n__Z17attachMethodListsP7class_tPP13method_list_tiaPa\n__Z15fixupMethodListP13method_list_ta\n_memdup\n__ZNSt3__113__stable_sortIRN8method_t16SortBySELAddressEN13method_list_t15method_iteratorEEEvT0_S6_T_NS_15iterator_traitsIS6_E1\n__Z9addMethodP7class_tP13objc_selectorPFP11objc_objectS3_S1_zEPKca\n__Z23getMethodNoSuper_nolockP7class_tP13objc_selector\n__ZN7class_t14setHasCustomRREv\n__Z20unattachedCategoriesv\n_NXMapRemove\n__Z21attachCategoryMethodsP7class_tP13category_listPa\n_objc_addRegisteredClass\n_layout_bitmap_create\n_set_bits\n_layout_bitmap_free\n__ZNSt3__116__insertion_sortIRN8method_t16SortBySELAddressEN13method_list_t15method_iteratorEEEvT0_S6_T_\n__Z17buildProtocolListP13category_listPK15protocol_list_tPS3_\n__Z17buildPropertyListPK15property_list_tP13category_lista\n__ZNSt3__120get_temporary_bufferI8method_tEENS_4pairIPT_lEEl\n__ZNSt3__118__stable_sort_moveIRN8method_t16SortBySELAddressEN13method_list_t15method_iteratorEEEvT0_S6_T_NS_15iterator_traitsI\n__ZNSt3__122__merge_move_constructIRN8method_t16SortBySELAddressEN13method_list_t15method_iteratorES5_EEvT0_S6_T1_S7_PNS_15iter\n__ZNSt3__119__merge_move_assignIRN8method_t16SortBySELAddressEPS1_S4_N13method_list_t15method_iteratorEEEvT0_S7_T1_S8_T2_T_\n_NXPtrIsEqual\n__getObjc2CategoryList\n__Z29addUnattachedCategoryForClassP10category_tP7class_tP12_header_info\n__Z16remethodizeClassP7class_t\n__Z11flushCachesP7class_t\n_flush_cache\n__class_getCache\n_load_images\n_load_images_nolock\n_prepare_load_methods\n__Z19schedule_class_loadP7class_t\n_add_class_to_loadable_list\n__class_getLoadMethod\n__getObjc2NonlazyCategoryList\n_call_load_methods\n+[Protocol load]\n_objc_lookUpClass\n_look_up_class\n_object_getClass\n_protocol_copyMethodDescriptionList\n_class_getClassMethod\n__class_getMeta\n_look_up_method\n__cache_getMethod\n__class_getMethod\n_method_getTypeEncoding\n_method_getImplementation\n_method_getName\n_class_addMethod\n_class_getInstanceMethod\n__Z12flushVtablesP7class_t\n__Z12updateVtableP7class_ta\n_class_replaceMethod\n__Z25_method_setImplementationP7class_tP8method_tPFP11objc_objectS4_P13objc_selectorzE\n_class_addProtocol\n_class_conformsToProtocol\n_objc_setExceptionPreprocessor\n_objc_setExceptionMatcher\n_objc_setUncaughtExceptionHandler\n_objc_setForwardHandler\n_objc_setEnumerationMutationHandler\n_objc_collectingEnabled\n_objc_getFutureClass\n_objc_assign_strongCast_non_gc\n_objc_getClass\n__objc_insert_tagged_isa\n_objc_msgSend_fixup\n__objc_fixupMessageRef\n_objc_msgSend\n__class_lookupMethodAndLoadCache3\n_lookUpMethod\n_prepareForMethodLookup\n__class_initialize\n__class_getNonMetaClass\n__Z15getNonMetaClassP7class_t\n__class_getSuperclass\n__class_isInitialized\n__class_isInitializing\n__class_setInitializing\n__fetchInitializingClassList\n__objc_fetch_pthread_data\n_lockForMethodLookup\n__cache_getImp\n__class_getMethodNoSuper_nolock\n_log_and_fill_cache\n__cache_fill\n_unlockForMethodLookup\n_objc_assign_global_non_gc\n_class_setSuperclass\n_class_setVersion\n_objc_msgSend_vtable1\n__objc_rootAlloc\n_class_getInstanceSize\n__class_getInstanceSize\n_class_createInstance\n_object_getClassName\n__class_getName\n_object_getIndexedIvars\n_objc_msgSend_vtable0\n__objc_rootAllocWithZone\n__objc_rootInit\n_objc_msgSend_vtable3\n_objc_assign_ivar_non_gc\n__objc_rootRetain\n__ZN4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE16FindAndConstructERKS2_\n__ZNK4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE15LookupBucketForERKS2_RPNSt3__14pairIS2_mEE\n__ZN4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE16InsertIntoBucketERKS2_RKmPNSt3__14pairIS2_mEE\n__objc_rootRelease\n__objc_rootReleaseWasZero\n__ZN4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE4findERKS2_\n__finishInitializing\n__class_setInitialized\n_NXFreeMapTable\n_NXResetMapTable\n__cache_malloc\n__class_setCache\n__class_setGrowCache\n_objc_initializeClassPair\n__Z33objc_initializeClassPair_internalP10objc_classPKcS0_S0_\n_objc_registerClassPair\n_add_category_to_loadable_list\n__category_getLoadMethod\n__category_getClass\n__class_isLoadable\n_objc_msgSendSuper2\n__objc_autoreleasePoolPush\n_objc_autoreleasePoolPush\n__ZN12_GLOBAL__N_119AutoreleasePoolPageC1EPS0_\n__ZN12_GLOBAL__N_119AutoreleasePoolPage9fastcheckEb\n_objc_destructInstance\n_objc_clear_deallocating\n__ZN4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE5eraseERKS2_\n_objc_msgSend_vtable9\n__class_shouldGrowCache\n__cache_collect_free\n__cache_collect\n_class_getSuperclass\n_objc_msgSend_vtable2\n_objc_msgSend_vtable13\n_objc_msgSend_vtable14\n_objc_memmove_collectable\n_class_respondsToSelector\n__class_resolveMethod\n__class_isMetaClass\n__cache_addForwardEntry\n__objc_rootDealloc\n_object_dispose\n_objc_msgSend_fixedup\n_class_getName\n_objc_atomicCompareAndSwapPtrBarrier\n_objc_msgSend_vtable7\n__objc_rootAutorelease\n__Z22_objc_rootAutorelease2P11objc_object\n_objc_msgSend_vtable12\n_objc_msgSend_vtable11\n_objc_msgSend_vtable8\n_objc_msgSend_vtable15\n__objc_autoreleasePoolPop\n__ZN12_GLOBAL__N_119AutoreleasePoolPage3popEPv\n_objc_msgSend_vtable4\n_objc_msgSend_vtable10\n_objc_retain\n_objc_atomicCompareAndSwapInstanceVariableBarrier\n_objc_msgSendSuper2_fixup\n_objc_msgSendSuper2_fixedup\n__collecting_in_critical\n__cache_free_block\n_class_getVersion\n_objc_finalizeOnMainThread\n_class_getImageName\n__objc_rootZone\n__Z35_protocol_conformsToProtocol_nolockP10protocol_tS0_\n_objc_msgSend_vtable5\n_objc_sync_enter\n_id2data\n_fetch_cache\n_objc_sync_exit\n_gc_enforcer\n_cache_region_calloc\n_class_getMethodImplementation\n_objc_msgSend_stret\n__ZN4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE4growEj\n__objc_rootHash\n_objc_assign_weak_non_gc\n_objc_read_weak_non_gc\n_sel_getName\n_method_getArgumentType\n_encoding_getArgumentType\n_encoding_getArgumentInfo\n_SkipFirstType\n_class_isMetaClass\n_objc_allocateClassPair\n__calloc_class\n_class_getInstanceVariable\n__class_getVariable\n__Z7getIvarP7class_tPKc\n_object_setClass\n__class_instancesHaveAssociatedObjects\n_method_getNumberOfArguments\n_encoding_getNumberOfArguments\n_method_copyReturnType\n_encoding_copyReturnType\n_method_copyArgumentType\n_encoding_copyArgumentType\n__objc_rootRetainCount\n_objc_getAssociatedObject_non_gc\n__object_get_associative_reference\n__ZN19AssociationsManagerC2Ev\n__ZN19AssociationsManager12associationsEv\n__ZNK23objc_references_support15ObjcPointerHashclEPv\n_objc_release\n_objc_removeAssociatedObjects\n_objc_setProperty_non_gc\n_objc_getProperty_non_gc\n_objc_autoreleaseReturnValue\n_objc_setAssociatedObject_non_gc\n__object_set_associative_reference\n__ZN9__gnu_cxx8hash_mapIPvPN23objc_references_support20ObjectAssociationMapENS2_15ObjcPointerHashENS2_16ObjcPointerEqualENS2_13\n__ZNSt3__13mapIPvN23objc_references_support15ObjcAssociationENS2_17ObjectPointerLessENS2_13ObjcAllocatorINS_4pairIKS1_S3_EEEEEi\n__ZNSt3__13mapIPvN23objc_references_support15ObjcAssociationENS2_17ObjectPointerLessENS2_13ObjcAllocatorINS_4pairIKS1_S3_EEEEE1\n__ZNSt3__127__tree_balance_after_insertIPNS_16__tree_node_baseIPvEEEEvT_S5_\n__class_setInstancesHaveAssociatedObjects\n_ivar_getTypeEncoding\n_object_getIvar\n_ivar_getOffset\n__class_usesAutomaticRetainRelease\n__objc_msgForward_internal\n__objc_msgForward\n_class_copyProtocolList\n_protocol_getMethodDescription\n__protocol_getMethod\n__Z26_protocol_getMethod_nolockP10protocol_tP13objc_selectoraa\n_method_getDescription\n_ivar_getName\n_objc_addExceptionHandler\n_read_address\n_read_sleb\n_fetch_handler_list\n_objc_removeExceptionHandler\n_SubtypeUntil\n_objc_collecting_enabled\n_objc_msgSend_vtable6\n_objc_is_finalized\n_class_copyPropertyList\n_property_getName\n_property_getAttributes\n_objc_msgSendSuper2_stret\n_object_setInstanceVariable\n_object_setIvar\n_objc_assign_ivar\n__ZN12_GLOBAL__N_119AutoreleasePoolPage15autoreleaseSlowEP11objc_object\n_objc_atomicCompareAndSwapPtr\n_objc_atomicCompareAndSwapGlobalBarrier\n_sel_getUid\n__ZN12_GLOBAL__N_119AutoreleasePoolPage11tls_deallocEPv\n__ZN12_GLOBAL__N_119AutoreleasePoolPage4killEv\n__objc_constructOrFree\n_object_cxxConstruct\n_object_cxxConstructFromClass\n__class_hasCxxStructors\n_lookupMethodInClassAndLoadCache\n__class_getMethodNoSuper\n_object_cxxDestruct\n_object_cxxDestructFromClass\n_class_copyIvarList\n__objc_rootRetain_slow\n__objc_rootReleaseWasZero_slow\n_object_copy\n__Z20_object_copyFromZoneP11objc_objectmPv\n__objc_pthread_destroyspecific\n__destroyInitializingClassList\n__destroySyncCache\n__destroyAltHandlerList\n__object_remove_assocations\n__ZNSt3__114__split_bufferIN23objc_references_support15ObjcAssociationERNS1_13ObjcAllocatorIS2_EEE9push_backERKS2_\n__ZNSt3__16vectorIN23objc_references_support15ObjcAssociationENS1_13ObjcAllocatorIS2_EEE26__swap_out_circular_bufferERNS_14__sp\n__ZNSt3__112__hash_tableINS_4pairIPvPN23objc_references_support20ObjectAssociationMapEEEN9__gnu_cxx17__hash_map_hasherIS6_NS3_1\n__ZNSt3__114__split_bufferIN23objc_references_support15ObjcAssociationERNS1_13ObjcAllocatorIS2_EEE10push_frontERKS2_\n__ZNSt3__16__treeINS_4pairIPvN23objc_references_support15ObjcAssociationEEENS_19__map_value_compareIS2_S4_NS3_17ObjectPointerLe\n__ZNSt3__113__tree_removeIPNS_16__tree_node_baseIPvEEEEvT_S5_\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/markgc.cpp",
    "content": "/*\n * Copyright (c) 2007-2009 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include <stdlib.h>\n#include <unistd.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdbool.h>\n#include <fcntl.h>\n#include <limits.h>\n#include <sys/mman.h>\n#include <sys/stat.h>\n#include <sys/errno.h>\n#include <os/overflow.h>\n#include <mach-o/fat.h>\n#include <mach-o/arch.h>\n#include <mach-o/loader.h>\n\n// Some OS X SDKs don't define these.\n#ifndef CPU_TYPE_ARM\n#define CPU_TYPE_ARM            ((cpu_type_t) 12)\n#endif\n#ifndef CPU_ARCH_ABI64\n#define CPU_ARCH_ABI64  0x01000000              /* 64 bit ABI */\n#endif\n#ifndef CPU_TYPE_ARM64\n#define CPU_TYPE_ARM64          (CPU_TYPE_ARM | CPU_ARCH_ABI64)\n#endif\n\n// File abstraction taken from ld64/FileAbstraction.hpp \n// and ld64/MachOFileAbstraction.hpp.\n\n#ifdef __OPTIMIZE__\n#define INLINE\t__attribute__((always_inline))\n#else\n#define INLINE\n#endif\n\n//\n// This abstraction layer is for use with file formats that have 64-bit/32-bit and Big-Endian/Little-Endian variants\n//\n// For example: to make a utility that handles 32-bit little enidan files use:  Pointer32<LittleEndian>\n//\n//\n//\t\tget16()\t\t\tread a 16-bit number from an E endian struct\n//\t\tset16()\t\t\twrite a 16-bit number to an E endian struct\n//\t\tget32()\t\t\tread a 32-bit number from an E endian struct\n//\t\tset32()\t\t\twrite a 32-bit number to an E endian struct\n//\t\tget64()\t\t\tread a 64-bit number from an E endian struct\n//\t\tset64()\t\t\twrite a 64-bit number to an E endian struct\n//\n//\t\tgetBits()\t\tread a bit field from an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)\n//\t\tsetBits()\t\twrite a bit field to an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)\n//\n//\t\tgetBitsRaw()\tread a bit field from a struct with native endianness\n//\t\tsetBitsRaw()\twrite a bit field from a struct with native endianness\n//\n\nclass BigEndian\n{\npublic:\n\tstatic uint16_t\tget16(const uint16_t& from)\t\t\t\tINLINE { return OSReadBigInt16(&from, 0); }\n\tstatic void\t\tset16(uint16_t& into, uint16_t value)\tINLINE { OSWriteBigInt16(&into, 0, value); }\n\t\n\tstatic uint32_t\tget32(const uint32_t& from)\t\t\t\tINLINE { return OSReadBigInt32(&from, 0); }\n\tstatic void\t\tset32(uint32_t& into, uint32_t value)\tINLINE { OSWriteBigInt32(&into, 0, value); }\n\t\n\tstatic uint64_t get64(const uint64_t& from)\t\t\t\tINLINE { return OSReadBigInt64(&from, 0); }\n\tstatic void\t\tset64(uint64_t& into, uint64_t value)\tINLINE { OSWriteBigInt64(&into, 0, value); }\n\t\n\tstatic uint32_t\tgetBits(const uint32_t& from, \n\t\t\t\t\t\tuint8_t firstBit, uint8_t bitCount)\tINLINE { return getBitsRaw(get32(from), firstBit, bitCount); }\n\tstatic void\t\tsetBits(uint32_t& into, uint32_t value,\n\t\t\t\t\t\tuint8_t firstBit, uint8_t bitCount)\tINLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }\n\n\tstatic uint32_t\tgetBitsRaw(const uint32_t& from, \n\t\t\t\t\t\tuint8_t firstBit, uint8_t bitCount)\tINLINE { return ((from >> (32-firstBit-bitCount)) & ((1<<bitCount)-1)); }\n\tstatic void\t\tsetBitsRaw(uint32_t& into, uint32_t value,\n\t\t\t\t\t\tuint8_t firstBit, uint8_t bitCount)\tINLINE { uint32_t temp = into; \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst uint32_t mask = ((1<<bitCount)-1); \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttemp &= ~(mask << (32-firstBit-bitCount)); \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttemp |= ((value & mask) << (32-firstBit-bitCount)); \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tinto = temp; }\n\tenum { little_endian = 0 };\n};\n\n\nclass LittleEndian\n{\npublic:\n\tstatic uint16_t\tget16(const uint16_t& from)\t\t\t\tINLINE { return OSReadLittleInt16(&from, 0); }\n\tstatic void\t\tset16(uint16_t& into, uint16_t value)\tINLINE { OSWriteLittleInt16(&into, 0, value); }\n\t\n\tstatic uint32_t\tget32(const uint32_t& from)\t\t\t\tINLINE { return OSReadLittleInt32(&from, 0); }\n\tstatic void\t\tset32(uint32_t& into, uint32_t value)\tINLINE { OSWriteLittleInt32(&into, 0, value); }\n\t\n\tstatic uint64_t get64(const uint64_t& from)\t\t\t\tINLINE { return OSReadLittleInt64(&from, 0); }\n\tstatic void\t\tset64(uint64_t& into, uint64_t value)\tINLINE { OSWriteLittleInt64(&into, 0, value); }\n\n\tstatic uint32_t\tgetBits(const uint32_t& from,\n\t\t\t\t\t\tuint8_t firstBit, uint8_t bitCount)\tINLINE { return getBitsRaw(get32(from), firstBit, bitCount); }\n\tstatic void\t\tsetBits(uint32_t& into, uint32_t value,\n\t\t\t\t\t\tuint8_t firstBit, uint8_t bitCount)\tINLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }\n\n\tstatic uint32_t\tgetBitsRaw(const uint32_t& from,\n\t\t\t\t\t\tuint8_t firstBit, uint8_t bitCount)\tINLINE { return ((from >> firstBit) & ((1<<bitCount)-1)); }\n\tstatic void\t\tsetBitsRaw(uint32_t& into, uint32_t value,\n\t\t\t\t\t\tuint8_t firstBit, uint8_t bitCount)\tINLINE {  uint32_t temp = into; \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst uint32_t mask = ((1<<bitCount)-1); \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttemp &= ~(mask << firstBit); \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttemp |= ((value & mask) << firstBit); \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tinto = temp; }\n\tenum { little_endian = 1 };\n};\n\n#if __BIG_ENDIAN__\ntypedef BigEndian CurrentEndian;\ntypedef LittleEndian OtherEndian;\n#elif __LITTLE_ENDIAN__\ntypedef LittleEndian CurrentEndian;\ntypedef BigEndian OtherEndian;\n#else\n#error unknown endianness\n#endif\n\n\ntemplate <typename _E>\nclass Pointer32\n{\npublic:\n\ttypedef uint32_t\tuint_t;\n\ttypedef int32_t\t\tsint_t;\n\ttypedef _E\t\t\tE;\n\t\n\tstatic uint64_t\tgetP(const uint_t& from)\t\t\t\tINLINE { return _E::get32(from); }\n\tstatic void\t\tsetP(uint_t& into, uint64_t value)\t\tINLINE { _E::set32(into, value); }\n};\n\n\ntemplate <typename _E>\nclass Pointer64\n{\npublic:\n\ttypedef uint64_t\tuint_t;\n\ttypedef int64_t\t\tsint_t;\n\ttypedef _E\t\t\tE;\n\t\n\tstatic uint64_t\tgetP(const uint_t& from)\t\t\t\tINLINE { return _E::get64(from); }\n\tstatic void\t\tsetP(uint_t& into, uint64_t value)\t\tINLINE { _E::set64(into, value); }\n};\n\n\n//\n// mach-o file header\n//\ntemplate <typename P> struct macho_header_content {};\ntemplate <> struct macho_header_content<Pointer32<BigEndian> >    { mach_header\t\tfields; };\ntemplate <> struct macho_header_content<Pointer64<BigEndian> >\t  { mach_header_64\tfields; };\ntemplate <> struct macho_header_content<Pointer32<LittleEndian> > { mach_header\t\tfields; };\ntemplate <> struct macho_header_content<Pointer64<LittleEndian> > { mach_header_64\tfields; };\n\ntemplate <typename P>\nclass macho_header {\npublic:\n\tuint32_t\t\tmagic() const\t\t\t\t\tINLINE { return E::get32(header.fields.magic); }\n\tvoid\t\t\tset_magic(uint32_t value)\t\tINLINE { E::set32(header.fields.magic, value); }\n\n\tuint32_t\t\tcputype() const\t\t\t\t\tINLINE { return E::get32(header.fields.cputype); }\n\tvoid\t\t\tset_cputype(uint32_t value)\t\tINLINE { E::set32((uint32_t&)header.fields.cputype, value); }\n\n\tuint32_t\t\tcpusubtype() const\t\t\t\tINLINE { return E::get32(header.fields.cpusubtype); }\n\tvoid\t\t\tset_cpusubtype(uint32_t value)\tINLINE { E::set32((uint32_t&)header.fields.cpusubtype, value); }\n\n\tuint32_t\t\tfiletype() const\t\t\t\tINLINE { return E::get32(header.fields.filetype); }\n\tvoid\t\t\tset_filetype(uint32_t value)\tINLINE { E::set32(header.fields.filetype, value); }\n\n\tuint32_t\t\tncmds() const\t\t\t\t\tINLINE { return E::get32(header.fields.ncmds); }\n\tvoid\t\t\tset_ncmds(uint32_t value)\t\tINLINE { E::set32(header.fields.ncmds, value); }\n\n\tuint32_t\t\tsizeofcmds() const\t\t\t\tINLINE { return E::get32(header.fields.sizeofcmds); }\n\tvoid\t\t\tset_sizeofcmds(uint32_t value)\tINLINE { E::set32(header.fields.sizeofcmds, value); }\n\n\tuint32_t\t\tflags() const\t\t\t\t\tINLINE { return E::get32(header.fields.flags); }\n\tvoid\t\t\tset_flags(uint32_t value)\t\tINLINE { E::set32(header.fields.flags, value); }\n\n\tuint32_t\t\treserved() const\t\t\t\tINLINE { return E::get32(header.fields.reserved); }\n\tvoid\t\t\tset_reserved(uint32_t value)\tINLINE { E::set32(header.fields.reserved, value); }\n\n\ttypedef typename P::E\t\tE;\nprivate:\n\tmacho_header_content<P>\theader;\n};\n\n\n//\n// mach-o load command\n//\ntemplate <typename P>\nclass macho_load_command {\npublic:\n\tuint32_t\t\tcmd() const\t\t\t\t\t\tINLINE { return E::get32(command.cmd); }\n\tvoid\t\t\tset_cmd(uint32_t value)\t\t\tINLINE { E::set32(command.cmd, value); }\n\n\tuint32_t\t\tcmdsize() const\t\t\t\t\tINLINE { return E::get32(command.cmdsize); }\n\tvoid\t\t\tset_cmdsize(uint32_t value)\t\tINLINE { E::set32(command.cmdsize, value); }\n\n\ttypedef typename P::E\t\tE;\nprivate:\n\tload_command\tcommand;\n};\n\n\n\n\n//\n// mach-o segment load command\n//\ntemplate <typename P> struct macho_segment_content {};\ntemplate <> struct macho_segment_content<Pointer32<BigEndian> >    { segment_command\tfields; enum { CMD = LC_SEGMENT\t\t}; };\ntemplate <> struct macho_segment_content<Pointer64<BigEndian> >\t   { segment_command_64\tfields; enum { CMD = LC_SEGMENT_64\t}; };\ntemplate <> struct macho_segment_content<Pointer32<LittleEndian> > { segment_command\tfields; enum { CMD = LC_SEGMENT\t\t}; };\ntemplate <> struct macho_segment_content<Pointer64<LittleEndian> > { segment_command_64\tfields; enum { CMD = LC_SEGMENT_64\t}; };\n\ntemplate <typename P>\nclass macho_segment_command {\npublic:\n\tuint32_t\t\tcmd() const\t\t\t\t\t\tINLINE { return E::get32(segment.fields.cmd); }\n\tvoid\t\t\tset_cmd(uint32_t value)\t\t\tINLINE { E::set32(segment.fields.cmd, value); }\n\n\tuint32_t\t\tcmdsize() const\t\t\t\t\tINLINE { return E::get32(segment.fields.cmdsize); }\n\tvoid\t\t\tset_cmdsize(uint32_t value)\t\tINLINE { E::set32(segment.fields.cmdsize, value); }\n\n\tconst char*\t\tsegname() const\t\t\t\t\tINLINE { return segment.fields.segname; }\n\tvoid\t\t\tset_segname(const char* value)\tINLINE { strncpy(segment.fields.segname, value, 16); }\n\t\n\tuint64_t\t\tvmaddr() const\t\t\t\t\tINLINE { return P::getP(segment.fields.vmaddr); }\n\tvoid\t\t\tset_vmaddr(uint64_t value)\t\tINLINE { P::setP(segment.fields.vmaddr, value); }\n\n\tuint64_t\t\tvmsize() const\t\t\t\t\tINLINE { return P::getP(segment.fields.vmsize); }\n\tvoid\t\t\tset_vmsize(uint64_t value)\t\tINLINE { P::setP(segment.fields.vmsize, value); }\n\n\tuint64_t\t\tfileoff() const\t\t\t\t\tINLINE { return P::getP(segment.fields.fileoff); }\n\tvoid\t\t\tset_fileoff(uint64_t value)\t\tINLINE { P::setP(segment.fields.fileoff, value); }\n\n\tuint64_t\t\tfilesize() const\t\t\t\tINLINE { return P::getP(segment.fields.filesize); }\n\tvoid\t\t\tset_filesize(uint64_t value)\tINLINE { P::setP(segment.fields.filesize, value); }\n\n\tuint32_t\t\tmaxprot() const\t\t\t\t\tINLINE { return E::get32(segment.fields.maxprot); }\n\tvoid\t\t\tset_maxprot(uint32_t value)\t\tINLINE { E::set32((uint32_t&)segment.fields.maxprot, value); }\n\n\tuint32_t\t\tinitprot() const\t\t\t\tINLINE { return E::get32(segment.fields.initprot); }\n\tvoid\t\t\tset_initprot(uint32_t value)\tINLINE { E::set32((uint32_t&)segment.fields.initprot, value); }\n\n\tuint32_t\t\tnsects() const\t\t\t\t\tINLINE { return E::get32(segment.fields.nsects); }\n\tvoid\t\t\tset_nsects(uint32_t value)\t\tINLINE { E::set32(segment.fields.nsects, value); }\n\n\tuint32_t\t\tflags() const\t\t\t\t\tINLINE { return E::get32(segment.fields.flags); }\n\tvoid\t\t\tset_flags(uint32_t value)\t\tINLINE { E::set32(segment.fields.flags, value); }\n\n\tenum {\n\t\tCMD = macho_segment_content<P>::CMD\n\t};\n\n\ttypedef typename P::E\t\tE;\nprivate:\n\tmacho_segment_content<P>\tsegment;\n};\n\n\n//\n// mach-o section \n//\ntemplate <typename P> struct macho_section_content {};\ntemplate <> struct macho_section_content<Pointer32<BigEndian> >    { section\tfields; };\ntemplate <> struct macho_section_content<Pointer64<BigEndian> >\t   { section_64\tfields; };\ntemplate <> struct macho_section_content<Pointer32<LittleEndian> > { section\tfields; };\ntemplate <> struct macho_section_content<Pointer64<LittleEndian> > { section_64\tfields; };\n\ntemplate <typename P>\nclass macho_section {\npublic:\n\tconst char*\t\tsectname() const\t\t\t\tINLINE { return section.fields.sectname; }\n\tvoid\t\t\tset_sectname(const char* value)\tINLINE { strncpy(section.fields.sectname, value, 16); }\n\t\n\tconst char*\t\tsegname() const\t\t\t\t\tINLINE { return section.fields.segname; }\n\tvoid\t\t\tset_segname(const char* value)\tINLINE { strncpy(section.fields.segname, value, 16); }\n\t\n\tuint64_t\t\taddr() const\t\t\t\t\tINLINE { return P::getP(section.fields.addr); }\n\tvoid\t\t\tset_addr(uint64_t value)\t\tINLINE { P::setP(section.fields.addr, value); }\n\n\tuint64_t\t\tsize() const\t\t\t\t\tINLINE { return P::getP(section.fields.size); }\n\tvoid\t\t\tset_size(uint64_t value)\t\tINLINE { P::setP(section.fields.size, value); }\n\n\tuint32_t\t\toffset() const\t\t\t\t\tINLINE { return E::get32(section.fields.offset); }\n\tvoid\t\t\tset_offset(uint32_t value)\t\tINLINE { E::set32(section.fields.offset, value); }\n\n\tuint32_t\t\talign() const\t\t\t\t\tINLINE { return E::get32(section.fields.align); }\n\tvoid\t\t\tset_align(uint32_t value)\t\tINLINE { E::set32(section.fields.align, value); }\n\n\tuint32_t\t\treloff() const\t\t\t\t\tINLINE { return E::get32(section.fields.reloff); }\n\tvoid\t\t\tset_reloff(uint32_t value)\t\tINLINE { E::set32(section.fields.reloff, value); }\n\n\tuint32_t\t\tnreloc() const\t\t\t\t\tINLINE { return E::get32(section.fields.nreloc); }\n\tvoid\t\t\tset_nreloc(uint32_t value)\t\tINLINE { E::set32(section.fields.nreloc, value); }\n\n\tuint32_t\t\tflags() const\t\t\t\t\tINLINE { return E::get32(section.fields.flags); }\n\tvoid\t\t\tset_flags(uint32_t value)\t\tINLINE { E::set32(section.fields.flags, value); }\n\n\tuint32_t\t\treserved1() const\t\t\t\tINLINE { return E::get32(section.fields.reserved1); }\n\tvoid\t\t\tset_reserved1(uint32_t value)\tINLINE { E::set32(section.fields.reserved1, value); }\n\n\tuint32_t\t\treserved2() const\t\t\t\tINLINE { return E::get32(section.fields.reserved2); }\n\tvoid\t\t\tset_reserved2(uint32_t value)\tINLINE { E::set32(section.fields.reserved2, value); }\n\n\ttypedef typename P::E\t\tE;\nprivate:\n\tmacho_section_content<P>\tsection;\n};\n\n\n\n\nstatic bool debug = true;\n\nbool processFile(const char *filename);\n\nint main(int argc, const char *argv[]) {\n    for (int i = 1; i < argc; ++i) {\n        if (!processFile(argv[i])) return 1;\n    }\n    return 0;\n}\n\nstruct imageinfo {\n    uint32_t version;\n    uint32_t flags;\n};\n\n\n// Segment and section names are 16 bytes and may be un-terminated.\nbool segnameEquals(const char *lhs, const char *rhs)\n{\n    return 0 == strncmp(lhs, rhs, 16);\n}\n\nbool segnameStartsWith(const char *segname, const char *prefix)\n{\n    return 0 == strncmp(segname, prefix, strlen(prefix));\n}\n\nbool sectnameEquals(const char *lhs, const char *rhs)\n{\n    return segnameEquals(lhs, rhs);\n}\n\n\ntemplate <typename P>\nvoid dosect(uint8_t *start, macho_section<P> *sect)\n{\n    if (debug) printf(\"section %.16s from segment %.16s\\n\",\n                      sect->sectname(), sect->segname());\n\n    // Strip S_MOD_INIT/TERM_FUNC_POINTERS. We don't want dyld to call \n    // our init funcs because it is too late, and we don't want anyone to \n    // call our term funcs ever.\n    if (segnameStartsWith(sect->segname(), \"__DATA\")  &&  \n        sectnameEquals(sect->sectname(), \"__mod_init_func\"))\n    {\n        // section type 0 is S_REGULAR\n        sect->set_flags(sect->flags() & ~SECTION_TYPE);\n        sect->set_sectname(\"__objc_init_func\");\n        if (debug) printf(\"disabled __mod_init_func section\\n\");\n    }\n    if (segnameStartsWith(sect->segname(), \"__DATA\")  &&  \n        sectnameEquals(sect->sectname(), \"__mod_term_func\"))\n    {\n        // section type 0 is S_REGULAR\n        sect->set_flags(sect->flags() & ~SECTION_TYPE);\n        sect->set_sectname(\"__objc_term_func\");\n        if (debug) printf(\"disabled __mod_term_func section\\n\");\n    }\n}\n\ntemplate <typename P>\nvoid doseg(uint8_t *start, macho_segment_command<P> *seg)\n{\n    if (debug) printf(\"segment name: %.16s, nsects %u\\n\",\n                      seg->segname(), seg->nsects());\n    macho_section<P> *sect = (macho_section<P> *)(seg + 1);\n    for (uint32_t i = 0; i < seg->nsects(); ++i) {\n        dosect(start, &sect[i]);\n    }\n}\n\n\ntemplate<typename P>\nbool parse_macho(uint8_t *buffer)\n{\n    macho_header<P>* mh = (macho_header<P>*)buffer;\n    uint8_t *cmds = (uint8_t *)(mh + 1);\n    for (uint32_t c = 0; c < mh->ncmds(); c++) {\n        macho_load_command<P>* cmd = (macho_load_command<P>*)cmds;\n        cmds += cmd->cmdsize();\n        if (cmd->cmd() == LC_SEGMENT  ||  cmd->cmd() == LC_SEGMENT_64) {\n            doseg(buffer, (macho_segment_command<P>*)cmd);\n        }\n    }\n\n    return true;\n}\n\n\nbool parse_macho(uint8_t *buffer)\n{\n    uint32_t magic = *(uint32_t *)buffer;\n\n    switch (magic) {\n    case MH_MAGIC_64:\n        return parse_macho<Pointer64<CurrentEndian>>(buffer);\n    case MH_MAGIC:\n        return parse_macho<Pointer32<CurrentEndian>>(buffer);\n    case MH_CIGAM_64:\n        return parse_macho<Pointer64<OtherEndian>>(buffer);\n    case MH_CIGAM:\n        return parse_macho<Pointer32<OtherEndian>>(buffer);\n    default:\n        printf(\"file is not mach-o (magic %x)\\n\", magic);\n        return false;\n    }\n}\n\n\nbool parse_fat(uint8_t *buffer, size_t size)\n{\n    uint32_t magic;\n\n    if (size < sizeof(magic)) {\n        printf(\"file is too small\\n\");\n        return false;\n    }\n\n    magic = *(uint32_t *)buffer;\n    if (magic != FAT_MAGIC && magic != FAT_CIGAM) {\n        /* Not a fat file */\n        return parse_macho(buffer);\n    } else {\n        struct fat_header *fh;\n        uint32_t fat_magic, fat_nfat_arch;\n        struct fat_arch *archs;\n        \n        if (size < sizeof(struct fat_header)) {\n            printf(\"file is too small\\n\");\n            return false;\n        }\n\n        fh = (struct fat_header *)buffer;\n        fat_magic = OSSwapBigToHostInt32(fh->magic);\n        fat_nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch);\n\n        size_t fat_arch_size;\n        // fat_nfat_arch * sizeof(struct fat_arch) + sizeof(struct fat_header)\n        if (os_mul_and_add_overflow(fat_nfat_arch, sizeof(struct fat_arch),\n                                    sizeof(struct fat_header), &fat_arch_size))\n        {\n            printf(\"too many fat archs\\n\");\n            return false;\n        }\n        if (size < fat_arch_size) {\n            printf(\"file is too small\\n\");\n            return false;\n        }\n\n        archs = (struct fat_arch *)(buffer + sizeof(struct fat_header));\n\n        /* Special case hidden CPU_TYPE_ARM64 */\n        size_t fat_arch_plus_one_size;\n        if (os_add_overflow(fat_arch_size, sizeof(struct fat_arch),\n                            &fat_arch_plus_one_size))\n        {\n            printf(\"too many fat archs\\n\");\n            return false;\n        }\n        if (size >= fat_arch_plus_one_size) {\n            if (fat_nfat_arch > 0\n                && OSSwapBigToHostInt32(archs[fat_nfat_arch].cputype) == CPU_TYPE_ARM64) {\n                fat_nfat_arch++;\n            }\n        }\n        /* End special case hidden CPU_TYPE_ARM64 */\n\n        if (debug) printf(\"%d fat architectures\\n\", \n                          fat_nfat_arch);\n\n        for (uint32_t i = 0; i < fat_nfat_arch; i++) {\n            uint32_t arch_cputype = OSSwapBigToHostInt32(archs[i].cputype);\n            uint32_t arch_cpusubtype = OSSwapBigToHostInt32(archs[i].cpusubtype);\n            uint32_t arch_offset = OSSwapBigToHostInt32(archs[i].offset);\n            uint32_t arch_size = OSSwapBigToHostInt32(archs[i].size);\n\n            if (debug) printf(\"cputype %d cpusubtype %d\\n\", \n                              arch_cputype, arch_cpusubtype);\n\n            /* Check that slice data is after all fat headers and archs */\n            if (arch_offset < fat_arch_size) {\n                printf(\"file is badly formed\\n\");\n                return false;\n            }\n\n            /* Check that the slice ends before the file does */\n            if (arch_offset > size) {\n                printf(\"file is badly formed\\n\");\n                return false;\n            }\n\n            if (arch_size > size) {\n                printf(\"file is badly formed\\n\");\n                return false;\n            }\n\n            if (arch_offset > (size - arch_size)) {\n                printf(\"file is badly formed\\n\");\n                return false;\n            }\n\n            bool ok = parse_macho(buffer + arch_offset);\n            if (!ok) return false;\n        }\n        return true;\n    }\n}\n\nbool processFile(const char *filename)\n{\n    if (debug) printf(\"file %s\\n\", filename);\n    int fd = open(filename, O_RDWR);\n    if (fd < 0) {\n        printf(\"open %s: %s\\n\", filename, strerror(errno));\n        return false;\n    }\n    \n    struct stat st;\n    if (fstat(fd, &st) < 0) {\n        printf(\"fstat %s: %s\\n\", filename, strerror(errno));\n        return false;\n    }\n\n    void *buffer = mmap(NULL, (size_t)st.st_size, PROT_READ|PROT_WRITE, \n                        MAP_FILE|MAP_SHARED, fd, 0);\n    if (buffer == MAP_FAILED) {\n        printf(\"mmap %s: %s\\n\", filename, strerror(errno));\n        return false;\n    }\n\n    bool result = parse_fat((uint8_t *)buffer, (size_t)st.st_size);\n    munmap(buffer, (size_t)st.st_size);\n    close(fd);\n    return result;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/objc.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 9.00\r\n# Visual C++ Express 2005\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"objc\", \"objc.vcproj\", \"{B3408263-0CF1-47BE-83CC-56070EFC9BC1}\"\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"objcrt\", \"objcrt\\objcrt.vcproj\", \"{E38C1996-8B3D-4050-A4B2-DC85957B047D}\"\r\n\tProjectSection(ProjectDependencies) = postProject\r\n\t\t{B3408263-0CF1-47BE-83CC-56070EFC9BC1} = {B3408263-0CF1-47BE-83CC-56070EFC9BC1}\r\n\tEndProjectSection\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Win32 = Debug|Win32\r\n\t\tDebugDLL|Win32 = DebugDLL|Win32\r\n\t\tRelease|Win32 = Release|Win32\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Debug|Win32.ActiveCfg = Debug|Win32\r\n\t\t{B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Debug|Win32.Build.0 = Debug|Win32\r\n\t\t{B3408263-0CF1-47BE-83CC-56070EFC9BC1}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32\r\n\t\t{B3408263-0CF1-47BE-83CC-56070EFC9BC1}.DebugDLL|Win32.Build.0 = DebugDLL|Win32\r\n\t\t{B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Release|Win32.ActiveCfg = Release|Win32\r\n\t\t{B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Release|Win32.Build.0 = Release|Win32\r\n\t\t{E38C1996-8B3D-4050-A4B2-DC85957B047D}.Debug|Win32.ActiveCfg = Debug|Win32\r\n\t\t{E38C1996-8B3D-4050-A4B2-DC85957B047D}.Debug|Win32.Build.0 = Debug|Win32\r\n\t\t{E38C1996-8B3D-4050-A4B2-DC85957B047D}.DebugDLL|Win32.ActiveCfg = Debug|Win32\r\n\t\t{E38C1996-8B3D-4050-A4B2-DC85957B047D}.DebugDLL|Win32.Build.0 = Debug|Win32\r\n\t\t{E38C1996-8B3D-4050-A4B2-DC85957B047D}.Release|Win32.ActiveCfg = Release|Win32\r\n\t\t{E38C1996-8B3D-4050-A4B2-DC85957B047D}.Release|Win32.Build.0 = Release|Win32\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/objc.vcproj",
    "content": "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\r\n<VisualStudioProject\r\n\tProjectType=\"Visual C++\"\r\n\tVersion=\"8.00\"\r\n\tName=\"objc\"\r\n\tProjectGUID=\"{B3408263-0CF1-47BE-83CC-56070EFC9BC1}\"\r\n\tRootNamespace=\"objc\"\r\n\tKeyword=\"Win32Proj\"\r\n\t>\r\n\t<Platforms>\r\n\t\t<Platform\r\n\t\t\tName=\"Win32\"\r\n\t\t/>\r\n\t</Platforms>\r\n\t<ToolFiles>\r\n\t</ToolFiles>\r\n\t<Configurations>\r\n\t\t<Configuration\r\n\t\t\tName=\"Debug|Win32\"\r\n\t\t\tOutputDirectory=\"$(SolutionDir)$(ConfigurationName)\"\r\n\t\t\tIntermediateDirectory=\"$(ConfigurationName)\"\r\n\t\t\tConfigurationType=\"2\"\r\n\t\t\tCharacterSet=\"1\"\r\n\t\t\t>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCPreBuildEventTool\"\r\n\t\t\t\tDescription=\"prebuild.bat...\"\r\n\t\t\t\tCommandLine=\"prebuild\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCCustomBuildTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCMIDLTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\tOptimization=\"0\"\r\n\t\t\t\tAdditionalIncludeDirectories=\"&quot;$(ProjectDir)\\runtime&quot;;&quot;$(DSTROOT)\\AppleInternal\\include&quot;;&quot;$(SRCROOT)\\AppleInternal\\include&quot;\"\r\n\t\t\t\tPreprocessorDefinitions=\"WIN32;_DEBUG;_WINDOWS;_USRDLL;OBJC_EXPORTS;BUILDING_OBJC;__WIN32__;_CRT_SECURE_NO_DEPRECATE\"\r\n\t\t\t\tMinimalRebuild=\"true\"\r\n\t\t\t\tBasicRuntimeChecks=\"3\"\r\n\t\t\t\tRuntimeLibrary=\"3\"\r\n\t\t\t\tUsePrecompiledHeader=\"0\"\r\n\t\t\t\tWarningLevel=\"3\"\r\n\t\t\t\tDetect64BitPortabilityProblems=\"true\"\r\n\t\t\t\tDebugInformationFormat=\"4\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCResourceCompilerTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCPreLinkEventTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCLinkerTool\"\r\n\t\t\t\tAdditionalOptions=\"/dynamicbase\"\r\n\t\t\t\tOutputFile=\"$(OutDir)\\$(ProjectName)_debug.dll\"\r\n\t\t\t\tLinkIncremental=\"2\"\r\n\t\t\t\tGenerateDebugInformation=\"true\"\r\n\t\t\t\tStripPrivateSymbols=\"$(TargetDir)$(TargetName).pdbstripped\"\r\n\t\t\t\tSubSystem=\"2\"\r\n\t\t\t\tOptimizeReferences=\"1\"\r\n\t\t\t\tEnableCOMDATFolding=\"0\"\r\n\t\t\t\tTargetMachine=\"1\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCALinkTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCManifestTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCXDCMakeTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCBscMakeTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCFxCopTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCAppVerifierTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCWebDeploymentTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCPostBuildEventTool\"\r\n\t\t\t\tDescription=\"Install\"\r\n\t\t\t\tCommandLine=\"xcopy /Y &quot;$(TargetDir)$(TargetName).dll&quot; &quot;%DSTROOT%\\AppleInternal\\bin\\&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).exp&quot; &quot;%DSTROOT%\\AppleInternal\\bin\\&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).lib&quot; &quot;%DSTROOT%\\AppleInternal\\lib\\&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;%DSTROOT%\\AppleInternal\\bin\\&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).pdbstripped&quot; &quot;$(TargetDir)$(TargetName).pdb&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;%DSTROOT%\\AppleInternal\\public\\sym\\&quot;&#x0D;&#x0A;\"\r\n\t\t\t/>\r\n\t\t</Configuration>\r\n\t\t<Configuration\r\n\t\t\tName=\"Release|Win32\"\r\n\t\t\tOutputDirectory=\"$(SolutionDir)$(ConfigurationName)\"\r\n\t\t\tIntermediateDirectory=\"$(ConfigurationName)\"\r\n\t\t\tConfigurationType=\"2\"\r\n\t\t\tCharacterSet=\"1\"\r\n\t\t\tWholeProgramOptimization=\"1\"\r\n\t\t\t>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCPreBuildEventTool\"\r\n\t\t\t\tDescription=\"prebuild.bat...\"\r\n\t\t\t\tCommandLine=\"prebuild\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCCustomBuildTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCMIDLTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\tAdditionalIncludeDirectories=\"&quot;$(ProjectDir)\\runtime&quot;;&quot;$(DSTROOT)\\AppleInternal\\include&quot;;&quot;$(SRCROOT)\\AppleInternal\\include&quot;\"\r\n\t\t\t\tPreprocessorDefinitions=\"WIN32;NDEBUG;_WINDOWS;_USRDLL;OBJC_EXPORTS;BUILDING_OBJC;__WIN32__;_CRT_SECURE_NO_DEPRECATE\"\r\n\t\t\t\tRuntimeLibrary=\"2\"\r\n\t\t\t\tUsePrecompiledHeader=\"0\"\r\n\t\t\t\tWarningLevel=\"3\"\r\n\t\t\t\tDetect64BitPortabilityProblems=\"true\"\r\n\t\t\t\tDebugInformationFormat=\"3\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCResourceCompilerTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCPreLinkEventTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCLinkerTool\"\r\n\t\t\t\tAdditionalOptions=\"/dynamicbase\"\r\n\t\t\t\tLinkIncremental=\"1\"\r\n\t\t\t\tGenerateDebugInformation=\"true\"\r\n\t\t\t\tStripPrivateSymbols=\"$(TargetDir)$(TargetName).pdbstripped\"\r\n\t\t\t\tSubSystem=\"2\"\r\n\t\t\t\tOptimizeReferences=\"1\"\r\n\t\t\t\tEnableCOMDATFolding=\"2\"\r\n\t\t\t\tTargetMachine=\"1\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCALinkTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCManifestTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCXDCMakeTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCBscMakeTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCFxCopTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCAppVerifierTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCWebDeploymentTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCPostBuildEventTool\"\r\n\t\t\t\tDescription=\"Install\"\r\n\t\t\t\tCommandLine=\"xcopy /Y &quot;$(TargetDir)$(TargetName).dll&quot; &quot;%DSTROOT%\\AppleInternal\\bin\\&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).exp&quot; &quot;%DSTROOT%\\AppleInternal\\bin\\&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).lib&quot; &quot;%DSTROOT%\\AppleInternal\\lib\\&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;%DSTROOT%\\AppleInternal\\bin\\&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).pdbstripped&quot; &quot;$(TargetDir)$(TargetName).pdb&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;%DSTROOT%\\AppleInternal\\public\\sym\\&quot;&#x0D;&#x0A;\"\r\n\t\t\t/>\r\n\t\t</Configuration>\r\n\t\t<Configuration\r\n\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\tOutputDirectory=\"$(SolutionDir)$(ConfigurationName)\"\r\n\t\t\tIntermediateDirectory=\"$(ConfigurationName)\"\r\n\t\t\tConfigurationType=\"2\"\r\n\t\t\tCharacterSet=\"1\"\r\n\t\t\t>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCPreBuildEventTool\"\r\n\t\t\t\tDescription=\"prebuild.bat...\"\r\n\t\t\t\tCommandLine=\"prebuild\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCCustomBuildTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCMIDLTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\tOptimization=\"0\"\r\n\t\t\t\tAdditionalIncludeDirectories=\"&quot;$(ProjectDir)\\runtime&quot;;&quot;$(DSTROOT)\\AppleInternal\\include&quot;;&quot;$(SRCROOT)\\AppleInternal\\include&quot;\"\r\n\t\t\t\tPreprocessorDefinitions=\"WIN32;_DEBUG;_WINDOWS;_USRDLL;OBJC_EXPORTS;BUILDING_OBJC;__WIN32__;_CRT_SECURE_NO_DEPRECATE\"\r\n\t\t\t\tMinimalRebuild=\"true\"\r\n\t\t\t\tBasicRuntimeChecks=\"3\"\r\n\t\t\t\tRuntimeLibrary=\"3\"\r\n\t\t\t\tUsePrecompiledHeader=\"0\"\r\n\t\t\t\tWarningLevel=\"3\"\r\n\t\t\t\tDetect64BitPortabilityProblems=\"true\"\r\n\t\t\t\tDebugInformationFormat=\"4\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCResourceCompilerTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCPreLinkEventTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCLinkerTool\"\r\n\t\t\t\tAdditionalOptions=\"/dynamicbase\"\r\n\t\t\t\tOutputFile=\"$(OutDir)\\$(ProjectName)_debug.dll\"\r\n\t\t\t\tLinkIncremental=\"2\"\r\n\t\t\t\tGenerateDebugInformation=\"true\"\r\n\t\t\t\tStripPrivateSymbols=\"$(TargetDir)$(TargetName).pdbstripped\"\r\n\t\t\t\tSubSystem=\"2\"\r\n\t\t\t\tOptimizeReferences=\"1\"\r\n\t\t\t\tEnableCOMDATFolding=\"0\"\r\n\t\t\t\tTargetMachine=\"1\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCALinkTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCManifestTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCXDCMakeTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCBscMakeTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCFxCopTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCAppVerifierTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCWebDeploymentTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCPostBuildEventTool\"\r\n\t\t\t\tDescription=\"Install\"\r\n\t\t\t\tCommandLine=\"xcopy /Y &quot;$(TargetDir)$(TargetName).dll&quot; &quot;%DSTROOT%\\AppleInternal\\bin\\&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).exp&quot; &quot;%DSTROOT%\\AppleInternal\\bin\\&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).lib&quot; &quot;%DSTROOT%\\AppleInternal\\lib\\&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;%DSTROOT%\\AppleInternal\\bin\\&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).pdbstripped&quot; &quot;$(TargetDir)$(TargetName).pdb&quot;&#x0D;&#x0A;xcopy /Y &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;%DSTROOT%\\AppleInternal\\public\\sym\\&quot;&#x0D;&#x0A;\"\r\n\t\t\t/>\r\n\t\t</Configuration>\r\n\t</Configurations>\r\n\t<References>\r\n\t</References>\r\n\t<Files>\r\n\t\t<Filter\r\n\t\t\tName=\"Source Files\"\r\n\t\t\tFilter=\"cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx\"\r\n\t\t\tUniqueIdentifier=\"{4FC737F1-C7A5-4376-A066-2A32D752A2FF}\"\r\n\t\t\t>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\hashtable2.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\maptable.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-cache.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-class-old.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-class.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-errors.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-exception.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-file-old.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-file.mm\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-initialize.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-layout.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-load.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-loadmethod.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-lockdebug.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\Messengers.subproj\\objc-msg-win32.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-os.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-references.mm\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-runtime-new.mm\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-runtime-old.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-runtime.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-sel-set.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-sel.mm\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-sync.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-typeencoding.m\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCCLCompilerTool\"\r\n\t\t\t\t\t\tCompileAs=\"1\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t</Filter>\r\n\t\t<Filter\r\n\t\t\tName=\"Header Files\"\r\n\t\t\tFilter=\"h;hpp;hxx;hm;inl;inc;xsd\"\r\n\t\t\tUniqueIdentifier=\"{93995380-89BD-4b04-88EB-625FBE52EBFB}\"\r\n\t\t\t>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\error.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\hashtable.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\hashtable2.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\maptable.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\message.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-api.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-auto.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-class.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-config.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-exception.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-file-old.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-file.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-initialize.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-load.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-loadmethod.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-os.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-private.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-references.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-runtime-new.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-runtime.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-sel-set.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-sel-table.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc-sync.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objc.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\objcrt.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\Protocol.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\runtime\\runtime.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t</Filter>\r\n\t\t<Filter\r\n\t\t\tName=\"Resource Files\"\r\n\t\t\tFilter=\"rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav\"\r\n\t\t\tUniqueIdentifier=\"{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}\"\r\n\t\t\t>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\".\\version.rc\"\r\n\t\t\t\t>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Debug|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCResourceCompilerTool\"\r\n\t\t\t\t\t\tAdditionalIncludeDirectories=\"$(OBJROOT)\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"Release|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCResourceCompilerTool\"\r\n\t\t\t\t\t\tAdditionalIncludeDirectories=\"$(OBJROOT)\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t\t<FileConfiguration\r\n\t\t\t\t\tName=\"DebugDLL|Win32\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t<Tool\r\n\t\t\t\t\t\tName=\"VCResourceCompilerTool\"\r\n\t\t\t\t\t\tAdditionalIncludeDirectories=\"$(OBJROOT)\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</FileConfiguration>\r\n\t\t\t</File>\r\n\t\t</Filter>\r\n\t</Files>\r\n\t<Globals>\r\n\t</Globals>\r\n</VisualStudioProject>\r\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/objc.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXAggregateTarget section */\n\t\t837F67A81A771F63004D34FA /* objc-simulator */ = {\n\t\t\tisa = PBXAggregateTarget;\n\t\t\tbuildConfigurationList = 837F67A91A771F63004D34FA /* Build configuration list for PBXAggregateTarget \"objc-simulator\" */;\n\t\t\tbuildPhases = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t837F67AD1A771F6E004D34FA /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = \"objc-simulator\";\n\t\t\tproductName = objc_simulator;\n\t\t};\n/* End PBXAggregateTarget section */\n\n/* Begin PBXBuildFile section */\n\t\t393CEAC00DC69E3E000B69DE /* objc-references.mm in Sources */ = {isa = PBXBuildFile; fileRef = 393CEABF0DC69E3E000B69DE /* objc-references.mm */; };\n\t\t393CEAC60DC69E67000B69DE /* objc-references.h in Headers */ = {isa = PBXBuildFile; fileRef = 393CEAC50DC69E67000B69DE /* objc-references.h */; };\n\t\t39ABD72312F0B61800D1054C /* objc-weak.h in Headers */ = {isa = PBXBuildFile; fileRef = 39ABD71F12F0B61800D1054C /* objc-weak.h */; };\n\t\t39ABD72412F0B61800D1054C /* objc-weak.mm in Sources */ = {isa = PBXBuildFile; fileRef = 39ABD72012F0B61800D1054C /* objc-weak.mm */; };\n\t\t7593EC58202248E50046AB96 /* objc-object.h in Headers */ = {isa = PBXBuildFile; fileRef = 7593EC57202248DF0046AB96 /* objc-object.h */; };\n\t\t75A9504F202BAA0600D7D56F /* objc-locks-new.h in Headers */ = {isa = PBXBuildFile; fileRef = 75A9504E202BAA0300D7D56F /* objc-locks-new.h */; };\n\t\t75A95051202BAA9A00D7D56F /* objc-locks.h in Headers */ = {isa = PBXBuildFile; fileRef = 75A95050202BAA9A00D7D56F /* objc-locks.h */; };\n\t\t75A95053202BAC4100D7D56F /* objc-lockdebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 75A95052202BAC4100D7D56F /* objc-lockdebug.h */; };\n\t\t8306440920D24A5D00E356D2 /* objc-block-trampolines.h in Headers */ = {isa = PBXBuildFile; fileRef = 8306440620D24A3E00E356D2 /* objc-block-trampolines.h */; settings = {ATTRIBUTES = (Private, ); }; };\n\t\t830F2A740D737FB800392440 /* objc-msg-arm.s in Sources */ = {isa = PBXBuildFile; fileRef = 830F2A690D737FB800392440 /* objc-msg-arm.s */; };\n\t\t830F2A750D737FB900392440 /* objc-msg-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = 830F2A6A0D737FB800392440 /* objc-msg-i386.s */; };\n\t\t830F2A7D0D737FBB00392440 /* objc-msg-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = 830F2A720D737FB800392440 /* objc-msg-x86_64.s */; };\n\t\t830F2A950D73876100392440 /* objc-accessors.mm in Sources */ = {isa = PBXBuildFile; fileRef = 830F2A930D73876100392440 /* objc-accessors.mm */; };\n\t\t830F2A980D738DC200392440 /* hashtable.h in Headers */ = {isa = PBXBuildFile; fileRef = 830F2A970D738DC200392440 /* hashtable.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t83112ED40F00599600A5FBAF /* objc-internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 83112ED30F00599600A5FBAF /* objc-internal.h */; settings = {ATTRIBUTES = (Private, ); }; };\n\t\t831C85D50E10CF850066E64C /* objc-os.h in Headers */ = {isa = PBXBuildFile; fileRef = 831C85D30E10CF850066E64C /* objc-os.h */; };\n\t\t831C85D60E10CF850066E64C /* objc-os.mm in Sources */ = {isa = PBXBuildFile; fileRef = 831C85D40E10CF850066E64C /* objc-os.mm */; };\n\t\t834266D80E665A8B002E4DA2 /* objc-gdb.h in Headers */ = {isa = PBXBuildFile; fileRef = 834266D70E665A8B002E4DA2 /* objc-gdb.h */; settings = {ATTRIBUTES = (Private, ); }; };\n\t\t834DF8B715993EE1002F2BC9 /* objc-sel-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 834DF8B615993EE1002F2BC9 /* objc-sel-old.mm */; };\n\t\t834EC0A411614167009B2563 /* objc-abi.h in Headers */ = {isa = PBXBuildFile; fileRef = 834EC0A311614167009B2563 /* objc-abi.h */; settings = {ATTRIBUTES = (Private, ); }; };\n\t\t83725F4A14CA5BFA0014370E /* objc-opt.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83725F4914CA5BFA0014370E /* objc-opt.mm */; };\n\t\t838485BF0D6D687300CEA253 /* hashtable2.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485B70D6D687300CEA253 /* hashtable2.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t838485C00D6D687300CEA253 /* hashtable2.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485B80D6D687300CEA253 /* hashtable2.mm */; };\n\t\t838485C30D6D687300CEA253 /* maptable.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485BB0D6D687300CEA253 /* maptable.h */; settings = {ATTRIBUTES = (Private, ); }; };\n\t\t838485C40D6D687300CEA253 /* maptable.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485BC0D6D687300CEA253 /* maptable.mm */; };\n\t\t838485EF0D6D68A200CEA253 /* objc-api.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485C80D6D68A200CEA253 /* objc-api.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t838485F00D6D68A200CEA253 /* objc-auto.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485C90D6D68A200CEA253 /* objc-auto.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t838485F10D6D68A200CEA253 /* objc-auto.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485CA0D6D68A200CEA253 /* objc-auto.mm */; settings = {COMPILER_FLAGS = \"-fexceptions\"; }; };\n\t\t838485F20D6D68A200CEA253 /* objc-cache.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485CB0D6D68A200CEA253 /* objc-cache.mm */; };\n\t\t838485F30D6D68A200CEA253 /* objc-class-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485CC0D6D68A200CEA253 /* objc-class-old.mm */; };\n\t\t838485F40D6D68A200CEA253 /* objc-class.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485CD0D6D68A200CEA253 /* objc-class.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t838485F50D6D68A200CEA253 /* objc-class.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485CE0D6D68A200CEA253 /* objc-class.mm */; };\n\t\t838485F60D6D68A200CEA253 /* objc-config.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485CF0D6D68A200CEA253 /* objc-config.h */; };\n\t\t838485F70D6D68A200CEA253 /* objc-errors.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485D00D6D68A200CEA253 /* objc-errors.mm */; };\n\t\t838485F80D6D68A200CEA253 /* objc-exception.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485D10D6D68A200CEA253 /* objc-exception.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t838485F90D6D68A200CEA253 /* objc-exception.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485D20D6D68A200CEA253 /* objc-exception.mm */; settings = {COMPILER_FLAGS = \"-fexceptions\"; }; };\n\t\t838485FA0D6D68A200CEA253 /* objc-file.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485D30D6D68A200CEA253 /* objc-file.mm */; };\n\t\t838485FB0D6D68A200CEA253 /* objc-initialize.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485D40D6D68A200CEA253 /* objc-initialize.h */; };\n\t\t838485FC0D6D68A200CEA253 /* objc-initialize.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485D50D6D68A200CEA253 /* objc-initialize.mm */; };\n\t\t838485FD0D6D68A200CEA253 /* objc-layout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485D60D6D68A200CEA253 /* objc-layout.mm */; };\n\t\t838485FE0D6D68A200CEA253 /* objc-load.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485D70D6D68A200CEA253 /* objc-load.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t838485FF0D6D68A200CEA253 /* objc-load.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485D80D6D68A200CEA253 /* objc-load.mm */; };\n\t\t838486000D6D68A200CEA253 /* objc-loadmethod.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485D90D6D68A200CEA253 /* objc-loadmethod.h */; };\n\t\t838486010D6D68A200CEA253 /* objc-loadmethod.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485DA0D6D68A200CEA253 /* objc-loadmethod.mm */; };\n\t\t838486020D6D68A200CEA253 /* objc-lockdebug.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485DB0D6D68A200CEA253 /* objc-lockdebug.mm */; settings = {COMPILER_FLAGS = \"-Os\"; }; };\n\t\t838486030D6D68A200CEA253 /* objc-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485DC0D6D68A200CEA253 /* objc-private.h */; };\n\t\t838486070D6D68A200CEA253 /* objc-runtime-new.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485E00D6D68A200CEA253 /* objc-runtime-new.h */; };\n\t\t838486080D6D68A200CEA253 /* objc-runtime-new.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485E10D6D68A200CEA253 /* objc-runtime-new.mm */; };\n\t\t838486090D6D68A200CEA253 /* objc-runtime-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485E20D6D68A200CEA253 /* objc-runtime-old.mm */; };\n\t\t8384860A0D6D68A200CEA253 /* objc-runtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485E30D6D68A200CEA253 /* objc-runtime.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t8384860B0D6D68A200CEA253 /* objc-runtime.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485E40D6D68A200CEA253 /* objc-runtime.mm */; };\n\t\t8384860C0D6D68A200CEA253 /* objc-sel-set.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485E50D6D68A200CEA253 /* objc-sel-set.h */; };\n\t\t8384860D0D6D68A200CEA253 /* objc-sel-set.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485E60D6D68A200CEA253 /* objc-sel-set.mm */; };\n\t\t8384860F0D6D68A200CEA253 /* objc-sel.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485E80D6D68A200CEA253 /* objc-sel.mm */; };\n\t\t838486100D6D68A200CEA253 /* objc-sync.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485E90D6D68A200CEA253 /* objc-sync.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t838486110D6D68A200CEA253 /* objc-sync.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485EA0D6D68A200CEA253 /* objc-sync.mm */; };\n\t\t838486120D6D68A200CEA253 /* objc-typeencoding.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485EB0D6D68A200CEA253 /* objc-typeencoding.mm */; };\n\t\t838486130D6D68A200CEA253 /* objc.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485EC0D6D68A200CEA253 /* objc.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t838486140D6D68A200CEA253 /* Object.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485ED0D6D68A200CEA253 /* Object.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t838486150D6D68A200CEA253 /* Object.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485EE0D6D68A200CEA253 /* Object.mm */; };\n\t\t8384861E0D6D68A800CEA253 /* Protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 838486180D6D68A800CEA253 /* Protocol.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t8384861F0D6D68A800CEA253 /* Protocol.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838486190D6D68A800CEA253 /* Protocol.mm */; };\n\t\t838486200D6D68A800CEA253 /* runtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 8384861A0D6D68A800CEA253 /* runtime.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t838486250D6D68F000CEA253 /* List.m in Sources */ = {isa = PBXBuildFile; fileRef = 838486230D6D68F000CEA253 /* List.m */; };\n\t\t838486260D6D68F000CEA253 /* List.h in Headers */ = {isa = PBXBuildFile; fileRef = 838486240D6D68F000CEA253 /* List.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t838486280D6D6A2400CEA253 /* message.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485BD0D6D687300CEA253 /* message.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t83A4AEDC1EA0840800ACADDE /* module.modulemap in Headers */ = {isa = PBXBuildFile; fileRef = 83A4AED71EA06D9D00ACADDE /* module.modulemap */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t83A4AEDE1EA08C7200ACADDE /* ObjectiveC.apinotes in Headers */ = {isa = PBXBuildFile; fileRef = 83A4AEDD1EA08C5700ACADDE /* ObjectiveC.apinotes */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t83B1A8BE0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = 83B1A8BC0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s */; };\n\t\t83BE02E40FCCB23400661494 /* objc-file-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83BE02E30FCCB23400661494 /* objc-file-old.mm */; };\n\t\t83BE02E80FCCB24D00661494 /* objc-file-old.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE02E50FCCB24D00661494 /* objc-file-old.h */; };\n\t\t83BE02E90FCCB24D00661494 /* objc-file.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE02E60FCCB24D00661494 /* objc-file.h */; };\n\t\t83BE02EA0FCCB24D00661494 /* objc-runtime-old.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE02E70FCCB24D00661494 /* objc-runtime-old.h */; };\n\t\t83C9C3391668B50E00F4E544 /* objc-msg-simulator-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = 83C9C3381668B50E00F4E544 /* objc-msg-simulator-x86_64.s */; };\n\t\t83D49E4F13C7C84F0057F1DD /* objc-msg-arm64.s in Sources */ = {isa = PBXBuildFile; fileRef = 83D49E4E13C7C84F0057F1DD /* objc-msg-arm64.s */; };\n\t\t83EB007B121C9EC200B92C16 /* objc-sel-table.s in Sources */ = {isa = PBXBuildFile; fileRef = 83EB007A121C9EC200B92C16 /* objc-sel-table.s */; };\n\t\t83EF5E9820D2298400F486A4 /* objc-blocktramps-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = E8923D9C116AB2820071B552 /* objc-blocktramps-i386.s */; };\n\t\t83EF5E9920D2298400F486A4 /* objc-blocktramps-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = E8923D9D116AB2820071B552 /* objc-blocktramps-x86_64.s */; };\n\t\t83EF5E9C20D2299E00F486A4 /* objc-blocktramps-arm.s in Sources */ = {isa = PBXBuildFile; fileRef = 8383A3A1122600E9009290B8 /* objc-blocktramps-arm.s */; };\n\t\t83F4B52815E843B100E0926F /* NSObjCRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F4B52615E843B100E0926F /* NSObjCRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t83F4B52915E843B100E0926F /* NSObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F4B52715E843B100E0926F /* NSObject.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t83F550E0155E030800E95D3B /* objc-cache-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83F550DF155E030800E95D3B /* objc-cache-old.mm */; };\n\t\t87BB4EA70EC39854005D08E1 /* objc-probes.d in Sources */ = {isa = PBXBuildFile; fileRef = 87BB4E900EC39633005D08E1 /* objc-probes.d */; };\n\t\t9672F7EE14D5F488007CEC96 /* NSObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9672F7ED14D5F488007CEC96 /* NSObject.mm */; };\n\t\tE8923DA5116AB2820071B552 /* objc-block-trampolines.mm in Sources */ = {isa = PBXBuildFile; fileRef = E8923DA0116AB2820071B552 /* objc-block-trampolines.mm */; };\n\t\tF9BCC71B205C68E800DD9AFC /* objc-blocktramps-arm64.s in Sources */ = {isa = PBXBuildFile; fileRef = 8379996D13CBAF6F007C2B5F /* objc-blocktramps-arm64.s */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t837F67AC1A771F6E004D34FA /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = D2AAC0620554660B00DB518D;\n\t\t\tremoteInfo = objc;\n\t\t};\n\t\tF9BCC728205C6A0900DD9AFC /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = F9BCC6CA205C68E800DD9AFC;\n\t\t\tremoteInfo = \"objc-trampolines\";\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t393CEABF0DC69E3E000B69DE /* objc-references.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-references.mm\"; path = \"runtime/objc-references.mm\"; sourceTree = \"<group>\"; };\n\t\t393CEAC50DC69E67000B69DE /* objc-references.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-references.h\"; path = \"runtime/objc-references.h\"; sourceTree = \"<group>\"; };\n\t\t39ABD71F12F0B61800D1054C /* objc-weak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-weak.h\"; path = \"runtime/objc-weak.h\"; sourceTree = \"<group>\"; };\n\t\t39ABD72012F0B61800D1054C /* objc-weak.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-weak.mm\"; path = \"runtime/objc-weak.mm\"; sourceTree = \"<group>\"; };\n\t\t7593EC57202248DF0046AB96 /* objc-object.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = \"objc-object.h\"; path = \"runtime/objc-object.h\"; sourceTree = \"<group>\"; };\n\t\t75A9504E202BAA0300D7D56F /* objc-locks-new.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = \"objc-locks-new.h\"; path = \"runtime/objc-locks-new.h\"; sourceTree = \"<group>\"; };\n\t\t75A95050202BAA9A00D7D56F /* objc-locks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-locks.h\"; path = \"runtime/objc-locks.h\"; sourceTree = \"<group>\"; };\n\t\t75A95052202BAC4100D7D56F /* objc-lockdebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-lockdebug.h\"; path = \"runtime/objc-lockdebug.h\"; sourceTree = \"<group>\"; };\n\t\t8306440620D24A3E00E356D2 /* objc-block-trampolines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = \"objc-block-trampolines.h\"; path = \"runtime/objc-block-trampolines.h\"; sourceTree = \"<group>\"; };\n\t\t830F2A690D737FB800392440 /* objc-msg-arm.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = \"objc-msg-arm.s\"; path = \"runtime/Messengers.subproj/objc-msg-arm.s\"; sourceTree = \"<group>\"; };\n\t\t830F2A6A0D737FB800392440 /* objc-msg-i386.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = \"objc-msg-i386.s\"; path = \"runtime/Messengers.subproj/objc-msg-i386.s\"; sourceTree = \"<group>\"; };\n\t\t830F2A720D737FB800392440 /* objc-msg-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = \"objc-msg-x86_64.s\"; path = \"runtime/Messengers.subproj/objc-msg-x86_64.s\"; sourceTree = \"<group>\"; tabWidth = 8; usesTabs = 1; };\n\t\t830F2A930D73876100392440 /* objc-accessors.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-accessors.mm\"; path = \"runtime/objc-accessors.mm\"; sourceTree = \"<group>\"; };\n\t\t830F2A970D738DC200392440 /* hashtable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hashtable.h; path = runtime/hashtable.h; sourceTree = \"<group>\"; };\n\t\t830F2AA50D7394C200392440 /* markgc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = markgc.cpp; sourceTree = \"<group>\"; };\n\t\t83112ED30F00599600A5FBAF /* objc-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-internal.h\"; path = \"runtime/objc-internal.h\"; sourceTree = \"<group>\"; };\n\t\t831C85D30E10CF850066E64C /* objc-os.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-os.h\"; path = \"runtime/objc-os.h\"; sourceTree = \"<group>\"; };\n\t\t831C85D40E10CF850066E64C /* objc-os.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-os.mm\"; path = \"runtime/objc-os.mm\"; sourceTree = \"<group>\"; };\n\t\t834266D70E665A8B002E4DA2 /* objc-gdb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-gdb.h\"; path = \"runtime/objc-gdb.h\"; sourceTree = \"<group>\"; };\n\t\t834DF8B615993EE1002F2BC9 /* objc-sel-old.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-sel-old.mm\"; path = \"runtime/objc-sel-old.mm\"; sourceTree = \"<group>\"; };\n\t\t834EC0A311614167009B2563 /* objc-abi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-abi.h\"; path = \"runtime/objc-abi.h\"; sourceTree = \"<group>\"; };\n\t\t83725F4914CA5BFA0014370E /* objc-opt.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-opt.mm\"; path = \"runtime/objc-opt.mm\"; sourceTree = \"<group>\"; };\n\t\t8379996D13CBAF6F007C2B5F /* objc-blocktramps-arm64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = \"objc-blocktramps-arm64.s\"; path = \"runtime/objc-blocktramps-arm64.s\"; sourceTree = \"<group>\"; };\n\t\t8383A3A1122600E9009290B8 /* objc-blocktramps-arm.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = \"objc-blocktramps-arm.s\"; path = \"runtime/objc-blocktramps-arm.s\"; sourceTree = \"<group>\"; };\n\t\t838485B30D6D682B00CEA253 /* libobjc.order */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = libobjc.order; sourceTree = \"<group>\"; };\n\t\t838485B40D6D683300CEA253 /* APPLE_LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = APPLE_LICENSE; sourceTree = \"<group>\"; };\n\t\t838485B50D6D683300CEA253 /* ReleaseNotes.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = ReleaseNotes.rtf; sourceTree = \"<group>\"; };\n\t\t838485B70D6D687300CEA253 /* hashtable2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hashtable2.h; path = runtime/hashtable2.h; sourceTree = \"<group>\"; };\n\t\t838485B80D6D687300CEA253 /* hashtable2.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = hashtable2.mm; path = runtime/hashtable2.mm; sourceTree = \"<group>\"; };\n\t\t838485BB0D6D687300CEA253 /* maptable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = maptable.h; path = runtime/maptable.h; sourceTree = \"<group>\"; };\n\t\t838485BC0D6D687300CEA253 /* maptable.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = maptable.mm; path = runtime/maptable.mm; sourceTree = \"<group>\"; };\n\t\t838485BD0D6D687300CEA253 /* message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = message.h; path = runtime/message.h; sourceTree = \"<group>\"; };\n\t\t838485C80D6D68A200CEA253 /* objc-api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-api.h\"; path = \"runtime/objc-api.h\"; sourceTree = \"<group>\"; };\n\t\t838485C90D6D68A200CEA253 /* objc-auto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-auto.h\"; path = \"runtime/objc-auto.h\"; sourceTree = \"<group>\"; };\n\t\t838485CA0D6D68A200CEA253 /* objc-auto.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-auto.mm\"; path = \"runtime/objc-auto.mm\"; sourceTree = \"<group>\"; };\n\t\t838485CB0D6D68A200CEA253 /* objc-cache.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-cache.mm\"; path = \"runtime/objc-cache.mm\"; sourceTree = \"<group>\"; };\n\t\t838485CC0D6D68A200CEA253 /* objc-class-old.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-class-old.mm\"; path = \"runtime/objc-class-old.mm\"; sourceTree = \"<group>\"; };\n\t\t838485CD0D6D68A200CEA253 /* objc-class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-class.h\"; path = \"runtime/objc-class.h\"; sourceTree = \"<group>\"; };\n\t\t838485CE0D6D68A200CEA253 /* objc-class.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-class.mm\"; path = \"runtime/objc-class.mm\"; sourceTree = \"<group>\"; };\n\t\t838485CF0D6D68A200CEA253 /* objc-config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-config.h\"; path = \"runtime/objc-config.h\"; sourceTree = \"<group>\"; };\n\t\t838485D00D6D68A200CEA253 /* objc-errors.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-errors.mm\"; path = \"runtime/objc-errors.mm\"; sourceTree = \"<group>\"; };\n\t\t838485D10D6D68A200CEA253 /* objc-exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-exception.h\"; path = \"runtime/objc-exception.h\"; sourceTree = \"<group>\"; };\n\t\t838485D20D6D68A200CEA253 /* objc-exception.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-exception.mm\"; path = \"runtime/objc-exception.mm\"; sourceTree = \"<group>\"; };\n\t\t838485D30D6D68A200CEA253 /* objc-file.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-file.mm\"; path = \"runtime/objc-file.mm\"; sourceTree = \"<group>\"; };\n\t\t838485D40D6D68A200CEA253 /* objc-initialize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-initialize.h\"; path = \"runtime/objc-initialize.h\"; sourceTree = \"<group>\"; };\n\t\t838485D50D6D68A200CEA253 /* objc-initialize.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-initialize.mm\"; path = \"runtime/objc-initialize.mm\"; sourceTree = \"<group>\"; };\n\t\t838485D60D6D68A200CEA253 /* objc-layout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-layout.mm\"; path = \"runtime/objc-layout.mm\"; sourceTree = \"<group>\"; };\n\t\t838485D70D6D68A200CEA253 /* objc-load.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-load.h\"; path = \"runtime/objc-load.h\"; sourceTree = \"<group>\"; };\n\t\t838485D80D6D68A200CEA253 /* objc-load.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-load.mm\"; path = \"runtime/objc-load.mm\"; sourceTree = \"<group>\"; };\n\t\t838485D90D6D68A200CEA253 /* objc-loadmethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-loadmethod.h\"; path = \"runtime/objc-loadmethod.h\"; sourceTree = \"<group>\"; };\n\t\t838485DA0D6D68A200CEA253 /* objc-loadmethod.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-loadmethod.mm\"; path = \"runtime/objc-loadmethod.mm\"; sourceTree = \"<group>\"; };\n\t\t838485DB0D6D68A200CEA253 /* objc-lockdebug.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-lockdebug.mm\"; path = \"runtime/objc-lockdebug.mm\"; sourceTree = \"<group>\"; };\n\t\t838485DC0D6D68A200CEA253 /* objc-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-private.h\"; path = \"runtime/objc-private.h\"; sourceTree = \"<group>\"; };\n\t\t838485E00D6D68A200CEA253 /* objc-runtime-new.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-runtime-new.h\"; path = \"runtime/objc-runtime-new.h\"; sourceTree = \"<group>\"; };\n\t\t838485E10D6D68A200CEA253 /* objc-runtime-new.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-runtime-new.mm\"; path = \"runtime/objc-runtime-new.mm\"; sourceTree = \"<group>\"; };\n\t\t838485E20D6D68A200CEA253 /* objc-runtime-old.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-runtime-old.mm\"; path = \"runtime/objc-runtime-old.mm\"; sourceTree = \"<group>\"; };\n\t\t838485E30D6D68A200CEA253 /* objc-runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-runtime.h\"; path = \"runtime/objc-runtime.h\"; sourceTree = \"<group>\"; };\n\t\t838485E40D6D68A200CEA253 /* objc-runtime.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-runtime.mm\"; path = \"runtime/objc-runtime.mm\"; sourceTree = \"<group>\"; };\n\t\t838485E50D6D68A200CEA253 /* objc-sel-set.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-sel-set.h\"; path = \"runtime/objc-sel-set.h\"; sourceTree = \"<group>\"; };\n\t\t838485E60D6D68A200CEA253 /* objc-sel-set.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-sel-set.mm\"; path = \"runtime/objc-sel-set.mm\"; sourceTree = \"<group>\"; };\n\t\t838485E80D6D68A200CEA253 /* objc-sel.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-sel.mm\"; path = \"runtime/objc-sel.mm\"; sourceTree = \"<group>\"; };\n\t\t838485E90D6D68A200CEA253 /* objc-sync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-sync.h\"; path = \"runtime/objc-sync.h\"; sourceTree = \"<group>\"; };\n\t\t838485EA0D6D68A200CEA253 /* objc-sync.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-sync.mm\"; path = \"runtime/objc-sync.mm\"; sourceTree = \"<group>\"; };\n\t\t838485EB0D6D68A200CEA253 /* objc-typeencoding.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-typeencoding.mm\"; path = \"runtime/objc-typeencoding.mm\"; sourceTree = \"<group>\"; };\n\t\t838485EC0D6D68A200CEA253 /* objc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = objc.h; path = runtime/objc.h; sourceTree = \"<group>\"; };\n\t\t838485ED0D6D68A200CEA253 /* Object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Object.h; path = runtime/Object.h; sourceTree = \"<group>\"; };\n\t\t838485EE0D6D68A200CEA253 /* Object.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Object.mm; path = runtime/Object.mm; sourceTree = \"<group>\"; };\n\t\t838486180D6D68A800CEA253 /* Protocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Protocol.h; path = runtime/Protocol.h; sourceTree = \"<group>\"; };\n\t\t838486190D6D68A800CEA253 /* Protocol.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Protocol.mm; path = runtime/Protocol.mm; sourceTree = \"<group>\"; };\n\t\t8384861A0D6D68A800CEA253 /* runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = runtime.h; path = runtime/runtime.h; sourceTree = \"<group>\"; };\n\t\t838486230D6D68F000CEA253 /* List.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = List.m; path = runtime/OldClasses.subproj/List.m; sourceTree = \"<group>\"; };\n\t\t838486240D6D68F000CEA253 /* List.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = List.h; path = runtime/OldClasses.subproj/List.h; sourceTree = \"<group>\"; };\n\t\t83A4AED71EA06D9D00ACADDE /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = \"sourcecode.module-map\"; name = module.modulemap; path = runtime/Module/module.modulemap; sourceTree = \"<group>\"; };\n\t\t83A4AEDD1EA08C5700ACADDE /* ObjectiveC.apinotes */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ObjectiveC.apinotes; path = runtime/Module/ObjectiveC.apinotes; sourceTree = \"<group>\"; };\n\t\t83B1A8BC0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = \"objc-msg-simulator-i386.s\"; path = \"runtime/Messengers.subproj/objc-msg-simulator-i386.s\"; sourceTree = \"<group>\"; };\n\t\t83BE02E30FCCB23400661494 /* objc-file-old.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-file-old.mm\"; path = \"runtime/objc-file-old.mm\"; sourceTree = \"<group>\"; };\n\t\t83BE02E50FCCB24D00661494 /* objc-file-old.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-file-old.h\"; path = \"runtime/objc-file-old.h\"; sourceTree = \"<group>\"; };\n\t\t83BE02E60FCCB24D00661494 /* objc-file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-file.h\"; path = \"runtime/objc-file.h\"; sourceTree = \"<group>\"; };\n\t\t83BE02E70FCCB24D00661494 /* objc-runtime-old.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"objc-runtime-old.h\"; path = \"runtime/objc-runtime-old.h\"; sourceTree = \"<group>\"; };\n\t\t83C9C3381668B50E00F4E544 /* objc-msg-simulator-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = \"objc-msg-simulator-x86_64.s\"; path = \"runtime/Messengers.subproj/objc-msg-simulator-x86_64.s\"; sourceTree = \"<group>\"; };\n\t\t83CE671D1E6E76B60095A33E /* interposable.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = interposable.txt; sourceTree = \"<group>\"; };\n\t\t83D49E4E13C7C84F0057F1DD /* objc-msg-arm64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = \"objc-msg-arm64.s\"; path = \"runtime/Messengers.subproj/objc-msg-arm64.s\"; sourceTree = \"<group>\"; };\n\t\t83EB007A121C9EC200B92C16 /* objc-sel-table.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = \"objc-sel-table.s\"; path = \"runtime/objc-sel-table.s\"; sourceTree = \"<group>\"; };\n\t\t83F4B52615E843B100E0926F /* NSObjCRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSObjCRuntime.h; path = runtime/NSObjCRuntime.h; sourceTree = \"<group>\"; };\n\t\t83F4B52715E843B100E0926F /* NSObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSObject.h; path = runtime/NSObject.h; sourceTree = \"<group>\"; };\n\t\t83F550DF155E030800E95D3B /* objc-cache-old.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-cache-old.mm\"; path = \"runtime/objc-cache-old.mm\"; sourceTree = \"<group>\"; };\n\t\t87BB4E900EC39633005D08E1 /* objc-probes.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; name = \"objc-probes.d\"; path = \"runtime/objc-probes.d\"; sourceTree = \"<group>\"; };\n\t\t9672F7ED14D5F488007CEC96 /* NSObject.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NSObject.mm; path = runtime/NSObject.mm; sourceTree = \"<group>\"; };\n\t\tBC8B5D1212D3D48100C78A5B /* libauto.dylib */ = {isa = PBXFileReference; lastKnownFileType = \"compiled.mach-o.dylib\"; name = libauto.dylib; path = /usr/lib/libauto.dylib; sourceTree = \"<absolute>\"; };\n\t\tD2AAC0630554660B00DB518D /* libobjc.A.dylib */ = {isa = PBXFileReference; explicitFileType = \"compiled.mach-o.dylib\"; includeInIndex = 0; path = libobjc.A.dylib; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tE8923D9C116AB2820071B552 /* objc-blocktramps-i386.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = \"objc-blocktramps-i386.s\"; path = \"runtime/objc-blocktramps-i386.s\"; sourceTree = \"<group>\"; };\n\t\tE8923D9D116AB2820071B552 /* objc-blocktramps-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = \"objc-blocktramps-x86_64.s\"; path = \"runtime/objc-blocktramps-x86_64.s\"; sourceTree = \"<group>\"; };\n\t\tE8923DA0116AB2820071B552 /* objc-block-trampolines.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = \"objc-block-trampolines.mm\"; path = \"runtime/objc-block-trampolines.mm\"; sourceTree = \"<group>\"; };\n\t\tF9BCC727205C68E800DD9AFC /* libobjc-trampolines.dylib */ = {isa = PBXFileReference; explicitFileType = \"compiled.mach-o.dylib\"; includeInIndex = 0; path = \"libobjc-trampolines.dylib\"; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tD289988505E68E00004EDB86 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tF9BCC721205C68E800DD9AFC /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t08FB7794FE84155DC02AAC07 /* objc */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBC8B5D1212D3D48100C78A5B /* libauto.dylib */,\n\t\t\t\t838485C60D6D687700CEA253 /* Public Headers */,\n\t\t\t\t838485C70D6D688200CEA253 /* Private Headers */,\n\t\t\t\t8384862A0D6D6ABC00CEA253 /* Project Headers */,\n\t\t\t\t838486220D6D68E300CEA253 /* Obsolete Headers */,\n\t\t\t\t838486270D6D690F00CEA253 /* Obsolete Source */,\n\t\t\t\t08FB7795FE84155DC02AAC07 /* Source */,\n\t\t\t\t838485B20D6D67F900CEA253 /* Other */,\n\t\t\t\t1AB674ADFE9D54B511CA2CBB /* Products */,\n\t\t\t\tF9BCC72A205C6A1600DD9AFC /* Frameworks */,\n\t\t\t);\n\t\t\tname = objc;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t08FB7795FE84155DC02AAC07 /* Source */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t838485B80D6D687300CEA253 /* hashtable2.mm */,\n\t\t\t\t838485BC0D6D687300CEA253 /* maptable.mm */,\n\t\t\t\t9672F7ED14D5F488007CEC96 /* NSObject.mm */,\n\t\t\t\t838486190D6D68A800CEA253 /* Protocol.mm */,\n\t\t\t\t830F2A930D73876100392440 /* objc-accessors.mm */,\n\t\t\t\t838485CA0D6D68A200CEA253 /* objc-auto.mm */,\n\t\t\t\t39ABD72012F0B61800D1054C /* objc-weak.mm */,\n\t\t\t\tE8923DA0116AB2820071B552 /* objc-block-trampolines.mm */,\n\t\t\t\t838485CB0D6D68A200CEA253 /* objc-cache.mm */,\n\t\t\t\t83F550DF155E030800E95D3B /* objc-cache-old.mm */,\n\t\t\t\t838485CC0D6D68A200CEA253 /* objc-class-old.mm */,\n\t\t\t\t838485CE0D6D68A200CEA253 /* objc-class.mm */,\n\t\t\t\t838485D00D6D68A200CEA253 /* objc-errors.mm */,\n\t\t\t\t838485D20D6D68A200CEA253 /* objc-exception.mm */,\n\t\t\t\t838485D30D6D68A200CEA253 /* objc-file.mm */,\n\t\t\t\t83BE02E30FCCB23400661494 /* objc-file-old.mm */,\n\t\t\t\t838485D50D6D68A200CEA253 /* objc-initialize.mm */,\n\t\t\t\t838485D60D6D68A200CEA253 /* objc-layout.mm */,\n\t\t\t\t838485D80D6D68A200CEA253 /* objc-load.mm */,\n\t\t\t\t838485DA0D6D68A200CEA253 /* objc-loadmethod.mm */,\n\t\t\t\t838485DB0D6D68A200CEA253 /* objc-lockdebug.mm */,\n\t\t\t\t83725F4914CA5BFA0014370E /* objc-opt.mm */,\n\t\t\t\t831C85D40E10CF850066E64C /* objc-os.mm */,\n\t\t\t\t393CEABF0DC69E3E000B69DE /* objc-references.mm */,\n\t\t\t\t838485E10D6D68A200CEA253 /* objc-runtime-new.mm */,\n\t\t\t\t838485E20D6D68A200CEA253 /* objc-runtime-old.mm */,\n\t\t\t\t838485E40D6D68A200CEA253 /* objc-runtime.mm */,\n\t\t\t\t838485E60D6D68A200CEA253 /* objc-sel-set.mm */,\n\t\t\t\t83EB007A121C9EC200B92C16 /* objc-sel-table.s */,\n\t\t\t\t838485E80D6D68A200CEA253 /* objc-sel.mm */,\n\t\t\t\t834DF8B615993EE1002F2BC9 /* objc-sel-old.mm */,\n\t\t\t\t838485EA0D6D68A200CEA253 /* objc-sync.mm */,\n\t\t\t\t838485EB0D6D68A200CEA253 /* objc-typeencoding.mm */,\n\t\t\t\t8383A3A1122600E9009290B8 /* objc-blocktramps-arm.s */,\n\t\t\t\t8379996D13CBAF6F007C2B5F /* objc-blocktramps-arm64.s */,\n\t\t\t\tE8923D9C116AB2820071B552 /* objc-blocktramps-i386.s */,\n\t\t\t\tE8923D9D116AB2820071B552 /* objc-blocktramps-x86_64.s */,\n\t\t\t\t830F2A690D737FB800392440 /* objc-msg-arm.s */,\n\t\t\t\t83D49E4E13C7C84F0057F1DD /* objc-msg-arm64.s */,\n\t\t\t\t830F2A6A0D737FB800392440 /* objc-msg-i386.s */,\n\t\t\t\t83B1A8BC0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s */,\n\t\t\t\t83C9C3381668B50E00F4E544 /* objc-msg-simulator-x86_64.s */,\n\t\t\t\t830F2A720D737FB800392440 /* objc-msg-x86_64.s */,\n\t\t\t\t87BB4E900EC39633005D08E1 /* objc-probes.d */,\n\t\t\t);\n\t\t\tname = Source;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t1AB674ADFE9D54B511CA2CBB /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD2AAC0630554660B00DB518D /* libobjc.A.dylib */,\n\t\t\t\tF9BCC727205C68E800DD9AFC /* libobjc-trampolines.dylib */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t838485B20D6D67F900CEA253 /* Other */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t830F2AA50D7394C200392440 /* markgc.cpp */,\n\t\t\t\t838485B40D6D683300CEA253 /* APPLE_LICENSE */,\n\t\t\t\t838485B50D6D683300CEA253 /* ReleaseNotes.rtf */,\n\t\t\t\t83CE671D1E6E76B60095A33E /* interposable.txt */,\n\t\t\t\t838485B30D6D682B00CEA253 /* libobjc.order */,\n\t\t\t);\n\t\t\tname = Other;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t838485C60D6D687700CEA253 /* Public Headers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t83A4AEDD1EA08C5700ACADDE /* ObjectiveC.apinotes */,\n\t\t\t\t83A4AED71EA06D9D00ACADDE /* module.modulemap */,\n\t\t\t\t83F4B52615E843B100E0926F /* NSObjCRuntime.h */,\n\t\t\t\t83F4B52715E843B100E0926F /* NSObject.h */,\n\t\t\t\t838485BD0D6D687300CEA253 /* message.h */,\n\t\t\t\t838485C80D6D68A200CEA253 /* objc-api.h */,\n\t\t\t\t838485C90D6D68A200CEA253 /* objc-auto.h */,\n\t\t\t\t838485D10D6D68A200CEA253 /* objc-exception.h */,\n\t\t\t\t838485E90D6D68A200CEA253 /* objc-sync.h */,\n\t\t\t\t838485EC0D6D68A200CEA253 /* objc.h */,\n\t\t\t\t8384861A0D6D68A800CEA253 /* runtime.h */,\n\t\t\t);\n\t\t\tname = \"Public Headers\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t838485C70D6D688200CEA253 /* Private Headers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t83112ED30F00599600A5FBAF /* objc-internal.h */,\n\t\t\t\t834EC0A311614167009B2563 /* objc-abi.h */,\n\t\t\t\t838485BB0D6D687300CEA253 /* maptable.h */,\n\t\t\t\t834266D70E665A8B002E4DA2 /* objc-gdb.h */,\n\t\t\t\t8306440620D24A3E00E356D2 /* objc-block-trampolines.h */,\n\t\t\t);\n\t\t\tname = \"Private Headers\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t838486220D6D68E300CEA253 /* Obsolete Headers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t830F2A970D738DC200392440 /* hashtable.h */,\n\t\t\t\t838485B70D6D687300CEA253 /* hashtable2.h */,\n\t\t\t\t838485CD0D6D68A200CEA253 /* objc-class.h */,\n\t\t\t\t838485D70D6D68A200CEA253 /* objc-load.h */,\n\t\t\t\t838485E30D6D68A200CEA253 /* objc-runtime.h */,\n\t\t\t\t838486240D6D68F000CEA253 /* List.h */,\n\t\t\t\t838485ED0D6D68A200CEA253 /* Object.h */,\n\t\t\t\t838486180D6D68A800CEA253 /* Protocol.h */,\n\t\t\t);\n\t\t\tname = \"Obsolete Headers\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t838486270D6D690F00CEA253 /* Obsolete Source */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t838486230D6D68F000CEA253 /* List.m */,\n\t\t\t\t838485EE0D6D68A200CEA253 /* Object.mm */,\n\t\t\t);\n\t\t\tname = \"Obsolete Source\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t8384862A0D6D6ABC00CEA253 /* Project Headers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t838485CF0D6D68A200CEA253 /* objc-config.h */,\n\t\t\t\t83BE02E50FCCB24D00661494 /* objc-file-old.h */,\n\t\t\t\t83BE02E60FCCB24D00661494 /* objc-file.h */,\n\t\t\t\t838485D40D6D68A200CEA253 /* objc-initialize.h */,\n\t\t\t\t838485D90D6D68A200CEA253 /* objc-loadmethod.h */,\n\t\t\t\t75A9504E202BAA0300D7D56F /* objc-locks-new.h */,\n\t\t\t\t75A95052202BAC4100D7D56F /* objc-lockdebug.h */,\n\t\t\t\t75A95050202BAA9A00D7D56F /* objc-locks.h */,\n\t\t\t\t7593EC57202248DF0046AB96 /* objc-object.h */,\n\t\t\t\t831C85D30E10CF850066E64C /* objc-os.h */,\n\t\t\t\t838485DC0D6D68A200CEA253 /* objc-private.h */,\n\t\t\t\t393CEAC50DC69E67000B69DE /* objc-references.h */,\n\t\t\t\t838485E00D6D68A200CEA253 /* objc-runtime-new.h */,\n\t\t\t\t83BE02E70FCCB24D00661494 /* objc-runtime-old.h */,\n\t\t\t\t838485E50D6D68A200CEA253 /* objc-sel-set.h */,\n\t\t\t\t39ABD71F12F0B61800D1054C /* objc-weak.h */,\n\t\t\t);\n\t\t\tname = \"Project Headers\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF9BCC72A205C6A1600DD9AFC /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXHeadersBuildPhase section */\n\t\t8306440820D24A5300E356D2 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t8306440920D24A5D00E356D2 /* objc-block-trampolines.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tD2AAC0600554660B00DB518D /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t83A4AEDE1EA08C7200ACADDE /* ObjectiveC.apinotes in Headers */,\n\t\t\t\t75A95051202BAA9A00D7D56F /* objc-locks.h in Headers */,\n\t\t\t\t83A4AEDC1EA0840800ACADDE /* module.modulemap in Headers */,\n\t\t\t\t830F2A980D738DC200392440 /* hashtable.h in Headers */,\n\t\t\t\t838485BF0D6D687300CEA253 /* hashtable2.h in Headers */,\n\t\t\t\t838486260D6D68F000CEA253 /* List.h in Headers */,\n\t\t\t\t838485C30D6D687300CEA253 /* maptable.h in Headers */,\n\t\t\t\t838486280D6D6A2400CEA253 /* message.h in Headers */,\n\t\t\t\t834EC0A411614167009B2563 /* objc-abi.h in Headers */,\n\t\t\t\t838485EF0D6D68A200CEA253 /* objc-api.h in Headers */,\n\t\t\t\t838485F00D6D68A200CEA253 /* objc-auto.h in Headers */,\n\t\t\t\t838485F40D6D68A200CEA253 /* objc-class.h in Headers */,\n\t\t\t\t838485F60D6D68A200CEA253 /* objc-config.h in Headers */,\n\t\t\t\t838485F80D6D68A200CEA253 /* objc-exception.h in Headers */,\n\t\t\t\t83BE02E80FCCB24D00661494 /* objc-file-old.h in Headers */,\n\t\t\t\t83BE02E90FCCB24D00661494 /* objc-file.h in Headers */,\n\t\t\t\t75A9504F202BAA0600D7D56F /* objc-locks-new.h in Headers */,\n\t\t\t\t834266D80E665A8B002E4DA2 /* objc-gdb.h in Headers */,\n\t\t\t\t838485FB0D6D68A200CEA253 /* objc-initialize.h in Headers */,\n\t\t\t\t7593EC58202248E50046AB96 /* objc-object.h in Headers */,\n\t\t\t\t83112ED40F00599600A5FBAF /* objc-internal.h in Headers */,\n\t\t\t\t838485FE0D6D68A200CEA253 /* objc-load.h in Headers */,\n\t\t\t\t838486000D6D68A200CEA253 /* objc-loadmethod.h in Headers */,\n\t\t\t\t75A95053202BAC4100D7D56F /* objc-lockdebug.h in Headers */,\n\t\t\t\t831C85D50E10CF850066E64C /* objc-os.h in Headers */,\n\t\t\t\t838486030D6D68A200CEA253 /* objc-private.h in Headers */,\n\t\t\t\t393CEAC60DC69E67000B69DE /* objc-references.h in Headers */,\n\t\t\t\t838486070D6D68A200CEA253 /* objc-runtime-new.h in Headers */,\n\t\t\t\t83BE02EA0FCCB24D00661494 /* objc-runtime-old.h in Headers */,\n\t\t\t\t8384860A0D6D68A200CEA253 /* objc-runtime.h in Headers */,\n\t\t\t\t8384860C0D6D68A200CEA253 /* objc-sel-set.h in Headers */,\n\t\t\t\t838486100D6D68A200CEA253 /* objc-sync.h in Headers */,\n\t\t\t\t838486130D6D68A200CEA253 /* objc.h in Headers */,\n\t\t\t\t838486140D6D68A200CEA253 /* Object.h in Headers */,\n\t\t\t\t8384861E0D6D68A800CEA253 /* Protocol.h in Headers */,\n\t\t\t\t838486200D6D68A800CEA253 /* runtime.h in Headers */,\n\t\t\t\t39ABD72312F0B61800D1054C /* objc-weak.h in Headers */,\n\t\t\t\t83F4B52815E843B100E0926F /* NSObjCRuntime.h in Headers */,\n\t\t\t\t83F4B52915E843B100E0926F /* NSObject.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXHeadersBuildPhase section */\n\n/* Begin PBXNativeTarget section */\n\t\tD2AAC0620554660B00DB518D /* objc */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 1DEB914A08733D8E0010E9CD /* Build configuration list for PBXNativeTarget \"objc\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tD2AAC0600554660B00DB518D /* Headers */,\n\t\t\t\tD2AAC0610554660B00DB518D /* Sources */,\n\t\t\t\tD289988505E68E00004EDB86 /* Frameworks */,\n\t\t\t\t830F2AB60D739AB600392440 /* Run Script (markgc) */,\n\t\t\t\t830F2AFA0D73BC5800392440 /* Run Script (symlink) */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tF9BCC729205C6A0900DD9AFC /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = objc;\n\t\t\tproductName = objc;\n\t\t\tproductReference = D2AAC0630554660B00DB518D /* libobjc.A.dylib */;\n\t\t\tproductType = \"com.apple.product-type.library.dynamic\";\n\t\t};\n\t\tF9BCC6CA205C68E800DD9AFC /* objc-trampolines */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = F9BCC724205C68E800DD9AFC /* Build configuration list for PBXNativeTarget \"objc-trampolines\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t8306440820D24A5300E356D2 /* Headers */,\n\t\t\t\tF9BCC6EF205C68E800DD9AFC /* Sources */,\n\t\t\t\tF9BCC721205C68E800DD9AFC /* Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"objc-trampolines\";\n\t\t\tproductName = objc;\n\t\t\tproductReference = F9BCC727205C68E800DD9AFC /* libobjc-trampolines.dylib */;\n\t\t\tproductType = \"com.apple.product-type.library.dynamic\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t08FB7793FE84155DC02AAC07 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = NO;\n\t\t\t\tLastUpgradeCheck = 0440;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t837F67A81A771F63004D34FA = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.3;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject \"objc\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 1;\n\t\t\tknownRegions = (\n\t\t\t\tEnglish,\n\t\t\t\tJapanese,\n\t\t\t\tFrench,\n\t\t\t\tGerman,\n\t\t\t);\n\t\t\tmainGroup = 08FB7794FE84155DC02AAC07 /* objc */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tD2AAC0620554660B00DB518D /* objc */,\n\t\t\t\t837F67A81A771F63004D34FA /* objc-simulator */,\n\t\t\t\tF9BCC6CA205C68E800DD9AFC /* objc-trampolines */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t830F2AB60D739AB600392440 /* Run Script (markgc) */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tcomments = \"Modify the built dylib (mod_init_funcs and mod_term_funcs).\";\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Run Script (markgc)\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"set -x\\n/usr/bin/xcrun -sdk macosx.internal clang++ -Wall -mmacosx-version-min=10.12 -arch x86_64 -std=c++11 \\\"${SRCROOT}/markgc.cpp\\\" -o \\\"${BUILT_PRODUCTS_DIR}/markgc\\\"\\n\\\"${BUILT_PRODUCTS_DIR}/markgc\\\" \\\"${BUILT_PRODUCTS_DIR}/libobjc.A.dylib\\\"\";\n\t\t};\n\t\t830F2AFA0D73BC5800392440 /* Run Script (symlink) */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 8;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Run Script (symlink)\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 1;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"cd \\\"${INSTALL_DIR}\\\"\\n/bin/ln -s libobjc.A.dylib libobjc.dylib\\n\\nTBD_UPPER=`echo ${GENERATE_TEXT_BASED_STUBS} | tr a-z A-Z`\\n\\nif [ ${TBD_UPPER} = \\\"YES\\\" ] || [ ${TBD_UPPER} = \\\"TRUE\\\" ] || [ ${TBD_UPPER} = \\\"1\\\" ]; then\\nGENERATE_TBD=1\\nfi\\n\\nif [ ${GENERATE_TBD} ]; then\\n    /bin/ln -s libobjc.A.tbd libobjc.tbd\\nfi\\n\";\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tD2AAC0610554660B00DB518D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t838485C00D6D687300CEA253 /* hashtable2.mm in Sources */,\n\t\t\t\t838485C40D6D687300CEA253 /* maptable.mm in Sources */,\n\t\t\t\t838485F10D6D68A200CEA253 /* objc-auto.mm in Sources */,\n\t\t\t\t838485F20D6D68A200CEA253 /* objc-cache.mm in Sources */,\n\t\t\t\t838485F30D6D68A200CEA253 /* objc-class-old.mm in Sources */,\n\t\t\t\t838485F50D6D68A200CEA253 /* objc-class.mm in Sources */,\n\t\t\t\t838485F70D6D68A200CEA253 /* objc-errors.mm in Sources */,\n\t\t\t\t838485F90D6D68A200CEA253 /* objc-exception.mm in Sources */,\n\t\t\t\t838485FA0D6D68A200CEA253 /* objc-file.mm in Sources */,\n\t\t\t\t838485FC0D6D68A200CEA253 /* objc-initialize.mm in Sources */,\n\t\t\t\t838485FD0D6D68A200CEA253 /* objc-layout.mm in Sources */,\n\t\t\t\t838485FF0D6D68A200CEA253 /* objc-load.mm in Sources */,\n\t\t\t\t838486010D6D68A200CEA253 /* objc-loadmethod.mm in Sources */,\n\t\t\t\t838486020D6D68A200CEA253 /* objc-lockdebug.mm in Sources */,\n\t\t\t\t838486080D6D68A200CEA253 /* objc-runtime-new.mm in Sources */,\n\t\t\t\t838486090D6D68A200CEA253 /* objc-runtime-old.mm in Sources */,\n\t\t\t\t8384860B0D6D68A200CEA253 /* objc-runtime.mm in Sources */,\n\t\t\t\t8384860D0D6D68A200CEA253 /* objc-sel-set.mm in Sources */,\n\t\t\t\t8384860F0D6D68A200CEA253 /* objc-sel.mm in Sources */,\n\t\t\t\t838486110D6D68A200CEA253 /* objc-sync.mm in Sources */,\n\t\t\t\t838486120D6D68A200CEA253 /* objc-typeencoding.mm in Sources */,\n\t\t\t\t838486150D6D68A200CEA253 /* Object.mm in Sources */,\n\t\t\t\t8384861F0D6D68A800CEA253 /* Protocol.mm in Sources */,\n\t\t\t\t838486250D6D68F000CEA253 /* List.m in Sources */,\n\t\t\t\t830F2A740D737FB800392440 /* objc-msg-arm.s in Sources */,\n\t\t\t\t830F2A750D737FB900392440 /* objc-msg-i386.s in Sources */,\n\t\t\t\t830F2A7D0D737FBB00392440 /* objc-msg-x86_64.s in Sources */,\n\t\t\t\t830F2A950D73876100392440 /* objc-accessors.mm in Sources */,\n\t\t\t\t393CEAC00DC69E3E000B69DE /* objc-references.mm in Sources */,\n\t\t\t\t831C85D60E10CF850066E64C /* objc-os.mm in Sources */,\n\t\t\t\t87BB4EA70EC39854005D08E1 /* objc-probes.d in Sources */,\n\t\t\t\t83BE02E40FCCB23400661494 /* objc-file-old.mm in Sources */,\n\t\t\t\tE8923DA5116AB2820071B552 /* objc-block-trampolines.mm in Sources */,\n\t\t\t\t83B1A8BE0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s in Sources */,\n\t\t\t\t83EB007B121C9EC200B92C16 /* objc-sel-table.s in Sources */,\n\t\t\t\t39ABD72412F0B61800D1054C /* objc-weak.mm in Sources */,\n\t\t\t\t83D49E4F13C7C84F0057F1DD /* objc-msg-arm64.s in Sources */,\n\t\t\t\t9672F7EE14D5F488007CEC96 /* NSObject.mm in Sources */,\n\t\t\t\t83725F4A14CA5BFA0014370E /* objc-opt.mm in Sources */,\n\t\t\t\t83F550E0155E030800E95D3B /* objc-cache-old.mm in Sources */,\n\t\t\t\t834DF8B715993EE1002F2BC9 /* objc-sel-old.mm in Sources */,\n\t\t\t\t83C9C3391668B50E00F4E544 /* objc-msg-simulator-x86_64.s in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tF9BCC6EF205C68E800DD9AFC /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t83EF5E9C20D2299E00F486A4 /* objc-blocktramps-arm.s in Sources */,\n\t\t\t\t83EF5E9820D2298400F486A4 /* objc-blocktramps-i386.s in Sources */,\n\t\t\t\t83EF5E9920D2298400F486A4 /* objc-blocktramps-x86_64.s in Sources */,\n\t\t\t\tF9BCC71B205C68E800DD9AFC /* objc-blocktramps-arm64.s in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t837F67AD1A771F6E004D34FA /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = D2AAC0620554660B00DB518D /* objc */;\n\t\t\ttargetProxy = 837F67AC1A771F6E004D34FA /* PBXContainerItemProxy */;\n\t\t};\n\t\tF9BCC729205C6A0900DD9AFC /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = F9BCC6CA205C68E800DD9AFC /* objc-trampolines */;\n\t\t\ttargetProxy = F9BCC728205C6A0900DD9AFC /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin XCBuildConfiguration section */\n\t\t1DEB914B08733D8E0010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tARCHS = \"$(ARCHS_STANDARD_32_64_BIT)\";\n\t\t\t\tCOPY_HEADERS_RUN_UNIFDEF = YES;\n\t\t\t\tCOPY_HEADERS_UNIFDEF_FLAGS = \"-UBUILD_FOR_OSX\";\n\t\t\t\t\"COPY_HEADERS_UNIFDEF_FLAGS[sdk=macosx*]\" = \"-DBUILD_FOR_OSX\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDYLIB_CURRENT_VERSION = 228;\n\t\t\t\tEXECUTABLE_PREFIX = lib;\n\t\t\t\tGCC_CW_ASM_SYNTAX = NO;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(DSTROOT)/usr/include/**\",\n\t\t\t\t\t\"$(DSTROOT)/usr/local/include/**\",\n\t\t\t\t\t\"$(CONFIGURATION_BUILD_DIR)/usr/include/**\",\n\t\t\t\t\t\"$(CONFIGURATION_BUILD_DIR)/usr/local/include/**\",\n\t\t\t\t\t/System/Library/Frameworks/System.framework/PrivateHeaders,\n\t\t\t\t);\n\t\t\t\tINSTALL_PATH = /usr/lib;\n\t\t\t\tIS_ZIPPERED = YES;\n\t\t\t\tORDER_FILE = \"$(SDKROOT)/AppleInternal/OrderFiles/libobjc.order\";\n\t\t\t\t\"ORDER_FILE[sdk=iphonesimulator*]\" = \"\";\n\t\t\t\tOTHER_CFLAGS = (\n\t\t\t\t\t\"-fdollars-in-identifiers\",\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t);\n\t\t\t\t\"OTHER_LDFLAGS[sdk=iphoneos*][arch=*]\" = (\n\t\t\t\t\t\"-lc++abi\",\n\t\t\t\t\t\"-Wl,-segalign,0x4000\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t\"-sectalign\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t__DATA,\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t__objc_data,\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t0x1000,\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t\"-interposable_list\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\tinterposable.txt,\n\t\t\t\t);\n\t\t\t\t\"OTHER_LDFLAGS[sdk=iphonesimulator*][arch=*]\" = (\n\t\t\t\t\t\"-lc++abi\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t\"-interposable_list\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\tinterposable.txt,\n\t\t\t\t);\n\t\t\t\t\"OTHER_LDFLAGS[sdk=macosx*]\" = (\n\t\t\t\t\t\"-lCrashReporterClient\",\n\t\t\t\t\t\"-lc++abi\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t\"-sectalign\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t__DATA,\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t__objc_data,\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t0x1000,\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t\"-interposable_list\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\tinterposable.txt,\n\t\t\t\t);\n\t\t\t\tOTHER_TAPI_FLAGS = \"-exclude-public-header $(DSTROOT)/usr/include/objc/ObjectiveC.apinotes -exclude-public-header $(DSTROOT)/usr/include/objc/module.modulemap -Xparser -Wno-deprecated-declarations -Xparser -Wno-unavailable-declarations -Xparser -D_OBJC_PRIVATE_H_=1 -DOBJC_DECLARE_SYMBOLS=1\";\n\t\t\t\tPRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/objc;\n\t\t\t\tPRODUCT_NAME = objc.A;\n\t\t\t\tPUBLIC_HEADERS_FOLDER_PATH = /usr/include/objc;\n\t\t\t\tSUPPORTS_TEXT_BASED_API = YES;\n\t\t\t\tTAPI_VERIFY_MODE = Pedantic;\n\t\t\t\tUNEXPORTED_SYMBOLS_FILE = unexported_symbols;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB914C08733D8E0010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCOPY_HEADERS_RUN_UNIFDEF = YES;\n\t\t\t\tCOPY_HEADERS_UNIFDEF_FLAGS = \"-UBUILD_FOR_OSX\";\n\t\t\t\t\"COPY_HEADERS_UNIFDEF_FLAGS[sdk=macosx*]\" = \"-DBUILD_FOR_OSX\";\n\t\t\t\tDYLIB_CURRENT_VERSION = 228;\n\t\t\t\tEXECUTABLE_PREFIX = lib;\n\t\t\t\tGCC_CW_ASM_SYNTAX = NO;\n\t\t\t\tGCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(DSTROOT)/usr/include/**\",\n\t\t\t\t\t\"$(DSTROOT)/usr/local/include/**\",\n\t\t\t\t\t\"$(CONFIGURATION_BUILD_DIR)/usr/include/**\",\n\t\t\t\t\t\"$(CONFIGURATION_BUILD_DIR)/usr/local/include/**\",\n\t\t\t\t\t/System/Library/Frameworks/System.framework/PrivateHeaders,\n\t\t\t\t);\n\t\t\t\tINSTALL_PATH = /usr/lib;\n\t\t\t\tIS_ZIPPERED = YES;\n\t\t\t\tORDER_FILE = \"$(SDKROOT)/AppleInternal/OrderFiles/libobjc.order\";\n\t\t\t\t\"ORDER_FILE[sdk=iphonesimulator*]\" = \"\";\n\t\t\t\tOTHER_CFLAGS = (\n\t\t\t\t\t\"-fdollars-in-identifiers\",\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t);\n\t\t\t\t\"OTHER_LDFLAGS[sdk=iphoneos*][arch=*]\" = (\n\t\t\t\t\t\"-lc++abi\",\n\t\t\t\t\t\"-Wl,-segalign,0x4000\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t\"-sectalign\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t__DATA,\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t__objc_data,\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t0x1000,\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t\"-interposable_list\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\tinterposable.txt,\n\t\t\t\t);\n\t\t\t\t\"OTHER_LDFLAGS[sdk=iphonesimulator*][arch=*]\" = (\n\t\t\t\t\t\"-lc++abi\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t\"-interposable_list\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\tinterposable.txt,\n\t\t\t\t);\n\t\t\t\t\"OTHER_LDFLAGS[sdk=macosx*]\" = (\n\t\t\t\t\t\"-lCrashReporterClient\",\n\t\t\t\t\t\"-lc++abi\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t\"-sectalign\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t__DATA,\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t__objc_data,\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t0x1000,\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t\"-interposable_list\",\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\tinterposable.txt,\n\t\t\t\t);\n\t\t\t\tOTHER_TAPI_FLAGS = \"-exclude-public-header $(DSTROOT)/usr/include/objc/ObjectiveC.apinotes -exclude-public-header $(DSTROOT)/usr/include/objc/module.modulemap -Xparser -Wno-deprecated-declarations -Xparser -Wno-unavailable-declarations -Xparser -D_OBJC_PRIVATE_H_=1 -DOBJC_DECLARE_SYMBOLS=1\";\n\t\t\t\tPRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/objc;\n\t\t\t\tPRODUCT_NAME = objc.A;\n\t\t\t\tPUBLIC_HEADERS_FOLDER_PATH = /usr/include/objc;\n\t\t\t\tSUPPORTS_TEXT_BASED_API = YES;\n\t\t\t\tTAPI_VERIFY_MODE = Pedantic;\n\t\t\t\tUNEXPORTED_SYMBOLS_FILE = unexported_symbols;\n\t\t\t\tWARNING_CFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"-Wglobal-constructors\",\n\t\t\t\t);\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t1DEB914F08733D8E0010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_LINK_OBJC_RUNTIME = NO;\n\t\t\t\tCLANG_OBJC_RUNTIME = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tEXCLUDED_INSTALLSRC_SUBDIRECTORY_PATTERNS = \"$(inherited) test\";\n\t\t\t\tGCC_ENABLE_CPP_EXCEPTIONS = NO;\n\t\t\t\tGCC_ENABLE_CPP_RTTI = NO;\n\t\t\t\tGCC_INLINES_ARE_PRIVATE_EXTERN = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = \"OS_OBJECT_USE_OBJC=0\";\n\t\t\t\tGCC_STRICT_ALIASING = YES;\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = YES;\n\t\t\t\tGCC_VERSION = com.apple.compilers.llvm.clang.1_0;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;\n\t\t\t\tGCC_WARN_ABOUT_MISSING_NEWLINE = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;\n\t\t\t\tGCC_WARN_SHADOW = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tOTHER_CFLAGS = \"\";\n\t\t\t\t\"OTHER_CFLAGS[arch=x86_64]\" = \"-fobjc-legacy-dispatch\";\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"-D_LIBCPP_VISIBLE=\\\"\\\"\",\n\t\t\t\t);\n\t\t\t\tWARNING_CFLAGS = (\n\t\t\t\t\t\"-Wall\",\n\t\t\t\t\t\"-Wextra\",\n\t\t\t\t\t\"-Wstrict-aliasing=2\",\n\t\t\t\t\t\"-Wstrict-overflow=4\",\n\t\t\t\t\t\"-Wno-unused-parameter\",\n\t\t\t\t\t\"-Wno-deprecated-objc-isa-usage\",\n\t\t\t\t\t\"-Wno-cast-of-sel-type\",\n\t\t\t\t);\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB915008733D8E0010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_LINK_OBJC_RUNTIME = NO;\n\t\t\t\tCLANG_OBJC_RUNTIME = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tEXCLUDED_INSTALLSRC_SUBDIRECTORY_PATTERNS = \"$(inherited) test\";\n\t\t\t\tGCC_ENABLE_CPP_EXCEPTIONS = NO;\n\t\t\t\tGCC_ENABLE_CPP_RTTI = NO;\n\t\t\t\tGCC_INLINES_ARE_PRIVATE_EXTERN = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"OS_OBJECT_USE_OBJC=0\",\n\t\t\t\t\t\"NDEBUG=1\",\n\t\t\t\t);\n\t\t\t\tGCC_STRICT_ALIASING = YES;\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = YES;\n\t\t\t\tGCC_VERSION = com.apple.compilers.llvm.clang.1_0;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;\n\t\t\t\tGCC_WARN_ABOUT_MISSING_NEWLINE = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;\n\t\t\t\tGCC_WARN_SHADOW = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\t\"OTHER_CFLAGS[arch=i386]\" = \"-momit-leaf-frame-pointer\";\n\t\t\t\t\"OTHER_CFLAGS[arch=x86_64]\" = (\n\t\t\t\t\t\"-momit-leaf-frame-pointer\",\n\t\t\t\t\t\"-fobjc-legacy-dispatch\",\n\t\t\t\t);\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"-D_LIBCPP_VISIBLE=\\\"\\\"\",\n\t\t\t\t);\n\t\t\t\tWARNING_CFLAGS = (\n\t\t\t\t\t\"-Wall\",\n\t\t\t\t\t\"-Wextra\",\n\t\t\t\t\t\"-Wstrict-aliasing=2\",\n\t\t\t\t\t\"-Wstrict-overflow=4\",\n\t\t\t\t\t\"-Wno-unused-parameter\",\n\t\t\t\t\t\"-Wno-deprecated-objc-isa-usage\",\n\t\t\t\t\t\"-Wno-cast-of-sel-type\",\n\t\t\t\t);\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t837F67AA1A771F63004D34FA /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t837F67AB1A771F63004D34FA /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tF9BCC725205C68E800DD9AFC /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tARCHS = \"$(ARCHS_STANDARD_32_64_BIT)\";\n\t\t\t\tCOPY_HEADERS_RUN_UNIFDEF = YES;\n\t\t\t\tCOPY_HEADERS_UNIFDEF_FLAGS = \"-UBUILD_FOR_OSX\";\n\t\t\t\t\"COPY_HEADERS_UNIFDEF_FLAGS[sdk=macosx*]\" = \"-DBUILD_FOR_OSX\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDYLIB_CURRENT_VERSION = 228;\n\t\t\t\tEXECUTABLE_PREFIX = lib;\n\t\t\t\tGCC_CW_ASM_SYNTAX = NO;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(DSTROOT)/usr/include/**\",\n\t\t\t\t\t\"$(DSTROOT)/usr/local/include/**\",\n\t\t\t\t\t\"$(CONFIGURATION_BUILD_DIR)/usr/include/**\",\n\t\t\t\t\t\"$(CONFIGURATION_BUILD_DIR)/usr/local/include/**\",\n\t\t\t\t\t/System/Library/Frameworks/System.framework/PrivateHeaders,\n\t\t\t\t);\n\t\t\t\tINSTALL_PATH = /usr/lib;\n\t\t\t\tIS_ZIPPERED = YES;\n\t\t\t\tOTHER_CFLAGS = (\n\t\t\t\t\t\"-fdollars-in-identifiers\",\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t);\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t\"-not_for_dyld_shared_cache\",\n\t\t\t\t);\n\t\t\t\tPRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/objc;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPUBLIC_HEADERS_FOLDER_PATH = /usr/include/objc;\n\t\t\t\tSUPPORTS_TEXT_BASED_API = YES;\n\t\t\t\tTAPI_VERIFY_MODE = Pedantic;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tF9BCC726205C68E800DD9AFC /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCOPY_HEADERS_RUN_UNIFDEF = YES;\n\t\t\t\tCOPY_HEADERS_UNIFDEF_FLAGS = \"-UBUILD_FOR_OSX\";\n\t\t\t\t\"COPY_HEADERS_UNIFDEF_FLAGS[sdk=macosx*]\" = \"-DBUILD_FOR_OSX\";\n\t\t\t\tDYLIB_CURRENT_VERSION = 228;\n\t\t\t\tEXECUTABLE_PREFIX = lib;\n\t\t\t\tGCC_CW_ASM_SYNTAX = NO;\n\t\t\t\tGCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(DSTROOT)/usr/include/**\",\n\t\t\t\t\t\"$(DSTROOT)/usr/local/include/**\",\n\t\t\t\t\t\"$(CONFIGURATION_BUILD_DIR)/usr/include/**\",\n\t\t\t\t\t\"$(CONFIGURATION_BUILD_DIR)/usr/local/include/**\",\n\t\t\t\t\t/System/Library/Frameworks/System.framework/PrivateHeaders,\n\t\t\t\t);\n\t\t\t\tINSTALL_PATH = /usr/lib;\n\t\t\t\tIS_ZIPPERED = YES;\n\t\t\t\tOTHER_CFLAGS = (\n\t\t\t\t\t\"-fdollars-in-identifiers\",\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t);\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"-Xlinker\",\n\t\t\t\t\t\"-not_for_dyld_shared_cache\",\n\t\t\t\t);\n\t\t\t\tPRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/objc;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPUBLIC_HEADERS_FOLDER_PATH = /usr/include/objc;\n\t\t\t\tSUPPORTS_TEXT_BASED_API = YES;\n\t\t\t\tTAPI_VERIFY_MODE = Pedantic;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t1DEB914A08733D8E0010E9CD /* Build configuration list for PBXNativeTarget \"objc\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB914B08733D8E0010E9CD /* Debug */,\n\t\t\t\t1DEB914C08733D8E0010E9CD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject \"objc\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB914F08733D8E0010E9CD /* Debug */,\n\t\t\t\t1DEB915008733D8E0010E9CD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t837F67A91A771F63004D34FA /* Build configuration list for PBXAggregateTarget \"objc-simulator\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t837F67AA1A771F63004D34FA /* Debug */,\n\t\t\t\t837F67AB1A771F63004D34FA /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tF9BCC724205C68E800DD9AFC /* Build configuration list for PBXNativeTarget \"objc-trampolines\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tF9BCC725205C68E800DD9AFC /* Debug */,\n\t\t\t\tF9BCC726205C68E800DD9AFC /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 08FB7793FE84155DC02AAC07 /* Project object */;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/objc.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/objc.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/objcrt/objcrt.vcproj",
    "content": "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\r\n<VisualStudioProject\r\n\tProjectType=\"Visual C++\"\r\n\tVersion=\"8.00\"\r\n\tName=\"objcrt\"\r\n\tProjectGUID=\"{E38C1996-8B3D-4050-A4B2-DC85957B047D}\"\r\n\tRootNamespace=\"objcrt\"\r\n\t>\r\n\t<Platforms>\r\n\t\t<Platform\r\n\t\t\tName=\"Win32\"\r\n\t\t/>\r\n\t</Platforms>\r\n\t<ToolFiles>\r\n\t</ToolFiles>\r\n\t<Configurations>\r\n\t\t<Configuration\r\n\t\t\tName=\"Debug|Win32\"\r\n\t\t\tOutputDirectory=\"$(SolutionDir)$(ConfigurationName)\"\r\n\t\t\tIntermediateDirectory=\"$(ConfigurationName)\"\r\n\t\t\tConfigurationType=\"10\"\r\n\t\t\tCharacterSet=\"2\"\r\n\t\t\t>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCPreBuildEventTool\"\r\n\t\t\t\tCommandLine=\"cl /nologo /c /MDd /D_DEBUG /Od /Zl /DYNAMICBASE /GS /I&quot;%DSTROOT%\\AppleInternal\\include&quot; /I&quot;%SRCROOT%\\AppleInternal\\include&quot; /I&quot;$(ProjectDir)\\runtime&quot; /D&quot;_WINDOWS&quot; /Dnil=0 ..\\runtime\\objcrt.c /Fo&quot;$(OutDir)\\objcrt_debug.obj\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCCustomBuildTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCMIDLTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCPostBuildEventTool\"\r\n\t\t\t\tCommandLine=\"xcopy /Y &quot;$(OutDir)\\objcrt_debug.obj&quot; &quot;%DSTROOT%\\AppleInternal\\lib&quot;\"\r\n\t\t\t/>\r\n\t\t</Configuration>\r\n\t\t<Configuration\r\n\t\t\tName=\"Release|Win32\"\r\n\t\t\tOutputDirectory=\"$(SolutionDir)$(ConfigurationName)\"\r\n\t\t\tIntermediateDirectory=\"$(ConfigurationName)\"\r\n\t\t\tConfigurationType=\"10\"\r\n\t\t\tCharacterSet=\"2\"\r\n\t\t\tWholeProgramOptimization=\"1\"\r\n\t\t\t>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCPreBuildEventTool\"\r\n\t\t\t\tCommandLine=\"cl /nologo /c /MD /O1 /Zi /MP2 /DYNAMICBASE /GS /I&quot;%DSTROOT%\\AppleInternal\\include&quot; /I&quot;%SRCROOT%\\AppleInternal\\include&quot; /I&quot;$(ProjectDir)\\..\\runtime&quot; /D&quot;_WINDOWS&quot; /Dnil=0 ..\\runtime\\objcrt.c /Fo&quot;$(OutDir)\\objcrt.obj\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCCustomBuildTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCMIDLTool\"\r\n\t\t\t/>\r\n\t\t\t<Tool\r\n\t\t\t\tName=\"VCPostBuildEventTool\"\r\n\t\t\t\tCommandLine=\"xcopy /Y &quot;$(OutDir)\\objcrt.obj&quot; &quot;%DSTROOT%\\AppleInternal\\lib&quot;\"\r\n\t\t\t/>\r\n\t\t</Configuration>\r\n\t</Configurations>\r\n\t<References>\r\n\t</References>\r\n\t<Files>\r\n\t\t<Filter\r\n\t\t\tName=\"Source Files\"\r\n\t\t\tFilter=\"cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx\"\r\n\t\t\tUniqueIdentifier=\"{4FC737F1-C7A5-4376-A066-2A32D752A2FF}\"\r\n\t\t\t>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\"..\\runtime\\objcrt.c\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t</Filter>\r\n\t\t<Filter\r\n\t\t\tName=\"Header Files\"\r\n\t\t\tFilter=\"h;hpp;hxx;hm;inl;inc;xsd\"\r\n\t\t\tUniqueIdentifier=\"{93995380-89BD-4b04-88EB-625FBE52EBFB}\"\r\n\t\t\t>\r\n\t\t\t<File\r\n\t\t\t\tRelativePath=\"..\\runtime\\objcrt.h\"\r\n\t\t\t\t>\r\n\t\t\t</File>\r\n\t\t</Filter>\r\n\t\t<Filter\r\n\t\t\tName=\"Resource Files\"\r\n\t\t\tFilter=\"rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav\"\r\n\t\t\tUniqueIdentifier=\"{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}\"\r\n\t\t\t>\r\n\t\t</Filter>\r\n\t</Files>\r\n\t<Globals>\r\n\t</Globals>\r\n</VisualStudioProject>\r\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/prebuild.bat",
    "content": "@echo off\n\necho prebuild: installing headers\nxcopy /Y \"%ProjectDir%runtime\\objc.h\" \"%DSTROOT%\\AppleInternal\\include\\objc\\\"\nxcopy /Y \"%ProjectDir%runtime\\objc-api.h\" \"%DSTROOT%\\AppleInternal\\include\\objc\\\"\nxcopy /Y \"%ProjectDir%runtime\\objc-auto.h\" \"%DSTROOT%\\AppleInternal\\include\\objc\\\"\nxcopy /Y \"%ProjectDir%runtime\\objc-exception.h\" \"%DSTROOT%\\AppleInternal\\include\\objc\\\"\nxcopy /Y \"%ProjectDir%runtime\\message.h\" \"%DSTROOT%\\AppleInternal\\include\\objc\\\"\nxcopy /Y \"%ProjectDir%runtime\\runtime.h\" \"%DSTROOT%\\AppleInternal\\include\\objc\\\"\nxcopy /Y \"%ProjectDir%runtime\\hashtable.h\" \"%DSTROOT%\\AppleInternal\\include\\objc\\\"\nxcopy /Y \"%ProjectDir%runtime\\hashtable2.h\" \"%DSTROOT%\\AppleInternal\\include\\objc\\\"\nxcopy /Y \"%ProjectDir%runtime\\maptable.h\" \"%DSTROOT%\\AppleInternal\\include\\objc\\\"\n\necho prebuild: setting version\nversion\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/Messengers.subproj/objc-msg-arm.s",
    "content": "/*\n * @APPLE_LICENSE_HEADER_START@\n * \n * Copyright (c) 1999-2007 Apple Computer, Inc.  All Rights Reserved.\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/********************************************************************\n * \n *  objc-msg-arm.s - ARM code to support objc messaging\n *\n ********************************************************************/\n\n#ifdef __arm__\n\t\n#include <arm/arch.h>\n#include \"objc-config.h\"\n#include \"isa.h\"\n\n#ifndef _ARM_ARCH_7\n#   error requires armv7\n#endif\n\n// Set FP=1 on architectures that pass parameters in floating-point registers\n#if __ARM_ARCH_7K__\n#   define FP 1\n#else\n#   define FP 0\n#endif\n\n#if FP\n\n#   if !__ARM_NEON__\n#       error sorry\n#   endif\n\n#   define FP_RETURN_ZERO \\\n\tvmov.i32  q0, #0  ; \\\n\tvmov.i32  q1, #0  ; \\\n\tvmov.i32  q2, #0  ; \\\n\tvmov.i32  q3, #0\n\n#   define FP_SAVE \\\n\tvpush\t{q0-q3}\n\n#   define FP_RESTORE \\\n\tvpop\t{q0-q3}\n\n#else\n\n#   define FP_RETURN_ZERO\n#   define FP_SAVE\n#   define FP_RESTORE\n\n#endif\n\n.syntax unified\t\n\t\n#define MI_EXTERN(var) \\\n\t.non_lazy_symbol_pointer                        ;\\\nL##var##$$non_lazy_ptr:                                 ;\\\n\t.indirect_symbol var                            ;\\\n\t.long 0\n\n#define MI_GET_EXTERN(reg,var)  \\\n\tmovw\treg, :lower16:(L##var##$$non_lazy_ptr-7f-4)  ;\\\n\tmovt\treg, :upper16:(L##var##$$non_lazy_ptr-7f-4)  ;\\\n7:\tadd\treg, pc                                      ;\\\n\tldr\treg, [reg]\n\t\n#define MI_GET_ADDRESS(reg,var)  \\\n\tmovw\treg, :lower16:(var-7f-4)  ;\\\n\tmovt\treg, :upper16:(var-7f-4)  ;\\\n7:\tadd\treg, pc                                     ;\\\n\n\n.data\n\n#if SUPPORT_INDEXED_ISA\n\n\t.align 2\n\t.globl _objc_indexed_classes\n_objc_indexed_classes:\n\t.fill ISA_INDEX_COUNT, 4, 0\n\n#endif\n\n\n\n// _objc_entryPoints and _objc_exitPoints are used by method dispatch\n// caching code to figure out whether any threads are actively \n// in the cache for dispatching.  The labels surround the asm code\n// that do cache lookups.  The tables are zero-terminated.\n\n.align 2\n.private_extern _objc_entryPoints\n_objc_entryPoints:\n\t.long   _cache_getImp\n\t.long   _objc_msgSend\n\t.long   _objc_msgSend_stret\n\t.long   _objc_msgSendSuper\n\t.long   _objc_msgSendSuper_stret\n\t.long   _objc_msgSendSuper2\n\t.long   _objc_msgSendSuper2_stret\n\t.long   _objc_msgLookup\n\t.long   _objc_msgLookup_stret\n\t.long   _objc_msgLookupSuper2\n\t.long   _objc_msgLookupSuper2_stret\n\t.long   0\n\n.private_extern _objc_exitPoints\n_objc_exitPoints:\n\t.long   LExit_cache_getImp\n\t.long   LExit_objc_msgSend\n\t.long   LExit_objc_msgSend_stret\n\t.long   LExit_objc_msgSendSuper\n\t.long   LExit_objc_msgSendSuper_stret\n\t.long   LExit_objc_msgSendSuper2\n\t.long   LExit_objc_msgSendSuper2_stret\n\t.long   LExit_objc_msgLookup\n\t.long   LExit_objc_msgLookup_stret\n\t.long   LExit_objc_msgLookupSuper2\n\t.long   LExit_objc_msgLookupSuper2_stret\n\t.long   0\n\n\t\n/********************************************************************\n * Names for relative labels\n * DO NOT USE THESE LABELS ELSEWHERE\n * Reserved labels: 6: 7: 8: 9:\n ********************************************************************/\n// 6: used by CacheLookup\n// 7: used by MI_GET_ADDRESS etc\n// 8: used by CacheLookup\n#define LNilReceiver \t9\n#define LNilReceiver_f \t9f\n#define LNilReceiver_b \t9b\n\n\n/********************************************************************\n * Macro parameters\n ********************************************************************/\n\n#define NORMAL 0\n#define STRET 1\n\n\n/********************************************************************\n *\n * Structure definitions.\n *\n ********************************************************************/\n\n/* objc_super parameter to sendSuper */\n#define RECEIVER         0\n#define CLASS            4\n\n/* Selected field offsets in class structure */\n#define ISA              0\n#define SUPERCLASS       4\n#define CACHE            8\n#define CACHE_MASK      12\n\n/* Field offsets in method cache bucket */\n#define CACHED_SEL       0\n#define CACHED_IMP       4\n\n/* Selected field offsets in method structure */\n#define METHOD_NAME      0\n#define METHOD_TYPES     4\n#define METHOD_IMP       8\n\n\n//////////////////////////////////////////////////////////////////////\n//\n// ENTRY\t\tfunctionName\n//\n// Assembly directives to begin an exported function.\n//\n// Takes: functionName - name of the exported function\n//////////////////////////////////////////////////////////////////////\n\n.macro ENTRY /* name */\n\t.text\n\t.thumb\n\t.align 5\n\t.globl $0\n\t.thumb_func\n$0:\t\n.endmacro\n\n.macro STATIC_ENTRY /*name*/\n\t.text\n\t.thumb\n\t.align 5\n\t.private_extern $0\n\t.thumb_func\n$0:\t\n.endmacro\n\t\n\t\n//////////////////////////////////////////////////////////////////////\n//\n// END_ENTRY\tfunctionName\n//\n// Assembly directives to end an exported function.  Just a placeholder,\n// a close-parenthesis for ENTRY, until it is needed for something.\n//\n// Takes: functionName - name of the exported function\n//////////////////////////////////////////////////////////////////////\n\n.macro END_ENTRY /* name */\nLExit$0:\t\n.endmacro\n\n\n/////////////////////////////////////////////////////////////////////\n//\n// CacheLookup\tNORMAL|STRET\n// CacheLookup2\tNORMAL|STRET\n//\n// Locate the implementation for a selector in a class's method cache.\n//\n// Takes: \n//\t  $0 = NORMAL, STRET\n//\t  r0 or r1 (STRET) = receiver\n//\t  r1 or r2 (STRET) = selector\n//\t  r9 = class to search in\n//\n// On exit: r9 clobbered\n//\t    (found) continues after CacheLookup, IMP in r12, eq set\n//\t    (not found) continues after CacheLookup2\n//\n/////////////////////////////////////////////////////////////////////\n\t\n.macro CacheLookup\n\t\n\tldrh\tr12, [r9, #CACHE_MASK]\t// r12 = mask\n\tldr\tr9, [r9, #CACHE]\t// r9 = buckets\n.if $0 == STRET\n\tand\tr12, r12, r2\t\t// r12 = index = SEL & mask\n.else\n\tand\tr12, r12, r1\t\t// r12 = index = SEL & mask\n.endif\n\tadd\tr9, r9, r12, LSL #3\t// r9 = bucket = buckets+index*8\n\tldr\tr12, [r9, #CACHED_SEL]\t// r12 = bucket->sel\n6:\n.if $0 == STRET\n\tteq\tr12, r2\n.else\n\tteq\tr12, r1\n.endif\n\tbne\t8f\n\tldr\tr12, [r9, #CACHED_IMP]\t// r12 = bucket->imp\n\n.if $0 == STRET\n\ttst\tr12, r12\t\t// set ne for stret forwarding\n.else\n\t// eq already set for nonstret forwarding by `teq` above\n.endif\n\n.endmacro\n\n.macro CacheLookup2\n#if CACHED_SEL != 0\n#   error this code requires that SEL be at offset 0\n#endif\n8:\t\n\tcmp\tr12, #1\n\tblo\t8f\t\t\t// if (bucket->sel == 0) cache miss\n\tit\teq\t\t\t// if (bucket->sel == 1) cache wrap\n\tldreq\tr9, [r9, #CACHED_IMP]\t// bucket->imp is before first bucket\n\tldr\tr12, [r9, #8]!\t\t// r12 = (++bucket)->sel\n\tb\t6b\n8:\n\n.endmacro\n\n/////////////////////////////////////////////////////////////////////\n//\n// GetClassFromIsa\treturn-type\n//\n// Given an Isa, return the class for the Isa.\n//\n// Takes:\n//\t  r9 = class\n//\n// On exit: r12 clobbered\n//          r9 contains the class for this Isa.\n//\n/////////////////////////////////////////////////////////////////////\n.macro GetClassFromIsa\n\n#if SUPPORT_INDEXED_ISA\n\t// Note: We are doing a little wasted work here to load values we might not\n\t// need.  Branching turns out to be even worse when performance was measured.\n\tMI_GET_ADDRESS(r12, _objc_indexed_classes)\n\ttst.w\tr9, #ISA_INDEX_IS_NPI_MASK\n\titt\tne\n\tubfxne\tr9, r9, #ISA_INDEX_SHIFT, #ISA_INDEX_BITS\n\tldrne.w\tr9, [r12, r9, lsl #2]\n#endif\n\n.endmacro\n\n\n/********************************************************************\n * IMP cache_getImp(Class cls, SEL sel)\n *\n * On entry:    r0 = class whose cache is to be searched\n *              r1 = selector to search for\n *\n * If found, returns method implementation.\n * If not found, returns NULL.\n ********************************************************************/\n\n\tSTATIC_ENTRY _cache_getImp\n\n\tmov\tr9, r0\n\tCacheLookup NORMAL\n\t// cache hit, IMP in r12\n\tmov\tr0, r12\n\tbx\tlr\t\t\t// return imp\n\t\n\tCacheLookup2 GETIMP\n\t// cache miss, return nil\n\tmov\tr0, #0\n\tbx\tlr\n\n\tEND_ENTRY _cache_getImp\n\n\n/********************************************************************\n *\n * id objc_msgSend(id self, SEL _cmd, ...);\n * IMP objc_msgLookup(id self, SEL _cmd, ...);\n * \n * objc_msgLookup ABI:\n * IMP returned in r12\n * Forwarding returned in Z flag\n * r9 reserved for our use but not used\n *\n ********************************************************************/\n\n\tENTRY _objc_msgSend\n\t\n\tcbz\tr0, LNilReceiver_f\n\n\tldr\tr9, [r0]\t\t// r9 = self->isa\n\tGetClassFromIsa\t\t\t// r9 = class\n\tCacheLookup NORMAL\n\t// cache hit, IMP in r12, eq already set for nonstret forwarding\n\tbx\tr12\t\t\t// call imp\n\n\tCacheLookup2 NORMAL\n\t// cache miss\n\tldr\tr9, [r0]\t\t// r9 = self->isa\n\tGetClassFromIsa\t\t\t// r9 = class\n\tb\t__objc_msgSend_uncached\n\nLNilReceiver:\n\t// r0 is already zero\n\tmov\tr1, #0\n\tmov\tr2, #0\n\tmov\tr3, #0\n\tFP_RETURN_ZERO\n\tbx\tlr\t\n\n\tEND_ENTRY _objc_msgSend\n\n\t\n\tENTRY _objc_msgLookup\n\n\tcbz\tr0, LNilReceiver_f\n\n\tldr\tr9, [r0]\t\t// r9 = self->isa\n\tGetClassFromIsa\t\t\t// r9 = class\n\tCacheLookup NORMAL\n\t// cache hit, IMP in r12, eq already set for nonstret forwarding\n\tbx\tlr\n\n\tCacheLookup2 NORMAL\n\t// cache miss\n\tldr\tr9, [r0]\t\t// r9 = self->isa\n\tGetClassFromIsa\t\t\t// r9 = class\n\tb\t__objc_msgLookup_uncached\n\nLNilReceiver:\n\tMI_GET_ADDRESS(r12, __objc_msgNil)\n\tbx\tlr\n\n\tEND_ENTRY _objc_msgLookup\n\n\n\tSTATIC_ENTRY __objc_msgNil\n\t\n\t// r0 is already zero\n\tmov\tr1, #0\n\tmov\tr2, #0\n\tmov\tr3, #0\n\tFP_RETURN_ZERO\n\tbx\tlr\n\t\n\tEND_ENTRY __objc_msgNil\n\n\n/********************************************************************\n * void objc_msgSend_stret(void *st_addr, id self, SEL op, ...);\n * IMP objc_msgLookup_stret(void *st_addr, id self, SEL op, ...);\n *\n * objc_msgSend_stret is the struct-return form of msgSend.\n * The ABI calls for r0 to be used as the address of the structure\n * being returned, with the parameters in the succeeding registers.\n *\n * On entry: r0 is the address where the structure is returned,\n *           r1 is the message receiver,\n *           r2 is the selector\n ********************************************************************/\n\n\tENTRY _objc_msgSend_stret\n\t\n\tcbz\tr1, LNilReceiver_f\n\n\tldr\tr9, [r1]\t\t// r9 = self->isa\n\tGetClassFromIsa\t\t\t// r9 = class\n\tCacheLookup STRET\n\t// cache hit, IMP in r12, ne already set for stret forwarding\n\tbx\tr12\n\n\tCacheLookup2 STRET\n\t// cache miss\n\tldr\tr9, [r1]\t\t// r9 = self->isa\n\tGetClassFromIsa\t\t\t// r9 = class\n\tb\t__objc_msgSend_stret_uncached\n\nLNilReceiver:\n\tbx\tlr\n\t\n\tEND_ENTRY _objc_msgSend_stret\n\n\n\tENTRY _objc_msgLookup_stret\n\t\n\tcbz\tr1, LNilReceiver_f\n\n\tldr\tr9, [r1]\t\t// r9 = self->isa\n\tGetClassFromIsa\t\t\t// r9 = class\n\tCacheLookup STRET\n\t// cache hit, IMP in r12, ne already set for stret forwarding\n\tbx\tlr\n\n\tCacheLookup2 STRET\n\t// cache miss\n\tldr\tr9, [r1]\t\t// r9 = self->isa\n\tGetClassFromIsa\t\t\t// r9 = class\n\tb\t__objc_msgLookup_stret_uncached\n\nLNilReceiver:\n\tMI_GET_ADDRESS(r12, __objc_msgNil_stret)\n\tbx\tlr\n\n\tEND_ENTRY _objc_msgLookup_stret\n\n\n\tSTATIC_ENTRY __objc_msgNil_stret\n\t\n\tbx\tlr\n\n\tEND_ENTRY __objc_msgNil_stret\n\n\n/********************************************************************\n * id objc_msgSendSuper(struct objc_super *super, SEL op, ...)\n *\n * struct objc_super {\n *     id receiver;\n *     Class cls;\t// the class to search\n * }\n ********************************************************************/\n\n\tENTRY _objc_msgSendSuper\n\t\n\tldr\tr9, [r0, #CLASS]\t// r9 = struct super->class\n\tCacheLookup NORMAL\n\t// cache hit, IMP in r12, eq already set for nonstret forwarding\n\tldr\tr0, [r0, #RECEIVER]\t// load real receiver\n\tbx\tr12\t\t\t// call imp\n\n\tCacheLookup2 NORMAL\n\t// cache miss\n\tldr\tr9, [r0, #CLASS]\t// r9 = struct super->class\n\tldr\tr0, [r0, #RECEIVER]\t// load real receiver\n\tb\t__objc_msgSend_uncached\n\t\n\tEND_ENTRY _objc_msgSendSuper\n\n\n/********************************************************************\n * id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)\n *\n * struct objc_super {\n *     id receiver;\n *     Class cls;\t// SUBCLASS of the class to search\n * }\n ********************************************************************/\n\t\n\tENTRY _objc_msgSendSuper2\n\t\n\tldr\tr9, [r0, #CLASS]\t// class = struct super->class\n\tldr\tr9, [r9, #SUPERCLASS]   // class = class->superclass\n\tCacheLookup NORMAL\n\t// cache hit, IMP in r12, eq already set for nonstret forwarding\n\tldr\tr0, [r0, #RECEIVER]\t// load real receiver\n\tbx\tr12\t\t\t// call imp\n\n\tCacheLookup2 NORMAL\n\t// cache miss\n\tldr\tr9, [r0, #CLASS]\t// class = struct super->class\n\tldr\tr9, [r9, #SUPERCLASS]   // class = class->superclass\n\tldr\tr0, [r0, #RECEIVER]\t// load real receiver\n\tb\t__objc_msgSend_uncached\n\t\n\tEND_ENTRY _objc_msgSendSuper2\n\n\t\n\tENTRY _objc_msgLookupSuper2\n\t\n\tldr\tr9, [r0, #CLASS]\t// class = struct super->class\n\tldr\tr9, [r9, #SUPERCLASS]   // class = class->superclass\n\tCacheLookup NORMAL\n\t// cache hit, IMP in r12, eq already set for nonstret forwarding\n\tldr\tr0, [r0, #RECEIVER]\t// load real receiver\n\tbx\tlr\n\n\tCacheLookup2 NORMAL\n\t// cache miss\n\tldr\tr9, [r0, #CLASS]\n\tldr\tr9, [r9, #SUPERCLASS]\t// r9 = class to search\n\tldr\tr0, [r0, #RECEIVER]\t// load real receiver\n\tb\t__objc_msgLookup_uncached\n\t\n\tEND_ENTRY _objc_msgLookupSuper2\n\n\n/********************************************************************\n * void objc_msgSendSuper_stret(void *st_addr, objc_super *self, SEL op, ...);\n *\n * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.\n * The ABI calls for r0 to be used as the address of the structure\n * being returned, with the parameters in the succeeding registers.\n *\n * On entry: r0 is the address where the structure is returned,\n *           r1 is the address of the objc_super structure,\n *           r2 is the selector\n ********************************************************************/\n\n\tENTRY _objc_msgSendSuper_stret\n\t\n\tldr\tr9, [r1, #CLASS]\t// r9 = struct super->class\n\tCacheLookup STRET\n\t// cache hit, IMP in r12, ne already set for stret forwarding\n\tldr\tr1, [r1, #RECEIVER]\t// load real receiver\n\tbx\tr12\t\t\t// call imp\n\n\tCacheLookup2 STRET\n\t// cache miss\n\tldr\tr9, [r1, #CLASS]\t// r9 = struct super->class\n\tldr\tr1, [r1, #RECEIVER]\t// load real receiver\n\tb\t__objc_msgSend_stret_uncached\n\n\tEND_ENTRY _objc_msgSendSuper_stret\n\n\n/********************************************************************\n * id objc_msgSendSuper2_stret\n ********************************************************************/\n\n\tENTRY _objc_msgSendSuper2_stret\n\t\n\tldr\tr9, [r1, #CLASS]\t// class = struct super->class\n\tldr\tr9, [r9, #SUPERCLASS]\t// class = class->superclass\n\tCacheLookup STRET\n\t// cache hit, IMP in r12, ne already set for stret forwarding\n\tldr\tr1, [r1, #RECEIVER]\t// load real receiver\n\tbx\tr12\t\t\t// call imp\n\n\tCacheLookup2 STRET\n\t// cache miss\n\tldr\tr9, [r1, #CLASS]\t// class = struct super->class\n\tldr\tr9, [r9, #SUPERCLASS]\t// class = class->superclass\n\tldr\tr1, [r1, #RECEIVER]\t// load real receiver\n\tb\t__objc_msgSend_stret_uncached\n\t\n\tEND_ENTRY _objc_msgSendSuper2_stret\n\n\t\n\tENTRY _objc_msgLookupSuper2_stret\n\t\n\tldr\tr9, [r1, #CLASS]\t// class = struct super->class\n\tldr\tr9, [r9, #SUPERCLASS]\t// class = class->superclass\n\tCacheLookup STRET\n\t// cache hit, IMP in r12, ne already set for stret forwarding\n\tldr\tr1, [r1, #RECEIVER]\t// load real receiver\n\tbx\tlr\n\n\tCacheLookup2 STRET\n\t// cache miss\n\tldr\tr9, [r1, #CLASS]\n\tldr\tr9, [r9, #SUPERCLASS]\t// r9 = class to search\n\tldr\tr1, [r1, #RECEIVER]\t// load real receiver\n\tb\t__objc_msgLookup_stret_uncached\n\t\n\tEND_ENTRY _objc_msgLookupSuper2_stret\n\n\t\n/////////////////////////////////////////////////////////////////////\n//\n// MethodTableLookup\tNORMAL|STRET\n//\n// Locate the implementation for a selector in a class's method lists.\n//\n// Takes: \n//\t  $0 = NORMAL, STRET\n//\t  r0 or r1 (STRET) = receiver\n//\t  r1 or r2 (STRET) = selector\n//\t  r9 = class to search in\n//\n// On exit: IMP in r12, eq/ne set for forwarding\n//\n/////////////////////////////////////////////////////////////////////\n\t\n.macro MethodTableLookup\n\t\n\tstmfd\tsp!, {r0-r3,r7,lr}\n\tadd\tr7, sp, #16\n\tsub\tsp, #8\t\t\t// align stack\n\tFP_SAVE\n\n.if $0 == NORMAL\n\t// receiver already in r0\n\t// selector already in r1\n.else\n\tmov \tr0, r1\t\t\t// receiver\n\tmov \tr1, r2\t\t\t// selector\n.endif\n\tmov\tr2, r9\t\t\t// class to search\n\n\tblx\t__class_lookupMethodAndLoadCache3\n\tmov\tr12, r0\t\t\t// r12 = IMP\n\t\n.if $0 == NORMAL\n\tcmp\tr12, r12\t\t// set eq for nonstret forwarding\n.else\n\ttst\tr12, r12\t\t// set ne for stret forwarding\n.endif\n\n\tFP_RESTORE\n\tadd\tsp, #8\t\t\t// align stack\n\tldmfd\tsp!, {r0-r3,r7,lr}\n\n.endmacro\n\n\n/********************************************************************\n *\n * _objc_msgSend_uncached\n * _objc_msgSend_stret_uncached\n * _objc_msgLookup_uncached\n * _objc_msgLookup_stret_uncached\n * The uncached method lookup.\n *\n ********************************************************************/\n\n\tSTATIC_ENTRY __objc_msgSend_uncached\n\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band r9 is the class to search\n\t\n\tMethodTableLookup NORMAL\t// returns IMP in r12\n\tbx\tr12\n\n\tEND_ENTRY __objc_msgSend_uncached\n\n\n\tSTATIC_ENTRY __objc_msgSend_stret_uncached\n\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band r9 is the class to search\n\n\tMethodTableLookup STRET\t\t// returns IMP in r12\n\tbx\tr12\n\t\n\tEND_ENTRY __objc_msgSend_stret_uncached\n\n\t\n\tSTATIC_ENTRY __objc_msgLookup_uncached\n\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band r9 is the class to search\n\t\n\tMethodTableLookup NORMAL\t// returns IMP in r12\n\tbx\tlr\n\n\tEND_ENTRY __objc_msgLookup_uncached\n\n\n\tSTATIC_ENTRY __objc_msgLookup_stret_uncached\n\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band r9 is the class to search\n\n\tMethodTableLookup STRET\t\t// returns IMP in r12\n\tbx\tlr\n\t\n\tEND_ENTRY __objc_msgLookup_stret_uncached\n\n\t\n/********************************************************************\n*\n* id _objc_msgForward(id self, SEL _cmd,...);\n*\n* _objc_msgForward and _objc_msgForward_stret are the externally-callable\n*   functions returned by things like method_getImplementation().\n* _objc_msgForward_impcache is the function pointer actually stored in\n*   method caches.\n*\n********************************************************************/\n\n\tMI_EXTERN(__objc_forward_handler)\n\tMI_EXTERN(__objc_forward_stret_handler)\n\t\n\tSTATIC_ENTRY __objc_msgForward_impcache\n\t// Method cache version\n\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band Z is 0 (EQ) for normal, 1 (NE) for stret\n\n\tbeq\t__objc_msgForward\n\tb\t__objc_msgForward_stret\n\t\n\tEND_ENTRY __objc_msgForward_impcache\n\t\n\n\tENTRY __objc_msgForward\n\t// Non-stret version\n\n\tMI_GET_EXTERN(r12, __objc_forward_handler)\n\tldr\tr12, [r12]\n\tbx\tr12\n\n\tEND_ENTRY __objc_msgForward\n\n\n\tENTRY __objc_msgForward_stret\n\t// Struct-return version\n\n\tMI_GET_EXTERN(r12, __objc_forward_stret_handler)\n\tldr\tr12, [r12]\n\tbx\tr12\n\n\tEND_ENTRY __objc_msgForward_stret\n\n\n\tENTRY _objc_msgSend_noarg\n\tb \t_objc_msgSend\n\tEND_ENTRY _objc_msgSend_noarg\n\n\tENTRY _objc_msgSend_debug\n\tb\t_objc_msgSend\n\tEND_ENTRY _objc_msgSend_debug\n\n\tENTRY _objc_msgSendSuper2_debug\n\tb\t_objc_msgSendSuper2\n\tEND_ENTRY _objc_msgSendSuper2_debug\n\n\tENTRY _objc_msgSend_stret_debug\n\tb\t_objc_msgSend_stret\n\tEND_ENTRY _objc_msgSend_stret_debug\n\n\tENTRY _objc_msgSendSuper2_stret_debug\n\tb\t_objc_msgSendSuper2_stret\n\tEND_ENTRY _objc_msgSendSuper2_stret_debug\n\n\n\tENTRY _method_invoke\n\t// r1 is method triplet instead of SEL\n\tldr\tr12, [r1, #METHOD_IMP]\n\tldr\tr1, [r1, #METHOD_NAME]\n\tbx\tr12\n\tEND_ENTRY _method_invoke\n\n\n\tENTRY _method_invoke_stret\n\t// r2 is method triplet instead of SEL\n\tldr\tr12, [r2, #METHOD_IMP]\n\tldr\tr2, [r2, #METHOD_NAME]\n\tbx\tr12\n\tEND_ENTRY _method_invoke_stret\n\t\n\n.section __DATA,__objc_msg_break\n.long 0\n.long 0\n\t\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/Messengers.subproj/objc-msg-arm64.s",
    "content": "/*\n * @APPLE_LICENSE_HEADER_START@\n * \n * Copyright (c) 2011 Apple Inc.  All Rights Reserved.\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/********************************************************************\n * \n *  objc-msg-arm64.s - ARM64 code to support objc messaging\n *\n ********************************************************************/\n\n#ifdef __arm64__\n\n#include <arm/arch.h>\n#include \"isa.h\"\n#include \"arm64-asm.h\"\n\n.data\n\n// _objc_entryPoints and _objc_exitPoints are used by method dispatch\n// caching code to figure out whether any threads are actively \n// in the cache for dispatching.  The labels surround the asm code\n// that do cache lookups.  The tables are zero-terminated.\n\n.align 4\n.private_extern _objc_entryPoints\n_objc_entryPoints:\n\tPTR   _cache_getImp\n\tPTR   _objc_msgSend\n\tPTR   _objc_msgSendSuper\n\tPTR   _objc_msgSendSuper2\n\tPTR   _objc_msgLookup\n\tPTR   _objc_msgLookupSuper2\n\tPTR   0\n\n.private_extern _objc_exitPoints\n_objc_exitPoints:\n\tPTR   LExit_cache_getImp\n\tPTR   LExit_objc_msgSend\n\tPTR   LExit_objc_msgSendSuper\n\tPTR   LExit_objc_msgSendSuper2\n\tPTR   LExit_objc_msgLookup\n\tPTR   LExit_objc_msgLookupSuper2\n\tPTR   0\n\n\n/* objc_super parameter to sendSuper */\n#define RECEIVER         0\n#define CLASS            __SIZEOF_POINTER__\n\n/* Selected field offsets in class structure */\n#define SUPERCLASS       __SIZEOF_POINTER__\n#define CACHE            (2 * __SIZEOF_POINTER__)\n\n/* Selected field offsets in method structure */\n#define METHOD_NAME      0\n#define METHOD_TYPES     __SIZEOF_POINTER__\n#define METHOD_IMP       (2 * __SIZEOF_POINTER__)\n\n#define BUCKET_SIZE      (2 * __SIZEOF_POINTER__)\n\n\n/********************************************************************\n * GetClassFromIsa_p16 src\n * src is a raw isa field. Sets p16 to the corresponding class pointer.\n * The raw isa might be an indexed isa to be decoded, or a\n * packed isa that needs to be masked.\n *\n * On exit:\n *   $0 is unchanged\n *   p16 is a class pointer\n *   x10 is clobbered\n ********************************************************************/\n\n#if SUPPORT_INDEXED_ISA\n\t.align 3\n\t.globl _objc_indexed_classes\n_objc_indexed_classes:\n\t.fill ISA_INDEX_COUNT, PTRSIZE, 0\n#endif\n\n.macro GetClassFromIsa_p16 /* src */\n\n#if SUPPORT_INDEXED_ISA\n\t// Indexed isa\n\tmov\tp16, $0\t\t\t// optimistically set dst = src\n\ttbz\tp16, #ISA_INDEX_IS_NPI_BIT, 1f\t// done if not non-pointer isa\n\t// isa in p16 is indexed\n\tadrp\tx10, _objc_indexed_classes@PAGE\n\tadd\tx10, x10, _objc_indexed_classes@PAGEOFF\n\tubfx\tp16, p16, #ISA_INDEX_SHIFT, #ISA_INDEX_BITS  // extract index\n\tldr\tp16, [x10, p16, UXTP #PTRSHIFT]\t// load class from array\n1:\n\n#elif __LP64__\n\t// 64-bit packed isa\n\tand\tp16, $0, #ISA_MASK\n\n#else\n\t// 32-bit raw isa\n\tmov\tp16, $0\n\n#endif\n\n.endmacro\n\n\n/********************************************************************\n * ENTRY functionName\n * STATIC_ENTRY functionName\n * END_ENTRY functionName\n ********************************************************************/\n\n.macro ENTRY /* name */\n\t.text\n\t.align 5\n\t.globl    $0\n$0:\n.endmacro\n\n.macro STATIC_ENTRY /*name*/\n\t.text\n\t.align 5\n\t.private_extern $0\n$0:\n.endmacro\n\n.macro END_ENTRY /* name */\nLExit$0:\n.endmacro\n\n\n/********************************************************************\n * UNWIND name, flags\n * Unwind info generation\t\n ********************************************************************/\n.macro UNWIND\n\t.section __LD,__compact_unwind,regular,debug\n\tPTR $0\n\t.set  LUnwind$0, LExit$0 - $0\n\t.long LUnwind$0\n\t.long $1\n\tPTR 0\t /* no personality */\n\tPTR 0  /* no LSDA */\n\t.text\n.endmacro\n\n#define NoFrame 0x02000000  // no frame, no SP adjustment\n#define FrameWithNoSaves 0x04000000  // frame, no non-volatile saves\n\n\n/********************************************************************\n *\n * CacheLookup NORMAL|GETIMP|LOOKUP\n * \n * Locate the implementation for a selector in a class method cache.\n *\n * Takes:\n *\t x1 = selector\n *\t x16 = class to be searched\n *\n * Kills:\n * \t x9,x10,x11,x12, x17\n *\n * On exit: (found) calls or returns IMP\n *                  with x16 = class, x17 = IMP\n *          (not found) jumps to LCacheMiss\n *\n ********************************************************************/\n\n#define NORMAL 0\n#define GETIMP 1\n#define LOOKUP 2\n\n// CacheHit: x17 = cached IMP, x12 = address of cached IMP\n.macro CacheHit\n.if $0 == NORMAL\n\tTailCallCachedImp x17, x12\t// authenticate and call imp\n.elseif $0 == GETIMP\n\tmov\tp0, p17\n\tAuthAndResignAsIMP x0, x12\t// authenticate imp and re-sign as IMP\n\tret\t\t\t\t// return IMP\n.elseif $0 == LOOKUP\n\tAuthAndResignAsIMP x17, x12\t// authenticate imp and re-sign as IMP\n\tret\t\t\t\t// return imp via x17\n.else\n.abort oops\n.endif\n.endmacro\n\n.macro CheckMiss\n\t// miss if bucket->sel == 0\n.if $0 == GETIMP\n\tcbz\tp9, LGetImpMiss\n.elseif $0 == NORMAL\n\tcbz\tp9, __objc_msgSend_uncached\n.elseif $0 == LOOKUP\n\tcbz\tp9, __objc_msgLookup_uncached\n.else\n.abort oops\n.endif\n.endmacro\n\n.macro JumpMiss\n.if $0 == GETIMP\n\tb\tLGetImpMiss\n.elseif $0 == NORMAL\n\tb\t__objc_msgSend_uncached\n.elseif $0 == LOOKUP\n\tb\t__objc_msgLookup_uncached\n.else\n.abort oops\n.endif\n.endmacro\n\n.macro CacheLookup\n\t// p1 = SEL, p16 = isa\n\tldp\tp10, p11, [x16, #CACHE]\t// p10 = buckets, p11 = occupied|mask\n#if !__LP64__\n\tand\tw11, w11, 0xffff\t// p11 = mask\n#endif\n\tand\tw12, w1, w11\t\t// x12 = _cmd & mask\n\tadd\tp12, p10, p12, LSL #(1+PTRSHIFT)\n\t\t             // p12 = buckets + ((_cmd & mask) << (1+PTRSHIFT))\n\n\tldp\tp17, p9, [x12]\t\t// {imp, sel} = *bucket\n1:\tcmp\tp9, p1\t\t\t// if (bucket->sel != _cmd)\n\tb.ne\t2f\t\t\t//     scan more\n\tCacheHit $0\t\t\t// call or return imp\n\t\n2:\t// not hit: p12 = not-hit bucket\n\tCheckMiss $0\t\t\t// miss if bucket->sel == 0\n\tcmp\tp12, p10\t\t// wrap if bucket == buckets\n\tb.eq\t3f\n\tldp\tp17, p9, [x12, #-BUCKET_SIZE]!\t// {imp, sel} = *--bucket\n\tb\t1b\t\t\t// loop\n\n3:\t// wrap: p12 = first bucket, w11 = mask\n\tadd\tp12, p12, w11, UXTW #(1+PTRSHIFT)\n\t\t                        // p12 = buckets + (mask << 1+PTRSHIFT)\n\n\t// Clone scanning loop to miss instead of hang when cache is corrupt.\n\t// The slow path may detect any corruption and halt later.\n\n\tldp\tp17, p9, [x12]\t\t// {imp, sel} = *bucket\n1:\tcmp\tp9, p1\t\t\t// if (bucket->sel != _cmd)\n\tb.ne\t2f\t\t\t//     scan more\n\tCacheHit $0\t\t\t// call or return imp\n\t\n2:\t// not hit: p12 = not-hit bucket\n\tCheckMiss $0\t\t\t// miss if bucket->sel == 0\n\tcmp\tp12, p10\t\t// wrap if bucket == buckets\n\tb.eq\t3f\n\tldp\tp17, p9, [x12, #-BUCKET_SIZE]!\t// {imp, sel} = *--bucket\n\tb\t1b\t\t\t// loop\n\n3:\t// double wrap\n\tJumpMiss $0\n\t\n.endmacro\n\n\n/********************************************************************\n *\n * id objc_msgSend(id self, SEL _cmd, ...);\n * IMP objc_msgLookup(id self, SEL _cmd, ...);\n * \n * objc_msgLookup ABI:\n * IMP returned in x17\n * x16 reserved for our use but not used\n *\n ********************************************************************/\n\n#if SUPPORT_TAGGED_POINTERS\n\t.data\n\t.align 3\n\t.globl _objc_debug_taggedpointer_classes\n_objc_debug_taggedpointer_classes:\n\t.fill 16, 8, 0\n\t.globl _objc_debug_taggedpointer_ext_classes\n_objc_debug_taggedpointer_ext_classes:\n\t.fill 256, 8, 0\n#endif\n\n\tENTRY _objc_msgSend\n\tUNWIND _objc_msgSend, NoFrame\n\n\tcmp\tp0, #0\t\t\t// nil check and tagged pointer check\n#if SUPPORT_TAGGED_POINTERS\n\tb.le\tLNilOrTagged\t\t//  (MSB tagged pointer looks negative)\n#else\n\tb.eq\tLReturnZero\n#endif\n\tldr\tp13, [x0]\t\t// p13 = isa\n\tGetClassFromIsa_p16 p13\t\t// p16 = class\nLGetIsaDone:\n\tCacheLookup NORMAL\t\t// calls imp or objc_msgSend_uncached\n\n#if SUPPORT_TAGGED_POINTERS\nLNilOrTagged:\n\tb.eq\tLReturnZero\t\t// nil check\n\n\t// tagged\n\tadrp\tx10, _objc_debug_taggedpointer_classes@PAGE\n\tadd\tx10, x10, _objc_debug_taggedpointer_classes@PAGEOFF\n\tubfx\tx11, x0, #60, #4\n\tldr\tx16, [x10, x11, LSL #3]\n\tadrp\tx10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGE\n\tadd\tx10, x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGEOFF\n\tcmp\tx10, x16\n\tb.ne\tLGetIsaDone\n\n\t// ext tagged\n\tadrp\tx10, _objc_debug_taggedpointer_ext_classes@PAGE\n\tadd\tx10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF\n\tubfx\tx11, x0, #52, #8\n\tldr\tx16, [x10, x11, LSL #3]\n\tb\tLGetIsaDone\n// SUPPORT_TAGGED_POINTERS\n#endif\n\nLReturnZero:\n\t// x0 is already zero\n\tmov\tx1, #0\n\tmovi\td0, #0\n\tmovi\td1, #0\n\tmovi\td2, #0\n\tmovi\td3, #0\n\tret\n\n\tEND_ENTRY _objc_msgSend\n\n\n\tENTRY _objc_msgLookup\n\tUNWIND _objc_msgLookup, NoFrame\n\tcmp\tp0, #0\t\t\t// nil check and tagged pointer check\n#if SUPPORT_TAGGED_POINTERS\n\tb.le\tLLookup_NilOrTagged\t//  (MSB tagged pointer looks negative)\n#else\n\tb.eq\tLLookup_Nil\n#endif\n\tldr\tp13, [x0]\t\t// p13 = isa\n\tGetClassFromIsa_p16 p13\t\t// p16 = class\nLLookup_GetIsaDone:\n\tCacheLookup LOOKUP\t\t// returns imp\n\n#if SUPPORT_TAGGED_POINTERS\nLLookup_NilOrTagged:\n\tb.eq\tLLookup_Nil\t// nil check\n\n\t// tagged\n\tmov\tx10, #0xf000000000000000\n\tcmp\tx0, x10\n\tb.hs\tLLookup_ExtTag\n\tadrp\tx10, _objc_debug_taggedpointer_classes@PAGE\n\tadd\tx10, x10, _objc_debug_taggedpointer_classes@PAGEOFF\n\tubfx\tx11, x0, #60, #4\n\tldr\tx16, [x10, x11, LSL #3]\n\tb\tLLookup_GetIsaDone\n\nLLookup_ExtTag:\t\n\tadrp\tx10, _objc_debug_taggedpointer_ext_classes@PAGE\n\tadd\tx10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF\n\tubfx\tx11, x0, #52, #8\n\tldr\tx16, [x10, x11, LSL #3]\n\tb\tLLookup_GetIsaDone\n// SUPPORT_TAGGED_POINTERS\n#endif\n\nLLookup_Nil:\n\tadrp\tx17, __objc_msgNil@PAGE\n\tadd\tx17, x17, __objc_msgNil@PAGEOFF\n\tret\n\n\tEND_ENTRY _objc_msgLookup\n\n\t\n\tSTATIC_ENTRY __objc_msgNil\n\n\t// x0 is already zero\n\tmov\tx1, #0\n\tmovi\td0, #0\n\tmovi\td1, #0\n\tmovi\td2, #0\n\tmovi\td3, #0\n\tret\n\t\n\tEND_ENTRY __objc_msgNil\n\n\n\tENTRY _objc_msgSendSuper\n\tUNWIND _objc_msgSendSuper, NoFrame\n\n\tldp\tp0, p16, [x0]\t\t// p0 = real receiver, p16 = class\n\tCacheLookup NORMAL\t\t// calls imp or objc_msgSend_uncached\n\n\tEND_ENTRY _objc_msgSendSuper\n\n\t// no _objc_msgLookupSuper\n\n\tENTRY _objc_msgSendSuper2\n\tUNWIND _objc_msgSendSuper2, NoFrame\n\n\tldp\tp0, p16, [x0]\t\t// p0 = real receiver, p16 = class\n\tldr\tp16, [x16, #SUPERCLASS]\t// p16 = class->superclass\n\tCacheLookup NORMAL\n\n\tEND_ENTRY _objc_msgSendSuper2\n\n\t\n\tENTRY _objc_msgLookupSuper2\n\tUNWIND _objc_msgLookupSuper2, NoFrame\n\n\tldp\tp0, p16, [x0]\t\t// p0 = real receiver, p16 = class\n\tldr\tp16, [x16, #SUPERCLASS]\t// p16 = class->superclass\n\tCacheLookup LOOKUP\n\n\tEND_ENTRY _objc_msgLookupSuper2\n\n\n.macro MethodTableLookup\n\t\n\t// push frame\n\tSignLR\n\tstp\tfp, lr, [sp, #-16]!\n\tmov\tfp, sp\n\n\t// save parameter registers: x0..x8, q0..q7\n\tsub\tsp, sp, #(10*8 + 8*16)\n\tstp\tq0, q1, [sp, #(0*16)]\n\tstp\tq2, q3, [sp, #(2*16)]\n\tstp\tq4, q5, [sp, #(4*16)]\n\tstp\tq6, q7, [sp, #(6*16)]\n\tstp\tx0, x1, [sp, #(8*16+0*8)]\n\tstp\tx2, x3, [sp, #(8*16+2*8)]\n\tstp\tx4, x5, [sp, #(8*16+4*8)]\n\tstp\tx6, x7, [sp, #(8*16+6*8)]\n\tstr\tx8,     [sp, #(8*16+8*8)]\n\n\t// receiver and selector already in x0 and x1\n\tmov\tx2, x16\n\tbl\t__class_lookupMethodAndLoadCache3\n\n\t// IMP in x0\n\tmov\tx17, x0\n\t\n\t// restore registers and return\n\tldp\tq0, q1, [sp, #(0*16)]\n\tldp\tq2, q3, [sp, #(2*16)]\n\tldp\tq4, q5, [sp, #(4*16)]\n\tldp\tq6, q7, [sp, #(6*16)]\n\tldp\tx0, x1, [sp, #(8*16+0*8)]\n\tldp\tx2, x3, [sp, #(8*16+2*8)]\n\tldp\tx4, x5, [sp, #(8*16+4*8)]\n\tldp\tx6, x7, [sp, #(8*16+6*8)]\n\tldr\tx8,     [sp, #(8*16+8*8)]\n\n\tmov\tsp, fp\n\tldp\tfp, lr, [sp], #16\n\tAuthenticateLR\n\n.endmacro\n\n\tSTATIC_ENTRY __objc_msgSend_uncached\n\tUNWIND __objc_msgSend_uncached, FrameWithNoSaves\n\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band p16 is the class to search\n\t\n\tMethodTableLookup\n\tTailCallFunctionPointer x17\n\n\tEND_ENTRY __objc_msgSend_uncached\n\n\n\tSTATIC_ENTRY __objc_msgLookup_uncached\n\tUNWIND __objc_msgLookup_uncached, FrameWithNoSaves\n\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band p16 is the class to search\n\t\n\tMethodTableLookup\n\tret\n\n\tEND_ENTRY __objc_msgLookup_uncached\n\n\n\tSTATIC_ENTRY _cache_getImp\n\n\tGetClassFromIsa_p16 p0\n\tCacheLookup GETIMP\n\nLGetImpMiss:\n\tmov\tp0, #0\n\tret\n\n\tEND_ENTRY _cache_getImp\n\n\n/********************************************************************\n*\n* id _objc_msgForward(id self, SEL _cmd,...);\n*\n* _objc_msgForward is the externally-callable\n*   function returned by things like method_getImplementation().\n* _objc_msgForward_impcache is the function pointer actually stored in\n*   method caches.\n*\n********************************************************************/\n\n\tSTATIC_ENTRY __objc_msgForward_impcache\n\n\t// No stret specialization.\n\tb\t__objc_msgForward\n\n\tEND_ENTRY __objc_msgForward_impcache\n\n\t\n\tENTRY __objc_msgForward\n\n\tadrp\tx17, __objc_forward_handler@PAGE\n\tldr\tp17, [x17, __objc_forward_handler@PAGEOFF]\n\tTailCallFunctionPointer x17\n\t\n\tEND_ENTRY __objc_msgForward\n\t\n\t\n\tENTRY _objc_msgSend_noarg\n\tb\t_objc_msgSend\n\tEND_ENTRY _objc_msgSend_noarg\n\n\tENTRY _objc_msgSend_debug\n\tb\t_objc_msgSend\n\tEND_ENTRY _objc_msgSend_debug\n\n\tENTRY _objc_msgSendSuper2_debug\n\tb\t_objc_msgSendSuper2\n\tEND_ENTRY _objc_msgSendSuper2_debug\n\n\t\n\tENTRY _method_invoke\n\t// x1 is method triplet instead of SEL\n\tadd\tp16, p1, #METHOD_IMP\n\tldr\tp17, [x16]\n\tldr\tp1, [x1, #METHOD_NAME]\n\tTailCallMethodListImp x17, x16\n\tEND_ENTRY _method_invoke\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/Messengers.subproj/objc-msg-i386.s",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include <TargetConditionals.h>\n#if defined(__i386__)  &&  !TARGET_OS_SIMULATOR\n\n/********************************************************************\n ********************************************************************\n **\n **  objc-msg-i386.s - i386 code to support objc messaging.\n **\n ********************************************************************\n ********************************************************************/\n\n\n/********************************************************************\n* Data used by the ObjC runtime.\n*\n********************************************************************/\n\n.data\n\n// _objc_entryPoints and _objc_exitPoints are used by objc\n// to get the critical regions for which method caches \n// cannot be garbage collected.\n\n.align 2\n.private_extern _objc_entryPoints\n_objc_entryPoints:\n\t.long\t__cache_getImp\n\t.long\t__cache_getMethod\n\t.long\t_objc_msgSend\n\t.long\t_objc_msgSend_fpret\n\t.long\t_objc_msgSend_stret\n\t.long\t_objc_msgSendSuper\n\t.long\t_objc_msgSendSuper_stret\n\t.long\t0\n\n.private_extern _objc_exitPoints\n_objc_exitPoints:\n\t.long\tLGetImpExit\n\t.long\tLGetMethodExit\n\t.long\tLMsgSendExit\n\t.long\tLMsgSendFpretExit\n\t.long\tLMsgSendStretExit\n\t.long\tLMsgSendSuperExit\n\t.long\tLMsgSendSuperStretExit\n\t.long\t0\n\n\n/********************************************************************\n *\n * Common offsets.\n *\n ********************************************************************/\n\n\tself            = 4\n\tsuper           = 4\n\tselector        = 8\n\tmarg_size       = 12\n\tmarg_list       = 16\n\tfirst_arg       = 12\n\n\tstruct_addr     = 4\n\n\tself_stret      = 8\n\tsuper_stret     = 8\n\tselector_stret  = 12\n\tmarg_size_stret = 16\n\tmarg_list_stret = 20\n\n\n/********************************************************************\n *\n * Structure definitions.\n *\n ********************************************************************/\n\n// objc_super parameter to sendSuper\n\treceiver        = 0\n\tclass           = 4\n\n// Selected field offsets in class structure\n\tisa             = 0\n\tcache           = 32\n\n// Method descriptor\n\tmethod_name     = 0\n\tmethod_imp      = 8\n\n// Cache header\n\tmask            = 0\n\toccupied        = 4\n\tbuckets         = 8\t\t// variable length array\n\n#if defined(OBJC_INSTRUMENTED)\n// Cache instrumentation data, follows buckets\n\thitCount        = 0\n\thitProbes       = hitCount + 4\n\tmaxHitProbes    = hitProbes + 4\n\tmissCount       = maxHitProbes + 4\n\tmissProbes      = missCount + 4\n\tmaxMissProbes   = missProbes + 4\n\tflushCount      = maxMissProbes + 4\n\tflushedEntries  = flushCount + 4\n\n// Buckets in CacheHitHistogram and CacheMissHistogram\n\tCACHE_HISTOGRAM_SIZE = 512\n#endif\n\n\n//////////////////////////////////////////////////////////////////////\n//\n// ENTRY\t\tfunctionName\n//\n// Assembly directives to begin an exported function.\n//\n// Takes: functionName - name of the exported function\n//////////////////////////////////////////////////////////////////////\n\n.macro ENTRY\n\t.text\n\t.globl\t$0\n\t.align\t4, 0x90\n$0:\n.endmacro\n\n.macro STATIC_ENTRY\n\t.text\n\t.private_extern\t$0\n\t.align\t4, 0x90\n$0:\n.endmacro\n\n//////////////////////////////////////////////////////////////////////\n//\n// END_ENTRY\tfunctionName\n//\n// Assembly directives to end an exported function.  Just a placeholder,\n// a close-parenthesis for ENTRY, until it is needed for something.\n//\n// Takes: functionName - name of the exported function\n//////////////////////////////////////////////////////////////////////\n\n.macro END_ENTRY\n.endmacro\n\n//////////////////////////////////////////////////////////////////////\n//\n// CALL_MCOUNTER\n//\n// Calls mcount() profiling routine. Must be called immediately on\n// function entry, before any prologue executes.\n//\n//////////////////////////////////////////////////////////////////////\n\n.macro CALL_MCOUNTER\n#ifdef PROFILE\n\t// Current stack contents: ret\n\tpushl\t%ebp\n\tmovl\t%esp,%ebp\n\tsubl\t$$8,%esp\n\t// Current stack contents: ret, ebp, pad, pad\n\tcall\tmcount\n\tmovl\t%ebp,%esp\n\tpopl\t%ebp\n#endif\n.endmacro\n\n\n/////////////////////////////////////////////////////////////////////\n//\n//\n// CacheLookup\tWORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER | CACHE_GET, cacheMissLabel\n//\n// Locate the implementation for a selector in a class method cache.\n//\n// Takes: WORD_RETURN\t(first parameter is at sp+4)\n//        STRUCT_RETURN\t(struct address is at sp+4, first parameter at sp+8)\n//        MSG_SEND\t(first parameter is receiver)\n//        MSG_SENDSUPER\t(first parameter is address of objc_super structure)\n//        CACHE_GET\t(first parameter is class; return method triplet)\n//        selector in %ecx\n//        class to search in %edx\n//\n//\t  cacheMissLabel = label to branch to iff method is not cached\n//\n// On exit: (found) MSG_SEND and MSG_SENDSUPER: return imp in eax\n//          (found) CACHE_GET: return method triplet in eax\n//          (not found) jumps to cacheMissLabel\n//\t\n/////////////////////////////////////////////////////////////////////\n\n\n// Values to specify to method lookup macros whether the return type of\n// the method is word or structure.\nWORD_RETURN   = 0\nSTRUCT_RETURN = 1\n\n// Values to specify to method lookup macros whether the first argument\n// is an object/class reference or a 'objc_super' structure.\nMSG_SEND      = 0\t// first argument is receiver, search the isa\nMSG_SENDSUPER = 1\t// first argument is objc_super, search the class\nCACHE_GET     = 2\t// first argument is class, search that class\n\n.macro\tCacheLookup\n\n// load variables and save caller registers.\n\n\tpushl\t%edi\t\t\t// save scratch register\n\tmovl\tcache(%edx), %edi\t// cache = class->cache\n\tpushl\t%esi\t\t\t// save scratch register\n\n#if defined(OBJC_INSTRUMENTED)\n\tpushl\t%ebx\t\t\t// save non-volatile register\n\tpushl\t%eax\t\t\t// save cache pointer\n\txorl\t%ebx, %ebx\t\t// probeCount = 0\n#endif\n\tmovl\tmask(%edi), %esi\t\t// mask = cache->mask\n\tmovl\t%ecx, %edx\t\t// index = selector\n\tshrl\t$$2, %edx\t\t// index = selector >> 2\n\n// search the receiver's cache\n// ecx = selector\n// edi = cache\n// esi = mask\n// edx = index\n// eax = method (soon)\nLMsgSendProbeCache_$0_$1_$2:\n#if defined(OBJC_INSTRUMENTED)\n\taddl\t$$1, %ebx\t\t\t// probeCount += 1\n#endif\n\tandl\t%esi, %edx\t\t// index &= mask\n\tmovl\tbuckets(%edi, %edx, 4), %eax\t// meth = cache->buckets[index]\n\n\ttestl\t%eax, %eax\t\t// check for end of bucket\n\tje\tLMsgSendCacheMiss_$0_$1_$2\t// go to cache miss code\n\tcmpl\tmethod_name(%eax), %ecx\t// check for method name match\n\tje\tLMsgSendCacheHit_$0_$1_$2\t// go handle cache hit\n\taddl\t$$1, %edx\t\t\t// bump index ...\n\tjmp\tLMsgSendProbeCache_$0_$1_$2 // ... and loop\n\n// not found in cache: restore state and go to callers handler\nLMsgSendCacheMiss_$0_$1_$2:\n#if defined(OBJC_INSTRUMENTED)\n\tpopl\t%edx\t\t\t// retrieve cache pointer\n\tmovl\tmask(%edx), %esi\t\t// mask = cache->mask\n\ttestl\t%esi, %esi\t\t// a mask of zero is only for the...\n\tje\tLMsgSendMissInstrumentDone_$0_$1_$2\t// ... emptyCache, do not record anything\n\n\t// locate and update the CacheInstrumentation structure\n\taddl\t$$1, %esi\t\t\t// entryCount = mask + 1\n\tshll\t$$2, %esi\t\t// tableSize = entryCount * sizeof(entry)\n\taddl\t$buckets, %esi\t\t// offset = buckets + tableSize\n\taddl\t%edx, %esi\t\t// cacheData = &cache->buckets[mask+1]\n\n\tmovl\tmissCount(%esi), %edi\t// \n\taddl\t$$1, %edi\t\t\t// \n\tmovl\t%edi, missCount(%esi)\t// cacheData->missCount += 1\n\tmovl\tmissProbes(%esi), %edi\t// \n\taddl\t%ebx, %edi\t\t// \n\tmovl\t%edi, missProbes(%esi)\t// cacheData->missProbes += probeCount\n\tmovl\tmaxMissProbes(%esi), %edi// if (cacheData->maxMissProbes < probeCount)\n\tcmpl\t%ebx, %edi\t\t// \n\tjge\tLMsgSendMaxMissProbeOK_$0_$1_$2\t// \n\tmovl\t%ebx, maxMissProbes(%esi)// cacheData->maxMissProbes = probeCount\nLMsgSendMaxMissProbeOK_$0_$1_$2:\n\n\t// update cache miss probe histogram\n\tcmpl\t$CACHE_HISTOGRAM_SIZE, %ebx\t// pin probeCount to max index\n\tjl\tLMsgSendMissHistoIndexSet_$0_$1_$2\n\tmovl\t$(CACHE_HISTOGRAM_SIZE-1), %ebx\nLMsgSendMissHistoIndexSet_$0_$1_$2:\n\tLEA_STATIC_DATA\t%esi, _CacheMissHistogram, EXTERNAL_SYMBOL\n\tshll\t$$2, %ebx\t\t// convert probeCount to histogram index\n\taddl\t%ebx, %esi\t\t// calculate &CacheMissHistogram[probeCount<<2]\n\tmovl\t0(%esi), %edi\t\t// get current tally\n\taddl\t$$1, %edi\t\t\t// \n\tmovl\t%edi, 0(%esi)\t\t// tally += 1\nLMsgSendMissInstrumentDone_$0_$1_$2:\n\tpopl\t%ebx\t\t\t// restore non-volatile register\n#endif\n\n.if $0 == WORD_RETURN\t\t\t// Regular word return\n.if $1 == MSG_SEND\t\t\t// MSG_SEND\n\tpopl\t%esi\t\t\t//  restore callers register\n\tpopl\t%edi\t\t\t//  restore callers register\n\tmovl\tself(%esp), %edx\t//  get messaged object\n\tmovl\tisa(%edx), %eax\t\t//  get objects class\n.elseif $1 == MSG_SENDSUPER\t\t// MSG_SENDSUPER\n\t// replace \"super\" arg with \"receiver\"\n\tmovl\tsuper+8(%esp), %edi\t//  get super structure\n\tmovl\treceiver(%edi), %edx\t//  get messaged object\n\tmovl\t%edx, super+8(%esp)\t//  make it the first argument\n\tmovl\tclass(%edi), %eax\t//  get messaged class\n\tpopl\t%esi\t\t\t//  restore callers register\n\tpopl\t%edi\t\t\t//  restore callers register\n.else\t\t\t\t\t// CACHE_GET\n\tpopl\t%esi\t\t\t//  restore callers register\n\tpopl\t%edi\t\t\t//  restore callers register\n.endif\n.else\t\t\t\t\t// Struct return\n.if $1 == MSG_SEND\t\t\t// MSG_SEND (stret)\n\tpopl\t%esi\t\t\t//  restore callers register\n\tpopl\t%edi\t\t\t//  restore callers register\n\tmovl\tself_stret(%esp), %edx\t//  get messaged object\n\tmovl\tisa(%edx), %eax\t\t//  get objects class\n.elseif $1 == MSG_SENDSUPER\t\t// MSG_SENDSUPER (stret)\n\t// replace \"super\" arg with \"receiver\"\n\tmovl\tsuper_stret+8(%esp), %edi//  get super structure\n\tmovl\treceiver(%edi), %edx\t//  get messaged object\n\tmovl\t%edx, super_stret+8(%esp)//  make it the first argument\n\tmovl\tclass(%edi), %eax\t//  get messaged class\n\tpopl\t%esi\t\t\t//  restore callers register\n\tpopl\t%edi\t\t\t//  restore callers register\n.else\t\t\t\t\t// CACHE_GET\n\t!! This should not happen.\n.endif\n.endif\n\n\t\t\t\t\t// edx = receiver\n\t\t\t\t\t// ecx = selector\n\t\t\t\t\t// eax = class\n\tjmp\t$2\t\t\t// go to callers handler\n\n// eax points to matching cache entry\n\t.align\t4, 0x90\nLMsgSendCacheHit_$0_$1_$2:\n#if defined(OBJC_INSTRUMENTED)\n\tpopl\t%edx\t\t\t// retrieve cache pointer\n\tmovl\tmask(%edx), %esi\t\t// mask = cache->mask\n\ttestl\t%esi, %esi\t\t// a mask of zero is only for the...\n\tje\tLMsgSendHitInstrumentDone_$0_$1_$2\t// ... emptyCache, do not record anything\n\n\t// locate and update the CacheInstrumentation structure\n\taddl\t$$1, %esi\t\t\t// entryCount = mask + 1\n\tshll\t$$2, %esi\t\t// tableSize = entryCount * sizeof(entry)\n\taddl\t$buckets, %esi\t\t// offset = buckets + tableSize\n\taddl\t%edx, %esi\t\t// cacheData = &cache->buckets[mask+1]\n\n\tmovl\thitCount(%esi), %edi\n\taddl\t$$1, %edi\n\tmovl\t%edi, hitCount(%esi)\t// cacheData->hitCount += 1\n\tmovl\thitProbes(%esi), %edi\n\taddl\t%ebx, %edi\n\tmovl\t%edi, hitProbes(%esi)\t// cacheData->hitProbes += probeCount\n\tmovl\tmaxHitProbes(%esi), %edi// if (cacheData->maxHitProbes < probeCount)\n\tcmpl\t%ebx, %edi\n\tjge\tLMsgSendMaxHitProbeOK_$0_$1_$2\n\tmovl\t%ebx, maxHitProbes(%esi)// cacheData->maxHitProbes = probeCount\nLMsgSendMaxHitProbeOK_$0_$1_$2:\n\n\t// update cache hit probe histogram\n\tcmpl\t$CACHE_HISTOGRAM_SIZE, %ebx\t// pin probeCount to max index\n\tjl\tLMsgSendHitHistoIndexSet_$0_$1_$2\n\tmovl\t$(CACHE_HISTOGRAM_SIZE-1), %ebx\nLMsgSendHitHistoIndexSet_$0_$1_$2:\n\tLEA_STATIC_DATA\t%esi, _CacheHitHistogram, EXTERNAL_SYMBOL\n\tshll\t$$2, %ebx\t\t// convert probeCount to histogram index\n\taddl\t%ebx, %esi\t\t// calculate &CacheHitHistogram[probeCount<<2]\n\tmovl\t0(%esi), %edi\t\t// get current tally\n\taddl\t$$1, %edi\t\t\t// \n\tmovl\t%edi, 0(%esi)\t\t// tally += 1\nLMsgSendHitInstrumentDone_$0_$1_$2:\n\tpopl\t%ebx\t\t\t// restore non-volatile register\n#endif\n\n// load implementation address, restore state, and we're done\n.if $1 == CACHE_GET\n\t// method triplet is already in eax\n.else\n\tmovl\tmethod_imp(%eax), %eax\t// imp = method->method_imp\n.endif\n\n.if $0 == WORD_RETURN\t\t\t// Regular word return\n.if $1 == MSG_SENDSUPER\t\t\t// MSG_SENDSUPER\n\t// replace \"super\" arg with \"self\"\n\tmovl\tsuper+8(%esp), %edi\n\tmovl\treceiver(%edi), %esi\n\tmovl\t%esi, super+8(%esp)\n.endif\n.else\t\t\t\t\t// Struct return\n.if $1 == MSG_SENDSUPER\t\t\t// MSG_SENDSUPER (stret)\n\t// replace \"super\" arg with \"self\"\n\tmovl\tsuper_stret+8(%esp), %edi\n\tmovl\treceiver(%edi), %esi\n\tmovl\t%esi, super_stret+8(%esp)\n.endif\n.endif\n\n\t// restore caller registers\n\tpopl\t%esi\n\tpopl\t%edi\n.endmacro\n\n\n/////////////////////////////////////////////////////////////////////\n//\n// MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER\n//\n// Takes: WORD_RETURN\t(first parameter is at sp+4)\n//\t  STRUCT_RETURN\t(struct address is at sp+4, first parameter at sp+8)\n// \t  MSG_SEND\t(first parameter is receiver)\n//\t  MSG_SENDSUPER\t(first parameter is address of objc_super structure)\n//\n//\t  edx = receiver\n// \t  ecx = selector\n// \t  eax = class\n//        (all set by CacheLookup's miss case)\n// \n// Stack must be at 0xXXXXXXXc on entrance.\n//\n// On exit:  esp unchanged\n//           imp in eax\n//\n/////////////////////////////////////////////////////////////////////\n\n.macro MethodTableLookup\n\t// stack has return address and nothing else\n\tsubl\t$$(12+5*16), %esp\n\n\tmovdqa  %xmm3, 4*16(%esp)\n\tmovdqa  %xmm2, 3*16(%esp)\n\tmovdqa  %xmm1, 2*16(%esp)\n\tmovdqa  %xmm0, 1*16(%esp)\n\t\n\tmovl\t%eax, 8(%esp)\t\t// class\n\tmovl\t%ecx, 4(%esp)\t\t// selector\n\tmovl\t%edx, 0(%esp)\t\t// receiver\n\tcall\t__class_lookupMethodAndLoadCache3\n\n\tmovdqa  4*16(%esp), %xmm3\n\tmovdqa  3*16(%esp), %xmm2\n\tmovdqa  2*16(%esp), %xmm1\n\tmovdqa  1*16(%esp), %xmm0\n\n\taddl    $$(12+5*16), %esp\t// pop parameters\n.endmacro\n\n\n/********************************************************************\n * Method _cache_getMethod(Class cls, SEL sel, IMP msgForward_internal_imp)\n *\n * If found, returns method triplet pointer.\n * If not found, returns NULL.\n *\n * NOTE: _cache_getMethod never returns any cache entry whose implementation\n * is _objc_msgForward_impcache. It returns 1 instead. This prevents thread-\n * safety and memory management bugs in _class_lookupMethodAndLoadCache. \n * See _class_lookupMethodAndLoadCache for details.\n *\n * _objc_msgForward_impcache is passed as a parameter because it's more \n * efficient to do the (PIC) lookup once in the caller than repeatedly here.\n ********************************************************************/\n        \n\tSTATIC_ENTRY __cache_getMethod\n\n// load the class and selector\n\tmovl\tselector(%esp), %ecx\n\tmovl\tself(%esp), %edx\n\n// do lookup\n\tCacheLookup WORD_RETURN, CACHE_GET, LGetMethodMiss\n\n// cache hit, method triplet in %eax\n\tmovl    first_arg(%esp), %ecx   // check for _objc_msgForward_impcache\n\tcmpl    method_imp(%eax), %ecx  // if (imp==_objc_msgForward_impcache)\n\tje      1f                      //     return (Method)1\n\tret                             // else return method triplet address\n1:\tmovl\t$1, %eax\n\tret\n\nLGetMethodMiss:\n// cache miss, return nil\n\txorl    %eax, %eax      // zero %eax\n\tret\n\nLGetMethodExit:\n\tEND_ENTRY __cache_getMethod\n\n\n/********************************************************************\n * IMP _cache_getImp(Class cls, SEL sel)\n *\n * If found, returns method implementation.\n * If not found, returns NULL.\n ********************************************************************/\n\n\tSTATIC_ENTRY __cache_getImp\n\n// load the class and selector\n\tmovl    selector(%esp), %ecx\n\tmovl\tself(%esp), %edx\n\n// do lookup\n\tCacheLookup WORD_RETURN, CACHE_GET, LGetImpMiss\n\n// cache hit, method triplet in %eax\n\tmovl    method_imp(%eax), %eax  // return method imp\n\tret\n\nLGetImpMiss:\n// cache miss, return nil\n\txorl    %eax, %eax      // zero %eax\n\tret\n\nLGetImpExit:\n\tEND_ENTRY __cache_getImp\n\n\n/********************************************************************\n *\n * id objc_msgSend(id self, SEL\t_cmd,...);\n *\n ********************************************************************/\n\n\tENTRY\t_objc_msgSend\n\tCALL_MCOUNTER\n\n// load receiver and selector\n\tmovl    selector(%esp), %ecx\n\tmovl\tself(%esp), %eax\n\n// check whether receiver is nil \n\ttestl\t%eax, %eax\n\tje\tLMsgSendNilSelf\n\n// receiver (in %eax) is non-nil: search the cache\nLMsgSendReceiverOk:\n\tmovl\tisa(%eax), %edx\t\t// class = self->isa\n\tCacheLookup WORD_RETURN, MSG_SEND, LMsgSendCacheMiss\n\txor\t%edx, %edx\t\t// set nonstret for msgForward_internal\n\tjmp\t*%eax\n\n// cache miss: go search the method lists\nLMsgSendCacheMiss:\n\tMethodTableLookup WORD_RETURN, MSG_SEND\n\txor\t%edx, %edx\t\t// set nonstret for msgForward_internal\n\tjmp\t*%eax\t\t\t// goto *imp\n\n// message sent to nil: redirect to nil receiver, if any\nLMsgSendNilSelf:\n\t// %eax is already zero\n\tmovl\t$0,%edx\n\txorps\t%xmm0, %xmm0\nLMsgSendDone:\n\tret\n\n// guaranteed non-nil entry point (disabled for now)\n// .globl _objc_msgSendNonNil\n// _objc_msgSendNonNil:\n// \tmovl\tself(%esp), %eax\n// \tjmp     LMsgSendReceiverOk\n\nLMsgSendExit:\n\tEND_ENTRY\t_objc_msgSend\n\n/********************************************************************\n *\n * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);\n *\n * struct objc_super {\n *\t\tid\treceiver;\n *\t\tClass\tclass;\n * };\n ********************************************************************/\n\n\tENTRY\t_objc_msgSendSuper\n\tCALL_MCOUNTER\n\n// load selector and class to search\n\tmovl\tsuper(%esp), %eax\t// struct objc_super\n\tmovl    selector(%esp), %ecx\n\tmovl\tclass(%eax), %edx\t// struct objc_super->class\n\n// search the cache (class in %edx)\n\tCacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperCacheMiss\n\txor\t%edx, %edx\t\t// set nonstret for msgForward_internal\n\tjmp\t*%eax\t\t\t// goto *imp\n\n// cache miss: go search the method lists\nLMsgSendSuperCacheMiss:\n\tMethodTableLookup WORD_RETURN, MSG_SENDSUPER\n\txor\t%edx, %edx\t\t// set nonstret for msgForward_internal\n\tjmp\t*%eax\t\t\t// goto *imp\n\n// ignored selector: return self\nLMsgSendSuperIgnored:\n\tmovl\tsuper(%esp), %eax\n\tmovl    receiver(%eax), %eax\n\tret\n\t\nLMsgSendSuperExit:\n\tEND_ENTRY\t_objc_msgSendSuper\n\n/********************************************************************\n * id objc_msgSendv(id self, SEL _cmd, unsigned size, marg_list frame);\n *\n * On entry:\n *\t\t(sp+4)  is the message receiver,\n *\t\t(sp+8)\tis the selector,\n *\t\t(sp+12) is the size of the marg_list, in bytes,\n *\t\t(sp+16) is the address of the marg_list\n *\n ********************************************************************/\n\n\tENTRY\t_objc_msgSendv\n\n#if defined(KERNEL)\n\ttrap\t\t\t\t// _objc_msgSendv is not for the kernel\n#else\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\t// stack is currently aligned assuming no extra arguments\n\tmovl\t(marg_list+4)(%ebp), %edx\n\taddl\t$8, %edx\t\t\t// skip self & selector\n\tmovl\t(marg_size+4)(%ebp), %ecx\n\tsubl    $8, %ecx\t\t\t// skip self & selector\n\tshrl\t$2, %ecx\n\tje      LMsgSendvArgsOK\n\n\t// %esp = %esp - (16 - ((numVariableArguments & 3) << 2))\n\tmovl    %ecx, %eax\t\t\t// 16-byte align stack\n\tandl    $3, %eax\n\tshll    $2, %eax\n\tsubl    $16, %esp\n\taddl    %eax, %esp\n\nLMsgSendvArgLoop:\n\tdecl\t%ecx\n\tmovl\t0(%edx, %ecx, 4), %eax\n\tpushl\t%eax\n\tjg\tLMsgSendvArgLoop\n\nLMsgSendvArgsOK:\n\tmovl\t(selector+4)(%ebp), %ecx\n\tpushl\t%ecx\n\tmovl\t(self+4)(%ebp),%ecx\n\tpushl\t%ecx\n\tcall\t_objc_msgSend\n\tmovl\t%ebp,%esp\n\tpopl\t%ebp\n\n\tret\n#endif\n\tEND_ENTRY\t_objc_msgSendv\n\n/********************************************************************\n *\n * double objc_msgSend_fpret(id self, SEL _cmd,...);\n *\n ********************************************************************/\n\n\tENTRY\t_objc_msgSend_fpret\n\tCALL_MCOUNTER\n\n// load receiver and selector\n\tmovl    selector(%esp), %ecx\n\tmovl\tself(%esp), %eax\n\n// check whether receiver is nil \n\ttestl\t%eax, %eax\n\tje\tLMsgSendFpretNilSelf\n\n// receiver (in %eax) is non-nil: search the cache\nLMsgSendFpretReceiverOk:\n\tmovl\tisa(%eax), %edx\t\t// class = self->isa\n\tCacheLookup WORD_RETURN, MSG_SEND, LMsgSendFpretCacheMiss\n\txor\t%edx, %edx\t\t// set nonstret for msgForward_internal\n\tjmp\t*%eax\t\t\t// goto *imp\n\n// cache miss: go search the method lists\nLMsgSendFpretCacheMiss:\n\tMethodTableLookup WORD_RETURN, MSG_SEND\n\txor\t%edx, %edx\t\t// set nonstret for msgForward_internal\n\tjmp\t*%eax\t\t\t// goto *imp\n\n// message sent to nil: redirect to nil receiver, if any\nLMsgSendFpretNilSelf:\n\t// %eax is already zero\n\tfldz\nLMsgSendFpretDone:\n\tret\n\nLMsgSendFpretExit:\n\tEND_ENTRY\t_objc_msgSend_fpret\n\t\n/********************************************************************\n * double objc_msgSendv_fpret(id self, SEL _cmd, unsigned size, marg_list frame);\n *\n * On entry:\n *\t\t(sp+4)  is the message receiver,\n *\t\t(sp+8)\tis the selector,\n *\t\t(sp+12) is the size of the marg_list, in bytes,\n *\t\t(sp+16) is the address of the marg_list\n *\n ********************************************************************/\n\n\tENTRY\t_objc_msgSendv_fpret\n\n#if defined(KERNEL)\n\ttrap\t\t\t\t// _objc_msgSendv is not for the kernel\n#else\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\t// stack is currently aligned assuming no extra arguments\n\tmovl\t(marg_list+4)(%ebp), %edx\n\taddl\t$8, %edx\t\t\t// skip self & selector\n\tmovl\t(marg_size+4)(%ebp), %ecx\n\tsubl    $8, %ecx\t\t\t// skip self & selector\n\tshrl\t$2, %ecx\n\tje      LMsgSendvFpretArgsOK\n\n\t// %esp = %esp - (16 - ((numVariableArguments & 3) << 2))\n\tmovl    %ecx, %eax\t\t\t// 16-byte align stack\n\tandl    $3, %eax\n\tshll    $2, %eax\n\tsubl    $16, %esp\n\taddl    %eax, %esp\n\nLMsgSendvFpretArgLoop:\n\tdecl\t%ecx\n\tmovl\t0(%edx, %ecx, 4), %eax\n\tpushl\t%eax\n\tjg\tLMsgSendvFpretArgLoop\n\nLMsgSendvFpretArgsOK:\n\tmovl\t(selector+4)(%ebp), %ecx\n\tpushl\t%ecx\n\tmovl\t(self+4)(%ebp),%ecx\n\tpushl\t%ecx\n\tcall\t_objc_msgSend_fpret\n\tmovl\t%ebp,%esp\n\tpopl\t%ebp\n\n\tret\n#endif\n\tEND_ENTRY\t_objc_msgSendv_fpret\n\n/********************************************************************\n *\n * void\tobjc_msgSend_stret(void *st_addr\t, id self, SEL _cmd, ...);\n *\n *\n * objc_msgSend_stret is the struct-return form of msgSend.\n * The ABI calls for (sp+4) to be used as the address of the structure\n * being returned, with the parameters in the succeeding locations.\n *\n * On entry:\t(sp+4)is the address where the structure is returned,\n *\t\t(sp+8) is the message receiver,\n *\t\t(sp+12) is the selector\n ********************************************************************/\n\n\tENTRY\t_objc_msgSend_stret\n\tCALL_MCOUNTER\n\n// load receiver and selector\n\tmovl\tself_stret(%esp), %eax\n\tmovl\t(selector_stret)(%esp), %ecx\n\n// check whether receiver is nil \n\ttestl\t%eax, %eax\n\tje\tLMsgSendStretNilSelf\n\n// receiver (in %eax) is non-nil: search the cache\nLMsgSendStretReceiverOk:\n\tmovl\tisa(%eax), %edx\t\t//   class = self->isa\n\tCacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretCacheMiss\n\tmovl\t$1, %edx\t\t// set stret for objc_msgForward\n\tjmp\t*%eax\t\t\t// goto *imp\n\n// cache miss: go search the method lists\nLMsgSendStretCacheMiss:\n\tMethodTableLookup STRUCT_RETURN, MSG_SEND\n\tmovl\t$1, %edx\t\t// set stret for objc_msgForward\n\tjmp\t*%eax\t\t\t// goto *imp\n\n// message sent to nil: redirect to nil receiver, if any\nLMsgSendStretNilSelf:\n\tret\t$4\t\t\t// pop struct return address (#2995932)\n\n// guaranteed non-nil entry point (disabled for now)\n// .globl _objc_msgSendNonNil_stret\n// _objc_msgSendNonNil_stret:\n// \tCALL_MCOUNTER\n// \tmovl\tself_stret(%esp), %eax\n// \tjmp     LMsgSendStretReceiverOk\n\nLMsgSendStretExit:\n\tEND_ENTRY\t_objc_msgSend_stret\n\n/********************************************************************\n *\n * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);\n *\n * struct objc_super {\n *\t\tid\treceiver;\n *\t\tClass\tclass;\n * };\n *\n * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.\n * The ABI calls for (sp+4) to be used as the address of the structure\n * being returned, with the parameters in the succeeding registers.\n *\n * On entry:\t(sp+4)is the address where the structure is returned,\n *\t\t(sp+8) is the address of the objc_super structure,\n *\t\t(sp+12) is the selector\n *\n ********************************************************************/\n\n\tENTRY\t_objc_msgSendSuper_stret\n\tCALL_MCOUNTER\n\n// load selector and class to search\n\tmovl\tsuper_stret(%esp), %eax\t// struct objc_super\n\tmovl\t(selector_stret)(%esp), %ecx\t//   get selector\n\tmovl\tclass(%eax), %edx\t// struct objc_super->class\n\n// search the cache (class in %edx)\n\tCacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretCacheMiss\n\tmovl\t$1, %edx\t\t// set stret for objc_msgForward\n\tjmp\t*%eax\t\t\t// goto *imp\n\n// cache miss: go search the method lists\nLMsgSendSuperStretCacheMiss:\n\tMethodTableLookup STRUCT_RETURN, MSG_SENDSUPER\n\tmovl\t$1, %edx\t\t// set stret for objc_msgForward\n\tjmp\t*%eax\t\t\t// goto *imp\n\nLMsgSendSuperStretExit:\n\tEND_ENTRY\t_objc_msgSendSuper_stret\n\n\n/********************************************************************\n * void objc_msgSendv_stret(void *st_addr, id self, SEL _cmd, unsigned size, marg_list frame);\n *\n * objc_msgSendv_stret is the struct-return form of msgSendv.\n * This function does not use the struct-return ABI; instead, the\n * structure return address is passed as a normal parameter.\n * \n * On entry:\t(sp+4)  is the address in which the returned struct is put,\n *\t\t(sp+8)  is the message receiver,\n *\t\t(sp+12) is the selector,\n *\t\t(sp+16) is the size of the marg_list, in bytes,\n *\t\t(sp+20) is the address of the marg_list\n *\n ********************************************************************/\n\n\tENTRY\t_objc_msgSendv_stret\n\n#if defined(KERNEL)\n\ttrap\t\t\t\t// _objc_msgSendv_stret is not for the kernel\n#else\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\tsubl    $12, %esp\t// align stack assuming no extra arguments\n\tmovl\t(marg_list_stret+4)(%ebp), %edx\n\taddl\t$8, %edx\t\t\t// skip self & selector\n\tmovl\t(marg_size_stret+4)(%ebp), %ecx\n\tsubl\t$5, %ecx\t\t\t// skip self & selector\n\tshrl\t$2, %ecx\n\tjle\tLMsgSendvStretArgsOK\n\n\t// %esp = %esp - (16 - ((numVariableArguments & 3) << 2))\n\tmovl    %ecx, %eax\t\t\t// 16-byte align stack\n\tandl    $3, %eax\n\tshll    $2, %eax\n\tsubl    $16, %esp\n\taddl    %eax, %esp\n\nLMsgSendvStretArgLoop:\n\tdecl\t%ecx\n\tmovl\t0(%edx, %ecx, 4), %eax\n\tpushl\t%eax\n\tjg\tLMsgSendvStretArgLoop\n\nLMsgSendvStretArgsOK:\n\tmovl\t(selector_stret+4)(%ebp), %ecx\n\tpushl\t%ecx\n\tmovl\t(self_stret+4)(%ebp),%ecx\n\tpushl\t%ecx\n\tmovl\t(struct_addr+4)(%ebp),%ecx\n\tpushl\t%ecx\n\tcall\t_objc_msgSend_stret\n\tmovl\t%ebp,%esp\n\tpopl\t%ebp\n\n\tret\n#endif\n\tEND_ENTRY\t_objc_msgSendv_stret\n\n\n/********************************************************************\n *\n * id _objc_msgForward(id self, SEL _cmd,...);\n *\n ********************************************************************/\n\n// _FwdSel is @selector(forward::), set up in map_images().\n// ALWAYS dereference _FwdSel to get to \"forward::\" !!\n\t.data\n\t.align 2\n\t.private_extern _FwdSel\n_FwdSel: .long 0\n\n\t.cstring\n\t.align 2\nLUnkSelStr: .ascii \"Does not recognize selector %s (while forwarding %s)\\0\"\n\n\t.non_lazy_symbol_pointer\nL_forward_handler:\n\t.indirect_symbol __objc_forward_handler\n\t.long 0\nL_forward_stret_handler:\n\t.indirect_symbol __objc_forward_stret_handler\n\t.long 0\n\n\tSTATIC_ENTRY\t__objc_msgForward_impcache\n\t// Method cache version\n\t\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band register %edx is nonzero for stret, zero otherwise\n\t\n\t// Check return type (stret or not)\n\ttestl\t%edx, %edx\n\tjnz\t__objc_msgForward_stret\n\tjmp\t__objc_msgForward\n\t\n\tEND_ENTRY\t_objc_msgForward_impcache\n\n\t\n\tENTRY\t__objc_msgForward\n\t// Non-struct return version\n\n\t// Get PIC base into %edx\n\tcall\tL__objc_msgForward$pic_base\nL__objc_msgForward$pic_base:\n\tpopl\t%edx\n\t\n\t// Call user handler, if any\n\tmovl\tL_forward_handler-L__objc_msgForward$pic_base(%edx),%ecx\n\tmovl\t(%ecx), %ecx\n\ttestl\t%ecx, %ecx\t\t// if not NULL\n\tje\t1f\t\t\t//   skip to default handler\n\tjmp\t*%ecx\t\t\t// call __objc_forward_handler\n1:\t\n\t// No user handler\n\t// Push stack frame\n\tpushl   %ebp\n\tmovl    %esp, %ebp\n\t\n\t// Die if forwarding \"forward::\"\n\tmovl    (selector+4)(%ebp), %eax\n\tmovl\t_FwdSel-L__objc_msgForward$pic_base(%edx),%ecx\n\tcmpl\t%ecx, %eax\n\tje\tLMsgForwardError\n\n\t// Call [receiver forward:sel :margs]\n\tsubl    $8, %esp\t\t// 16-byte align the stack\n\tleal    (self+4)(%ebp), %ecx\n\tpushl\t%ecx\t\t\t// &margs\n\tpushl\t%eax\t\t\t// sel\n\tmovl\t_FwdSel-L__objc_msgForward$pic_base(%edx),%ecx\n\tpushl\t%ecx\t\t\t// forward::\n\tpushl   (self+4)(%ebp)\t\t// receiver\n\t\n\tcall\t_objc_msgSend\n\t\n\tmovl    %ebp, %esp\n\tpopl    %ebp\n\tret\n\nLMsgForwardError:\n\t// Call __objc_error(receiver, \"unknown selector %s %s\", \"forward::\", forwardedSel)\n\tsubl    $8, %esp\t\t// 16-byte align the stack\n\tpushl\t(selector+4+4)(%ebp)\t// the forwarded selector\n\tmovl\t_FwdSel-L__objc_msgForward$pic_base(%edx),%eax\n\tpushl \t%eax\n\tleal\tLUnkSelStr-L__objc_msgForward$pic_base(%edx),%eax\n\tpushl \t%eax\n\tpushl   (self+4)(%ebp)\n\tcall\t___objc_error\t// never returns\n\n\tEND_ENTRY\t__objc_msgForward\n\n\n\tENTRY\t__objc_msgForward_stret\n\t// Struct return version\n\n\t// Get PIC base into %edx\n\tcall\tL__objc_msgForwardStret$pic_base\nL__objc_msgForwardStret$pic_base:\n\tpopl\t%edx\n\n\t// Call user handler, if any\n\tmovl\tL_forward_stret_handler-L__objc_msgForwardStret$pic_base(%edx), %ecx\n\tmovl\t(%ecx), %ecx\n\ttestl\t%ecx, %ecx\t\t// if not NULL\n\tje\t1f\t\t\t//   skip to default handler\n\tjmp\t*%ecx\t\t\t// call __objc_forward_stret_handler\n1:\t\n\t// No user handler\n\t// Push stack frame\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\n\t// Die if forwarding \"forward::\"\n\tmovl\t(selector_stret+4)(%ebp), %eax\n\tmovl\t_FwdSel-L__objc_msgForwardStret$pic_base(%edx), %ecx\n\tcmpl\t%ecx, %eax\n\tje\tLMsgForwardStretError\n\n\t// Call [receiver forward:sel :margs]\n\tsubl    $8, %esp\t\t// 16-byte align the stack\n\tleal    (self_stret+4)(%ebp), %ecx\n\tpushl\t%ecx\t\t\t// &margs\n\tpushl\t%eax\t\t\t// sel\n\tmovl\t_FwdSel-L__objc_msgForwardStret$pic_base(%edx),%ecx\n\tpushl\t%ecx\t\t\t// forward::\n\tpushl   (self_stret+4)(%ebp)\t// receiver\n\t\n\tcall\t_objc_msgSend\n\t\n\tmovl    %ebp, %esp\n\tpopl    %ebp\n\tret\t$4\t\t\t// pop struct return address (#2995932)\n\nLMsgForwardStretError:\n\t// Call __objc_error(receiver, \"unknown selector %s %s\", \"forward::\", forwardedSelector)\n\tsubl    $8, %esp\t\t// 16-byte align the stack\n\tpushl\t(selector_stret+4+4)(%ebp)\t// the forwarded selector\n\tleal\t_FwdSel-L__objc_msgForwardStret$pic_base(%edx),%eax\n\tpushl \t%eax\n\tleal\tLUnkSelStr-L__objc_msgForwardStret$pic_base(%edx),%eax\n\tpushl \t%eax\n\tpushl   (self_stret+4)(%ebp)\n\tcall\t___objc_error\t// never returns\n\n\tEND_ENTRY\t__objc_msgForward_stret\n\n\n\tENTRY _method_invoke\n\n\tmovl\tselector(%esp), %ecx\n\tmovl\tmethod_name(%ecx), %edx\n\tmovl\tmethod_imp(%ecx), %eax\n\tmovl\t%edx, selector(%esp)\n\tjmp\t*%eax\n\t\n\tEND_ENTRY _method_invoke\n\n\n\tENTRY _method_invoke_stret\n\n\tmovl\tselector_stret(%esp), %ecx\n\tmovl\tmethod_name(%ecx), %edx\n\tmovl\tmethod_imp(%ecx), %eax\n\tmovl\t%edx, selector_stret(%esp)\n\tjmp\t*%eax\n\t\n\tEND_ENTRY _method_invoke_stret\n\n\n.section __DATA,__objc_msg_break\n.long 0\n.long 0\n\t\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/Messengers.subproj/objc-msg-simulator-i386.s",
    "content": "/*\n * Copyright (c) 1999-2009 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include <TargetConditionals.h>\n#if defined(__i386__)  &&  TARGET_OS_SIMULATOR\n\n#include \"objc-config.h\"\n\n.data\n\n// _objc_entryPoints and _objc_exitPoints are used by objc\n// to get the critical regions for which method caches \n// cannot be garbage collected.\n\n.align 2\n.private_extern _objc_entryPoints\n_objc_entryPoints:\n\t.long\t_cache_getImp\n\t.long\t_objc_msgSend\n\t.long\t_objc_msgSend_fpret\n\t.long\t_objc_msgSend_stret\n\t.long\t_objc_msgSendSuper\n\t.long\t_objc_msgSendSuper2\n\t.long\t_objc_msgSendSuper_stret\n\t.long\t_objc_msgSendSuper2_stret\n\t.long\t_objc_msgLookup\n\t.long\t_objc_msgLookup_fpret\n\t.long\t_objc_msgLookup_stret\n\t.long\t_objc_msgLookupSuper2\n\t.long\t_objc_msgLookupSuper2_stret\n\t.long\t0\n\n.private_extern _objc_exitPoints\n_objc_exitPoints:\n\t.long\tLExit_cache_getImp\n\t.long\tLExit_objc_msgSend\n\t.long\tLExit_objc_msgSend_fpret\n\t.long\tLExit_objc_msgSend_stret\n\t.long\tLExit_objc_msgSendSuper\n\t.long\tLExit_objc_msgSendSuper2\n\t.long\tLExit_objc_msgSendSuper_stret\n\t.long\tLExit_objc_msgSendSuper2_stret\n\t.long\tLExit_objc_msgLookup\n\t.long\tLExit_objc_msgLookup_fpret\n\t.long\tLExit_objc_msgLookup_stret\n\t.long\tLExit_objc_msgLookupSuper2\n\t.long\tLExit_objc_msgLookupSuper2_stret\n\t.long\t0\n\n\n/********************************************************************\n * Names for relative labels\n * DO NOT USE THESE LABELS ELSEWHERE\n * Reserved labels: 5: 6: 7: 8: 9:\n ********************************************************************/\n#define LCacheMiss \t5\n#define LCacheMiss_f \t5f\n#define LCacheMiss_b \t5b\n#define LNilTestDone \t6\n#define LNilTestDone_f \t6f\n#define LNilTestDone_b \t6b\n#define LNilTestSlow \t7\n#define LNilTestSlow_f \t7f\n#define LNilTestSlow_b \t7b\n#define LGetIsaDone \t8\n#define LGetIsaDone_f \t8f\n#define LGetIsaDone_b \t8b\n#define LGetIsaSlow \t9\n#define LGetIsaSlow_f \t9f\n#define LGetIsaSlow_b \t9b\n\n/********************************************************************\n * Macro parameters\n ********************************************************************/\n\n\n#define NORMAL 0\n#define FPRET 1\n#define STRET 2\n\n#define CALL 100\n#define GETIMP 101\n#define LOOKUP 102\n\n\n/********************************************************************\n *\n * Structure definitions.\n *\n ********************************************************************/\n\n// Offsets from %esp\n#define self            4\n#define super           4\n#define selector        8\n#define marg_size       12\n#define marg_list       16\n#define first_arg       12\n\n#define struct_addr     4\n\n#define self_stret      8\n#define super_stret     8\n#define selector_stret  12\n#define marg_size_stret 16\n#define marg_list_stret 20\n\n// objc_super parameter to sendSuper\n#define receiver        0\n#define class           4\n\n// Selected field offsets in class structure\n#define isa             0\n#define superclass\t4\n#define cache_buckets\t8\n#define cache_mask\t12\n\n// Method cache\n#define cached_sel\t0\n#define cached_imp\t4\n\n// Method descriptor\n#define method_name     0\n#define method_imp      8\n\n\n//////////////////////////////////////////////////////////////////////\n//\n// ENTRY\t\tfunctionName\n//\n// Assembly directives to begin an exported function.\n//\n// Takes: functionName - name of the exported function\n//////////////////////////////////////////////////////////////////////\n\n.macro ENTRY\n\t.text\n\t.globl\t$0\n\t.align\t2, 0x90\n$0:\n.endmacro\n\n.macro STATIC_ENTRY\n\t.text\n\t.private_extern\t$0\n\t.align\t4, 0x90\n$0:\n.endmacro\n\n//////////////////////////////////////////////////////////////////////\n//\n// END_ENTRY\tfunctionName\n//\n// Assembly directives to end an exported function.  Just a placeholder,\n// a close-parenthesis for ENTRY, until it is needed for something.\n//\n// Takes: functionName - name of the exported function\n//////////////////////////////////////////////////////////////////////\n\n.macro END_ENTRY\nLExit$0:\n.endmacro\n\n\n /********************************************************************\n * UNWIND name, flags\n * Unwind info generation\t\n ********************************************************************/\n.macro UNWIND\n\t.section __LD,__compact_unwind,regular,debug\n\t.long $0\n\t.set  LUnwind$0, LExit$0 - $0\n\t.long LUnwind$0\n\t.long $1\n\t.long 0\t /* no personality */\n\t.long 0  /* no LSDA */\n\t.text\n.endmacro\n\n#define NoFrame 0x02010000  // no frame, no SP adjustment except return address\n#define FrameWithNoSaves 0x01000000  // frame, no non-volatile saves\n\n\n/////////////////////////////////////////////////////////////////////\n//\n// CacheLookup\treturn-type, caller\n//\n// Locate the implementation for a selector in a class method cache.\n//\n// Takes: \n//\t  $0 = NORMAL, FPRET, STRET\n//\t  $1 = CALL, LOOKUP, GETIMP\n//\t  ecx = selector to search for\n//\t  edx = class to search\n//\n// On exit: ecx clobbered\n//\t    (found) calls or returns IMP in eax, eq/ne set for forwarding\n//\t    (not found) jumps to LCacheMiss, class still in edx\n//\n/////////////////////////////////////////////////////////////////////\n\n.macro CacheHit\n\n\t// CacheHit must always be preceded by a not-taken `jne` instruction\n\t// in case the imp is _objc_msgForward_impcache.\n\n\t// eax = found bucket\n\t\n.if $1 == GETIMP\n\tmovl\tcached_imp(%eax), %eax\t// return imp\n\tret\n\n.else\n\n.if $0 != STRET\n\t// eq already set for forwarding by `jne`\n.else\n\ttest\t%eax, %eax\t\t// set ne for stret forwarding\n.endif\n\n.if $1 == CALL\n\tjmp\t*cached_imp(%eax)\t// call imp\n\n.elseif $1 == LOOKUP\n\tmovl\tcached_imp(%eax), %eax\t// return imp\n\tret\n\n.else\n.abort oops\n.endif\n\n.endif\n\n.endmacro\n\n\n.macro\tCacheLookup\n\n\tmovzwl\tcache_mask(%edx), %eax\t\t// eax = mask\n\tandl\t%ecx, %eax\t\t// eax = SEL & mask\n\tshll\t$$3, %eax\t\t// eax = offset = (SEL & mask) * 8\n\taddl\tcache_buckets(%edx), %eax  // eax = bucket = buckets+offset\n\tcmpl\tcached_sel(%eax), %ecx\t// if (bucket->sel != SEL)\n\tjne\t1f\t\t\t//     scan more\n\t// The `jne` above sets flags for CacheHit\n\tCacheHit $0, $1\t\t\t// call or return imp\n\n1:\n\t// loop\n\tcmpl\t$$1, cached_sel(%eax)\n\tjbe\t3f\t\t\t// if (bucket->sel <= 1) wrap or miss\n\t\n\taddl\t$$8, %eax\t\t// bucket++\n2:\n\tcmpl\tcached_sel(%eax), %ecx\t// if (bucket->sel != sel)\n\tjne\t1b\t\t\t//     scan more\n\t// The `jne` above sets flags for CacheHit\n\tCacheHit $0, $1\t\t\t// call or return imp\n\n3:\t\n\t// wrap or miss\n\tjb\tLCacheMiss_f\t\t// if (bucket->sel < 1) cache miss\n\t// wrap\n\tmovl\tcached_imp(%eax), %eax\t// bucket->imp is really first bucket\n\tjmp\t2f\n\n\t// Clone scanning loop to miss instead of hang when cache is corrupt.\n\t// The slow path may detect any corruption and halt later.\n\n1:\n\t// loop\n\tcmpl\t$$1, cached_sel(%eax)\n\tjbe\t3f\t\t\t// if (bucket->sel <= 1) wrap or miss\n\t\n\taddl\t$$8, %eax\t\t// bucket++\n2:\n\tcmpl\tcached_sel(%eax), %ecx\t// if (bucket->sel != sel)\n\tjne\t1b\t\t\t//     scan more\n\t// The `jne` above sets flags for CacheHit\n\tCacheHit $0, $1\t\t\t// call or return imp\n\n3:\t\n\t// double wrap or miss\n\tjmp\tLCacheMiss_f\n\t\n.endmacro\n\n\n/////////////////////////////////////////////////////////////////////\n//\n// MethodTableLookup NORMAL|STRET\n//\n// Takes:\n//\t  receiver (not struct objc_super) and selector on stack\n// \t  edx = class to search\n//\n// On exit: IMP in eax, eq/ne set for forwarding\n//\n/////////////////////////////////////////////////////////////////////\n\n.macro MethodTableLookup\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\n\tsubl\t$$(8+5*16), %esp\n\n.if $0 == NORMAL\n\tmovl\tself+4(%ebp), %eax\n\tmovl    selector+4(%ebp), %ecx\n.else\n\tmovl\tself_stret+4(%ebp), %eax\n\tmovl    selector_stret+4(%ebp), %ecx\n.endif\n\t\n\tmovdqa  %xmm3, 4*16(%esp)\n\tmovdqa  %xmm2, 3*16(%esp)\n\tmovdqa  %xmm1, 2*16(%esp)\n\tmovdqa  %xmm0, 1*16(%esp)\n\t\n\tmovl\t%edx, 8(%esp)\t\t// class\n\tmovl\t%ecx, 4(%esp)\t\t// selector\n\tmovl\t%eax, 0(%esp)\t\t// receiver\n\tcall\t__class_lookupMethodAndLoadCache3\n\n\t// imp in eax\n\n\tmovdqa  4*16(%esp), %xmm3\n\tmovdqa  3*16(%esp), %xmm2\n\tmovdqa  2*16(%esp), %xmm1\n\tmovdqa  1*16(%esp), %xmm0\n\n.if $0 == NORMAL\n\tcmp\t%eax, %eax\t// set eq for nonstret forwarding\n.else\n\ttest\t%eax, %eax\t// set ne for stret forwarding\n.endif\n\n\tleave\n\n.endmacro\n\n\n/////////////////////////////////////////////////////////////////////\n//\n// NilTest return-type\n//\n// Takes:\t$0 = NORMAL or FPRET or STRET\n//\t\teax = receiver\n//\n// On exit: \tLoads non-nil receiver in eax and self(esp) or self_stret(esp),\n//\t\tor returns zero.\n//\n// NilTestReturnZero return-type\n//\n// Takes:\t$0 = NORMAL or FPRET or STRET\n//\t\teax = receiver\n//\n// On exit: \tLoads non-nil receiver in eax and self(esp) or self_stret(esp),\n//\t\tor returns zero.\n//\n// NilTestReturnIMP return-type\n//\n// Takes:\t$0 = NORMAL or FPRET or STRET\n//\t\teax = receiver\n//\n// On exit: \tLoads non-nil receiver in eax and self(esp) or self_stret(esp),\n//\t\tor returns an IMP in eax that returns zero.\n//\n/////////////////////////////////////////////////////////////////////\n\n.macro ZeroReturn\n\txorl\t%eax, %eax\n\txorl\t%edx, %edx\n\txorps\t%xmm0, %xmm0\n\txorps\t%xmm1, %xmm1\n.endmacro\n\n.macro ZeroReturnFPRET\n\tfldz\n.endmacro\n\n.macro ZeroReturnSTRET\n\t// empty\n.endmacro\n\n\tSTATIC_ENTRY __objc_msgNil\n\tZeroReturn\n\tret\n\tEND_ENTRY __objc_msgNil\n\n\tSTATIC_ENTRY __objc_msgNil_fpret\n\tZeroReturnFPRET\n\tret\n\tEND_ENTRY __objc_msgNil_fpret\n\n\tSTATIC_ENTRY __objc_msgNil_stret\n\tZeroReturnSTRET\n\tret $4\n\tEND_ENTRY __objc_msgNil_stret\n\n\n.macro NilTest\n\ttestl\t%eax, %eax\n\tjz\tLNilTestSlow_f\nLNilTestDone:\n.endmacro\n\n.macro NilTestReturnZero\n\t.align 3\nLNilTestSlow:\n\n.if $0 == NORMAL\n\tZeroReturn\n\tret\n.elseif $0 == FPRET\n\tZeroReturnFPRET\n\tret\n.elseif $0 == STRET\n\tZeroReturnSTRET\n\tret $$4\n.else\n.abort oops\n.endif\n.endmacro\n\n.macro NilTestReturnIMP\n\t.align 3\nLNilTestSlow:\n\n\tcall\t1f\n1:\tpop\t%eax\n.if $0 == NORMAL\n\tleal\t__objc_msgNil-1b(%eax), %eax\n.elseif $0 == FPRET\n\tleal\t__objc_msgNil_fpret-1b(%eax), %eax\n.elseif $0 == STRET\n\tleal\t__objc_msgNil_stret-1b(%eax), %eax\n.else\n.abort oops\n.endif\n\tret\n.endmacro\n\n\n/********************************************************************\n * IMP _cache_getImp(Class cls, SEL sel)\n *\n * If found, returns method implementation.\n * If not found, returns NULL.\n ********************************************************************/\n\n\tSTATIC_ENTRY _cache_getImp\n\n// load the class and selector\n\tmovl    selector(%esp), %ecx\n\tmovl\tself(%esp), %edx\n\n\tCacheLookup NORMAL, GETIMP\t// returns IMP on success\n\nLCacheMiss:\n// cache miss, return nil\n\txorl    %eax, %eax\n\tret\n\n\tEND_ENTRY _cache_getImp\n\n\n/********************************************************************\n *\n * id objc_msgSend(id self, SEL _cmd, ...);\n * IMP objc_msgLookup(id self, SEL _cmd, ...);\n *\n * objc_msgLookup ABI:\n * IMP returned in eax\n * Forwarding returned in Z flag\n * edx reserved for our use but not used\n *\n ********************************************************************/\n\n\tENTRY _objc_msgSend\n\tUNWIND _objc_msgSend, NoFrame\n\t\n\tmovl    selector(%esp), %ecx\n\tmovl\tself(%esp), %eax\n\n\tNilTest NORMAL\n\n\tmovl\tisa(%eax), %edx\t\t// class = self->isa\n\tCacheLookup NORMAL, CALL\t// calls IMP on success\n\n\tNilTestReturnZero NORMAL\n\nLCacheMiss:\n\t// isa still in edx\n\tjmp\t__objc_msgSend_uncached\n\n\tEND_ENTRY _objc_msgSend\n\n\n\tENTRY _objc_msgLookup\n\tUNWIND _objc_msgLookup, NoFrame\n\t\n\tmovl    selector(%esp), %ecx\n\tmovl\tself(%esp), %eax\n\n\tNilTest NORMAL\n\n\tmovl\tisa(%eax), %edx\t\t// class = self->isa\n\tCacheLookup NORMAL, LOOKUP\t// returns IMP on success\n\n\tNilTestReturnIMP NORMAL\n\nLCacheMiss:\n\t// isa still in edx\n\tjmp\t__objc_msgLookup_uncached\n\n\tEND_ENTRY _objc_msgLookup\n\n\n/********************************************************************\n *\n * id objc_msgSendSuper(struct objc_super *super, SEL _cmd, ...);\n *\n ********************************************************************/\n\n\tENTRY _objc_msgSendSuper\n\tUNWIND _objc_msgSendSuper, NoFrame\n\n\tmovl    selector(%esp), %ecx\n\tmovl\tsuper(%esp), %eax\t// struct objc_super\n\tmovl\tclass(%eax), %edx\t// struct objc_super->class\n\tmovl\treceiver(%eax), %eax\t// struct objc_super->receiver\n\tmovl\t%eax, super(%esp)\t// replace super arg with receiver\n\tCacheLookup NORMAL, CALL\t// calls IMP on success\n\nLCacheMiss:\t\n\t// class still in edx\n\tjmp\t__objc_msgSend_uncached\n\n\tEND_ENTRY _objc_msgSendSuper\n\n\n/********************************************************************\n *\n * id objc_msgSendSuper2(struct objc_super *super, SEL _cmd, ...);\n * IMP objc_msgLookupSuper2(struct objc_super *super, SEL _cmd, ...);\n *\n ********************************************************************/\n\n\tENTRY _objc_msgSendSuper2\n\tUNWIND _objc_msgSendSuper2, NoFrame\n\n\tmovl    selector(%esp), %ecx\n\tmovl\tsuper(%esp), %eax\t// struct objc_super\n\tmovl\tclass(%eax), %edx\t// struct objc_super->class\n\tmovl\treceiver(%eax), %eax\t// struct objc_super->receiver\n\tmovl\t%eax, super(%esp)\t// replace super arg with receiver\n\tmovl\tsuperclass(%edx), %edx\t// edx = objc_super->class->super_class\n\tCacheLookup NORMAL, CALL\t// calls IMP on success\n\nLCacheMiss:\n\t// class still in edx\n\tjmp\t__objc_msgSend_uncached\n\n\tEND_ENTRY _objc_msgSendSuper2\n\n\n\tENTRY _objc_msgLookupSuper2\n\tUNWIND _objc_msgLookupSuper2, NoFrame\n\n\tmovl    selector(%esp), %ecx\n\tmovl\tsuper(%esp), %eax\t// struct objc_super\n\tmovl\tclass(%eax), %edx\t// struct objc_super->class\n\tmovl\treceiver(%eax), %eax\t// struct objc_super->receiver\n\tmovl\t%eax, super(%esp)\t// replace super arg with receiver\n\tmovl\tsuperclass(%edx), %edx\t// edx = objc_super->class->super_class\n\tCacheLookup NORMAL, LOOKUP\t// returns IMP on success\n\nLCacheMiss:\n\t// class still in edx\n\tjmp\t__objc_msgLookup_uncached\n\n\tEND_ENTRY _objc_msgLookupSuper2\n\n\n/********************************************************************\n *\n * double objc_msgSend_fpret(id self, SEL _cmd, ...);\n * IMP objc_msgLookup_fpret(id self, SEL _cmd, ...);\n *\n ********************************************************************/\n\n\tENTRY _objc_msgSend_fpret\n\tUNWIND _objc_msgSend_fpret, NoFrame\n\n\tmovl    selector(%esp), %ecx\n\tmovl\tself(%esp), %eax\n\n\tNilTest FPRET\n\n\tmovl\tisa(%eax), %edx\t\t// class = self->isa\n\tCacheLookup FPRET, CALL\t\t// calls IMP on success\n\n\tNilTestReturnZero FPRET\n\t\nLCacheMiss:\t\n\t// class still in edx\n\tjmp\t__objc_msgSend_uncached\n\n\tEND_ENTRY _objc_msgSend_fpret\n\n\n\tENTRY _objc_msgLookup_fpret\n\tUNWIND _objc_msgLookup_fpret, NoFrame\n\n\tmovl    selector(%esp), %ecx\n\tmovl\tself(%esp), %eax\n\n\tNilTest FPRET\n\n\tmovl\tisa(%eax), %edx\t\t// class = self->isa\n\tCacheLookup FPRET, LOOKUP\t// returns IMP on success\n\n\tNilTestReturnIMP FPRET\n\t\nLCacheMiss:\t\n\t// class still in edx\n\tjmp\t__objc_msgLookup_uncached\n\n\tEND_ENTRY _objc_msgLookup_fpret\n\t\n\n/********************************************************************\n *\n * void objc_msgSend_stret(void *st_addr, id self, SEL _cmd, ...);\n * IMP objc_msgLookup_stret(void *st_addr, id self, SEL _cmd, ...);\n *\n ********************************************************************/\n\n\tENTRY _objc_msgSend_stret\n\tUNWIND _objc_msgSend_stret, NoFrame\n\n\tmovl\tselector_stret(%esp), %ecx\n\tmovl\tself_stret(%esp), %eax\n\n\tNilTest STRET\n\n\tmovl\tisa(%eax), %edx\t\t// class = self->isa\n\tCacheLookup STRET, CALL\t\t// calls IMP on success\n\n\tNilTestReturnZero STRET\n\t\nLCacheMiss:\n\t// class still in edx\n\tjmp\t__objc_msgSend_stret_uncached\n\n\tEND_ENTRY _objc_msgSend_stret\n\n\n\tENTRY _objc_msgLookup_stret\n\tUNWIND _objc_msgLookup_stret, NoFrame\n\n\tmovl\tselector_stret(%esp), %ecx\n\tmovl\tself_stret(%esp), %eax\n\n\tNilTest STRET\n\n\tmovl\tisa(%eax), %edx\t\t// class = self->isa\n\tCacheLookup STRET, LOOKUP\t// returns IMP on success\n\n\tNilTestReturnIMP STRET\n\t\nLCacheMiss:\n\t// class still in edx\n\tjmp\t__objc_msgLookup_stret_uncached\n\n\tEND_ENTRY _objc_msgLookup_stret\n\n\t\n/********************************************************************\n *\n * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);\n *\n ********************************************************************/\n\n\tENTRY _objc_msgSendSuper_stret\n\tUNWIND _objc_msgSendSuper_stret, NoFrame\n\n\tmovl\tselector_stret(%esp), %ecx\n\tmovl\tsuper_stret(%esp), %eax\t// struct objc_super\n\tmovl\tclass(%eax), %edx\t// struct objc_super->class\n\tmovl\treceiver(%eax), %eax\t// struct objc_super->receiver\n\tmovl\t%eax, super_stret(%esp)\t// replace super arg with receiver\n\tCacheLookup STRET, CALL\t\t// calls IMP on success\n\nLCacheMiss:\n\t// class still in edx\n\tjmp\t__objc_msgSend_stret_uncached\n\n\tEND_ENTRY _objc_msgSendSuper_stret\n\n\n/********************************************************************\n *\n * void objc_msgSendSuper2_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);\n * IMP objc_msgLookupSuper2_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);\n *\n ********************************************************************/\n\n\tENTRY _objc_msgSendSuper2_stret\n\tUNWIND _objc_msgSendSuper2_stret, NoFrame\n\n\tmovl\tselector_stret(%esp), %ecx\n\tmovl\tsuper_stret(%esp), %eax\t// struct objc_super\n\tmovl\tclass(%eax), %edx\t// struct objc_super->class\n\tmovl\treceiver(%eax), %eax\t// struct objc_super->receiver\n\tmovl\t%eax, super_stret(%esp)\t// replace super arg with receiver\n\tmov\tsuperclass(%edx), %edx\t// edx = objc_super->class->super_class\n\tCacheLookup STRET, CALL\t\t// calls IMP on success\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// class still in edx\n\tjmp\t__objc_msgSend_stret_uncached\n\n\tEND_ENTRY _objc_msgSendSuper2_stret\n\n\n\tENTRY _objc_msgLookupSuper2_stret\n\tUNWIND _objc_msgLookupSuper2_stret, NoFrame\n\n\tmovl\tselector_stret(%esp), %ecx\n\tmovl\tsuper_stret(%esp), %eax\t// struct objc_super\n\tmovl\tclass(%eax), %edx\t// struct objc_super->class\n\tmovl\treceiver(%eax), %eax\t// struct objc_super->receiver\n\tmovl\t%eax, super_stret(%esp)\t// replace super arg with receiver\n\tmov\tsuperclass(%edx), %edx\t// edx = objc_super->class->super_class\n\tCacheLookup STRET, LOOKUP\t// returns IMP on success\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// class still in edx\n\tjmp\t__objc_msgLookup_stret_uncached\n\n\tEND_ENTRY _objc_msgLookupSuper2_stret\n\n\n/********************************************************************\n *\n * _objc_msgSend_uncached\n * _objc_msgSend_stret_uncached\n * _objc_msgLookup_uncached\n * _objc_msgLookup_stret_uncached\n *\n * The uncached method lookup.\n *\n ********************************************************************/\n\n\tSTATIC_ENTRY __objc_msgSend_uncached\n\tUNWIND __objc_msgSend_uncached, FrameWithNoSaves\n\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band edx is the searched class\n\n\t// edx is already the class to search\n\tMethodTableLookup NORMAL\n\tjmp\t*%eax\t\t// call imp\n\n\tEND_ENTRY __objc_msgSend_uncached\n\n\t\n\tSTATIC_ENTRY __objc_msgSend_stret_uncached\n\tUNWIND __objc_msgSend_stret_uncached, FrameWithNoSaves\n\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band edx is the searched class\n\n\t// edx is already the class to search\n\tMethodTableLookup STRET\n\tjmp\t*%eax\t\t// call imp\n\n\tEND_ENTRY __objc_msgSend_stret_uncached\n\n\n\tSTATIC_ENTRY __objc_msgLookup_uncached\n\tUNWIND __objc_msgLookup_uncached, FrameWithNoSaves\n\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band edx is the searched class\n\n\t// edx is already the class to search\n\tMethodTableLookup NORMAL\t// eax = IMP\n\tret\n\n\tEND_ENTRY __objc_msgLookup_uncached\n\n\t\n\tSTATIC_ENTRY __objc_msgLookup_stret_uncached\n\tUNWIND __objc_msgLookup_stret_uncached, FrameWithNoSaves\n\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band edx is the searched class\n\n\t// edx is already the class to search\n\tMethodTableLookup STRET\t\t// eax = IMP\n\tret\n\n\tEND_ENTRY __objc_msgLookup_stret_uncached\n\n\n/********************************************************************\n*\n* id _objc_msgForward(id self, SEL _cmd,...);\n*\n* _objc_msgForward and _objc_msgForward_stret are the externally-callable\n*   functions returned by things like method_getImplementation().\n* _objc_msgForward_impcache is the function pointer actually stored in\n*   method caches.\n*\n********************************************************************/\n\n\t.non_lazy_symbol_pointer\nL_forward_handler:\n\t.indirect_symbol __objc_forward_handler\n\t.long 0\nL_forward_stret_handler:\n\t.indirect_symbol __objc_forward_stret_handler\n\t.long 0\n\n\tSTATIC_ENTRY __objc_msgForward_impcache\n\t// Method cache version\n\t\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band condition register is NE for stret, EQ otherwise.\n\n\tjne\t__objc_msgForward_stret\n\tjmp\t__objc_msgForward\n\t\n\tEND_ENTRY _objc_msgForward_impcache\n\n\t\n\tENTRY __objc_msgForward\n\t// Non-struct return version\n\n\tcall\t1f\n1:\tpopl\t%edx\n\tmovl\tL_forward_handler-1b(%edx), %edx\n\tjmp\t*(%edx)\n\n\tEND_ENTRY __objc_msgForward\n\n\n\tENTRY __objc_msgForward_stret\n\t// Struct return version\n\n\tcall\t1f\n1:\tpopl\t%edx\n\tmovl\tL_forward_stret_handler-1b(%edx), %edx\n\tjmp\t*(%edx)\n\n\tEND_ENTRY __objc_msgForward_stret\n\n\n\tENTRY _objc_msgSend_debug\n\tjmp\t_objc_msgSend\n\tEND_ENTRY _objc_msgSend_debug\n\n\tENTRY _objc_msgSendSuper2_debug\n\tjmp\t_objc_msgSendSuper2\n\tEND_ENTRY _objc_msgSendSuper2_debug\n\n\tENTRY _objc_msgSend_stret_debug\n\tjmp\t_objc_msgSend_stret\n\tEND_ENTRY _objc_msgSend_stret_debug\n\n\tENTRY _objc_msgSendSuper2_stret_debug\n\tjmp\t_objc_msgSendSuper2_stret\n\tEND_ENTRY _objc_msgSendSuper2_stret_debug\n\n\tENTRY _objc_msgSend_fpret_debug\n\tjmp\t_objc_msgSend_fpret\n\tEND_ENTRY _objc_msgSend_fpret_debug\n\n\n\tENTRY _objc_msgSend_noarg\n\tjmp\t_objc_msgSend\n\tEND_ENTRY _objc_msgSend_noarg\n\t\n\n\tENTRY _method_invoke\n\n\tmovl\tselector(%esp), %ecx\n\tmovl\tmethod_name(%ecx), %edx\n\tmovl\tmethod_imp(%ecx), %eax\n\tmovl\t%edx, selector(%esp)\n\tjmp\t*%eax\n\t\n\tEND_ENTRY _method_invoke\n\n\n\tENTRY _method_invoke_stret\n\n\tmovl\tselector_stret(%esp), %ecx\n\tmovl\tmethod_name(%ecx), %edx\n\tmovl\tmethod_imp(%ecx), %eax\n\tmovl\t%edx, selector_stret(%esp)\n\tjmp\t*%eax\n\t\n\tEND_ENTRY _method_invoke_stret\n\t\n\n.section __DATA,__objc_msg_break\n.long 0\n.long 0\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/Messengers.subproj/objc-msg-simulator-x86_64.s",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include <TargetConditionals.h>\n#if __x86_64__  &&  TARGET_OS_SIMULATOR  &&  !TARGET_OS_IOSMAC\n\n/********************************************************************\n ********************************************************************\n **\n **  objc-msg-x86_64.s - x86-64 code to support objc messaging.\n **\n ********************************************************************\n ********************************************************************/\n\n.data\n\n// _objc_entryPoints and _objc_exitPoints are used by objc\n// to get the critical regions for which method caches \n// cannot be garbage collected.\n\n.align 4\n.private_extern\t_objc_entryPoints\n_objc_entryPoints:\n\t.quad\t_cache_getImp\n\t.quad\t_objc_msgSend\n\t.quad\t_objc_msgSend_fpret\n\t.quad\t_objc_msgSend_fp2ret\n\t.quad\t_objc_msgSend_stret\n\t.quad\t_objc_msgSendSuper\n\t.quad\t_objc_msgSendSuper_stret\n\t.quad\t_objc_msgSendSuper2\n\t.quad\t_objc_msgSendSuper2_stret\n\t.quad\t_objc_msgLookup\n\t.quad\t_objc_msgLookup_fpret\n\t.quad\t_objc_msgLookup_fp2ret\n\t.quad\t_objc_msgLookup_stret\n\t.quad\t_objc_msgLookupSuper2\n\t.quad\t_objc_msgLookupSuper2_stret\n\t.quad\t0\n\n.private_extern\t_objc_exitPoints\n_objc_exitPoints:\n\t.quad\tLExit_cache_getImp\n\t.quad\tLExit_objc_msgSend\n\t.quad\tLExit_objc_msgSend_fpret\n\t.quad\tLExit_objc_msgSend_fp2ret\n\t.quad\tLExit_objc_msgSend_stret\n\t.quad\tLExit_objc_msgSendSuper\n\t.quad\tLExit_objc_msgSendSuper_stret\n\t.quad\tLExit_objc_msgSendSuper2\n\t.quad\tLExit_objc_msgSendSuper2_stret\n\t.quad\tLExit_objc_msgLookup\n\t.quad\tLExit_objc_msgLookup_fpret\n\t.quad\tLExit_objc_msgLookup_fp2ret\n\t.quad\tLExit_objc_msgLookup_stret\n\t.quad\tLExit_objc_msgLookupSuper2\n\t.quad\tLExit_objc_msgLookupSuper2_stret\n\t.quad\t0\n\n\n/********************************************************************\n * Recommended multi-byte NOP instructions\n * (Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2B)\n ********************************************************************/\n#define nop1 .byte 0x90\n#define nop2 .byte 0x66,0x90\n#define nop3 .byte 0x0F,0x1F,0x00\n#define nop4 .byte 0x0F,0x1F,0x40,0x00\n#define nop5 .byte 0x0F,0x1F,0x44,0x00,0x00\n#define nop6 .byte 0x66,0x0F,0x1F,0x44,0x00,0x00\n#define nop7 .byte 0x0F,0x1F,0x80,0x00,0x00,0x00,0x00\n#define nop8 .byte 0x0F,0x1F,0x84,0x00,0x00,0x00,0x00,0x00\n#define nop9 .byte 0x66,0x0F,0x1F,0x84,0x00,0x00,0x00,0x00,0x00\n\n\n/********************************************************************\n * Names for parameter registers.\n ********************************************************************/\n\n#define a1  rdi\n#define a1d edi\n#define a1b dil\n#define a2  rsi\n#define a2d esi\n#define a2b sil\n#define a3  rdx\n#define a3d edx\n#define a4  rcx\n#define a4d ecx\n#define a5  r8\n#define a5d r8d\n#define a6  r9\n#define a6d r9d\n\n\n/********************************************************************\n * Names for relative labels\n * DO NOT USE THESE LABELS ELSEWHERE\n * Reserved labels: 6: 7: 8: 9:\n ********************************************************************/\n#define LCacheMiss \t6\n#define LCacheMiss_f \t6f\n#define LCacheMiss_b \t6b\n#define LGetIsaDone \t7\n#define LGetIsaDone_f \t7f\n#define LGetIsaDone_b \t7b\n#define LNilOrTagged \t8\n#define LNilOrTagged_f \t8f\n#define LNilOrTagged_b \t8b\n#define LNil\t\t9\n#define LNil_f\t\t9f\n#define LNil_b\t\t9b\n\n/********************************************************************\n * Macro parameters\n ********************************************************************/\n\n#define NORMAL 0\n#define FPRET 1\n#define FP2RET 2\n#define STRET 3\n\n#define CALL 100\n#define GETIMP 101\n#define LOOKUP 102\n\n\n/********************************************************************\n *\n * Structure definitions.\n *\n ********************************************************************/\n\n// objc_super parameter to sendSuper\n#define receiver \t0\n#define class \t\t8\n\n// Selected field offsets in class structure\n// #define isa\t\t0    USE GetIsa INSTEAD\n\n// Method descriptor\n#define method_name \t0\n#define method_imp \t16\n\n// Method cache\n#define cached_sel \t0\n#define cached_imp \t8\n\n\n//////////////////////////////////////////////////////////////////////\n//\n// ENTRY\t\tfunctionName\n//\n// Assembly directives to begin an exported function.\n//\n// Takes: functionName - name of the exported function\n//////////////////////////////////////////////////////////////////////\n\n.macro ENTRY\n\t.text\n\t.globl\t$0\n\t.align\t6, 0x90\n$0:\n.endmacro\n\n.macro STATIC_ENTRY\n\t.text\n\t.private_extern\t$0\n\t.align\t2, 0x90\n$0:\n.endmacro\n\n//////////////////////////////////////////////////////////////////////\n//\n// END_ENTRY\tfunctionName\n//\n// Assembly directives to end an exported function.  Just a placeholder,\n// a close-parenthesis for ENTRY, until it is needed for something.\n//\n// Takes: functionName - name of the exported function\n//////////////////////////////////////////////////////////////////////\n\n.macro END_ENTRY\nLExit$0:\n.endmacro\n\n\n /********************************************************************\n * UNWIND name, flags\n * Unwind info generation\t\n ********************************************************************/\n.macro UNWIND\n\t.section __LD,__compact_unwind,regular,debug\n\t.quad $0\n\t.set  LUnwind$0, LExit$0 - $0\n\t.long LUnwind$0\n\t.long $1\n\t.quad 0\t /* no personality */\n\t.quad 0  /* no LSDA */\n\t.text\n.endmacro\n\n#define NoFrame 0x02010000  // no frame, no SP adjustment except return address\n#define FrameWithNoSaves 0x01000000  // frame, no non-volatile saves\n\n\n/////////////////////////////////////////////////////////////////////\n//\n// CacheLookup\treturn-type, caller\n//\n// Locate the implementation for a class in a selector's method cache.\n//\n// Takes: \n//\t  $0 = NORMAL, FPRET, FP2RET, STRET\n//\t  $1 = CALL, LOOKUP, GETIMP\n//\t  a1 or a2 (STRET) = receiver\n//\t  a2 or a3 (STRET) = selector\n//\t  r10 = class to search\n//\n// On exit: r10 clobbered\n//\t    (found) calls or returns IMP in r11, eq/ne set for forwarding\n//\t    (not found) jumps to LCacheMiss, class still in r10\n//\n/////////////////////////////////////////////////////////////////////\n\n.macro CacheHit\n\n\t// CacheHit must always be preceded by a not-taken `jne` instruction\n\t// in order to set the correct flags for _objc_msgForward_impcache.\n\n\t// r11 = found bucket\n\t\n.if $1 == GETIMP\n\tmovq\tcached_imp(%r11), %rax\t// return imp\n\tret\n\n.else\n\n.if $0 != STRET\n\t// eq already set for forwarding by `jne`\n.else\n\ttest\t%r11, %r11\t\t// set ne for stret forwarding\n.endif\n\n.if $1 == CALL\n\tjmp\t*cached_imp(%r11)\t// call imp\n\t\n.elseif $1 == LOOKUP\n\tmovq\tcached_imp(%r11), %r11\t// return imp\n\tret\n\t\n.else\n.abort oops\n.endif\n\n.endif\n\n.endmacro\n\n\n.macro\tCacheLookup\n.if $0 != STRET\n\tmovq\t%a2, %r11\t\t// r11 = _cmd\n.else\n\tmovq\t%a3, %r11\t\t// r11 = _cmd\n.endif\n\tandl\t24(%r10), %r11d\t\t// r11 = _cmd & class->cache.mask\n\tshlq\t$$4, %r11\t\t// r11 = offset = (_cmd & mask)<<4\n\taddq\t16(%r10), %r11\t\t// r11 = class->cache.buckets + offset\n\n.if $0 != STRET\n\tcmpq\tcached_sel(%r11), %a2\t// if (bucket->sel != _cmd)\n.else\n\tcmpq\tcached_sel(%r11), %a3\t// if (bucket->sel != _cmd)\n.endif\n\tjne \t1f\t\t\t//     scan more\n\t// CacheHit must always be preceded by a not-taken `jne` instruction\n\tCacheHit $0, $1\t\t\t// call or return imp\n\n1:\n\t// loop\n\tcmpq\t$$1, cached_sel(%r11)\n\tjbe\t3f\t\t\t// if (bucket->sel <= 1) wrap or miss\n\n\taddq\t$$16, %r11\t\t// bucket++\n2:\t\n.if $0 != STRET\n\tcmpq\tcached_sel(%r11), %a2\t// if (bucket->sel != _cmd)\n.else\n\tcmpq\tcached_sel(%r11), %a3\t// if (bucket->sel != _cmd)\n.endif\n\tjne \t1b\t\t\t//     scan more\n\t// CacheHit must always be preceded by a not-taken `jne` instruction\n\tCacheHit $0, $1\t\t\t// call or return imp\n\n3:\n\t// wrap or miss\n\tjb\tLCacheMiss_f\t\t// if (bucket->sel < 1) cache miss\n\t// wrap\n\tmovq\tcached_imp(%r11), %r11\t// bucket->imp is really first bucket\n\tjmp \t2f\n\n\t// Clone scanning loop to miss instead of hang when cache is corrupt.\n\t// The slow path may detect any corruption and halt later.\n\n1:\n\t// loop\n\tcmpq\t$$1, cached_sel(%r11)\n\tjbe\t3f\t\t\t// if (bucket->sel <= 1) wrap or miss\n\n\taddq\t$$16, %r11\t\t// bucket++\n2:\t\n.if $0 != STRET\n\tcmpq\tcached_sel(%r11), %a2\t// if (bucket->sel != _cmd)\n.else\n\tcmpq\tcached_sel(%r11), %a3\t// if (bucket->sel != _cmd)\n.endif\n\tjne \t1b\t\t\t//     scan more\n\t// CacheHit must always be preceded by a not-taken `jne` instruction\n\tCacheHit $0, $1\t\t\t// call or return imp\n\n3:\n\t// double wrap or miss\n\tjmp\tLCacheMiss_f\n\n.endmacro\n\n\n/////////////////////////////////////////////////////////////////////\n//\n// MethodTableLookup NORMAL|STRET\n//\n// Takes:\ta1 or a2 (STRET) = receiver\n//\t\ta2 or a3 (STRET) = selector to search for\n// \t\tr10 = class to search\n//\n// On exit: imp in %r11, eq/ne set for forwarding\n//\n/////////////////////////////////////////////////////////////////////\n\n.macro MethodTableLookup\n\n\tpush\t%rbp\n\tmov\t%rsp, %rbp\n\t\n\tsub\t$$0x80+8, %rsp\t\t// +8 for alignment\n\n\tmovdqa\t%xmm0, -0x80(%rbp)\n\tpush\t%rax\t\t\t// might be xmm parameter count\n\tmovdqa\t%xmm1, -0x70(%rbp)\n\tpush\t%a1\n\tmovdqa\t%xmm2, -0x60(%rbp)\n\tpush\t%a2\n\tmovdqa\t%xmm3, -0x50(%rbp)\n\tpush\t%a3\n\tmovdqa\t%xmm4, -0x40(%rbp)\n\tpush\t%a4\n\tmovdqa\t%xmm5, -0x30(%rbp)\n\tpush\t%a5\n\tmovdqa\t%xmm6, -0x20(%rbp)\n\tpush\t%a6\n\tmovdqa\t%xmm7, -0x10(%rbp)\n\n\t// _class_lookupMethodAndLoadCache3(receiver, selector, class)\n\n.if $0 == NORMAL\n\t// receiver already in a1\n\t// selector already in a2\n.else\n\tmovq\t%a2, %a1\n\tmovq\t%a3, %a2\n.endif\n\tmovq\t%r10, %a3\n\tcall\t__class_lookupMethodAndLoadCache3\n\n\t// IMP is now in %rax\n\tmovq\t%rax, %r11\n\n\tmovdqa\t-0x80(%rbp), %xmm0\n\tpop\t%a6\n\tmovdqa\t-0x70(%rbp), %xmm1\n\tpop\t%a5\n\tmovdqa\t-0x60(%rbp), %xmm2\n\tpop\t%a4\n\tmovdqa\t-0x50(%rbp), %xmm3\n\tpop\t%a3\n\tmovdqa\t-0x40(%rbp), %xmm4\n\tpop\t%a2\n\tmovdqa\t-0x30(%rbp), %xmm5\n\tpop\t%a1\n\tmovdqa\t-0x20(%rbp), %xmm6\n\tpop\t%rax\n\tmovdqa\t-0x10(%rbp), %xmm7\n\n.if $0 == NORMAL\n\tcmp\t%r11, %r11\t\t// set eq for nonstret forwarding\n.else\n\ttest\t%r11, %r11\t\t// set ne for stret forwarding\n.endif\n\t\n\tleave\n\n.endmacro\n\n\n/////////////////////////////////////////////////////////////////////\n//\n// GetIsaCheckNil return-type\n// GetIsaSupport return-type\n// NilTestReturnZero return-type\n// NilTestReturnIMP return-type\n//\n// Sets r10 = obj->isa.\n// Looks up the real class if receiver is a tagged pointer object.\n// Returns zero or a zero-returning IMP if obj is nil.\n//\n// Takes:\t$0 = NORMAL or FPRET or FP2RET or STRET\n//\t\ta1 or a2 (STRET) = receiver\n//\n// On exit from GetIsaCheckNil:\n//\t\tr10 = receiver->isa\n//\t\tr11 is clobbered\n//\n/////////////////////////////////////////////////////////////////////\n\n.macro ZeroReturn\n\txorl\t%eax, %eax\n\txorl\t%edx, %edx\n\txorps\t%xmm0, %xmm0\n\txorps\t%xmm1, %xmm1\n.endmacro\n\n.macro ZeroReturnFPRET\n\tfldz\n\tZeroReturn\n.endmacro\n\n.macro ZeroReturnFP2RET\n\tfldz\n\tfldz\n\tZeroReturn\n.endmacro\n\n.macro ZeroReturnSTRET\n\t// rax gets the struct-return address as passed in rdi\n\tmovq\t%rdi, %rax\n.endmacro\n\n\tSTATIC_ENTRY __objc_msgNil\n\tZeroReturn\n\tret\n\tEND_ENTRY __objc_msgNil\n\n\tSTATIC_ENTRY __objc_msgNil_fpret\n\tZeroReturnFPRET\n\tret\n\tEND_ENTRY __objc_msgNil_fpret\n\n\tSTATIC_ENTRY __objc_msgNil_fp2ret\n\tZeroReturnFP2RET\n\tret\n\tEND_ENTRY __objc_msgNil_fp2ret\n\n\tSTATIC_ENTRY __objc_msgNil_stret\n\tZeroReturnSTRET\n\tret\n\tEND_ENTRY __objc_msgNil_stret\n\n\n.macro GetIsaCheckNil\n.if $0 != STRET\n\ttestq\t%a1, %a1\n.else\n\ttestq\t%a2, %a2\n.endif\n\tjle\tLNilOrTagged_f\t// MSB tagged pointer looks negative\n\n.if $0 != STRET\n\tmovq\t(%a1), %r10\t// r10 = isa\n.else\n\tmovq\t(%a2), %r10\t// r10 = isa\n.endif\n\nLGetIsaDone:\n.endmacro\n\n\n.macro GetIsaSupport\n\t.align 3\nLNilOrTagged:\n\tjz\tLNil_f\t\t// flags set by GetIsaCheckNil\n.if $0 != STRET\n\tmovq\t%a1, %r11\n.else\n\tmovq\t%a2, %r11\n.endif\n\t// basic tagged\n\tshrq\t$$60, %r11\n\tleaq\t_objc_debug_taggedpointer_classes(%rip), %r10\n\tmovq\t(%r10, %r11, 8), %r10\t// read isa from table\n\tleaq    _OBJC_CLASS_$___NSUnrecognizedTaggedPointer(%rip), %r11\n\tcmp    %r10, %r11\n\tjne\tLGetIsaDone_b\n\t// ext tagged\n.if $0 != STRET\n\tmovq\t%a1, %r11\n.else\n\tmovq\t%a2, %r11\n.endif\n\tshrq\t$$52, %r11\n\tandl\t$$0xff, %r11d\n\tleaq\t_objc_debug_taggedpointer_ext_classes(%rip), %r10\n\tmovq\t(%r10, %r11, 8), %r10\t// read isa from table\n\tjmp\tLGetIsaDone_b\t\n.endmacro\n\n\n.macro NilTestReturnZero\nLNil:\n.if $0 == NORMAL\n\tZeroReturn\n.elseif $0 == FPRET\n\tZeroReturnFPRET\n.elseif $0 == FP2RET\n\tZeroReturnFP2RET\n.elseif $0 == STRET\n\tZeroReturnSTRET\n.else\n.abort oops\n.endif\n\tret\n.endmacro\n\n\n.macro NilTestReturnIMP\nLNil:\t\n.if $0 == NORMAL\n\tleaq\t__objc_msgNil(%rip), %r11\n.elseif $0 == FPRET\n\tleaq\t__objc_msgNil_fpret(%rip), %r11\n.elseif $0 == FP2RET\n\tleaq\t__objc_msgNil_fp2ret(%rip), %r11\n.elseif $0 == STRET\n\tleaq\t__objc_msgNil_stret(%rip), %r11\n.else\n.abort oops\n.endif\n\tret\n.endmacro\n\n\n/********************************************************************\n * IMP cache_getImp(Class cls, SEL sel)\n *\n * On entry:\ta1 = class whose cache is to be searched\n *\t\ta2 = selector to search for\n *\n * If found, returns method implementation.\n * If not found, returns NULL.\n ********************************************************************/\n\n\tSTATIC_ENTRY _cache_getImp\n\n// do lookup\n\tmovq\t%a1, %r10\t\t// move class to r10 for CacheLookup\n\tCacheLookup NORMAL, GETIMP\t// returns IMP on success\n\nLCacheMiss:\n// cache miss, return nil\n\txorl\t%eax, %eax\n\tret\n\n\tEND_ENTRY _cache_getImp\n\n\n/********************************************************************\n *\n * id objc_msgSend(id self, SEL\t_cmd,...);\n * IMP objc_msgLookup(id self, SEL _cmd, ...);\n *\n * objc_msgLookup ABI:\n * IMP returned in r11\n * Forwarding returned in Z flag\n * r10 reserved for our use but not used\n *\n ********************************************************************/\n\t\n\t.data\n\t.align 3\n\t.globl _objc_debug_taggedpointer_classes\n_objc_debug_taggedpointer_classes:\n\t.fill 16, 8, 0\n\t.globl _objc_debug_taggedpointer_ext_classes\n_objc_debug_taggedpointer_ext_classes:\n\t.fill 256, 8, 0\n\n\tENTRY _objc_msgSend\n\tUNWIND _objc_msgSend, NoFrame\n\n\tGetIsaCheckNil NORMAL\t\t// r10 = self->isa, or return zero\n\tCacheLookup NORMAL, CALL\t// calls IMP on success\n\n\tGetIsaSupport NORMAL\n\tNilTestReturnZero NORMAL\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgSend_uncached\n\n\tEND_ENTRY _objc_msgSend\n\n\t\n\tENTRY _objc_msgLookup\n\n\tGetIsaCheckNil NORMAL\t\t// r10 = self->isa, or return zero IMP\n\tCacheLookup NORMAL, LOOKUP\t// returns IMP on success\n\n\tGetIsaSupport NORMAL\n\tNilTestReturnIMP NORMAL\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgLookup_uncached\n\n\tEND_ENTRY _objc_msgLookup\n\n\t\n\tENTRY _objc_msgSend_fixup\n\tint3\n\tEND_ENTRY _objc_msgSend_fixup\n\n\t\n\tSTATIC_ENTRY _objc_msgSend_fixedup\n\t// Load _cmd from the message_ref\n\tmovq\t8(%a2), %a2\n\tjmp\t_objc_msgSend\n\tEND_ENTRY _objc_msgSend_fixedup\n\n\t\n/********************************************************************\n *\n * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);\n *\n * struct objc_super {\n *\t\tid\treceiver;\n *\t\tClass\tclass;\n * };\n ********************************************************************/\n\t\n\tENTRY _objc_msgSendSuper\n\tUNWIND _objc_msgSendSuper, NoFrame\n\t\n// search the cache (objc_super in %a1)\n\tmovq\tclass(%a1), %r10\t// class = objc_super->class\n\tmovq\treceiver(%a1), %a1\t// load real receiver\n\tCacheLookup NORMAL, CALL\t// calls IMP on success\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// class still in r10\n\tjmp\t__objc_msgSend_uncached\n\t\n\tEND_ENTRY _objc_msgSendSuper\n\n\n/********************************************************************\n * id objc_msgSendSuper2\n ********************************************************************/\n\n\tENTRY _objc_msgSendSuper2\n\tUNWIND _objc_msgSendSuper2, NoFrame\n\t\n\t// objc_super->class is superclass of class to search\n\t\n// search the cache (objc_super in %a1)\n\tmovq\tclass(%a1), %r10\t// cls = objc_super->class\n\tmovq\treceiver(%a1), %a1\t// load real receiver\n\tmovq\t8(%r10), %r10\t\t// cls = class->superclass\n\tCacheLookup NORMAL, CALL\t// calls IMP on success\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// superclass still in r10\n\tjmp\t__objc_msgSend_uncached\n\t\n\tEND_ENTRY _objc_msgSendSuper2\n\n\n\tENTRY _objc_msgLookupSuper2\n\t\n\t// objc_super->class is superclass of class to search\n\t\n// search the cache (objc_super in %a1)\n\tmovq\tclass(%a1), %r10\t// cls = objc_super->class\n\tmovq\treceiver(%a1), %a1\t// load real receiver\n\tmovq\t8(%r10), %r10\t\t// cls = class->superclass\n\tCacheLookup NORMAL, LOOKUP\t// returns IMP on success\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// superclass still in r10\n\tjmp\t__objc_msgLookup_uncached\n\t\n\tEND_ENTRY _objc_msgLookupSuper2\n\n\n\tENTRY _objc_msgSendSuper2_fixup\n\tint3\n\tEND_ENTRY _objc_msgSendSuper2_fixup\n\n\t\n\tSTATIC_ENTRY _objc_msgSendSuper2_fixedup\n\t// Load _cmd from the message_ref\n\tmovq\t8(%a2), %a2\n\tjmp \t_objc_msgSendSuper2\n\tEND_ENTRY _objc_msgSendSuper2_fixedup\n\n\n/********************************************************************\n *\n * double objc_msgSend_fpret(id self, SEL _cmd,...);\n * Used for `long double` return only. `float` and `double` use objc_msgSend.\n *\n ********************************************************************/\n\n\tENTRY _objc_msgSend_fpret\n\tUNWIND _objc_msgSend_fpret, NoFrame\n\t\n\tGetIsaCheckNil FPRET\t\t// r10 = self->isa, or return zero\n\tCacheLookup FPRET, CALL\t\t// calls IMP on success\n\n\tGetIsaSupport FPRET\n\tNilTestReturnZero FPRET\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgSend_uncached\n\n\tEND_ENTRY _objc_msgSend_fpret\n\n\n\tENTRY _objc_msgLookup_fpret\n\t\n\tGetIsaCheckNil FPRET\t\t// r10 = self->isa, or return zero IMP\n\tCacheLookup FPRET, LOOKUP\t// returns IMP on success\n\n\tGetIsaSupport FPRET\n\tNilTestReturnIMP FPRET\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgLookup_uncached\n\n\tEND_ENTRY _objc_msgLookup_fpret\n\n\t\n\tENTRY _objc_msgSend_fpret_fixup\n\tint3\n\tEND_ENTRY _objc_msgSend_fpret_fixup\n\n\t\n\tSTATIC_ENTRY _objc_msgSend_fpret_fixedup\n\t// Load _cmd from the message_ref\n\tmovq\t8(%a2), %a2\n\tjmp\t_objc_msgSend_fpret\n\tEND_ENTRY _objc_msgSend_fpret_fixedup\n\n\n/********************************************************************\n *\n * double objc_msgSend_fp2ret(id self, SEL _cmd,...);\n * Used for `complex long double` return only.\n *\n ********************************************************************/\n\n\tENTRY _objc_msgSend_fp2ret\n\tUNWIND _objc_msgSend_fp2ret, NoFrame\n\t\n\tGetIsaCheckNil FP2RET\t\t// r10 = self->isa, or return zero\n\tCacheLookup FP2RET, CALL\t// calls IMP on success\n\n\tGetIsaSupport FP2RET\n\tNilTestReturnZero FP2RET\n\t\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgSend_uncached\n\n\tEND_ENTRY _objc_msgSend_fp2ret\n\n\n\tENTRY _objc_msgLookup_fp2ret\n\t\n\tGetIsaCheckNil FP2RET\t\t// r10 = self->isa, or return zero IMP\n\tCacheLookup FP2RET, LOOKUP\t// returns IMP on success\n\n\tGetIsaSupport FP2RET\n\tNilTestReturnIMP FP2RET\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgLookup_uncached\n\n\tEND_ENTRY _objc_msgLookup_fp2ret\n\n\n\tENTRY _objc_msgSend_fp2ret_fixup\n\tint3\n\tEND_ENTRY _objc_msgSend_fp2ret_fixup\n\n\t\n\tSTATIC_ENTRY _objc_msgSend_fp2ret_fixedup\n\t// Load _cmd from the message_ref\n\tmovq\t8(%a2), %a2\n\tjmp\t_objc_msgSend_fp2ret\n\tEND_ENTRY _objc_msgSend_fp2ret_fixedup\n\n\n/********************************************************************\n *\n * void\tobjc_msgSend_stret(void *st_addr, id self, SEL _cmd, ...);\n *\n * objc_msgSend_stret is the struct-return form of msgSend.\n * The ABI calls for %a1 to be used as the address of the structure\n * being returned, with the parameters in the succeeding locations.\n *\n * On entry:\t%a1 is the address where the structure is returned,\n *\t\t%a2 is the message receiver,\n *\t\t%a3 is the selector\n ********************************************************************/\n\n\tENTRY _objc_msgSend_stret\n\tUNWIND _objc_msgSend_stret, NoFrame\n\n\tGetIsaCheckNil STRET\t\t// r10 = self->isa, or return zero\n\tCacheLookup STRET, CALL\t\t// calls IMP on success\n\n\tGetIsaSupport STRET\n\tNilTestReturnZero STRET\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgSend_stret_uncached\n\n\tEND_ENTRY _objc_msgSend_stret\n\n\n\tENTRY _objc_msgLookup_stret\n\t\n\tGetIsaCheckNil STRET\t\t// r10 = self->isa, or return zero IMP\n\tCacheLookup STRET, LOOKUP\t// returns IMP on success\n\n\tGetIsaSupport STRET\n\tNilTestReturnIMP STRET\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgLookup_stret_uncached\n\n\tEND_ENTRY _objc_msgLookup_stret\n\n\n\tENTRY _objc_msgSend_stret_fixup\n\tint3\n\tEND_ENTRY _objc_msgSend_stret_fixup\n\n\n\tSTATIC_ENTRY _objc_msgSend_stret_fixedup\n\t// Load _cmd from the message_ref\n\tmovq\t8(%a3), %a3\n\tjmp\t_objc_msgSend_stret\n\tEND_ENTRY _objc_msgSend_stret_fixedup\n\n\n/********************************************************************\n *\n * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);\n *\n * struct objc_super {\n *\t\tid\treceiver;\n *\t\tClass\tclass;\n * };\n *\n * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.\n * The ABI calls for (sp+4) to be used as the address of the structure\n * being returned, with the parameters in the succeeding registers.\n *\n * On entry:\t%a1 is the address where the structure is returned,\n *\t\t%a2 is the address of the objc_super structure,\n *\t\t%a3 is the selector\n *\n ********************************************************************/\n\n\tENTRY _objc_msgSendSuper_stret\n\tUNWIND _objc_msgSendSuper_stret, NoFrame\n\t\n// search the cache (objc_super in %a2)\n\tmovq\tclass(%a2), %r10\t// class = objc_super->class\n\tmovq\treceiver(%a2), %a2\t// load real receiver\n\tCacheLookup STRET, CALL\t\t// calls IMP on success\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// class still in r10\n\tjmp\t__objc_msgSend_stret_uncached\n\t\n\tEND_ENTRY _objc_msgSendSuper_stret\n\n\n/********************************************************************\n * id objc_msgSendSuper2_stret\n ********************************************************************/\n\n\tENTRY _objc_msgSendSuper2_stret\n\tUNWIND _objc_msgSendSuper2_stret, NoFrame\n\t\n// search the cache (objc_super in %a2)\n\tmovq\tclass(%a2), %r10\t// class = objc_super->class\n\tmovq\treceiver(%a2), %a2\t// load real receiver\n\tmovq\t8(%r10), %r10\t\t// class = class->superclass\n\tCacheLookup STRET, CALL\t\t// calls IMP on success\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// superclass still in r10\n\tjmp\t__objc_msgSend_stret_uncached\n\n\tEND_ENTRY _objc_msgSendSuper2_stret\n\n\n\tENTRY _objc_msgLookupSuper2_stret\n\t\n// search the cache (objc_super in %a2)\n\tmovq\tclass(%a2), %r10\t// class = objc_super->class\n\tmovq\treceiver(%a2), %a2\t// load real receiver\n\tmovq\t8(%r10), %r10\t\t// class = class->superclass\n\tCacheLookup STRET, LOOKUP\t// returns IMP on success\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// superclass still in r10\n\tjmp\t__objc_msgLookup_stret_uncached\n\n\tEND_ENTRY _objc_msgLookupSuper2_stret\n\n\t\n\tENTRY _objc_msgSendSuper2_stret_fixup\n\tint3\n\tEND_ENTRY _objc_msgSendSuper2_stret_fixup\n\n\t\n\tSTATIC_ENTRY _objc_msgSendSuper2_stret_fixedup\n\t// Load _cmd from the message_ref\n\tmovq\t8(%a3), %a3\n\tjmp\t_objc_msgSendSuper2_stret\n\tEND_ENTRY _objc_msgSendSuper2_stret_fixedup\n\n\n/********************************************************************\n *\n * _objc_msgSend_uncached\n * _objc_msgSend_stret_uncached\n * The uncached method lookup.\n *\n ********************************************************************/\n\n\tSTATIC_ENTRY __objc_msgSend_uncached\n\tUNWIND __objc_msgSend_uncached, FrameWithNoSaves\n\t\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band r10 is the searched class\n\n\t// r10 is already the class to search\n\tMethodTableLookup NORMAL\t// r11 = IMP\n\tjmp\t*%r11\t\t\t// goto *imp\n\n\tEND_ENTRY __objc_msgSend_uncached\n\n\t\n\tSTATIC_ENTRY __objc_msgSend_stret_uncached\n\tUNWIND __objc_msgSend_stret_uncached, FrameWithNoSaves\n\t\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band r10 is the searched class\n\n\t// r10 is already the class to search\n\tMethodTableLookup STRET\t\t// r11 = IMP\n\tjmp\t*%r11\t\t\t// goto *imp\n\n\tEND_ENTRY __objc_msgSend_stret_uncached\n\n\t\n\tSTATIC_ENTRY __objc_msgLookup_uncached\n\tUNWIND __objc_msgLookup_uncached, FrameWithNoSaves\n\t\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band r10 is the searched class\n\n\t// r10 is already the class to search\n\tMethodTableLookup NORMAL\t// r11 = IMP\n\tret\n\n\tEND_ENTRY __objc_msgLookup_uncached\n\n\t\n\tSTATIC_ENTRY __objc_msgLookup_stret_uncached\n\tUNWIND __objc_msgLookup_stret_uncached, FrameWithNoSaves\n\t\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band r10 is the searched class\n\n\t// r10 is already the class to search\n\tMethodTableLookup STRET\t\t// r11 = IMP\n\tret\n\n\tEND_ENTRY __objc_msgLookup_stret_uncached\n\n\t\n/********************************************************************\n*\n* id _objc_msgForward(id self, SEL _cmd,...);\n*\n* _objc_msgForward and _objc_msgForward_stret are the externally-callable\n*   functions returned by things like method_getImplementation().\n* _objc_msgForward_impcache is the function pointer actually stored in\n*   method caches.\n*\n********************************************************************/\n\n\tSTATIC_ENTRY __objc_msgForward_impcache\n\t// Method cache version\n\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band condition register is NE for stret, EQ otherwise.\n\n\tjne\t__objc_msgForward_stret\n\tjmp\t__objc_msgForward\n\n\tEND_ENTRY __objc_msgForward_impcache\n\t\n\t\n\tENTRY __objc_msgForward\n\t// Non-stret version\n\n\tmovq\t__objc_forward_handler(%rip), %r11\n\tjmp\t*%r11\n\n\tEND_ENTRY __objc_msgForward\n\n\n\tENTRY __objc_msgForward_stret\n\t// Struct-return version\n\n\tmovq\t__objc_forward_stret_handler(%rip), %r11\n\tjmp\t*%r11\n\n\tEND_ENTRY __objc_msgForward_stret\n\n\n\tENTRY _objc_msgSend_debug\n\tjmp\t_objc_msgSend\n\tEND_ENTRY _objc_msgSend_debug\n\n\tENTRY _objc_msgSendSuper2_debug\n\tjmp\t_objc_msgSendSuper2\n\tEND_ENTRY _objc_msgSendSuper2_debug\n\n\tENTRY _objc_msgSend_stret_debug\n\tjmp\t_objc_msgSend_stret\n\tEND_ENTRY _objc_msgSend_stret_debug\n\n\tENTRY _objc_msgSendSuper2_stret_debug\n\tjmp\t_objc_msgSendSuper2_stret\n\tEND_ENTRY _objc_msgSendSuper2_stret_debug\n\n\tENTRY _objc_msgSend_fpret_debug\n\tjmp\t_objc_msgSend_fpret\n\tEND_ENTRY _objc_msgSend_fpret_debug\n\n\tENTRY _objc_msgSend_fp2ret_debug\n\tjmp\t_objc_msgSend_fp2ret\n\tEND_ENTRY _objc_msgSend_fp2ret_debug\n\n\n\tENTRY _objc_msgSend_noarg\n\tjmp\t_objc_msgSend\n\tEND_ENTRY _objc_msgSend_noarg\n\n\n\tENTRY _method_invoke\n\n\tmovq\tmethod_imp(%a2), %r11\n\tmovq\tmethod_name(%a2), %a2\n\tjmp\t*%r11\n\t\n\tEND_ENTRY _method_invoke\n\n\n\tENTRY _method_invoke_stret\n\n\tmovq\tmethod_imp(%a3), %r11\n\tmovq\tmethod_name(%a3), %a3\n\tjmp\t*%r11\n\t\n\tEND_ENTRY _method_invoke_stret\n\n\n.section __DATA,__objc_msg_break\n.quad 0\n.quad 0\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/Messengers.subproj/objc-msg-win32.m",
    "content": "#include \"objc-private.h\"\r\n\r\n// out-of-band parameter to objc_msgForward\r\n#define kFwdMsgSend 1\r\n#define kFwdMsgSendStret 0\r\n\r\n// objc_msgSend parameters\r\n#define SELF 8[ebp]\r\n#define SUPER 8[ebp]\r\n#define SELECTOR 12[ebp]\r\n#define FIRST_ARG 16[ebp]\r\n\r\n// objc_msgSend_stret parameters\r\n#define STRUCT_ADDR 8[ebp]\r\n#define SELF_STRET 12[ebp]\r\n#define SUPER_STRET 12[ebp]\r\n#define SELECTOR_STRET 16[ebp]\r\n\r\n// objc_super parameter to sendSuper\r\n#define super_receiver 0\r\n#define super_class 4\r\n\r\n// struct objc_class fields\r\n#define isa 0\r\n#define cache 32\r\n\r\n// struct objc_method fields\r\n#define method_name 0\r\n#define method_imp 8\r\n\r\n// struct objc_cache fields\r\n#define mask 0\r\n#define occupied 4\r\n#define buckets 8\r\n\r\nvoid *_objc_forward_handler = NULL;\r\nvoid *_objc_forward_stret_handler = NULL;\r\n\r\n__declspec(naked) Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)\r\n{\r\n    __asm {\r\n        push ebp\r\n        mov ebp, esp\r\n\r\n        mov ecx, SELECTOR\r\n        mov edx, SELF\r\n\r\n// CacheLookup WORD_RETURN, CACHE_GET\r\n        push edi\r\n        mov edi, cache[edx]\r\n\r\n        push esi\r\n        mov esi, mask[edi]\r\n        mov edx, ecx\r\n        shr edx, 2\r\nSCAN:\r\n        and edx, esi\r\n        mov eax, buckets[edi][edx*4]\r\n        test eax, eax\r\n        je MISS\r\n        cmp ecx, method_name[eax]\r\n        je HIT\r\n        add edx, 1\r\n        jmp SCAN\r\n\r\nMISS:\r\n        xor eax, eax\r\n        pop esi\r\n        pop edi\r\n        leave\r\n        ret\r\n\r\nHIT:\r\n        mov ecx, FIRST_ARG\r\n        cmp ecx, method_imp[eax]\r\n        je MISS\r\n        pop esi\r\n        pop edi\r\n        leave\r\n        ret\r\n    }\r\n}\r\n\r\n__declspec(naked) IMP _cache_getImp(Class cls, SEL sel)\r\n{\r\n    __asm {\r\n        push ebp\r\n        mov ebp, esp\r\n\r\n        mov ecx, SELECTOR\r\n        mov edx, SELF\r\n\r\n// CacheLookup WORD_RETURN, CACHE_GET\r\n        push edi\r\n        mov edi, cache[edx]\r\n\r\n        push esi\r\n        mov esi, mask[edi]\r\n        mov edx, ecx\r\n        shr edx, 2\r\nSCAN:\r\n        and edx, esi\r\n        mov eax, buckets[edi][edx*4]\r\n        test eax, eax\r\n        je MISS\r\n        cmp ecx, method_name[eax]\r\n        je HIT\r\n        add edx, 1\r\n        jmp SCAN\r\n\r\nMISS:\r\n        pop esi\r\n        pop edi\r\n        xor eax, eax\r\n        leave\r\n        ret\r\n\r\nHIT:\r\n        pop esi\r\n        pop edi\r\n        mov eax, method_imp[eax]\r\n        leave\r\n        ret\r\n    }\r\n}\r\n\r\n\r\nOBJC_EXPORT __declspec(naked) id objc_msgSend(id a, SEL b, ...)\r\n{\r\n    __asm {\r\n        push ebp\r\n        mov ebp, esp\r\n\r\n        // load receiver and selector\r\n        mov ecx, SELECTOR\r\n        mov eax, SELF\r\n\r\n        // check whether receiver is nil\r\n        test eax, eax\r\n        je NIL\r\n\r\n        // receiver (in eax) is non-nil: search the cache\r\n        mov edx, isa[eax]\r\n\r\n        // CacheLookup WORD_RETURN, MSG_SEND\r\n        push edi\r\n        mov edi, cache[edx]\r\n        push esi\r\n        mov esi, mask[edi]\r\n        mov edx, ecx\r\n        shr edx, 2\r\nSCAN:\r\n        and edx, esi\r\n        mov eax, buckets[edi][edx*4]\r\n        test eax, eax\r\n        je MISS\r\n        cmp ecx, method_name[eax]\r\n        je HIT\r\n        add edx, 1\r\n        jmp SCAN\r\n\r\nHIT:\r\n        mov eax, method_imp[eax]\r\n        pop esi\r\n        pop edi\r\n        mov edx, kFwdMsgSend\r\n        leave\r\n        jmp eax\r\n\r\n        // cache miss: search method lists\r\nMISS:\r\n        pop esi\r\n        pop edi\r\n        mov edx, SELF\r\n        mov eax, isa[edx]\r\n\r\n        // MethodTableLookup WORD_RETURN, MSG_SEND\r\n        push eax\r\n        push ecx\r\n        push edx\r\n        call _class_lookupMethodAndLoadCache3\r\n\r\n        mov edx, kFwdMsgSend\r\n        leave\r\n        jmp eax\r\n\r\n        // message send to nil: return zero\r\nNIL:\r\n        // eax is already zero\r\n        mov edx, 0\r\n        leave\r\n        ret\r\n    }\r\n}\r\n\r\n\r\nOBJC_EXPORT __declspec(naked) double objc_msgSend_fpret(id a, SEL b, ...)\r\n{\r\n    __asm {\r\n        push ebp\r\n        mov ebp, esp\r\n\r\n        // load receiver and selector\r\n        mov ecx, SELECTOR\r\n        mov eax, SELF\r\n\r\n        // check whether receiver is nil\r\n        test eax, eax\r\n        je NIL\r\n\r\n        // receiver (in eax) is non-nil: search the cache\r\n        mov edx, isa[eax]\r\n\r\n        // CacheLookup WORD_RETURN, MSG_SEND\r\n        push edi\r\n        mov edi, cache[edx]\r\n        push esi\r\n        mov esi, mask[edi]\r\n        mov edx, ecx\r\n        shr edx, 2\r\nSCAN:\r\n        and edx, esi\r\n        mov eax, buckets[edi][edx*4]\r\n        test eax, eax\r\n        je MISS\r\n        cmp ecx, method_name[eax]\r\n        je HIT\r\n        add edx, 1\r\n        jmp SCAN\r\n\r\nHIT:\r\n        mov eax, method_imp[eax]\r\n        pop esi\r\n        pop edi\r\n        mov edx, kFwdMsgSend\r\n        leave\r\n        jmp eax\r\n\r\n        // cache miss: search method lists\r\nMISS:\r\n        pop esi\r\n        pop edi\r\n        mov edx, SELF\r\n        mov eax, isa[edx]\r\n\r\n        // MethodTableLookup WORD_RETURN, MSG_SEND\r\n        push eax\r\n        push ecx\r\n        push edx\r\n        call _class_lookupMethodAndLoadCache3\r\n\r\n        mov edx, kFwdMsgSend\r\n        leave\r\n        jmp eax\r\n\r\n        // message send to nil: return zero\r\nNIL:\r\n        fldz\r\n        leave\r\n        ret\r\n    }\r\n}\r\n\r\n\r\nOBJC_EXPORT __declspec(naked) id objc_msgSendSuper(struct objc_super *a, SEL b, ...)\r\n{\r\n    __asm {\r\n        push ebp\r\n        mov ebp, esp\r\n\r\n        // load class and selector\r\n        mov eax, SUPER\r\n        mov ecx, SELECTOR\r\n        mov edx, super_class[eax]\r\n\r\n        // search the cache (class in edx)\r\n        // CacheLookup WORD_RETURN, MSG_SENDSUPER\r\n        push edi\r\n        mov edi, cache[edx]\r\n        push esi\r\n        mov esi, mask[edi]\r\n        mov edx, ecx\r\n        shr edx, 2\r\nSCAN:\r\n        and edx, esi\r\n        mov eax, buckets[edi][edx*4]\r\n        test eax, eax\r\n        je MISS\r\n        cmp ecx, method_name[eax]\r\n        je HIT\r\n        add edx, 1\r\n        jmp SCAN\r\n\r\nHIT:\r\n        mov eax, method_imp[eax]\r\n        pop esi\r\n        pop edi\r\n        mov edx, SUPER\r\n        mov edx, super_receiver[edx]\r\n        mov SUPER, edx\r\n        mov edx, kFwdMsgSend\r\n        leave\r\n        jmp eax\r\n\r\n        // cache miss: search method lists\r\nMISS:\r\n\r\n        pop esi\r\n        pop edi\r\n        mov eax, SUPER\r\n        mov edx, super_receiver[eax]\r\n        mov SUPER, edx\r\n        mov eax, super_class[eax]\r\n\r\n        // MethodTableLookup WORD_RETURN, MSG_SENDSUPER\r\n        push eax\r\n        push ecx\r\n        push edx\r\n        call _class_lookupMethodAndLoadCache3\r\n\r\n        mov edx, kFwdMsgSend\r\n        leave\r\n        jmp eax\r\n    }\r\n}\r\n\r\n\r\nOBJC_EXPORT __declspec(naked) void objc_msgSend_stret(void)\r\n{\r\n    __asm {\r\n        push ebp\r\n        mov ebp, esp\r\n\r\n        // load receiver and selector\r\n        mov ecx, SELECTOR_STRET\r\n        mov eax, SELF_STRET\r\n\r\n        // check whether receiver is nil\r\n        test eax, eax\r\n        je NIL\r\n\r\n        // receiver (in eax) is non-nil: search the cache\r\n        mov edx, isa[eax]\r\n\r\n        // CacheLookup WORD_RETURN, MSG_SEND\r\n        push edi\r\n        mov edi, cache[edx]\r\n        push esi\r\n        mov esi, mask[edi]\r\n        mov edx, ecx\r\n        shr edx, 2\r\nSCAN:\r\n        and edx, esi\r\n        mov eax, buckets[edi][edx*4]\r\n        test eax, eax\r\n        je MISS\r\n        cmp ecx, method_name[eax]\r\n        je HIT\r\n        add edx, 1\r\n        jmp SCAN\r\n\r\nHIT:\r\n        mov eax, method_imp[eax]\r\n        pop esi\r\n        pop edi\r\n        mov edx, kFwdMsgSendStret\r\n        leave\r\n        jmp eax\r\n\r\n        // cache miss: search method lists\r\nMISS:\r\n        pop esi\r\n        pop edi\r\n        mov edx, SELF_STRET\r\n        mov eax, isa[edx]\r\n\r\n        // MethodTableLookup WORD_RETURN, MSG_SEND\r\n        push eax\r\n        push ecx\r\n        push edx\r\n        call _class_lookupMethodAndLoadCache3\r\n\r\n        mov edx, kFwdMsgSendStret\r\n        leave\r\n        jmp eax\r\n\r\n        // message send to nil: return zero\r\nNIL:\r\n        // eax is already zero\r\n        mov edx, 0\r\n        leave\r\n        ret\r\n    }\r\n}\r\n\r\n\r\nOBJC_EXPORT __declspec(naked) id objc_msgSendSuper_stret(struct objc_super *a, SEL b, ...)\r\n{\r\n    __asm {\r\n        push ebp\r\n        mov ebp, esp\r\n\r\n        // load class and selector\r\n        mov eax, SUPER_STRET\r\n        mov ecx, SELECTOR_STRET\r\n        mov edx, super_class[eax]\r\n\r\n        // search the cache (class in edx)\r\n        // CacheLookup WORD_RETURN, MSG_SENDSUPER\r\n        push edi\r\n        mov edi, cache[edx]\r\n        push esi\r\n        mov esi, mask[edi]\r\n        mov edx, ecx\r\n        shr edx, 2\r\nSCAN:\r\n        and edx, esi\r\n        mov eax, buckets[edi][edx*4]\r\n        test eax, eax\r\n        je MISS\r\n        cmp ecx, method_name[eax]\r\n        je HIT\r\n        add edx, 1\r\n        jmp SCAN\r\n\r\nHIT:\r\n        mov eax, method_imp[eax]\r\n        pop esi\r\n        pop edi\r\n        mov edx, SUPER_STRET\r\n        mov edx, super_receiver[edx]\r\n        mov SUPER_STRET, edx\r\n        mov edx, kFwdMsgSendStret\r\n        leave\r\n        jmp eax\r\n\r\n        // cache miss: search method lists\r\nMISS:\r\n\r\n        pop esi\r\n        pop edi\r\n        mov eax, SUPER_STRET\r\n        mov edx, super_receiver[eax]\r\n        mov SUPER_STRET, edx\r\n        mov eax, super_class[eax]\r\n\r\n        // MethodTableLookup WORD_RETURN, MSG_SENDSUPER\r\n        push eax\r\n        push ecx\r\n        push edx\r\n        call _class_lookupMethodAndLoadCache3\r\n\r\n        mov edx, kFwdMsgSendStret\r\n        leave\r\n        jmp eax\r\n    }\r\n}\r\n\r\n\r\nOBJC_EXPORT __declspec(naked) id _objc_msgForward(id a, SEL b, ...)\r\n{\r\n    __asm {\r\n        mov ecx, _objc_forward_handler\r\n        jmp ecx\r\n    }\r\n}\r\n\r\nOBJC_EXPORT __declspec(naked) id _objc_msgForward_stret(id a, SEL b, ...)\r\n{\r\n    __asm {\r\n        mov ecx, _objc_forward_stret_handler\r\n        jmp ecx\r\n    }\r\n}\r\n\r\n\r\n__declspec(naked) id _objc_msgForward_cached(id a, SEL b, ...)\r\n{\r\n    __asm {\r\n        cmp edx, kFwdMsgSendStret\r\n        je  STRET\r\n        jmp _objc_msgForward\r\nSTRET:\r\n        jmp _objc_msgForward_stret\r\n    }\r\n}\r\n\r\n\r\nOBJC_EXPORT __declspec(naked) void method_invoke(void)\r\n{\r\n    __asm {\r\n        push ebp\r\n        mov ebp, esp\r\n\r\n        mov ecx, SELECTOR\r\n        mov edx, method_name[ecx]\r\n        mov eax, method_imp[ecx]\r\n        mov SELECTOR, edx\r\n\r\n        leave\r\n        jmp eax\r\n    }\r\n}\r\n\r\n\r\nOBJC_EXPORT __declspec(naked) void method_invoke_stret(void)\r\n{\r\n    __asm {\r\n        push ebp\r\n        mov ebp, esp\r\n\r\n        mov ecx, SELECTOR_STRET\r\n        mov edx, method_name[ecx]\r\n        mov eax, method_imp[ecx]\r\n        mov SELECTOR_STRET, edx\r\n\r\n        leave\r\n        jmp eax\r\n    }\r\n}\r\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/Messengers.subproj/objc-msg-x86_64.s",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include <TargetConditionals.h>\n#if __x86_64__  &&  !(TARGET_OS_SIMULATOR && !TARGET_OS_IOSMAC)\n\n#include \"isa.h\"\n\n/********************************************************************\n ********************************************************************\n **\n **  objc-msg-x86_64.s - x86-64 code to support objc messaging.\n **\n ********************************************************************\n ********************************************************************/\n\n.data\n\n// _objc_entryPoints and _objc_exitPoints are used by objc\n// to get the critical regions for which method caches \n// cannot be garbage collected.\n\n.align 4\n.private_extern\t_objc_entryPoints\n_objc_entryPoints:\n\t.quad\t_cache_getImp\n\t.quad\t_objc_msgSend\n\t.quad\t_objc_msgSend_fpret\n\t.quad\t_objc_msgSend_fp2ret\n\t.quad\t_objc_msgSend_stret\n\t.quad\t_objc_msgSendSuper\n\t.quad\t_objc_msgSendSuper_stret\n\t.quad\t_objc_msgSendSuper2\n\t.quad\t_objc_msgSendSuper2_stret\n\t.quad\t_objc_msgLookup\n\t.quad\t_objc_msgLookup_fpret\n\t.quad\t_objc_msgLookup_fp2ret\n\t.quad\t_objc_msgLookup_stret\n\t.quad\t_objc_msgLookupSuper2\n\t.quad\t_objc_msgLookupSuper2_stret\n\t.quad\t0\n\n.private_extern\t_objc_exitPoints\n_objc_exitPoints:\n\t.quad\tLExit_cache_getImp\n\t.quad\tLExit_objc_msgSend\n\t.quad\tLExit_objc_msgSend_fpret\n\t.quad\tLExit_objc_msgSend_fp2ret\n\t.quad\tLExit_objc_msgSend_stret\n\t.quad\tLExit_objc_msgSendSuper\n\t.quad\tLExit_objc_msgSendSuper_stret\n\t.quad\tLExit_objc_msgSendSuper2\n\t.quad\tLExit_objc_msgSendSuper2_stret\n\t.quad\tLExit_objc_msgLookup\n\t.quad\tLExit_objc_msgLookup_fpret\n\t.quad\tLExit_objc_msgLookup_fp2ret\n\t.quad\tLExit_objc_msgLookup_stret\n\t.quad\tLExit_objc_msgLookupSuper2\n\t.quad\tLExit_objc_msgLookupSuper2_stret\n\t.quad\t0\n\n\n/********************************************************************\n * Recommended multi-byte NOP instructions\n * (Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2B)\n ********************************************************************/\n#define nop1 .byte 0x90\n#define nop2 .byte 0x66,0x90\n#define nop3 .byte 0x0F,0x1F,0x00\n#define nop4 .byte 0x0F,0x1F,0x40,0x00\n#define nop5 .byte 0x0F,0x1F,0x44,0x00,0x00\n#define nop6 .byte 0x66,0x0F,0x1F,0x44,0x00,0x00\n#define nop7 .byte 0x0F,0x1F,0x80,0x00,0x00,0x00,0x00\n#define nop8 .byte 0x0F,0x1F,0x84,0x00,0x00,0x00,0x00,0x00\n#define nop9 .byte 0x66,0x0F,0x1F,0x84,0x00,0x00,0x00,0x00,0x00\n\n\t\n/********************************************************************\n * Harmless branch prefix hint for instruction alignment\n ********************************************************************/\n\t\n#define PN .byte 0x2e\n\n\n/********************************************************************\n * Names for parameter registers.\n ********************************************************************/\n\n#define a1  rdi\n#define a1d edi\n#define a1b dil\n#define a2  rsi\n#define a2d esi\n#define a2b sil\n#define a3  rdx\n#define a3d edx\n#define a4  rcx\n#define a4d ecx\n#define a5  r8\n#define a5d r8d\n#define a6  r9\n#define a6d r9d\n\n\n/********************************************************************\n * Names for relative labels\n * DO NOT USE THESE LABELS ELSEWHERE\n * Reserved labels: 6: 7: 8: 9:\n ********************************************************************/\n#define LCacheMiss \t6\n#define LCacheMiss_f \t6f\n#define LCacheMiss_b \t6b\n#define LNilTestSlow \t7\n#define LNilTestSlow_f \t7f\n#define LNilTestSlow_b \t7b\n#define LGetIsaDone \t8\n#define LGetIsaDone_f \t8f\n#define LGetIsaDone_b \t8b\n#define LGetIsaSlow \t9\n#define LGetIsaSlow_f \t9f\n#define LGetIsaSlow_b \t9b\n\n/********************************************************************\n * Macro parameters\n ********************************************************************/\n\n#define NORMAL 0\n#define FPRET 1\n#define FP2RET 2\n#define STRET 3\n\n#define CALL 100\n#define GETIMP 101\n#define LOOKUP 102\n\n\n/********************************************************************\n *\n * Structure definitions.\n *\n ********************************************************************/\n\n// objc_super parameter to sendSuper\n#define receiver \t0\n#define class \t\t8\n\n// Selected field offsets in class structure\n// #define isa\t\t0    USE GetIsa INSTEAD\n\n// Method descriptor\n#define method_name \t0\n#define method_imp \t16\n\n// Method cache\n#define cached_sel \t0\n#define cached_imp \t8\n\n\n//////////////////////////////////////////////////////////////////////\n//\n// ENTRY\t\tfunctionName\n//\n// Assembly directives to begin an exported function.\n//\n// Takes: functionName - name of the exported function\n//////////////////////////////////////////////////////////////////////\n\n.macro ENTRY\n\t.text\n\t.globl\t$0\n\t.align\t6, 0x90\n$0:\n.endmacro\n\n.macro STATIC_ENTRY\n\t.text\n\t.private_extern\t$0\n\t.align\t2, 0x90\n$0:\n.endmacro\n\n//////////////////////////////////////////////////////////////////////\n//\n// END_ENTRY\tfunctionName\n//\n// Assembly directives to end an exported function.  Just a placeholder,\n// a close-parenthesis for ENTRY, until it is needed for something.\n//\n// Takes: functionName - name of the exported function\n//////////////////////////////////////////////////////////////////////\n\n.macro END_ENTRY\nLExit$0:\n.endmacro\n\n\n /********************************************************************\n * UNWIND name, flags\n * Unwind info generation\t\n ********************************************************************/\n.macro UNWIND\n\t.section __LD,__compact_unwind,regular,debug\n\t.quad $0\n\t.set  LUnwind$0, LExit$0 - $0\n\t.long LUnwind$0\n\t.long $1\n\t.quad 0\t /* no personality */\n\t.quad 0  /* no LSDA */\n\t.text\n.endmacro\n\n#define NoFrame 0x02010000  // no frame, no SP adjustment except return address\n#define FrameWithNoSaves 0x01000000  // frame, no non-volatile saves\n\n\n/////////////////////////////////////////////////////////////////////\n//\n// CacheLookup\treturn-type, caller\n//\n// Locate the implementation for a class in a selector's method cache.\n//\n// Takes: \n//\t  $0 = NORMAL, FPRET, FP2RET, STRET\n//\t  $1 = CALL, LOOKUP, GETIMP\n//\t  a1 or a2 (STRET) = receiver\n//\t  a2 or a3 (STRET) = selector\n//\t  r10 = class to search\n//\n// On exit: r10 clobbered\n//\t    (found) calls or returns IMP in r11, eq/ne set for forwarding\n//\t    (not found) jumps to LCacheMiss, class still in r10\n//\n/////////////////////////////////////////////////////////////////////\n\n.macro CacheHit\n\n\t// CacheHit must always be preceded by a not-taken `jne` instruction\n\t// in order to set the correct flags for _objc_msgForward_impcache.\n\n\t// r11 = found bucket\n\t\n.if $1 == GETIMP\n\tmovq\tcached_imp(%r11), %rax\t// return imp\n\tret\n\n.else\n\n.if $0 != STRET\n\t// eq already set for forwarding by `jne`\n.else\n\ttest\t%r11, %r11\t\t// set ne for stret forwarding\n.endif\n\n.if $1 == CALL\n\tjmp\t*cached_imp(%r11)\t// call imp\n\t\n.elseif $1 == LOOKUP\n\tmovq\tcached_imp(%r11), %r11\t// return imp\n\tret\n\t\n.else\n.abort oops\n.endif\n\n.endif\n\n.endmacro\n\n\n.macro\tCacheLookup\n.if $0 != STRET\n\tmovq\t%a2, %r11\t\t// r11 = _cmd\n.else\n\tmovq\t%a3, %r11\t\t// r11 = _cmd\n.endif\n\tandl\t24(%r10), %r11d\t\t// r11 = _cmd & class->cache.mask\n\tshlq\t$$4, %r11\t\t// r11 = offset = (_cmd & mask)<<4\n\taddq\t16(%r10), %r11\t\t// r11 = class->cache.buckets + offset\n\n.if $0 != STRET\n\tcmpq\tcached_sel(%r11), %a2\t// if (bucket->sel != _cmd)\n.else\n\tcmpq\tcached_sel(%r11), %a3\t// if (bucket->sel != _cmd)\n.endif\n\tjne \t1f\t\t\t//     scan more\n\t// CacheHit must always be preceded by a not-taken `jne` instruction\n\tCacheHit $0, $1\t\t\t// call or return imp\n\n1:\n\t// loop\n\tcmpq\t$$1, cached_sel(%r11)\n\tjbe\t3f\t\t\t// if (bucket->sel <= 1) wrap or miss\n\n\taddq\t$$16, %r11\t\t// bucket++\n2:\t\n.if $0 != STRET\n\tcmpq\tcached_sel(%r11), %a2\t// if (bucket->sel != _cmd)\n.else\n\tcmpq\tcached_sel(%r11), %a3\t// if (bucket->sel != _cmd)\n.endif\n\tjne \t1b\t\t\t//     scan more\n\t// CacheHit must always be preceded by a not-taken `jne` instruction\n\tCacheHit $0, $1\t\t\t// call or return imp\n\n3:\n\t// wrap or miss\n\tjb\tLCacheMiss_f\t\t// if (bucket->sel < 1) cache miss\n\t// wrap\n\tmovq\tcached_imp(%r11), %r11\t// bucket->imp is really first bucket\n\tjmp \t2f\n\n\t// Clone scanning loop to miss instead of hang when cache is corrupt.\n\t// The slow path may detect any corruption and halt later.\n\n1:\n\t// loop\n\tcmpq\t$$1, cached_sel(%r11)\n\tjbe\t3f\t\t\t// if (bucket->sel <= 1) wrap or miss\n\n\taddq\t$$16, %r11\t\t// bucket++\n2:\t\n.if $0 != STRET\n\tcmpq\tcached_sel(%r11), %a2\t// if (bucket->sel != _cmd)\n.else\n\tcmpq\tcached_sel(%r11), %a3\t// if (bucket->sel != _cmd)\n.endif\n\tjne \t1b\t\t\t//     scan more\n\t// CacheHit must always be preceded by a not-taken `jne` instruction\n\tCacheHit $0, $1\t\t\t// call or return imp\n\n3:\n\t// double wrap or miss\n\tjmp\tLCacheMiss_f\n\n.endmacro\n\n\n/////////////////////////////////////////////////////////////////////\n//\n// MethodTableLookup NORMAL|STRET\n//\n// Takes:\ta1 or a2 (STRET) = receiver\n//\t\ta2 or a3 (STRET) = selector to search for\n// \t\tr10 = class to search\n//\n// On exit: imp in %r11, eq/ne set for forwarding\n//\n/////////////////////////////////////////////////////////////////////\n\n.macro MethodTableLookup\n\n\tpush\t%rbp\n\tmov\t%rsp, %rbp\n\t\n\tsub\t$$0x80+8, %rsp\t\t// +8 for alignment\n\n\tmovdqa\t%xmm0, -0x80(%rbp)\n\tpush\t%rax\t\t\t// might be xmm parameter count\n\tmovdqa\t%xmm1, -0x70(%rbp)\n\tpush\t%a1\n\tmovdqa\t%xmm2, -0x60(%rbp)\n\tpush\t%a2\n\tmovdqa\t%xmm3, -0x50(%rbp)\n\tpush\t%a3\n\tmovdqa\t%xmm4, -0x40(%rbp)\n\tpush\t%a4\n\tmovdqa\t%xmm5, -0x30(%rbp)\n\tpush\t%a5\n\tmovdqa\t%xmm6, -0x20(%rbp)\n\tpush\t%a6\n\tmovdqa\t%xmm7, -0x10(%rbp)\n\n\t// _class_lookupMethodAndLoadCache3(receiver, selector, class)\n\n.if $0 == NORMAL\n\t// receiver already in a1\n\t// selector already in a2\n.else\n\tmovq\t%a2, %a1\n\tmovq\t%a3, %a2\n.endif\n\tmovq\t%r10, %a3\n\tcall\t__class_lookupMethodAndLoadCache3\n\n\t// IMP is now in %rax\n\tmovq\t%rax, %r11\n\n\tmovdqa\t-0x80(%rbp), %xmm0\n\tpop\t%a6\n\tmovdqa\t-0x70(%rbp), %xmm1\n\tpop\t%a5\n\tmovdqa\t-0x60(%rbp), %xmm2\n\tpop\t%a4\n\tmovdqa\t-0x50(%rbp), %xmm3\n\tpop\t%a3\n\tmovdqa\t-0x40(%rbp), %xmm4\n\tpop\t%a2\n\tmovdqa\t-0x30(%rbp), %xmm5\n\tpop\t%a1\n\tmovdqa\t-0x20(%rbp), %xmm6\n\tpop\t%rax\n\tmovdqa\t-0x10(%rbp), %xmm7\n\n.if $0 == NORMAL\n\tcmp\t%r11, %r11\t\t// set eq for nonstret forwarding\n.else\n\ttest\t%r11, %r11\t\t// set ne for stret forwarding\n.endif\n\t\n\tleave\n\n.endmacro\n\n\n/////////////////////////////////////////////////////////////////////\n//\n// GetIsaFast return-type\n// GetIsaSupport return-type\n//\n// Sets r10 = obj->isa. Consults the tagged isa table if necessary.\n//\n// Takes:\t$0 = NORMAL or FPRET or FP2RET or STRET\n//\t\ta1 or a2 (STRET) = receiver\n//\n// On exit: \tr10 = receiver->isa\n//\t\tr11 is clobbered\n//\n/////////////////////////////////////////////////////////////////////\n\n.macro GetIsaFast\n.if $0 != STRET\n\ttestb\t$$1, %a1b\n\tPN\n\tjnz\tLGetIsaSlow_f\n\tmovq\t$$ ISA_MASK, %r10\n\tandq\t(%a1), %r10\n.else\n\ttestb\t$$1, %a2b\n\tPN\n\tjnz\tLGetIsaSlow_f\n\tmovq\t$$ ISA_MASK, %r10\n\tandq\t(%a2), %r10\n.endif\nLGetIsaDone:\t\n.endmacro\n\n.macro GetIsaSupport\nLGetIsaSlow:\n.if $0 != STRET\n\tmovl\t%a1d, %r11d\n.else\n\tmovl\t%a2d, %r11d\n.endif\n\tandl\t$$0xF, %r11d\n\t// basic tagged\n\tleaq\t_objc_debug_taggedpointer_classes(%rip), %r10\n\tmovq\t(%r10, %r11, 8), %r10\t// read isa from table\n\tleaq\t_OBJC_CLASS_$___NSUnrecognizedTaggedPointer(%rip), %r11\n\tcmp\t%r10, %r11\n\tjne\tLGetIsaDone_b\n\t// extended tagged\n.if $0 != STRET\n\tmovl\t%a1d, %r11d\n.else\n\tmovl\t%a2d, %r11d\n.endif\n\tshrl\t$$4, %r11d\n\tandl\t$$0xFF, %r11d\n\tleaq\t_objc_debug_taggedpointer_ext_classes(%rip), %r10\n\tmovq\t(%r10, %r11, 8), %r10\t// read isa from table\n\tjmp\tLGetIsaDone_b\n.endmacro\n\n\t\n/////////////////////////////////////////////////////////////////////\n//\n// NilTest return-type\n//\n// Takes:\t$0 = NORMAL or FPRET or FP2RET or STRET\n//\t\t%a1 or %a2 (STRET) = receiver\n//\n// On exit: \tLoads non-nil receiver in %a1 or %a2 (STRET)\n//\t\tor returns.\n//\n// NilTestReturnZero return-type\n//\n// Takes:\t$0 = NORMAL or FPRET or FP2RET or STRET\n//\t\t%a1 or %a2 (STRET) = receiver\n//\n// On exit: \tLoads non-nil receiver in %a1 or %a2 (STRET)\n//\t\tor returns zero.\n//\n// NilTestReturnIMP return-type\n//\n// Takes:\t$0 = NORMAL or FPRET or FP2RET or STRET\n//\t\t%a1 or %a2 (STRET) = receiver\n//\n// On exit: \tLoads non-nil receiver in %a1 or %a2 (STRET)\n//\t\tor returns an IMP in r11 that returns zero.\n//\n/////////////////////////////////////////////////////////////////////\n\n.macro ZeroReturn\n\txorl\t%eax, %eax\n\txorl\t%edx, %edx\n\txorps\t%xmm0, %xmm0\n\txorps\t%xmm1, %xmm1\n.endmacro\n\n.macro ZeroReturnFPRET\n\tfldz\n\tZeroReturn\n.endmacro\n\n.macro ZeroReturnFP2RET\n\tfldz\n\tfldz\n\tZeroReturn\n.endmacro\n\n.macro ZeroReturnSTRET\n\t// rax gets the struct-return address as passed in rdi\n\tmovq\t%rdi, %rax\n.endmacro\n\n\tSTATIC_ENTRY __objc_msgNil\n\tZeroReturn\n\tret\n\tEND_ENTRY __objc_msgNil\n\n\tSTATIC_ENTRY __objc_msgNil_fpret\n\tZeroReturnFPRET\n\tret\n\tEND_ENTRY __objc_msgNil_fpret\n\n\tSTATIC_ENTRY __objc_msgNil_fp2ret\n\tZeroReturnFP2RET\n\tret\n\tEND_ENTRY __objc_msgNil_fp2ret\n\n\tSTATIC_ENTRY __objc_msgNil_stret\n\tZeroReturnSTRET\n\tret\n\tEND_ENTRY __objc_msgNil_stret\n\n\n.macro NilTest\n.if $0 != STRET\n\ttestq\t%a1, %a1\n.else\n\ttestq\t%a2, %a2\n.endif\n\tPN\n\tjz\tLNilTestSlow_f\n.endmacro\n\n\n.macro NilTestReturnZero\n\t.align 3\nLNilTestSlow:\n\t\n.if $0 == NORMAL\n\tZeroReturn\n.elseif $0 == FPRET\n\tZeroReturnFPRET\n.elseif $0 == FP2RET\n\tZeroReturnFP2RET\n.elseif $0 == STRET\n\tZeroReturnSTRET\n.else\n.abort oops\n.endif\n\tret\t\n.endmacro\n\n\n.macro NilTestReturnIMP\n\t.align 3\nLNilTestSlow:\n\t\n.if $0 == NORMAL\n\tleaq\t__objc_msgNil(%rip), %r11\n.elseif $0 == FPRET\n\tleaq\t__objc_msgNil_fpret(%rip), %r11\n.elseif $0 == FP2RET\n\tleaq\t__objc_msgNil_fp2ret(%rip), %r11\n.elseif $0 == STRET\n\tleaq\t__objc_msgNil_stret(%rip), %r11\n.else\n.abort oops\n.endif\n\tret\n.endmacro\n\n\n/********************************************************************\n * IMP cache_getImp(Class cls, SEL sel)\n *\n * On entry:\ta1 = class whose cache is to be searched\n *\t\ta2 = selector to search for\n *\n * If found, returns method implementation.\n * If not found, returns NULL.\n ********************************************************************/\n\n\tSTATIC_ENTRY _cache_getImp\n\n// do lookup\n\tmovq\t%a1, %r10\t\t// move class to r10 for CacheLookup\n\tCacheLookup NORMAL, GETIMP\t// returns IMP on success\n\nLCacheMiss:\n// cache miss, return nil\n\txorl\t%eax, %eax\n\tret\n\n\tEND_ENTRY _cache_getImp\n\n\n/********************************************************************\n *\n * id objc_msgSend(id self, SEL\t_cmd,...);\n * IMP objc_msgLookup(id self, SEL _cmd, ...);\n *\n * objc_msgLookup ABI:\n * IMP returned in r11\n * Forwarding returned in Z flag\n * r10 reserved for our use but not used\n *\n ********************************************************************/\n\t\n\t.data\n\t.align 3\n\t.globl _objc_debug_taggedpointer_classes\n_objc_debug_taggedpointer_classes:\n\t.fill 16, 8, 0\n\t.globl _objc_debug_taggedpointer_ext_classes\n_objc_debug_taggedpointer_ext_classes:\n\t.fill 256, 8, 0\n\n\tENTRY _objc_msgSend\n\tUNWIND _objc_msgSend, NoFrame\n\n\tNilTest\tNORMAL\n\n\tGetIsaFast NORMAL\t\t// r10 = self->isa\n\tCacheLookup NORMAL, CALL\t// calls IMP on success\n\n\tNilTestReturnZero NORMAL\n\n\tGetIsaSupport NORMAL\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgSend_uncached\n\n\tEND_ENTRY _objc_msgSend\n\n\t\n\tENTRY _objc_msgLookup\n\n\tNilTest\tNORMAL\n\n\tGetIsaFast NORMAL\t\t// r10 = self->isa\n\tCacheLookup NORMAL, LOOKUP\t// returns IMP on success\n\n\tNilTestReturnIMP NORMAL\n\n\tGetIsaSupport NORMAL\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgLookup_uncached\n\n\tEND_ENTRY _objc_msgLookup\n\n\t\n\tENTRY _objc_msgSend_fixup\n\tint3\n\tEND_ENTRY _objc_msgSend_fixup\n\n\t\n\tSTATIC_ENTRY _objc_msgSend_fixedup\n\t// Load _cmd from the message_ref\n\tmovq\t8(%a2), %a2\n\tjmp\t_objc_msgSend\n\tEND_ENTRY _objc_msgSend_fixedup\n\n\t\n/********************************************************************\n *\n * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);\n *\n * struct objc_super {\n *\t\tid\treceiver;\n *\t\tClass\tclass;\n * };\n ********************************************************************/\n\t\n\tENTRY _objc_msgSendSuper\n\tUNWIND _objc_msgSendSuper, NoFrame\n\t\n// search the cache (objc_super in %a1)\n\tmovq\tclass(%a1), %r10\t// class = objc_super->class\n\tmovq\treceiver(%a1), %a1\t// load real receiver\n\tCacheLookup NORMAL, CALL\t// calls IMP on success\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// class still in r10\n\tjmp\t__objc_msgSend_uncached\n\t\n\tEND_ENTRY _objc_msgSendSuper\n\n\n/********************************************************************\n * id objc_msgSendSuper2\n ********************************************************************/\n\n\tENTRY _objc_msgSendSuper2\n\tUNWIND _objc_msgSendSuper2, NoFrame\n\t\n\t// objc_super->class is superclass of class to search\n\t\n// search the cache (objc_super in %a1)\n\tmovq\tclass(%a1), %r10\t// cls = objc_super->class\n\tmovq\treceiver(%a1), %a1\t// load real receiver\n\tmovq\t8(%r10), %r10\t\t// cls = class->superclass\n\tCacheLookup NORMAL, CALL\t// calls IMP on success\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// superclass still in r10\n\tjmp\t__objc_msgSend_uncached\n\t\n\tEND_ENTRY _objc_msgSendSuper2\n\n\n\tENTRY _objc_msgLookupSuper2\n\t\n\t// objc_super->class is superclass of class to search\n\t\n// search the cache (objc_super in %a1)\n\tmovq\tclass(%a1), %r10\t// cls = objc_super->class\n\tmovq\treceiver(%a1), %a1\t// load real receiver\n\tmovq\t8(%r10), %r10\t\t// cls = class->superclass\n\tCacheLookup NORMAL, LOOKUP\t// returns IMP on success\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// superclass still in r10\n\tjmp\t__objc_msgLookup_uncached\n\t\n\tEND_ENTRY _objc_msgLookupSuper2\n\n\n\tENTRY _objc_msgSendSuper2_fixup\n\tint3\n\tEND_ENTRY _objc_msgSendSuper2_fixup\n\n\t\n\tSTATIC_ENTRY _objc_msgSendSuper2_fixedup\n\t// Load _cmd from the message_ref\n\tmovq\t8(%a2), %a2\n\tjmp \t_objc_msgSendSuper2\n\tEND_ENTRY _objc_msgSendSuper2_fixedup\n\n\n/********************************************************************\n *\n * double objc_msgSend_fpret(id self, SEL _cmd,...);\n * Used for `long double` return only. `float` and `double` use objc_msgSend.\n *\n ********************************************************************/\n\n\tENTRY _objc_msgSend_fpret\n\tUNWIND _objc_msgSend_fpret, NoFrame\n\t\n\tNilTest\tFPRET\n\n\tGetIsaFast FPRET\t\t// r10 = self->isa\n\tCacheLookup FPRET, CALL\t\t// calls IMP on success\n\n\tNilTestReturnZero FPRET\n\n\tGetIsaSupport FPRET\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgSend_uncached\n\n\tEND_ENTRY _objc_msgSend_fpret\n\n\n\tENTRY _objc_msgLookup_fpret\n\t\n\tNilTest\tFPRET\n\n\tGetIsaFast FPRET\t\t// r10 = self->isa\n\tCacheLookup FPRET, LOOKUP\t// returns IMP on success\n\n\tNilTestReturnIMP FPRET\n\n\tGetIsaSupport FPRET\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgLookup_uncached\n\n\tEND_ENTRY _objc_msgLookup_fpret\n\n\t\n\tENTRY _objc_msgSend_fpret_fixup\n\tint3\n\tEND_ENTRY _objc_msgSend_fpret_fixup\n\n\t\n\tSTATIC_ENTRY _objc_msgSend_fpret_fixedup\n\t// Load _cmd from the message_ref\n\tmovq\t8(%a2), %a2\n\tjmp\t_objc_msgSend_fpret\n\tEND_ENTRY _objc_msgSend_fpret_fixedup\n\n\n/********************************************************************\n *\n * double objc_msgSend_fp2ret(id self, SEL _cmd,...);\n * Used for `complex long double` return only.\n *\n ********************************************************************/\n\n\tENTRY _objc_msgSend_fp2ret\n\tUNWIND _objc_msgSend_fp2ret, NoFrame\n\t\n\tNilTest\tFP2RET\n\n\tGetIsaFast FP2RET\t\t// r10 = self->isa\n\tCacheLookup FP2RET, CALL\t// calls IMP on success\n\n\tNilTestReturnZero FP2RET\n\n\tGetIsaSupport FP2RET\n\t\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgSend_uncached\n\n\tEND_ENTRY _objc_msgSend_fp2ret\n\n\n\tENTRY _objc_msgLookup_fp2ret\n\t\n\tNilTest\tFP2RET\n\n\tGetIsaFast FP2RET\t\t// r10 = self->isa\n\tCacheLookup FP2RET, LOOKUP\t// returns IMP on success\n\n\tNilTestReturnIMP FP2RET\n\n\tGetIsaSupport FP2RET\n\t\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgLookup_uncached\n\n\tEND_ENTRY _objc_msgLookup_fp2ret\n\n\n\tENTRY _objc_msgSend_fp2ret_fixup\n\tint3\n\tEND_ENTRY _objc_msgSend_fp2ret_fixup\n\n\t\n\tSTATIC_ENTRY _objc_msgSend_fp2ret_fixedup\n\t// Load _cmd from the message_ref\n\tmovq\t8(%a2), %a2\n\tjmp\t_objc_msgSend_fp2ret\n\tEND_ENTRY _objc_msgSend_fp2ret_fixedup\n\n\n/********************************************************************\n *\n * void\tobjc_msgSend_stret(void *st_addr, id self, SEL _cmd, ...);\n *\n * objc_msgSend_stret is the struct-return form of msgSend.\n * The ABI calls for %a1 to be used as the address of the structure\n * being returned, with the parameters in the succeeding locations.\n *\n * On entry:\t%a1 is the address where the structure is returned,\n *\t\t%a2 is the message receiver,\n *\t\t%a3 is the selector\n ********************************************************************/\n\n\tENTRY _objc_msgSend_stret\n\tUNWIND _objc_msgSend_stret, NoFrame\n\t\n\tNilTest\tSTRET\n\n\tGetIsaFast STRET\t\t// r10 = self->isa\n\tCacheLookup STRET, CALL\t\t// calls IMP on success\n\n\tNilTestReturnZero STRET\n\n\tGetIsaSupport STRET\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgSend_stret_uncached\n\n\tEND_ENTRY _objc_msgSend_stret\n\n\n\tENTRY _objc_msgLookup_stret\n\t\n\tNilTest\tSTRET\n\n\tGetIsaFast STRET\t\t// r10 = self->isa\n\tCacheLookup STRET, LOOKUP\t// returns IMP on success\n\n\tNilTestReturnIMP STRET\n\n\tGetIsaSupport STRET\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// isa still in r10\n\tjmp\t__objc_msgLookup_stret_uncached\n\n\tEND_ENTRY _objc_msgLookup_stret\n\n\n\tENTRY _objc_msgSend_stret_fixup\n\tint3\n\tEND_ENTRY _objc_msgSend_stret_fixup\n\n\n\tSTATIC_ENTRY _objc_msgSend_stret_fixedup\n\t// Load _cmd from the message_ref\n\tmovq\t8(%a3), %a3\n\tjmp\t_objc_msgSend_stret\n\tEND_ENTRY _objc_msgSend_stret_fixedup\n\n\n/********************************************************************\n *\n * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);\n *\n * struct objc_super {\n *\t\tid\treceiver;\n *\t\tClass\tclass;\n * };\n *\n * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.\n * The ABI calls for (sp+4) to be used as the address of the structure\n * being returned, with the parameters in the succeeding registers.\n *\n * On entry:\t%a1 is the address where the structure is returned,\n *\t\t%a2 is the address of the objc_super structure,\n *\t\t%a3 is the selector\n *\n ********************************************************************/\n\n\tENTRY _objc_msgSendSuper_stret\n\tUNWIND _objc_msgSendSuper_stret, NoFrame\n\t\n// search the cache (objc_super in %a2)\n\tmovq\tclass(%a2), %r10\t// class = objc_super->class\n\tmovq\treceiver(%a2), %a2\t// load real receiver\n\tCacheLookup STRET, CALL\t\t// calls IMP on success\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// class still in r10\n\tjmp\t__objc_msgSend_stret_uncached\n\t\n\tEND_ENTRY _objc_msgSendSuper_stret\n\n\n/********************************************************************\n * id objc_msgSendSuper2_stret\n ********************************************************************/\n\n\tENTRY _objc_msgSendSuper2_stret\n\tUNWIND _objc_msgSendSuper2_stret, NoFrame\n\t\n// search the cache (objc_super in %a2)\n\tmovq\tclass(%a2), %r10\t// class = objc_super->class\n\tmovq\treceiver(%a2), %a2\t// load real receiver\n\tmovq\t8(%r10), %r10\t\t// class = class->superclass\n\tCacheLookup STRET, CALL\t\t// calls IMP on success\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// superclass still in r10\n\tjmp\t__objc_msgSend_stret_uncached\n\n\tEND_ENTRY _objc_msgSendSuper2_stret\n\n\n\tENTRY _objc_msgLookupSuper2_stret\n\t\n// search the cache (objc_super in %a2)\n\tmovq\tclass(%a2), %r10\t// class = objc_super->class\n\tmovq\treceiver(%a2), %a2\t// load real receiver\n\tmovq\t8(%r10), %r10\t\t// class = class->superclass\n\tCacheLookup STRET, LOOKUP\t// returns IMP on success\n\n// cache miss: go search the method lists\nLCacheMiss:\n\t// superclass still in r10\n\tjmp\t__objc_msgLookup_stret_uncached\n\n\tEND_ENTRY _objc_msgLookupSuper2_stret\n\n\t\n\tENTRY _objc_msgSendSuper2_stret_fixup\n\tint3\n\tEND_ENTRY _objc_msgSendSuper2_stret_fixup\n\n\t\n\tSTATIC_ENTRY _objc_msgSendSuper2_stret_fixedup\n\t// Load _cmd from the message_ref\n\tmovq\t8(%a3), %a3\n\tjmp\t_objc_msgSendSuper2_stret\n\tEND_ENTRY _objc_msgSendSuper2_stret_fixedup\n\n\n/********************************************************************\n *\n * _objc_msgSend_uncached\n * _objc_msgSend_stret_uncached\n * _objc_msgLookup_uncached\n * _objc_msgLookup_stret_uncached\n *\n * The uncached method lookup.\n *\n ********************************************************************/\n\n\tSTATIC_ENTRY __objc_msgSend_uncached\n\tUNWIND __objc_msgSend_uncached, FrameWithNoSaves\n\t\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band r10 is the searched class\n\n\t// r10 is already the class to search\n\tMethodTableLookup NORMAL\t// r11 = IMP\n\tjmp\t*%r11\t\t\t// goto *imp\n\n\tEND_ENTRY __objc_msgSend_uncached\n\n\t\n\tSTATIC_ENTRY __objc_msgSend_stret_uncached\n\tUNWIND __objc_msgSend_stret_uncached, FrameWithNoSaves\n\t\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band r10 is the searched class\n\n\t// r10 is already the class to search\n\tMethodTableLookup STRET\t\t// r11 = IMP\n\tjmp\t*%r11\t\t\t// goto *imp\n\n\tEND_ENTRY __objc_msgSend_stret_uncached\n\n\t\n\tSTATIC_ENTRY __objc_msgLookup_uncached\n\tUNWIND __objc_msgLookup_uncached, FrameWithNoSaves\n\t\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band r10 is the searched class\n\n\t// r10 is already the class to search\n\tMethodTableLookup NORMAL\t// r11 = IMP\n\tret\n\n\tEND_ENTRY __objc_msgLookup_uncached\n\n\t\n\tSTATIC_ENTRY __objc_msgLookup_stret_uncached\n\tUNWIND __objc_msgLookup_stret_uncached, FrameWithNoSaves\n\t\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band r10 is the searched class\n\n\t// r10 is already the class to search\n\tMethodTableLookup STRET\t\t// r11 = IMP\n\tret\n\n\tEND_ENTRY __objc_msgLookup_stret_uncached\n\n\t\n/********************************************************************\n*\n* id _objc_msgForward(id self, SEL _cmd,...);\n*\n* _objc_msgForward and _objc_msgForward_stret are the externally-callable\n*   functions returned by things like method_getImplementation().\n* _objc_msgForward_impcache is the function pointer actually stored in\n*   method caches.\n*\n********************************************************************/\n\n\tSTATIC_ENTRY __objc_msgForward_impcache\n\t// Method cache version\n\n\t// THIS IS NOT A CALLABLE C FUNCTION\n\t// Out-of-band condition register is NE for stret, EQ otherwise.\n\t\n\tjne\t__objc_msgForward_stret\n\tjmp\t__objc_msgForward\n\n\tEND_ENTRY __objc_msgForward_impcache\n\t\n\t\n\tENTRY __objc_msgForward\n\t// Non-stret version\n\n\tmovq\t__objc_forward_handler(%rip), %r11\n\tjmp\t*%r11\n\n\tEND_ENTRY __objc_msgForward\n\n\n\tENTRY __objc_msgForward_stret\n\t// Struct-return version\n\n\tmovq\t__objc_forward_stret_handler(%rip), %r11\n\tjmp\t*%r11\n\n\tEND_ENTRY __objc_msgForward_stret\n\n\n\tENTRY _objc_msgSend_debug\n\tjmp\t_objc_msgSend\n\tEND_ENTRY _objc_msgSend_debug\n\n\tENTRY _objc_msgSendSuper2_debug\n\tjmp\t_objc_msgSendSuper2\n\tEND_ENTRY _objc_msgSendSuper2_debug\n\n\tENTRY _objc_msgSend_stret_debug\n\tjmp\t_objc_msgSend_stret\n\tEND_ENTRY _objc_msgSend_stret_debug\n\n\tENTRY _objc_msgSendSuper2_stret_debug\n\tjmp\t_objc_msgSendSuper2_stret\n\tEND_ENTRY _objc_msgSendSuper2_stret_debug\n\n\tENTRY _objc_msgSend_fpret_debug\n\tjmp\t_objc_msgSend_fpret\n\tEND_ENTRY _objc_msgSend_fpret_debug\n\n\tENTRY _objc_msgSend_fp2ret_debug\n\tjmp\t_objc_msgSend_fp2ret\n\tEND_ENTRY _objc_msgSend_fp2ret_debug\n\n\n\tENTRY _objc_msgSend_noarg\n\tjmp\t_objc_msgSend\n\tEND_ENTRY _objc_msgSend_noarg\n\n\n\tENTRY _method_invoke\n\n\tmovq\tmethod_imp(%a2), %r11\n\tmovq\tmethod_name(%a2), %a2\n\tjmp\t*%r11\n\t\n\tEND_ENTRY _method_invoke\n\n\n\tENTRY _method_invoke_stret\n\n\tmovq\tmethod_imp(%a3), %r11\n\tmovq\tmethod_name(%a3), %a3\n\tjmp\t*%r11\n\t\n\tEND_ENTRY _method_invoke_stret\n\n\n.section __DATA,__objc_msg_break\n.quad 0\n.quad 0\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/Module/ObjectiveC.apinotes",
    "content": "---\nName: ObjectiveC\nClasses:\n- Name: NSArray\n  SwiftBridge: 'Swift.Array'\n- Name: NSDictionary\n  SwiftBridge: 'Swift.Dictionary'\n- Name: NSSet\n  SwiftBridge: 'Swift.Set'\n- Name: NSString\n  SwiftBridge: 'Swift.String'\n- Name: List\n  Methods:\n  - Selector: init\n    MethodKind: Instance\n    NullabilityOfRet: N\n  - Selector: 'isEqual:'\n    MethodKind: Instance\n    Nullability:\n    - O\n    NullabilityOfRet: S\n- Name: NSObject\n  SwiftName: NSObject\n  Methods:\n  - Selector: alloc\n    MethodKind: Class\n    NullabilityOfRet: N\n  - Selector: 'allocWithZone:'\n    MethodKind: Class\n    Nullability:\n    - S\n    NullabilityOfRet: N\n  - Selector: class\n    MethodKind: Class\n    Availability: nonswift\n    AvailabilityMsg: use 'self' instead\n  - Selector: 'conformsToProtocol:'\n    MethodKind: Class\n    Nullability:\n    - N\n    NullabilityOfRet: S\n  - Selector: copy\n    MethodKind: Instance\n    NullabilityOfRet: N\n  - Selector: dealloc\n    MethodKind: Instance\n    Availability: nonswift\n    AvailabilityMsg: use 'deinit' to define a de-initializer\n  - Selector: debugDescription\n    MethodKind: Class\n    NullabilityOfRet: N\n  - Selector: description\n    MethodKind: Class\n    NullabilityOfRet: N\n  - Selector: 'forwardingTargetForSelector:'\n    MethodKind: Instance\n    Nullability:\n    - S\n    NullabilityOfRet: O\n  - Selector: 'forwardInvocation:'\n    MethodKind: Instance\n    Availability: nonswift\n  - Selector: init\n    MethodKind: Instance\n    NullabilityOfRet: N\n    DesignatedInit: true\n  - Selector: 'instanceMethodSignatureForSelector:'\n    MethodKind: Class\n    Availability: nonswift\n  - Selector: 'isSubclassOfClass:'\n    MethodKind: Class\n    Nullability:\n    - N\n    NullabilityOfRet: S\n  - Selector: 'methodSignatureForSelector:'\n    MethodKind: Instance\n    Availability: nonswift\n  - Selector: mutableCopy\n    MethodKind: Instance\n    NullabilityOfRet: N\n  - Selector: new\n    MethodKind: Class\n    NullabilityOfRet: N\n  - Selector: superclass\n    MethodKind: Class\n    NullabilityOfRet: O\n- Name: Object\n  Methods:\n  - Selector: init\n    MethodKind: Instance\n    NullabilityOfRet: N\n  - Selector: 'isEqual:'\n    MethodKind: Instance\n    Nullability:\n    - O\n    NullabilityOfRet: S\nProtocols:\n- Name: NSObject\n  SwiftName: NSObjectProtocol\n  Methods:\n  - Selector: class\n    MethodKind: Instance\n    Availability: nonswift\n    AvailabilityMsg: use 'type(of:)' instead\n  - Selector: 'conformsToProtocol:'\n    MethodKind: Instance\n    Nullability:\n    - N\n    NullabilityOfRet: S\n  - Selector: 'isEqual:'\n    MethodKind: Instance\n    Nullability:\n    - O\n    NullabilityOfRet: S\n  - Selector: 'isKindOfClass:'\n    MethodKind: Instance\n    Nullability:\n    - N\n    NullabilityOfRet: S\n  - Selector: 'isMemberOfClass:'\n    MethodKind: Instance\n    Nullability:\n    - N\n    NullabilityOfRet: S\n  - Selector: self\n    MethodKind: Instance\n    NullabilityOfRet: N\n  Properties:\n  - Name: debugDescription\n    Nullability: N\n  - Name: description\n    Nullability: N\n  - Name: superclass\n    Nullability: O\nTags:\n- Name: _NSZone\n  SwiftName: _NSZone\n\n\n# Runtime functions did not yet have nullability in Swift 3.\n\nSwiftVersions:\n- Version: 3\n  Functions:\n  # objc.h swift3\n  - Name: object_getClassName\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: sel_isMapped\n    Nullability: [U]\n  - Name: sel_getUid\n    NullabilityOfRet: U\n    Nullability: [U]\n\n  # objc-exception.h swift3\n  - Name: objc_exception_throw\n    Nullability: [U]\n  - Name: objc_begin_catch\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: objc_setExceptionPreprocessor\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: objc_setExceptionMatcher\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: objc_setUncaughtExceptionHandler\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: objc_addExceptionHandler\n    Nullability: [U, U]\n\n  # objc-sync.h swift3\n  - Name: objc_sync_enter\n    Nullability: [U]\n  - Name: objc_sync_exit\n    Nullability: [U]\n\n  # runtime.h swift3\n  - Name: object_getClass\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: object_setClass\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: object_isClass\n    Nullability: [U]\n  - Name: object_getIvar\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: object_setIvar\n    Nullability: [U, U, U]\n  - Name: object_setIvarWithStrongDefault\n    Nullability: [U, U, U]\n  - Name: objc_getClass\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: objc_getMetaClass\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: objc_lookUpClass\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: objc_getRequiredClass\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: objc_getClassList\n    Parameters:\n    - Position: 0\n      Type: \"Class _Nullable * _Null_unspecified\"\n  - Name: objc_copyClassList\n    ResultType: \"Class _Nullable * _Null_unspecified\"\n    Nullability: [U]\n  - Name: class_getName\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: class_isMetaClass\n    Nullability: [U]\n  - Name: class_getSuperclass\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: class_getVersion\n    Nullability: [U]\n  - Name: class_setVersion\n    Nullability: [U]\n  - Name: class_getInstanceSize\n    Nullability: [U]\n  - Name: class_getInstanceVariable\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: class_getClassVariable\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: class_copyIvarList\n    ResultType: \"Ivar _Nullable * _Null_unspecified\"\n    Nullability: [U, U]\n  - Name: class_getInstanceMethod\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: class_getClassMethod\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: class_getMethodImplementation\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: class_getMethodImplementation_stret\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: class_respondsToSelector\n    Nullability: [U, U]\n  - Name: class_copyMethodList\n    Nullability: [U, U]\n    ResultType: \"Method _Nullable * _Null_unspecified\"\n  - Name: class_conformsToProtocol\n    Nullability: [U, U]\n  - Name: class_copyProtocolList\n# fixme ResultType:\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: class_getProperty\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: class_copyPropertyList\n    ResultType: \"objc_property_t _Nullable * _Null_unspecified\"\n    Nullability: [U, U]\n  - Name: class_getIvarLayout\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: class_getWeakIvarLayout\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: class_addMethod\n    Nullability: [U, U, U, U]\n  - Name: class_replaceMethod\n    NullabilityOfRet: U\n    Nullability: [U, U, U, U]\n  - Name: class_addIvar\n    Nullability: [U, U, U, U, U]\n  - Name: class_addProtocol\n    Nullability: [U, U]\n  - Name: class_addProperty\n    Nullability: [U, U, U, U]\n  - Name: class_replaceProperty\n    Nullability: [U, U, U, U]\n  - Name: class_setIvarLayout\n    Nullability: [U, U]\n  - Name: class_setWeakIvarLayout\n    Nullability: [U, U]\n  - Name: class_createInstance\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: objc_allocateClassPair\n    NullabilityOfRet: U\n    Nullability: [U, U, U]\n  - Name: objc_registerClassPair\n    Nullability: [U]\n  - Name: objc_duplicateClass\n    NullabilityOfRet: U\n    Nullability: [U, U, U]\n  - Name: objc_disposeClassPair\n    Nullability: [U]\n  - Name: method_getName\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: method_getImplementation\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: method_getTypeEncoding\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: method_getNumberOfArguments\n    Nullability: [U]\n  - Name: method_copyReturnType\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: method_copyArgumentType\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: method_getReturnType\n    Nullability: [U, U, U]\n  - Name: method_getArgumentType\n    Nullability: [U, U, U, U]\n  - Name: method_getDescription\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: method_setImplementation\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: method_exchangeImplementations\n    Nullability: [U, U]\n  - Name: ivar_getName\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: ivar_getTypeEncoding\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: ivar_getOffset\n    Nullability: [U]\n  - Name: property_getName\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: property_getAttributes\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: property_copyAttributeList\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: property_copyAttributeValue\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: objc_getProtocol\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: objc_copyProtocolList\n# fixme ResultType:\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: protocol_conformsToProtocol\n    Nullability: [U, U]\n  - Name: protocol_isEqual\n    Nullability: [U, U]\n  - Name: protocol_getName\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: protocol_getMethodDescription\n    Nullability: [U, U, U, U]\n  - Name: protocol_copyMethodDescriptionList\n    NullabilityOfRet: U\n    Nullability: [U, U, U, U]\n  - Name: protocol_getProperty\n    NullabilityOfRet: U\n    Nullability: [U, U, U, U]\n  - Name: protocol_copyPropertyList\n    ResultType: \"objc_property_t _Nullable * _Null_unspecified\"\n    Nullability: [U, U]\n  - Name: protocol_copyPropertyList2\n    ResultType: \"objc_property_t _Nullable * _Null_unspecified\"\n    Nullability: [U, U, U, U]\n  - Name: protocol_copyProtocolList\n# fixme ResultType:\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: objc_allocateProtocol\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: objc_registerProtocol\n    Nullability: [U]\n  - Name: protocol_addMethodDescription\n    Nullability: [U, U, U, U, U]\n  - Name: protocol_addProtocol\n    Nullability: [U, U]\n  - Name: protocol_addProperty\n    Nullability: [U, U, U, U, U, U]\n  - Name: objc_copyImageNames\n    ResultType: \"const char * _Nullable * _Null_unspecified\"\n    Nullability: [U]\n  - Name: class_getImageName\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: objc_copyClassNamesForImage\n    ResultType: \"const char * _Nullable * _Null_unspecified\"\n    Nullability: [U, U]\n  - Name: sel_getName\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: sel_registerName\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: sel_isEqual\n    Nullability: [U, U]\n  - Name: objc_enumerationMutation\n    Nullability: [U]\n  - Name: objc_setEnumerationMutationHandler\n    Nullability: [U]\n  - Name: objc_setForwardHandler\n    Nullability: [U, U]\n  - Name: imp_implementationWithBlock\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: imp_getBlock\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: imp_removeBlock\n    Nullability: [U]\n  - Name: objc_loadWeak\n    NullabilityOfRet: U\n    Nullability: [U]\n  - Name: objc_storeWeak\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: objc_setAssociatedObject\n    Nullability: [U, U, U, U]\n  - Name: objc_getAssociatedObject\n    NullabilityOfRet: U\n    Nullability: [U, U]\n  - Name: objc_removeAssociatedObjects\n    Nullability: [U]\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/Module/module.modulemap",
    "content": "module ObjectiveC [system] [extern_c] {\n  umbrella \".\"\n  export *\n  module * { \n    export *\n  }\n\n  module NSObject {\n    requires objc\n    header \"NSObject.h\"\n    export *\n  }\n\n#if defined(BUILD_FOR_OSX)\n  module List {\n    // Uses @defs, which does not work in ObjC++ or non-ARC.\n    requires objc, !objc_arc, !cplusplus\n    header \"List.h\"\n    export *\n  }\n\n  module Object {\n    requires objc\n    header \"Object.h\"\n    export *\n  }\n\n  module Protocol {\n    requires objc\n    header \"Protocol.h\"\n    export *\n  }\n#endif\n\n#if !defined(BUILD_FOR_OSX)\n  // These file are not available outside macOS.\n  exclude header \"hashtable.h\"\n  exclude header \"hashtable2.h\"\n#endif\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/NSObjCRuntime.h",
    "content": "/*\tNSObjCRuntime.h\n\tCopyright (c) 1994-2012, Apple Inc. All rights reserved.\n*/\n\n#ifndef _OBJC_NSOBJCRUNTIME_H_\n#define _OBJC_NSOBJCRUNTIME_H_\n\n#include <TargetConditionals.h>\n#include <objc/objc.h>\n\n#if __LP64__ || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64\ntypedef long NSInteger;\ntypedef unsigned long NSUInteger;\n#else\ntypedef int NSInteger;\ntypedef unsigned int NSUInteger;\n#endif\n\n#define NSIntegerMax    LONG_MAX\n#define NSIntegerMin    LONG_MIN\n#define NSUIntegerMax   ULONG_MAX\n\n#define NSINTEGER_DEFINED 1\n\n#ifndef NS_DESIGNATED_INITIALIZER\n#if __has_attribute(objc_designated_initializer)\n#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))\n#else\n#define NS_DESIGNATED_INITIALIZER\n#endif\n#endif\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/NSObject.h",
    "content": "/*\tNSObject.h\n\tCopyright (c) 1994-2012, Apple Inc. All rights reserved.\n*/\n\n#ifndef _OBJC_NSOBJECT_H_\n#define _OBJC_NSOBJECT_H_\n\n#if __OBJC__\n\n#include <objc/objc.h>\n#include <objc/NSObjCRuntime.h>\n\n@class NSString, NSMethodSignature, NSInvocation;\n\n@protocol NSObject\n\n- (BOOL)isEqual:(id)object;\n@property (readonly) NSUInteger hash;\n\n@property (readonly) Class superclass;\n- (Class)class OBJC_SWIFT_UNAVAILABLE(\"use 'type(of: anObject)' instead\");\n- (instancetype)self;\n\n- (id)performSelector:(SEL)aSelector;\n- (id)performSelector:(SEL)aSelector withObject:(id)object;\n- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;\n\n- (BOOL)isProxy;\n\n- (BOOL)isKindOfClass:(Class)aClass;\n- (BOOL)isMemberOfClass:(Class)aClass;\n- (BOOL)conformsToProtocol:(Protocol *)aProtocol;\n\n- (BOOL)respondsToSelector:(SEL)aSelector;\n\n- (instancetype)retain OBJC_ARC_UNAVAILABLE;\n- (oneway void)release OBJC_ARC_UNAVAILABLE;\n- (instancetype)autorelease OBJC_ARC_UNAVAILABLE;\n- (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;\n\n- (struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;\n\n@property (readonly, copy) NSString *description;\n@optional\n@property (readonly, copy) NSString *debugDescription;\n\n@end\n\n\nOBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)\nOBJC_ROOT_CLASS\nOBJC_EXPORT\n@interface NSObject <NSObject> {\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wobjc-interface-ivars\"\n    Class isa  OBJC_ISA_AVAILABILITY;\n#pragma clang diagnostic pop\n}\n\n+ (void)load;\n\n+ (void)initialize;\n- (instancetype)init\n#if NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER\n    NS_DESIGNATED_INITIALIZER\n#endif\n    ;\n\n+ (instancetype)new OBJC_SWIFT_UNAVAILABLE(\"use object initializers instead\");\n+ (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE(\"use object initializers instead\");\n+ (instancetype)alloc OBJC_SWIFT_UNAVAILABLE(\"use object initializers instead\");\n- (void)dealloc OBJC_SWIFT_UNAVAILABLE(\"use 'deinit' to define a de-initializer\");\n\n- (void)finalize OBJC_DEPRECATED(\"Objective-C garbage collection is no longer supported\");\n\n- (id)copy;\n- (id)mutableCopy;\n\n+ (id)copyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;\n+ (id)mutableCopyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;\n\n+ (BOOL)instancesRespondToSelector:(SEL)aSelector;\n+ (BOOL)conformsToProtocol:(Protocol *)protocol;\n- (IMP)methodForSelector:(SEL)aSelector;\n+ (IMP)instanceMethodForSelector:(SEL)aSelector;\n- (void)doesNotRecognizeSelector:(SEL)aSelector;\n\n- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE(\"\");\n- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE(\"\");\n\n+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE(\"\");\n\n- (BOOL)allowsWeakReference UNAVAILABLE_ATTRIBUTE;\n- (BOOL)retainWeakReference UNAVAILABLE_ATTRIBUTE;\n\n+ (BOOL)isSubclassOfClass:(Class)aClass;\n\n+ (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n+ (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n+ (NSUInteger)hash;\n+ (Class)superclass;\n+ (Class)class OBJC_SWIFT_UNAVAILABLE(\"use 'aClass.self' instead\");\n+ (NSString *)description;\n+ (NSString *)debugDescription;\n\n@end\n\n#endif\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/NSObject.mm",
    "content": "/*\n * Copyright (c) 2010-2012 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"objc-private.h\"\n#include \"NSObject.h\"\n\n#include \"objc-weak.h\"\n#include \"llvm-DenseMap.h\"\n#include \"NSObject.h\"\n\n#include <malloc/malloc.h>\n#include <stdint.h>\n#include <stdbool.h>\n#include <mach/mach.h>\n#include <mach-o/dyld.h>\n#include <mach-o/nlist.h>\n#include <sys/types.h>\n#include <sys/mman.h>\n#include <libkern/OSAtomic.h>\n#include <Block.h>\n#include <map>\n#include <execinfo.h>\n\n@interface NSInvocation\n- (SEL)selector;\n@end\n\n\n/***********************************************************************\n* Weak ivar support\n**********************************************************************/\n\nstatic id defaultBadAllocHandler(Class cls)\n{\n    _objc_fatal(\"attempt to allocate object of class '%s' failed\", \n                cls->nameForLogging());\n}\n\nstatic id(*badAllocHandler)(Class) = &defaultBadAllocHandler;\n\nstatic id callBadAllocHandler(Class cls)\n{\n    // fixme add re-entrancy protection in case allocation fails inside handler\n    return (*badAllocHandler)(cls);\n}\n\nvoid _objc_setBadAllocHandler(id(*newHandler)(Class))\n{\n    badAllocHandler = newHandler;\n}\n\n\nnamespace {\n\n// The order of these bits is important.\n#define SIDE_TABLE_WEAKLY_REFERENCED (1UL<<0)\n#define SIDE_TABLE_DEALLOCATING      (1UL<<1)  // MSB-ward of weak bit\n#define SIDE_TABLE_RC_ONE            (1UL<<2)  // MSB-ward of deallocating bit\n#define SIDE_TABLE_RC_PINNED         (1UL<<(WORD_BITS-1))\n\n#define SIDE_TABLE_RC_SHIFT 2\n#define SIDE_TABLE_FLAG_MASK (SIDE_TABLE_RC_ONE-1)\n\n// RefcountMap disguises its pointers because we \n// don't want the table to act as a root for `leaks`.\ntypedef objc::DenseMap<DisguisedPtr<objc_object>,size_t,true> RefcountMap;\n\n// Template parameters.\nenum HaveOld { DontHaveOld = false, DoHaveOld = true };\nenum HaveNew { DontHaveNew = false, DoHaveNew = true };\n\nstruct SideTable {\n    spinlock_t slock;\n    RefcountMap refcnts;\n    weak_table_t weak_table;\n\n    SideTable() {\n        memset(&weak_table, 0, sizeof(weak_table));\n    }\n\n    ~SideTable() {\n        _objc_fatal(\"Do not delete SideTable.\");\n    }\n\n    void lock() { slock.lock(); }\n    void unlock() { slock.unlock(); }\n    void forceReset() { slock.forceReset(); }\n\n    // Address-ordered lock discipline for a pair of side tables.\n\n    template<HaveOld, HaveNew>\n    static void lockTwo(SideTable *lock1, SideTable *lock2);\n    template<HaveOld, HaveNew>\n    static void unlockTwo(SideTable *lock1, SideTable *lock2);\n};\n\n\ntemplate<>\nvoid SideTable::lockTwo<DoHaveOld, DoHaveNew>\n    (SideTable *lock1, SideTable *lock2)\n{\n    spinlock_t::lockTwo(&lock1->slock, &lock2->slock);\n}\n\ntemplate<>\nvoid SideTable::lockTwo<DoHaveOld, DontHaveNew>\n    (SideTable *lock1, SideTable *)\n{\n    lock1->lock();\n}\n\ntemplate<>\nvoid SideTable::lockTwo<DontHaveOld, DoHaveNew>\n    (SideTable *, SideTable *lock2)\n{\n    lock2->lock();\n}\n\ntemplate<>\nvoid SideTable::unlockTwo<DoHaveOld, DoHaveNew>\n    (SideTable *lock1, SideTable *lock2)\n{\n    spinlock_t::unlockTwo(&lock1->slock, &lock2->slock);\n}\n\ntemplate<>\nvoid SideTable::unlockTwo<DoHaveOld, DontHaveNew>\n    (SideTable *lock1, SideTable *)\n{\n    lock1->unlock();\n}\n\ntemplate<>\nvoid SideTable::unlockTwo<DontHaveOld, DoHaveNew>\n    (SideTable *, SideTable *lock2)\n{\n    lock2->unlock();\n}\n\n\n// We cannot use a C++ static initializer to initialize SideTables because\n// libc calls us before our C++ initializers run. We also don't want a global \n// pointer to this struct because of the extra indirection.\n// Do it the hard way.\nalignas(StripedMap<SideTable>) static uint8_t \n    SideTableBuf[sizeof(StripedMap<SideTable>)];\n\nstatic void SideTableInit() {\n    new (SideTableBuf) StripedMap<SideTable>();\n}\n\nstatic StripedMap<SideTable>& SideTables() {\n    return *reinterpret_cast<StripedMap<SideTable>*>(SideTableBuf);\n}\n\n// anonymous namespace\n};\n\nvoid SideTableLockAll() {\n    SideTables().lockAll();\n}\n\nvoid SideTableUnlockAll() {\n    SideTables().unlockAll();\n}\n\nvoid SideTableForceResetAll() {\n    SideTables().forceResetAll();\n}\n\nvoid SideTableDefineLockOrder() {\n    SideTables().defineLockOrder();\n}\n\nvoid SideTableLocksPrecedeLock(const void *newlock) {\n    SideTables().precedeLock(newlock);\n}\n\nvoid SideTableLocksSucceedLock(const void *oldlock) {\n    SideTables().succeedLock(oldlock);\n}\n\nvoid SideTableLocksPrecedeLocks(StripedMap<spinlock_t>& newlocks) {\n    int i = 0;\n    const void *newlock;\n    while ((newlock = newlocks.getLock(i++))) {\n        SideTables().precedeLock(newlock);\n    }\n}\n\nvoid SideTableLocksSucceedLocks(StripedMap<spinlock_t>& oldlocks) {\n    int i = 0;\n    const void *oldlock;\n    while ((oldlock = oldlocks.getLock(i++))) {\n        SideTables().succeedLock(oldlock);\n    }\n}\n\n//\n// The -fobjc-arc flag causes the compiler to issue calls to objc_{retain/release/autorelease/retain_block}\n//\n\nid objc_retainBlock(id x) {\n    return (id)_Block_copy(x);\n}\n\n//\n// The following SHOULD be called by the compiler directly, but the request hasn't been made yet :-)\n//\n\nBOOL objc_should_deallocate(id object) {\n    return YES;\n}\n\nid\nobjc_retain_autorelease(id obj)\n{\n    return objc_autorelease(objc_retain(obj));\n}\n\n\nvoid\nobjc_storeStrong(id *location, id obj)\n{\n    id prev = *location;\n    if (obj == prev) {\n        return;\n    }\n    objc_retain(obj);\n    *location = obj;\n    objc_release(prev);\n}\n\n\n// Update a weak variable.\n// If HaveOld is true, the variable has an existing value \n//   that needs to be cleaned up. This value might be nil.\n// If HaveNew is true, there is a new value that needs to be \n//   assigned into the variable. This value might be nil.\n// If CrashIfDeallocating is true, the process is halted if newObj is \n//   deallocating or newObj's class does not support weak references. \n//   If CrashIfDeallocating is false, nil is stored instead.\nenum CrashIfDeallocating {\n    DontCrashIfDeallocating = false, DoCrashIfDeallocating = true\n};\ntemplate <HaveOld haveOld, HaveNew haveNew,\n          CrashIfDeallocating crashIfDeallocating>\nstatic id \nstoreWeak(id *location, objc_object *newObj)\n{\n    assert(haveOld  ||  haveNew);\n    if (!haveNew) assert(newObj == nil);\n\n    Class previouslyInitializedClass = nil;\n    id oldObj;\n    SideTable *oldTable;\n    SideTable *newTable;\n\n    // Acquire locks for old and new values.\n    // Order by lock address to prevent lock ordering problems. \n    // Retry if the old value changes underneath us.\n retry:\n    if (haveOld) {\n        oldObj = *location;\n        oldTable = &SideTables()[oldObj];\n    } else {\n        oldTable = nil;\n    }\n    if (haveNew) {\n        newTable = &SideTables()[newObj];\n    } else {\n        newTable = nil;\n    }\n\n    SideTable::lockTwo<haveOld, haveNew>(oldTable, newTable);\n\n    if (haveOld  &&  *location != oldObj) {\n        SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);\n        goto retry;\n    }\n\n    // Prevent a deadlock between the weak reference machinery\n    // and the +initialize machinery by ensuring that no \n    // weakly-referenced object has an un-+initialized isa.\n    if (haveNew  &&  newObj) {\n        Class cls = newObj->getIsa();\n        if (cls != previouslyInitializedClass  &&  \n            !((objc_class *)cls)->isInitialized()) \n        {\n            SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);\n            _class_initialize(_class_getNonMetaClass(cls, (id)newObj));\n\n            // If this class is finished with +initialize then we're good.\n            // If this class is still running +initialize on this thread \n            // (i.e. +initialize called storeWeak on an instance of itself)\n            // then we may proceed but it will appear initializing and \n            // not yet initialized to the check above.\n            // Instead set previouslyInitializedClass to recognize it on retry.\n            previouslyInitializedClass = cls;\n\n            goto retry;\n        }\n    }\n\n    // Clean up old value, if any.\n    if (haveOld) {\n        weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);\n    }\n\n    // Assign new value, if any.\n    if (haveNew) {\n        newObj = (objc_object *)\n            weak_register_no_lock(&newTable->weak_table, (id)newObj, location, \n                                  crashIfDeallocating);\n        // weak_register_no_lock returns nil if weak store should be rejected\n\n        // Set is-weakly-referenced bit in refcount table.\n        if (newObj  &&  !newObj->isTaggedPointer()) {\n            newObj->setWeaklyReferenced_nolock();\n        }\n\n        // Do not set *location anywhere else. That would introduce a race.\n        *location = (id)newObj;\n    }\n    else {\n        // No new value. The storage is not changed.\n    }\n    \n    SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);\n\n    return (id)newObj;\n}\n\n\n/** \n * This function stores a new value into a __weak variable. It would\n * be used anywhere a __weak variable is the target of an assignment.\n * \n * @param location The address of the weak pointer itself\n * @param newObj The new object this weak ptr should now point to\n * \n * @return \\e newObj\n */\nid\nobjc_storeWeak(id *location, id newObj)\n{\n    return storeWeak<DoHaveOld, DoHaveNew, DoCrashIfDeallocating>\n        (location, (objc_object *)newObj);\n}\n\n\n/** \n * This function stores a new value into a __weak variable. \n * If the new object is deallocating or the new object's class \n * does not support weak references, stores nil instead.\n * \n * @param location The address of the weak pointer itself\n * @param newObj The new object this weak ptr should now point to\n * \n * @return The value stored (either the new object or nil)\n */\nid\nobjc_storeWeakOrNil(id *location, id newObj)\n{\n    return storeWeak<DoHaveOld, DoHaveNew, DontCrashIfDeallocating>\n        (location, (objc_object *)newObj);\n}\n\n\n/** \n * Initialize a fresh weak pointer to some object location. \n * It would be used for code like: \n *\n * (The nil case) \n * __weak id weakPtr;\n * (The non-nil case) \n * NSObject *o = ...;\n * __weak id weakPtr = o;\n * \n * This function IS NOT thread-safe with respect to concurrent \n * modifications to the weak variable. (Concurrent weak clear is safe.)\n *\n * @param location Address of __weak ptr. \n * @param newObj Object ptr. \n */\nid\nobjc_initWeak(id *location, id newObj)\n{\n    if (!newObj) {\n        *location = nil;\n        return nil;\n    }\n\n    return storeWeak<DontHaveOld, DoHaveNew, DoCrashIfDeallocating>\n        (location, (objc_object*)newObj);\n}\n\nid\nobjc_initWeakOrNil(id *location, id newObj)\n{\n    if (!newObj) {\n        *location = nil;\n        return nil;\n    }\n\n    return storeWeak<DontHaveOld, DoHaveNew, DontCrashIfDeallocating>\n        (location, (objc_object*)newObj);\n}\n\n\n/** \n * Destroys the relationship between a weak pointer\n * and the object it is referencing in the internal weak\n * table. If the weak pointer is not referencing anything, \n * there is no need to edit the weak table. \n *\n * This function IS NOT thread-safe with respect to concurrent \n * modifications to the weak variable. (Concurrent weak clear is safe.)\n * \n * @param location The weak pointer address. \n */\nvoid\nobjc_destroyWeak(id *location)\n{\n    (void)storeWeak<DoHaveOld, DontHaveNew, DontCrashIfDeallocating>\n        (location, nil);\n}\n\n\n/*\n  Once upon a time we eagerly cleared *location if we saw the object \n  was deallocating. This confuses code like NSPointerFunctions which \n  tries to pre-flight the raw storage and assumes if the storage is \n  zero then the weak system is done interfering. That is false: the \n  weak system is still going to check and clear the storage later. \n  This can cause objc_weak_error complaints and crashes.\n  So we now don't touch the storage until deallocation completes.\n*/\n\nid\nobjc_loadWeakRetained(id *location)\n{\n    id obj;\n    id result;\n    Class cls;\n\n    SideTable *table;\n    \n retry:\n    // fixme std::atomic this load\n    obj = *location;\n    if (!obj) return nil;\n    if (obj->isTaggedPointer()) return obj;\n    \n    table = &SideTables()[obj];\n    \n    table->lock();\n    if (*location != obj) {\n        table->unlock();\n        goto retry;\n    }\n    \n    result = obj;\n\n    cls = obj->ISA();\n    if (! cls->hasCustomRR()) {\n        // Fast case. We know +initialize is complete because\n        // default-RR can never be set before then.\n        assert(cls->isInitialized());\n        if (! obj->rootTryRetain()) {\n            result = nil;\n        }\n    }\n    else {\n        // Slow case. We must check for +initialize and call it outside\n        // the lock if necessary in order to avoid deadlocks.\n        if (cls->isInitialized() || _thisThreadIsInitializingClass(cls)) {\n            BOOL (*tryRetain)(id, SEL) = (BOOL(*)(id, SEL))\n                class_getMethodImplementation(cls, SEL_retainWeakReference);\n            if ((IMP)tryRetain == _objc_msgForward) {\n                result = nil;\n            }\n            else if (! (*tryRetain)(obj, SEL_retainWeakReference)) {\n                result = nil;\n            }\n        }\n        else {\n            table->unlock();\n            _class_initialize(cls);\n            goto retry;\n        }\n    }\n        \n    table->unlock();\n    return result;\n}\n\n/** \n * This loads the object referenced by a weak pointer and returns it, after\n * retaining and autoreleasing the object to ensure that it stays alive\n * long enough for the caller to use it. This function would be used\n * anywhere a __weak variable is used in an expression.\n * \n * @param location The weak pointer address\n * \n * @return The object pointed to by \\e location, or \\c nil if \\e location is \\c nil.\n */\nid\nobjc_loadWeak(id *location)\n{\n    if (!*location) return nil;\n    return objc_autorelease(objc_loadWeakRetained(location));\n}\n\n\n/** \n * This function copies a weak pointer from one location to another,\n * when the destination doesn't already contain a weak pointer. It\n * would be used for code like:\n *\n *  __weak id src = ...;\n *  __weak id dst = src;\n * \n * This function IS NOT thread-safe with respect to concurrent \n * modifications to the destination variable. (Concurrent weak clear is safe.)\n *\n * @param dst The destination variable.\n * @param src The source variable.\n */\nvoid\nobjc_copyWeak(id *dst, id *src)\n{\n    id obj = objc_loadWeakRetained(src);\n    objc_initWeak(dst, obj);\n    objc_release(obj);\n}\n\n/** \n * Move a weak pointer from one location to another.\n * Before the move, the destination must be uninitialized.\n * After the move, the source is nil.\n *\n * This function IS NOT thread-safe with respect to concurrent \n * modifications to either weak variable. (Concurrent weak clear is safe.)\n *\n */\nvoid\nobjc_moveWeak(id *dst, id *src)\n{\n    objc_copyWeak(dst, src);\n    objc_destroyWeak(src);\n    *src = nil;\n}\n\n\n/***********************************************************************\n   Autorelease pool implementation\n\n   A thread's autorelease pool is a stack of pointers. \n   Each pointer is either an object to release, or POOL_BOUNDARY which is \n     an autorelease pool boundary.\n   A pool token is a pointer to the POOL_BOUNDARY for that pool. When \n     the pool is popped, every object hotter than the sentinel is released.\n   The stack is divided into a doubly-linked list of pages. Pages are added \n     and deleted as necessary. \n   Thread-local storage points to the hot page, where newly autoreleased \n     objects are stored. \n**********************************************************************/\n\n// Set this to 1 to mprotect() autorelease pool contents\n#define PROTECT_AUTORELEASEPOOL 0\n\n// Set this to 1 to validate the entire autorelease pool header all the time\n// (i.e. use check() instead of fastcheck() everywhere)\n#define CHECK_AUTORELEASEPOOL (DEBUG)\n\nBREAKPOINT_FUNCTION(void objc_autoreleaseNoPool(id obj));\nBREAKPOINT_FUNCTION(void objc_autoreleasePoolInvalid(const void *token));\n\nnamespace {\n\nstruct magic_t {\n    static const uint32_t M0 = 0xA1A1A1A1;\n#   define M1 \"AUTORELEASE!\"\n    static const size_t M1_len = 12;\n    uint32_t m[4];\n    \n    magic_t() {\n        assert(M1_len == strlen(M1));\n        assert(M1_len == 3 * sizeof(m[1]));\n\n        m[0] = M0;\n        strncpy((char *)&m[1], M1, M1_len);\n    }\n\n    ~magic_t() {\n        m[0] = m[1] = m[2] = m[3] = 0;\n    }\n\n    bool check() const {\n        return (m[0] == M0 && 0 == strncmp((char *)&m[1], M1, M1_len));\n    }\n\n    bool fastcheck() const {\n#if CHECK_AUTORELEASEPOOL\n        return check();\n#else\n        return (m[0] == M0);\n#endif\n    }\n\n#   undef M1\n};\n    \n\nclass AutoreleasePoolPage \n{\n    // EMPTY_POOL_PLACEHOLDER is stored in TLS when exactly one pool is \n    // pushed and it has never contained any objects. This saves memory \n    // when the top level (i.e. libdispatch) pushes and pops pools but \n    // never uses them.\n#   define EMPTY_POOL_PLACEHOLDER ((id*)1)\n\n#   define POOL_BOUNDARY nil\n    static pthread_key_t const key = AUTORELEASE_POOL_KEY;\n    static uint8_t const SCRIBBLE = 0xA3;  // 0xA3A3A3A3 after releasing\n    static size_t const SIZE = \n#if PROTECT_AUTORELEASEPOOL\n        PAGE_MAX_SIZE;  // must be multiple of vm page size\n#else\n        PAGE_MAX_SIZE;  // size and alignment, power of 2\n#endif\n    static size_t const COUNT = SIZE / sizeof(id);\n\n    magic_t const magic;\n    id *next;\n    pthread_t const thread;\n    AutoreleasePoolPage * const parent;\n    AutoreleasePoolPage *child;\n    uint32_t const depth;\n    uint32_t hiwat;\n\n    // SIZE-sizeof(*this) bytes of contents follow\n\n    static void * operator new(size_t size) {\n        return malloc_zone_memalign(malloc_default_zone(), SIZE, SIZE);\n    }\n    static void operator delete(void * p) {\n        return free(p);\n    }\n\n    inline void protect() {\n#if PROTECT_AUTORELEASEPOOL\n        mprotect(this, SIZE, PROT_READ);\n        check();\n#endif\n    }\n\n    inline void unprotect() {\n#if PROTECT_AUTORELEASEPOOL\n        check();\n        mprotect(this, SIZE, PROT_READ | PROT_WRITE);\n#endif\n    }\n\n    AutoreleasePoolPage(AutoreleasePoolPage *newParent) \n        : magic(), next(begin()), thread(pthread_self()),\n          parent(newParent), child(nil), \n          depth(parent ? 1+parent->depth : 0), \n          hiwat(parent ? parent->hiwat : 0)\n    { \n        if (parent) {\n            parent->check();\n            assert(!parent->child);\n            parent->unprotect();\n            parent->child = this;\n            parent->protect();\n        }\n        protect();\n    }\n\n    ~AutoreleasePoolPage() \n    {\n        check();\n        unprotect();\n        assert(empty());\n\n        // Not recursive: we don't want to blow out the stack \n        // if a thread accumulates a stupendous amount of garbage\n        assert(!child);\n    }\n\n\n    void busted(bool die = true) \n    {\n        magic_t right;\n        (die ? _objc_fatal : _objc_inform)\n            (\"autorelease pool page %p corrupted\\n\"\n             \"  magic     0x%08x 0x%08x 0x%08x 0x%08x\\n\"\n             \"  should be 0x%08x 0x%08x 0x%08x 0x%08x\\n\"\n             \"  pthread   %p\\n\"\n             \"  should be %p\\n\", \n             this, \n             magic.m[0], magic.m[1], magic.m[2], magic.m[3], \n             right.m[0], right.m[1], right.m[2], right.m[3], \n             this->thread, pthread_self());\n    }\n\n    void check(bool die = true) \n    {\n        if (!magic.check() || !pthread_equal(thread, pthread_self())) {\n            busted(die);\n        }\n    }\n\n    void fastcheck(bool die = true) \n    {\n#if CHECK_AUTORELEASEPOOL\n        check(die);\n#else\n        if (! magic.fastcheck()) {\n            busted(die);\n        }\n#endif\n    }\n\n\n    id * begin() {\n        return (id *) ((uint8_t *)this+sizeof(*this));\n    }\n\n    id * end() {\n        return (id *) ((uint8_t *)this+SIZE);\n    }\n\n    bool empty() {\n        return next == begin();\n    }\n\n    bool full() { \n        return next == end();\n    }\n\n    bool lessThanHalfFull() {\n        return (next - begin() < (end() - begin()) / 2);\n    }\n\n    id *add(id obj)\n    {\n        assert(!full());\n        unprotect();\n        id *ret = next;  // faster than `return next-1` because of aliasing\n        *next++ = obj;\n        protect();\n        return ret;\n    }\n\n    void releaseAll() \n    {\n        releaseUntil(begin());\n    }\n\n    void releaseUntil(id *stop) \n    {\n        // Not recursive: we don't want to blow out the stack \n        // if a thread accumulates a stupendous amount of garbage\n        \n        while (this->next != stop) {\n            // Restart from hotPage() every time, in case -release \n            // autoreleased more objects\n            AutoreleasePoolPage *page = hotPage();\n\n            // fixme I think this `while` can be `if`, but I can't prove it\n            while (page->empty()) {\n                page = page->parent;\n                setHotPage(page);\n            }\n\n            page->unprotect();\n            id obj = *--page->next;\n            memset((void*)page->next, SCRIBBLE, sizeof(*page->next));\n            page->protect();\n\n            if (obj != POOL_BOUNDARY) {\n                objc_release(obj);\n            }\n        }\n\n        setHotPage(this);\n\n#if DEBUG\n        // we expect any children to be completely empty\n        for (AutoreleasePoolPage *page = child; page; page = page->child) {\n            assert(page->empty());\n        }\n#endif\n    }\n\n    void kill() \n    {\n        // Not recursive: we don't want to blow out the stack \n        // if a thread accumulates a stupendous amount of garbage\n        AutoreleasePoolPage *page = this;\n        while (page->child) page = page->child;\n\n        AutoreleasePoolPage *deathptr;\n        do {\n            deathptr = page;\n            page = page->parent;\n            if (page) {\n                page->unprotect();\n                page->child = nil;\n                page->protect();\n            }\n            delete deathptr;\n        } while (deathptr != this);\n    }\n\n    static void tls_dealloc(void *p) \n    {\n        if (p == (void*)EMPTY_POOL_PLACEHOLDER) {\n            // No objects or pool pages to clean up here.\n            return;\n        }\n\n        // reinstate TLS value while we work\n        setHotPage((AutoreleasePoolPage *)p);\n\n        if (AutoreleasePoolPage *page = coldPage()) {\n            if (!page->empty()) pop(page->begin());  // pop all of the pools\n            if (DebugMissingPools || DebugPoolAllocation) {\n                // pop() killed the pages already\n            } else {\n                page->kill();  // free all of the pages\n            }\n        }\n        \n        // clear TLS value so TLS destruction doesn't loop\n        setHotPage(nil);\n    }\n\n    static AutoreleasePoolPage *pageForPointer(const void *p) \n    {\n        return pageForPointer((uintptr_t)p);\n    }\n\n    static AutoreleasePoolPage *pageForPointer(uintptr_t p) \n    {\n        AutoreleasePoolPage *result;\n        uintptr_t offset = p % SIZE;\n\n        assert(offset >= sizeof(AutoreleasePoolPage));\n\n        result = (AutoreleasePoolPage *)(p - offset);\n        result->fastcheck();\n\n        return result;\n    }\n\n\n    static inline bool haveEmptyPoolPlaceholder()\n    {\n        id *tls = (id *)tls_get_direct(key);\n        return (tls == EMPTY_POOL_PLACEHOLDER);\n    }\n\n    static inline id* setEmptyPoolPlaceholder()\n    {\n        assert(tls_get_direct(key) == nil);\n        tls_set_direct(key, (void *)EMPTY_POOL_PLACEHOLDER);\n        return EMPTY_POOL_PLACEHOLDER;\n    }\n\n    static inline AutoreleasePoolPage *hotPage() \n    {\n        AutoreleasePoolPage *result = (AutoreleasePoolPage *)\n            tls_get_direct(key);\n        if ((id *)result == EMPTY_POOL_PLACEHOLDER) return nil;\n        if (result) result->fastcheck();\n        return result;\n    }\n\n    static inline void setHotPage(AutoreleasePoolPage *page) \n    {\n        if (page) page->fastcheck();\n        tls_set_direct(key, (void *)page);\n    }\n\n    static inline AutoreleasePoolPage *coldPage() \n    {\n        AutoreleasePoolPage *result = hotPage();\n        if (result) {\n            while (result->parent) {\n                result = result->parent;\n                result->fastcheck();\n            }\n        }\n        return result;\n    }\n\n\n    static inline id *autoreleaseFast(id obj)\n    {\n        AutoreleasePoolPage *page = hotPage();\n        if (page && !page->full()) {\n            return page->add(obj);\n        } else if (page) {\n            return autoreleaseFullPage(obj, page);\n        } else {\n            return autoreleaseNoPage(obj);\n        }\n    }\n\n    static __attribute__((noinline))\n    id *autoreleaseFullPage(id obj, AutoreleasePoolPage *page)\n    {\n        // The hot page is full. \n        // Step to the next non-full page, adding a new page if necessary.\n        // Then add the object to that page.\n        assert(page == hotPage());\n        assert(page->full()  ||  DebugPoolAllocation);\n\n        do {\n            if (page->child) page = page->child;\n            else page = new AutoreleasePoolPage(page);\n        } while (page->full());\n\n        setHotPage(page);\n        return page->add(obj);\n    }\n\n    static __attribute__((noinline))\n    id *autoreleaseNoPage(id obj)\n    {\n        // \"No page\" could mean no pool has been pushed\n        // or an empty placeholder pool has been pushed and has no contents yet\n        assert(!hotPage());\n\n        bool pushExtraBoundary = false;\n        if (haveEmptyPoolPlaceholder()) {\n            // We are pushing a second pool over the empty placeholder pool\n            // or pushing the first object into the empty placeholder pool.\n            // Before doing that, push a pool boundary on behalf of the pool \n            // that is currently represented by the empty placeholder.\n            pushExtraBoundary = true;\n        }\n        else if (obj != POOL_BOUNDARY  &&  DebugMissingPools) {\n            // We are pushing an object with no pool in place, \n            // and no-pool debugging was requested by environment.\n            _objc_inform(\"MISSING POOLS: (%p) Object %p of class %s \"\n                         \"autoreleased with no pool in place - \"\n                         \"just leaking - break on \"\n                         \"objc_autoreleaseNoPool() to debug\", \n                         pthread_self(), (void*)obj, object_getClassName(obj));\n            objc_autoreleaseNoPool(obj);\n            return nil;\n        }\n        else if (obj == POOL_BOUNDARY  &&  !DebugPoolAllocation) {\n            // We are pushing a pool with no pool in place,\n            // and alloc-per-pool debugging was not requested.\n            // Install and return the empty pool placeholder.\n            return setEmptyPoolPlaceholder();\n        }\n\n        // We are pushing an object or a non-placeholder'd pool.\n\n        // Install the first page.\n        AutoreleasePoolPage *page = new AutoreleasePoolPage(nil);\n        setHotPage(page);\n        \n        // Push a boundary on behalf of the previously-placeholder'd pool.\n        if (pushExtraBoundary) {\n            page->add(POOL_BOUNDARY);\n        }\n        \n        // Push the requested object or pool.\n        return page->add(obj);\n    }\n\n\n    static __attribute__((noinline))\n    id *autoreleaseNewPage(id obj)\n    {\n        AutoreleasePoolPage *page = hotPage();\n        if (page) return autoreleaseFullPage(obj, page);\n        else return autoreleaseNoPage(obj);\n    }\n\npublic:\n    static inline id autorelease(id obj)\n    {\n        assert(obj);\n        assert(!obj->isTaggedPointer());\n        id *dest __unused = autoreleaseFast(obj);\n        assert(!dest  ||  dest == EMPTY_POOL_PLACEHOLDER  ||  *dest == obj);\n        return obj;\n    }\n\n\n    static inline void *push() \n    {\n        id *dest;\n        if (DebugPoolAllocation) {\n            // Each autorelease pool starts on a new pool page.\n            dest = autoreleaseNewPage(POOL_BOUNDARY);\n        } else {\n            dest = autoreleaseFast(POOL_BOUNDARY);\n        }\n        assert(dest == EMPTY_POOL_PLACEHOLDER || *dest == POOL_BOUNDARY);\n        return dest;\n    }\n\n    static void badPop(void *token)\n    {\n        // Error. For bincompat purposes this is not \n        // fatal in executables built with old SDKs.\n\n        if (DebugPoolAllocation || sdkIsAtLeast(10_12, 10_0, 10_0, 3_0, 2_0)) {\n            // OBJC_DEBUG_POOL_ALLOCATION or new SDK. Bad pop is fatal.\n            _objc_fatal\n                (\"Invalid or prematurely-freed autorelease pool %p.\", token);\n        }\n\n        // Old SDK. Bad pop is warned once.\n        static bool complained = false;\n        if (!complained) {\n            complained = true;\n            _objc_inform_now_and_on_crash\n                (\"Invalid or prematurely-freed autorelease pool %p. \"\n                 \"Set a breakpoint on objc_autoreleasePoolInvalid to debug. \"\n                 \"Proceeding anyway because the app is old \"\n                 \"(SDK version \" SDK_FORMAT \"). Memory errors are likely.\",\n                     token, FORMAT_SDK(sdkVersion()));\n        }\n        objc_autoreleasePoolInvalid(token);\n    }\n    \n    static inline void pop(void *token) \n    {\n        AutoreleasePoolPage *page;\n        id *stop;\n\n        if (token == (void*)EMPTY_POOL_PLACEHOLDER) {\n            // Popping the top-level placeholder pool.\n            if (hotPage()) {\n                // Pool was used. Pop its contents normally.\n                // Pool pages remain allocated for re-use as usual.\n                pop(coldPage()->begin());\n            } else {\n                // Pool was never used. Clear the placeholder.\n                setHotPage(nil);\n            }\n            return;\n        }\n\n        page = pageForPointer(token);\n        stop = (id *)token;\n        if (*stop != POOL_BOUNDARY) {\n            if (stop == page->begin()  &&  !page->parent) {\n                // Start of coldest page may correctly not be POOL_BOUNDARY:\n                // 1. top-level pool is popped, leaving the cold page in place\n                // 2. an object is autoreleased with no pool\n            } else {\n                // Error. For bincompat purposes this is not \n                // fatal in executables built with old SDKs.\n                return badPop(token);\n            }\n        }\n\n        if (PrintPoolHiwat) printHiwat();\n\n        page->releaseUntil(stop);\n\n        // memory: delete empty children\n        if (DebugPoolAllocation  &&  page->empty()) {\n            // special case: delete everything during page-per-pool debugging\n            AutoreleasePoolPage *parent = page->parent;\n            page->kill();\n            setHotPage(parent);\n        } else if (DebugMissingPools  &&  page->empty()  &&  !page->parent) {\n            // special case: delete everything for pop(top) \n            // when debugging missing autorelease pools\n            page->kill();\n            setHotPage(nil);\n        } \n        else if (page->child) {\n            // hysteresis: keep one empty child if page is more than half full\n            if (page->lessThanHalfFull()) {\n                page->child->kill();\n            }\n            else if (page->child->child) {\n                page->child->child->kill();\n            }\n        }\n    }\n\n    static void init()\n    {\n        int r __unused = pthread_key_init_np(AutoreleasePoolPage::key, \n                                             AutoreleasePoolPage::tls_dealloc);\n        assert(r == 0);\n    }\n\n    void print() \n    {\n        _objc_inform(\"[%p]  ................  PAGE %s %s %s\", this, \n                     full() ? \"(full)\" : \"\", \n                     this == hotPage() ? \"(hot)\" : \"\", \n                     this == coldPage() ? \"(cold)\" : \"\");\n        check(false);\n        for (id *p = begin(); p < next; p++) {\n            if (*p == POOL_BOUNDARY) {\n                _objc_inform(\"[%p]  ################  POOL %p\", p, p);\n            } else {\n                _objc_inform(\"[%p]  %#16lx  %s\", \n                             p, (unsigned long)*p, object_getClassName(*p));\n            }\n        }\n    }\n\n    static void printAll()\n    {        \n        _objc_inform(\"##############\");\n        _objc_inform(\"AUTORELEASE POOLS for thread %p\", pthread_self());\n\n        AutoreleasePoolPage *page;\n        ptrdiff_t objects = 0;\n        for (page = coldPage(); page; page = page->child) {\n            objects += page->next - page->begin();\n        }\n        _objc_inform(\"%llu releases pending.\", (unsigned long long)objects);\n\n        if (haveEmptyPoolPlaceholder()) {\n            _objc_inform(\"[%p]  ................  PAGE (placeholder)\", \n                         EMPTY_POOL_PLACEHOLDER);\n            _objc_inform(\"[%p]  ################  POOL (placeholder)\", \n                         EMPTY_POOL_PLACEHOLDER);\n        }\n        else {\n            for (page = coldPage(); page; page = page->child) {\n                page->print();\n            }\n        }\n\n        _objc_inform(\"##############\");\n    }\n\n    static void printHiwat()\n    {\n        // Check and propagate high water mark\n        // Ignore high water marks under 256 to suppress noise.\n        AutoreleasePoolPage *p = hotPage();\n        uint32_t mark = p->depth*COUNT + (uint32_t)(p->next - p->begin());\n        if (mark > p->hiwat  &&  mark > 256) {\n            for( ; p; p = p->parent) {\n                p->unprotect();\n                p->hiwat = mark;\n                p->protect();\n            }\n            \n            _objc_inform(\"POOL HIGHWATER: new high water mark of %u \"\n                         \"pending releases for thread %p:\", \n                         mark, pthread_self());\n            \n            void *stack[128];\n            int count = backtrace(stack, sizeof(stack)/sizeof(stack[0]));\n            char **sym = backtrace_symbols(stack, count);\n            for (int i = 0; i < count; i++) {\n                _objc_inform(\"POOL HIGHWATER:     %s\", sym[i]);\n            }\n            free(sym);\n        }\n    }\n\n#undef POOL_BOUNDARY\n};\n\n// anonymous namespace\n};\n\n\n/***********************************************************************\n* Slow paths for inline control\n**********************************************************************/\n\n#if SUPPORT_NONPOINTER_ISA\n\nNEVER_INLINE id \nobjc_object::rootRetain_overflow(bool tryRetain)\n{\n    return rootRetain(tryRetain, true);\n}\n\n\nNEVER_INLINE bool \nobjc_object::rootRelease_underflow(bool performDealloc)\n{\n    return rootRelease(performDealloc, true);\n}\n\n\n// Slow path of clearDeallocating() \n// for objects with nonpointer isa\n// that were ever weakly referenced \n// or whose retain count ever overflowed to the side table.\nNEVER_INLINE void\nobjc_object::clearDeallocating_slow()\n{\n    assert(isa.nonpointer  &&  (isa.weakly_referenced || isa.has_sidetable_rc));\n\n    SideTable& table = SideTables()[this];\n    table.lock();\n    if (isa.weakly_referenced) {\n        weak_clear_no_lock(&table.weak_table, (id)this);\n    }\n    if (isa.has_sidetable_rc) {\n        table.refcnts.erase(this);\n    }\n    table.unlock();\n}\n\n#endif\n\n__attribute__((noinline,used))\nid \nobjc_object::rootAutorelease2()\n{\n    assert(!isTaggedPointer());\n    return AutoreleasePoolPage::autorelease((id)this);\n}\n\n\nBREAKPOINT_FUNCTION(\n    void objc_overrelease_during_dealloc_error(void)\n);\n\n\nNEVER_INLINE\nbool \nobjc_object::overrelease_error()\n{\n    _objc_inform_now_and_on_crash(\"%s object %p overreleased while already deallocating; break on objc_overrelease_during_dealloc_error to debug\", object_getClassName((id)this), this);\n    objc_overrelease_during_dealloc_error();\n    return false;  // allow rootRelease() to tail-call this\n}\n\n\n/***********************************************************************\n* Retain count operations for side table.\n**********************************************************************/\n\n\n#if DEBUG\n// Used to assert that an object is not present in the side table.\nbool\nobjc_object::sidetable_present()\n{\n    bool result = false;\n    SideTable& table = SideTables()[this];\n\n    table.lock();\n\n    RefcountMap::iterator it = table.refcnts.find(this);\n    if (it != table.refcnts.end()) result = true;\n\n    if (weak_is_registered_no_lock(&table.weak_table, (id)this)) result = true;\n\n    table.unlock();\n\n    return result;\n}\n#endif\n\n#if SUPPORT_NONPOINTER_ISA\n\nvoid \nobjc_object::sidetable_lock()\n{\n    SideTable& table = SideTables()[this];\n    table.lock();\n}\n\nvoid \nobjc_object::sidetable_unlock()\n{\n    SideTable& table = SideTables()[this];\n    table.unlock();\n}\n\n\n// Move the entire retain count to the side table, \n// as well as isDeallocating and weaklyReferenced.\nvoid \nobjc_object::sidetable_moveExtraRC_nolock(size_t extra_rc, \n                                          bool isDeallocating, \n                                          bool weaklyReferenced)\n{\n    assert(!isa.nonpointer);        // should already be changed to raw pointer\n    SideTable& table = SideTables()[this];\n\n    size_t& refcntStorage = table.refcnts[this];\n    size_t oldRefcnt = refcntStorage;\n    // not deallocating - that was in the isa\n    assert((oldRefcnt & SIDE_TABLE_DEALLOCATING) == 0);  \n    assert((oldRefcnt & SIDE_TABLE_WEAKLY_REFERENCED) == 0);  \n\n    uintptr_t carry;\n    size_t refcnt = addc(oldRefcnt, extra_rc << SIDE_TABLE_RC_SHIFT, 0, &carry);\n    if (carry) refcnt = SIDE_TABLE_RC_PINNED;\n    if (isDeallocating) refcnt |= SIDE_TABLE_DEALLOCATING;\n    if (weaklyReferenced) refcnt |= SIDE_TABLE_WEAKLY_REFERENCED;\n\n    refcntStorage = refcnt;\n}\n\n\n// Move some retain counts to the side table from the isa field.\n// Returns true if the object is now pinned.\nbool \nobjc_object::sidetable_addExtraRC_nolock(size_t delta_rc)\n{\n    assert(isa.nonpointer);\n    SideTable& table = SideTables()[this];\n\n    size_t& refcntStorage = table.refcnts[this];\n    size_t oldRefcnt = refcntStorage;\n    // isa-side bits should not be set here\n    assert((oldRefcnt & SIDE_TABLE_DEALLOCATING) == 0);\n    assert((oldRefcnt & SIDE_TABLE_WEAKLY_REFERENCED) == 0);\n\n    if (oldRefcnt & SIDE_TABLE_RC_PINNED) return true;\n\n    uintptr_t carry;\n    size_t newRefcnt = \n        addc(oldRefcnt, delta_rc << SIDE_TABLE_RC_SHIFT, 0, &carry);\n    if (carry) {\n        refcntStorage =\n            SIDE_TABLE_RC_PINNED | (oldRefcnt & SIDE_TABLE_FLAG_MASK);\n        return true;\n    }\n    else {\n        refcntStorage = newRefcnt;\n        return false;\n    }\n}\n\n\n// Move some retain counts from the side table to the isa field.\n// Returns the actual count subtracted, which may be less than the request.\nsize_t \nobjc_object::sidetable_subExtraRC_nolock(size_t delta_rc)\n{\n    assert(isa.nonpointer);\n    SideTable& table = SideTables()[this];\n\n    RefcountMap::iterator it = table.refcnts.find(this);\n    if (it == table.refcnts.end()  ||  it->second == 0) {\n        // Side table retain count is zero. Can't borrow.\n        return 0;\n    }\n    size_t oldRefcnt = it->second;\n\n    // isa-side bits should not be set here\n    assert((oldRefcnt & SIDE_TABLE_DEALLOCATING) == 0);\n    assert((oldRefcnt & SIDE_TABLE_WEAKLY_REFERENCED) == 0);\n\n    size_t newRefcnt = oldRefcnt - (delta_rc << SIDE_TABLE_RC_SHIFT);\n    assert(oldRefcnt > newRefcnt);  // shouldn't underflow\n    it->second = newRefcnt;\n    return delta_rc;\n}\n\n\nsize_t \nobjc_object::sidetable_getExtraRC_nolock()\n{\n    assert(isa.nonpointer);\n    SideTable& table = SideTables()[this];\n    RefcountMap::iterator it = table.refcnts.find(this);\n    if (it == table.refcnts.end()) return 0;\n    else return it->second >> SIDE_TABLE_RC_SHIFT;\n}\n\n\n// SUPPORT_NONPOINTER_ISA\n#endif\n\n\nid\nobjc_object::sidetable_retain()\n{\n#if SUPPORT_NONPOINTER_ISA\n    assert(!isa.nonpointer);\n#endif\n    SideTable& table = SideTables()[this];\n    \n    table.lock();\n    size_t& refcntStorage = table.refcnts[this];\n    if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {\n        refcntStorage += SIDE_TABLE_RC_ONE;\n    }\n    table.unlock();\n\n    return (id)this;\n}\n\n\nbool\nobjc_object::sidetable_tryRetain()\n{\n#if SUPPORT_NONPOINTER_ISA\n    assert(!isa.nonpointer);\n#endif\n    SideTable& table = SideTables()[this];\n\n    // NO SPINLOCK HERE\n    // _objc_rootTryRetain() is called exclusively by _objc_loadWeak(), \n    // which already acquired the lock on our behalf.\n\n    // fixme can't do this efficiently with os_lock_handoff_s\n    // if (table.slock == 0) {\n    //     _objc_fatal(\"Do not call -_tryRetain.\");\n    // }\n\n    bool result = true;\n    RefcountMap::iterator it = table.refcnts.find(this);\n    if (it == table.refcnts.end()) {\n        table.refcnts[this] = SIDE_TABLE_RC_ONE;\n    } else if (it->second & SIDE_TABLE_DEALLOCATING) {\n        result = false;\n    } else if (! (it->second & SIDE_TABLE_RC_PINNED)) {\n        it->second += SIDE_TABLE_RC_ONE;\n    }\n    \n    return result;\n}\n\n\nuintptr_t\nobjc_object::sidetable_retainCount()\n{\n    SideTable& table = SideTables()[this];\n\n    size_t refcnt_result = 1;\n    \n    table.lock();\n    RefcountMap::iterator it = table.refcnts.find(this);\n    if (it != table.refcnts.end()) {\n        // this is valid for SIDE_TABLE_RC_PINNED too\n        refcnt_result += it->second >> SIDE_TABLE_RC_SHIFT;\n    }\n    table.unlock();\n    return refcnt_result;\n}\n\n\nbool \nobjc_object::sidetable_isDeallocating()\n{\n    SideTable& table = SideTables()[this];\n\n    // NO SPINLOCK HERE\n    // _objc_rootIsDeallocating() is called exclusively by _objc_storeWeak(), \n    // which already acquired the lock on our behalf.\n\n\n    // fixme can't do this efficiently with os_lock_handoff_s\n    // if (table.slock == 0) {\n    //     _objc_fatal(\"Do not call -_isDeallocating.\");\n    // }\n\n    RefcountMap::iterator it = table.refcnts.find(this);\n    return (it != table.refcnts.end()) && (it->second & SIDE_TABLE_DEALLOCATING);\n}\n\n\nbool \nobjc_object::sidetable_isWeaklyReferenced()\n{\n    bool result = false;\n\n    SideTable& table = SideTables()[this];\n    table.lock();\n\n    RefcountMap::iterator it = table.refcnts.find(this);\n    if (it != table.refcnts.end()) {\n        result = it->second & SIDE_TABLE_WEAKLY_REFERENCED;\n    }\n\n    table.unlock();\n\n    return result;\n}\n\n\nvoid \nobjc_object::sidetable_setWeaklyReferenced_nolock()\n{\n#if SUPPORT_NONPOINTER_ISA\n    assert(!isa.nonpointer);\n#endif\n\n    SideTable& table = SideTables()[this];\n\n    table.refcnts[this] |= SIDE_TABLE_WEAKLY_REFERENCED;\n}\n\n\n// rdar://20206767\n// return uintptr_t instead of bool so that the various raw-isa \n// -release paths all return zero in eax\nuintptr_t\nobjc_object::sidetable_release(bool performDealloc)\n{\n#if SUPPORT_NONPOINTER_ISA\n    assert(!isa.nonpointer);\n#endif\n    SideTable& table = SideTables()[this];\n\n    bool do_dealloc = false;\n\n    table.lock();\n    RefcountMap::iterator it = table.refcnts.find(this);\n    if (it == table.refcnts.end()) {\n        do_dealloc = true;\n        table.refcnts[this] = SIDE_TABLE_DEALLOCATING;\n    } else if (it->second < SIDE_TABLE_DEALLOCATING) {\n        // SIDE_TABLE_WEAKLY_REFERENCED may be set. Don't change it.\n        do_dealloc = true;\n        it->second |= SIDE_TABLE_DEALLOCATING;\n    } else if (! (it->second & SIDE_TABLE_RC_PINNED)) {\n        it->second -= SIDE_TABLE_RC_ONE;\n    }\n    table.unlock();\n    if (do_dealloc  &&  performDealloc) {\n        ((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);\n    }\n    return do_dealloc;\n}\n\n\nvoid \nobjc_object::sidetable_clearDeallocating()\n{\n    SideTable& table = SideTables()[this];\n\n    // clear any weak table items\n    // clear extra retain count and deallocating bit\n    // (fixme warn or abort if extra retain count == 0 ?)\n    table.lock();\n    RefcountMap::iterator it = table.refcnts.find(this);\n    if (it != table.refcnts.end()) {\n        if (it->second & SIDE_TABLE_WEAKLY_REFERENCED) {\n            weak_clear_no_lock(&table.weak_table, (id)this);\n        }\n        table.refcnts.erase(it);\n    }\n    table.unlock();\n}\n\n\n/***********************************************************************\n* Optimized retain/release/autorelease entrypoints\n**********************************************************************/\n\n\n#if __OBJC2__\n\n__attribute__((aligned(16)))\nid \nobjc_retain(id obj)\n{\n    if (!obj) return obj;\n    if (obj->isTaggedPointer()) return obj;\n    return obj->retain();\n}\n\n\n__attribute__((aligned(16)))\nvoid \nobjc_release(id obj)\n{\n    if (!obj) return;\n    if (obj->isTaggedPointer()) return;\n    return obj->release();\n}\n\n\n__attribute__((aligned(16)))\nid\nobjc_autorelease(id obj)\n{\n    if (!obj) return obj;\n    if (obj->isTaggedPointer()) return obj;\n    return obj->autorelease();\n}\n\n\n// OBJC2\n#else\n// not OBJC2\n\n\nid objc_retain(id obj) { return [obj retain]; }\nvoid objc_release(id obj) { [obj release]; }\nid objc_autorelease(id obj) { return [obj autorelease]; }\n\n\n#endif\n\n\n/***********************************************************************\n* Basic operations for root class implementations a.k.a. _objc_root*()\n**********************************************************************/\n\nbool\n_objc_rootTryRetain(id obj) \n{\n    assert(obj);\n\n    return obj->rootTryRetain();\n}\n\nbool\n_objc_rootIsDeallocating(id obj) \n{\n    assert(obj);\n\n    return obj->rootIsDeallocating();\n}\n\n\nvoid \nobjc_clear_deallocating(id obj) \n{\n    assert(obj);\n\n    if (obj->isTaggedPointer()) return;\n    obj->clearDeallocating();\n}\n\n\nbool\n_objc_rootReleaseWasZero(id obj)\n{\n    assert(obj);\n\n    return obj->rootReleaseShouldDealloc();\n}\n\n\nid\n_objc_rootAutorelease(id obj)\n{\n    assert(obj);\n    return obj->rootAutorelease();\n}\n\nuintptr_t\n_objc_rootRetainCount(id obj)\n{\n    assert(obj);\n\n    return obj->rootRetainCount();\n}\n\n\nid\n_objc_rootRetain(id obj)\n{\n    assert(obj);\n\n    return obj->rootRetain();\n}\n\nvoid\n_objc_rootRelease(id obj)\n{\n    assert(obj);\n\n    obj->rootRelease();\n}\n\n\nid\n_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)\n{\n    id obj;\n\n#if __OBJC2__\n    // allocWithZone under __OBJC2__ ignores the zone parameter\n    (void)zone;\n    obj = class_createInstance(cls, 0);\n#else\n    if (!zone) {\n        obj = class_createInstance(cls, 0);\n    }\n    else {\n        obj = class_createInstanceFromZone(cls, 0, zone);\n    }\n#endif\n\n    if (slowpath(!obj)) obj = callBadAllocHandler(cls);\n    return obj;\n}\n\n\n// Call [cls alloc] or [cls allocWithZone:nil], with appropriate \n// shortcutting optimizations.\nstatic ALWAYS_INLINE id\ncallAlloc(Class cls, bool checkNil, bool allocWithZone=false)\n{\n    if (slowpath(checkNil && !cls)) return nil;\n\n#if __OBJC2__\n    if (fastpath(!cls->ISA()->hasCustomAWZ())) {\n        // No alloc/allocWithZone implementation. Go straight to the allocator.\n        // fixme store hasCustomAWZ in the non-meta class and \n        // add it to canAllocFast's summary\n        if (fastpath(cls->canAllocFast())) {\n            // No ctors, raw isa, etc. Go straight to the metal.\n            bool dtor = cls->hasCxxDtor();\n            id obj = (id)calloc(1, cls->bits.fastInstanceSize());\n            if (slowpath(!obj)) return callBadAllocHandler(cls);\n            obj->initInstanceIsa(cls, dtor);\n            return obj;\n        }\n        else {\n            // Has ctor or raw isa or something. Use the slower path.\n            id obj = class_createInstance(cls, 0);\n            if (slowpath(!obj)) return callBadAllocHandler(cls);\n            return obj;\n        }\n    }\n#endif\n\n    // No shortcuts available.\n    if (allocWithZone) return [cls allocWithZone:nil];\n    return [cls alloc];\n}\n\n\n// Base class implementation of +alloc. cls is not nil.\n// Calls [cls allocWithZone:nil].\nid\n_objc_rootAlloc(Class cls)\n{\n    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);\n}\n\n// Calls [cls alloc].\nid\nobjc_alloc(Class cls)\n{\n    return callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/);\n}\n\n// Calls [cls allocWithZone:nil].\nid \nobjc_allocWithZone(Class cls)\n{\n    return callAlloc(cls, true/*checkNil*/, true/*allocWithZone*/);\n}\n\n\nvoid\n_objc_rootDealloc(id obj)\n{\n    assert(obj);\n\n    obj->rootDealloc();\n}\n\nvoid\n_objc_rootFinalize(id obj __unused)\n{\n    assert(obj);\n    _objc_fatal(\"_objc_rootFinalize called with garbage collection off\");\n}\n\n\nid\n_objc_rootInit(id obj)\n{\n    // In practice, it will be hard to rely on this function.\n    // Many classes do not properly chain -init calls.\n    return obj;\n}\n\n\nmalloc_zone_t *\n_objc_rootZone(id obj)\n{\n    (void)obj;\n#if __OBJC2__\n    // allocWithZone under __OBJC2__ ignores the zone parameter\n    return malloc_default_zone();\n#else\n    malloc_zone_t *rval = malloc_zone_from_ptr(obj);\n    return rval ? rval : malloc_default_zone();\n#endif\n}\n\nuintptr_t\n_objc_rootHash(id obj)\n{\n    return (uintptr_t)obj;\n}\n\nvoid *\nobjc_autoreleasePoolPush(void)\n{\n    return AutoreleasePoolPage::push();\n}\n\nvoid\nobjc_autoreleasePoolPop(void *ctxt)\n{\n    AutoreleasePoolPage::pop(ctxt);\n}\n\n\nvoid *\n_objc_autoreleasePoolPush(void)\n{\n    return objc_autoreleasePoolPush();\n}\n\nvoid\n_objc_autoreleasePoolPop(void *ctxt)\n{\n    objc_autoreleasePoolPop(ctxt);\n}\n\nvoid \n_objc_autoreleasePoolPrint(void)\n{\n    AutoreleasePoolPage::printAll();\n}\n\n\n// Same as objc_release but suitable for tail-calling \n// if you need the value back and don't want to push a frame before this point.\n__attribute__((noinline))\nstatic id \nobjc_releaseAndReturn(id obj)\n{\n    objc_release(obj);\n    return obj;\n}\n\n// Same as objc_retainAutorelease but suitable for tail-calling \n// if you don't want to push a frame before this point.\n__attribute__((noinline))\nstatic id \nobjc_retainAutoreleaseAndReturn(id obj)\n{\n    return objc_retainAutorelease(obj);\n}\n\n\n// Prepare a value at +1 for return through a +0 autoreleasing convention.\nid \nobjc_autoreleaseReturnValue(id obj)\n{\n    if (prepareOptimizedReturn(ReturnAtPlus1)) return obj;\n\n    return objc_autorelease(obj);\n}\n\n// Prepare a value at +0 for return through a +0 autoreleasing convention.\nid \nobjc_retainAutoreleaseReturnValue(id obj)\n{\n    if (prepareOptimizedReturn(ReturnAtPlus0)) return obj;\n\n    // not objc_autoreleaseReturnValue(objc_retain(obj)) \n    // because we don't need another optimization attempt\n    return objc_retainAutoreleaseAndReturn(obj);\n}\n\n// Accept a value returned through a +0 autoreleasing convention for use at +1.\nid\nobjc_retainAutoreleasedReturnValue(id obj)\n{\n    if (acceptOptimizedReturn() == ReturnAtPlus1) return obj;\n\n    return objc_retain(obj);\n}\n\n// Accept a value returned through a +0 autoreleasing convention for use at +0.\nid\nobjc_unsafeClaimAutoreleasedReturnValue(id obj)\n{\n    if (acceptOptimizedReturn() == ReturnAtPlus0) return obj;\n\n    return objc_releaseAndReturn(obj);\n}\n\nid\nobjc_retainAutorelease(id obj)\n{\n    return objc_autorelease(objc_retain(obj));\n}\n\nvoid\n_objc_deallocOnMainThreadHelper(void *context)\n{\n    id obj = (id)context;\n    [obj dealloc];\n}\n\n// convert objc_objectptr_t to id, callee must take ownership.\nid objc_retainedObject(objc_objectptr_t pointer) { return (id)pointer; }\n\n// convert objc_objectptr_t to id, without ownership transfer.\nid objc_unretainedObject(objc_objectptr_t pointer) { return (id)pointer; }\n\n// convert id to objc_objectptr_t, no ownership transfer.\nobjc_objectptr_t objc_unretainedPointer(id object) { return object; }\n\n\nvoid arr_init(void) \n{\n    AutoreleasePoolPage::init();\n    SideTableInit();\n}\n\n\n#if SUPPORT_TAGGED_POINTERS\n\n// Placeholder for old debuggers. When they inspect an \n// extended tagged pointer object they will see this isa.\n\n@interface __NSUnrecognizedTaggedPointer : NSObject\n@end\n\n@implementation __NSUnrecognizedTaggedPointer\n+(void) load { } \n-(id) retain { return self; }\n-(oneway void) release { }\n-(id) autorelease { return self; }\n@end\n\n#endif\n\n\n@implementation NSObject\n\n+ (void)load {\n}\n\n+ (void)initialize {\n}\n\n+ (id)self {\n    return (id)self;\n}\n\n- (id)self {\n    return self;\n}\n\n+ (Class)class {\n    return self;\n}\n\n- (Class)class {\n    return object_getClass(self);\n}\n\n+ (Class)superclass {\n    return self->superclass;\n}\n\n- (Class)superclass {\n    return [self class]->superclass;\n}\n\n+ (BOOL)isMemberOfClass:(Class)cls {\n    return object_getClass((id)self) == cls;\n}\n\n- (BOOL)isMemberOfClass:(Class)cls {\n    return [self class] == cls;\n}\n\n+ (BOOL)isKindOfClass:(Class)cls {\n    for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {\n        if (tcls == cls) return YES;\n    }\n    return NO;\n}\n\n- (BOOL)isKindOfClass:(Class)cls {\n    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {\n        if (tcls == cls) return YES;\n    }\n    return NO;\n}\n\n+ (BOOL)isSubclassOfClass:(Class)cls {\n    for (Class tcls = self; tcls; tcls = tcls->superclass) {\n        if (tcls == cls) return YES;\n    }\n    return NO;\n}\n\n+ (BOOL)isAncestorOfObject:(NSObject *)obj {\n    for (Class tcls = [obj class]; tcls; tcls = tcls->superclass) {\n        if (tcls == self) return YES;\n    }\n    return NO;\n}\n\n+ (BOOL)instancesRespondToSelector:(SEL)sel {\n    if (!sel) return NO;\n    return class_respondsToSelector(self, sel);\n}\n\n+ (BOOL)respondsToSelector:(SEL)sel {\n    if (!sel) return NO;\n    return class_respondsToSelector_inst(object_getClass(self), sel, self);\n}\n\n- (BOOL)respondsToSelector:(SEL)sel {\n    if (!sel) return NO;\n    return class_respondsToSelector_inst([self class], sel, self);\n}\n\n+ (BOOL)conformsToProtocol:(Protocol *)protocol {\n    if (!protocol) return NO;\n    for (Class tcls = self; tcls; tcls = tcls->superclass) {\n        if (class_conformsToProtocol(tcls, protocol)) return YES;\n    }\n    return NO;\n}\n\n- (BOOL)conformsToProtocol:(Protocol *)protocol {\n    if (!protocol) return NO;\n    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {\n        if (class_conformsToProtocol(tcls, protocol)) return YES;\n    }\n    return NO;\n}\n\n+ (NSUInteger)hash {\n    return _objc_rootHash(self);\n}\n\n- (NSUInteger)hash {\n    return _objc_rootHash(self);\n}\n\n+ (BOOL)isEqual:(id)obj {\n    return obj == (id)self;\n}\n\n- (BOOL)isEqual:(id)obj {\n    return obj == self;\n}\n\n\n+ (BOOL)isFault {\n    return NO;\n}\n\n- (BOOL)isFault {\n    return NO;\n}\n\n+ (BOOL)isProxy {\n    return NO;\n}\n\n- (BOOL)isProxy {\n    return NO;\n}\n\n\n+ (IMP)instanceMethodForSelector:(SEL)sel {\n    if (!sel) [self doesNotRecognizeSelector:sel];\n    return class_getMethodImplementation(self, sel);\n}\n\n+ (IMP)methodForSelector:(SEL)sel {\n    if (!sel) [self doesNotRecognizeSelector:sel];\n    return object_getMethodImplementation((id)self, sel);\n}\n\n- (IMP)methodForSelector:(SEL)sel {\n    if (!sel) [self doesNotRecognizeSelector:sel];\n    return object_getMethodImplementation(self, sel);\n}\n\n+ (BOOL)resolveClassMethod:(SEL)sel {\n    return NO;\n}\n\n+ (BOOL)resolveInstanceMethod:(SEL)sel {\n    return NO;\n}\n\n// Replaced by CF (throws an NSException)\n+ (void)doesNotRecognizeSelector:(SEL)sel {\n    _objc_fatal(\"+[%s %s]: unrecognized selector sent to instance %p\", \n                class_getName(self), sel_getName(sel), self);\n}\n\n// Replaced by CF (throws an NSException)\n- (void)doesNotRecognizeSelector:(SEL)sel {\n    _objc_fatal(\"-[%s %s]: unrecognized selector sent to instance %p\", \n                object_getClassName(self), sel_getName(sel), self);\n}\n\n\n+ (id)performSelector:(SEL)sel {\n    if (!sel) [self doesNotRecognizeSelector:sel];\n    return ((id(*)(id, SEL))objc_msgSend)((id)self, sel);\n}\n\n+ (id)performSelector:(SEL)sel withObject:(id)obj {\n    if (!sel) [self doesNotRecognizeSelector:sel];\n    return ((id(*)(id, SEL, id))objc_msgSend)((id)self, sel, obj);\n}\n\n+ (id)performSelector:(SEL)sel withObject:(id)obj1 withObject:(id)obj2 {\n    if (!sel) [self doesNotRecognizeSelector:sel];\n    return ((id(*)(id, SEL, id, id))objc_msgSend)((id)self, sel, obj1, obj2);\n}\n\n- (id)performSelector:(SEL)sel {\n    if (!sel) [self doesNotRecognizeSelector:sel];\n    return ((id(*)(id, SEL))objc_msgSend)(self, sel);\n}\n\n- (id)performSelector:(SEL)sel withObject:(id)obj {\n    if (!sel) [self doesNotRecognizeSelector:sel];\n    return ((id(*)(id, SEL, id))objc_msgSend)(self, sel, obj);\n}\n\n- (id)performSelector:(SEL)sel withObject:(id)obj1 withObject:(id)obj2 {\n    if (!sel) [self doesNotRecognizeSelector:sel];\n    return ((id(*)(id, SEL, id, id))objc_msgSend)(self, sel, obj1, obj2);\n}\n\n\n// Replaced by CF (returns an NSMethodSignature)\n+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)sel {\n    _objc_fatal(\"+[NSObject instanceMethodSignatureForSelector:] \"\n                \"not available without CoreFoundation\");\n}\n\n// Replaced by CF (returns an NSMethodSignature)\n+ (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {\n    _objc_fatal(\"+[NSObject methodSignatureForSelector:] \"\n                \"not available without CoreFoundation\");\n}\n\n// Replaced by CF (returns an NSMethodSignature)\n- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {\n    _objc_fatal(\"-[NSObject methodSignatureForSelector:] \"\n                \"not available without CoreFoundation\");\n}\n\n+ (void)forwardInvocation:(NSInvocation *)invocation {\n    [self doesNotRecognizeSelector:(invocation ? [invocation selector] : 0)];\n}\n\n- (void)forwardInvocation:(NSInvocation *)invocation {\n    [self doesNotRecognizeSelector:(invocation ? [invocation selector] : 0)];\n}\n\n+ (id)forwardingTargetForSelector:(SEL)sel {\n    return nil;\n}\n\n- (id)forwardingTargetForSelector:(SEL)sel {\n    return nil;\n}\n\n\n// Replaced by CF (returns an NSString)\n+ (NSString *)description {\n    return nil;\n}\n\n// Replaced by CF (returns an NSString)\n- (NSString *)description {\n    return nil;\n}\n\n+ (NSString *)debugDescription {\n    return [self description];\n}\n\n- (NSString *)debugDescription {\n    return [self description];\n}\n\n\n+ (id)new {\n    return [callAlloc(self, false/*checkNil*/) init];\n}\n\n+ (id)retain {\n    return (id)self;\n}\n\n// Replaced by ObjectAlloc\n- (id)retain {\n    return ((id)self)->rootRetain();\n}\n\n\n+ (BOOL)_tryRetain {\n    return YES;\n}\n\n// Replaced by ObjectAlloc\n- (BOOL)_tryRetain {\n    return ((id)self)->rootTryRetain();\n}\n\n+ (BOOL)_isDeallocating {\n    return NO;\n}\n\n- (BOOL)_isDeallocating {\n    return ((id)self)->rootIsDeallocating();\n}\n\n+ (BOOL)allowsWeakReference { \n    return YES; \n}\n\n+ (BOOL)retainWeakReference { \n    return YES; \n}\n\n- (BOOL)allowsWeakReference { \n    return ! [self _isDeallocating]; \n}\n\n- (BOOL)retainWeakReference { \n    return [self _tryRetain]; \n}\n\n+ (oneway void)release {\n}\n\n// Replaced by ObjectAlloc\n- (oneway void)release {\n    ((id)self)->rootRelease();\n}\n\n+ (id)autorelease {\n    return (id)self;\n}\n\n// Replaced by ObjectAlloc\n- (id)autorelease {\n    return ((id)self)->rootAutorelease();\n}\n\n+ (NSUInteger)retainCount {\n    return ULONG_MAX;\n}\n\n- (NSUInteger)retainCount {\n    return ((id)self)->rootRetainCount();\n}\n\n+ (id)alloc {\n    return _objc_rootAlloc(self);\n}\n\n// Replaced by ObjectAlloc\n+ (id)allocWithZone:(struct _NSZone *)zone {\n    return _objc_rootAllocWithZone(self, (malloc_zone_t *)zone);\n}\n\n// Replaced by CF (throws an NSException)\n+ (id)init {\n    return (id)self;\n}\n\n- (id)init {\n    return _objc_rootInit(self);\n}\n\n// Replaced by CF (throws an NSException)\n+ (void)dealloc {\n}\n\n\n// Replaced by NSZombies\n- (void)dealloc {\n    _objc_rootDealloc(self);\n}\n\n// Previously used by GC. Now a placeholder for binary compatibility.\n- (void) finalize {\n}\n\n+ (struct _NSZone *)zone {\n    return (struct _NSZone *)_objc_rootZone(self);\n}\n\n- (struct _NSZone *)zone {\n    return (struct _NSZone *)_objc_rootZone(self);\n}\n\n+ (id)copy {\n    return (id)self;\n}\n\n+ (id)copyWithZone:(struct _NSZone *)zone {\n    return (id)self;\n}\n\n- (id)copy {\n    return [(id)self copyWithZone:nil];\n}\n\n+ (id)mutableCopy {\n    return (id)self;\n}\n\n+ (id)mutableCopyWithZone:(struct _NSZone *)zone {\n    return (id)self;\n}\n\n- (id)mutableCopy {\n    return [(id)self mutableCopyWithZone:nil];\n}\n\n@end\n\n\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/Object.h",
    "content": "/*\n * Copyright (c) 1999-2003, 2005-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\n\tObject.h\n\tCopyright 1988-1996 NeXT Software, Inc.\n  \n\tDEFINED AS:\tA common class\n\tHEADER FILES:\t<objc/Object.h>\n\n*/\n\n#ifndef _OBJC_OBJECT_H_\n#define _OBJC_OBJECT_H_\n\n#include <stdarg.h>\n#include <objc/objc-runtime.h>\n\n#if __OBJC__  &&  !__OBJC2__\n\n__OSX_AVAILABLE(10.0) \n__IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n__WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE\nOBJC_ROOT_CLASS\n@interface Object\n{\n\tClass isa;\t/* A pointer to the instance's class structure */\n}\n\n/* Initializing classes and instances */\n\n+ (id)initialize;\n- (id)init;\n\n/* Creating, copying, and freeing instances */\n\n+ (id)new;\n+ (id)free;\n- (id)free;\n+ (id)alloc;\n- (id)copy;\n+ (id)allocFromZone:(void *)zone;\n- (id)copyFromZone:(void *)zone;\n- (void *)zone;\n\n/* Identifying classes */\n\n+ (id)class;\n+ (id)superclass;\n+ (const char *) name;\n- (id)class;\n- (id)superclass;\n- (const char *) name;\n\n/* Identifying and comparing instances */\n\n- (id)self;\n- (unsigned int) hash;\n- (BOOL) isEqual:anObject;\n\n/* Testing inheritance relationships */\n\n- (BOOL) isKindOf: aClassObject;\n- (BOOL) isMemberOf: aClassObject;\n- (BOOL) isKindOfClassNamed: (const char *)aClassName;\n- (BOOL) isMemberOfClassNamed: (const char *)aClassName;\n\n/* Testing class functionality */\n\n+ (BOOL) instancesRespondTo:(SEL)aSelector;\n- (BOOL) respondsTo:(SEL)aSelector;\n\n/* Testing protocol conformance */\n\n- (BOOL) conformsTo: (Protocol *)aProtocolObject;\n+ (BOOL) conformsTo: (Protocol *)aProtocolObject;\n\n/* Obtaining method descriptors from protocols */\n\n- (struct objc_method_description *) descriptionForMethod:(SEL)aSel;\n+ (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel;\n\n/* Obtaining method handles */\n\n- (IMP) methodFor:(SEL)aSelector;\n+ (IMP) instanceMethodFor:(SEL)aSelector;\n\n/* Sending messages determined at run time */\n\n- (id)perform:(SEL)aSelector;\n- (id)perform:(SEL)aSelector with:anObject;\n- (id)perform:(SEL)aSelector with:object1 with:object2;\n\n/* Posing */\n\n+ (id)poseAs: aClassObject;\n\n/* Enforcing intentions */\n \n- (id)subclassResponsibility:(SEL)aSelector;\n- (id)notImplemented:(SEL)aSelector;\n\n/* Error handling */\n\n- (id)doesNotRecognize:(SEL)aSelector;\n- (id)error:(const char *)aString, ...;\n\n/* Debugging */\n\n- (void) printForDebugger:(void *)stream;\n\n/* Archiving */\n\n- (id)awake;\n- (id)write:(void *)stream;\n- (id)read:(void *)stream;\n+ (int) version;\n+ (id)setVersion: (int) aVersion;\n\n/* Forwarding */\n\n- (id)forward: (SEL)sel : (marg_list)args;\n- (id)performv: (SEL)sel : (marg_list)args;\n\n@end\n\n/* Abstract Protocol for Archiving */\n\n@interface Object (Archiving)\n\n- (id)startArchiving: (void *)stream;\n- (id)finishUnarchiving;\n\n@end\n\n/* Abstract Protocol for Dynamic Loading */\n\n@interface Object (DynamicLoading)\n\n//+ finishLoading:(headerType *)header;\nstruct mach_header;\n+ (id)finishLoading:(struct mach_header *)header;\n+ (id)startUnloading;\n\n@end\n\n#endif\n\n#endif /* _OBJC_OBJECT_H_ */\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/Object.mm",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\n\tObject.m\n\tCopyright 1988-1996 NeXT Software, Inc.\n*/\n\n#include \"objc-private.h\"\n\n#undef id\n#undef Class\n\ntypedef struct objc_class *Class;\ntypedef struct objc_object *id;\n\n#if __OBJC2__\n\n@implementation Object\n\n+ (id)initialize\n{\n    return self; \n}\n\n+ (id)class\n{\n    return self;\n}\n\n-(id) retain\n{\n    return _objc_rootRetain(self);\n}\n\n-(void) release\n{\n    _objc_rootRelease(self);\n}\n\n-(id) autorelease\n{\n    return _objc_rootAutorelease(self);\n}\n\n+(id) retain\n{\n    return self;\n}\n\n+(void) release\n{\n}\n\n+(id) autorelease\n{\n    return self;\n}\n\n\n@end\n\n\n// __OBJC2__\n#else\n// not __OBJC2__\n\n#include <stdlib.h>\n#include <stdarg.h>\n#include <string.h>\n#include <malloc/malloc.h>\n\n#include \"Object.h\"\n#include \"Protocol.h\"\n#include \"objc-runtime.h\"\n\n\n// Error Messages\nstatic const char\n\t_errShouldHaveImp[] = \"should have implemented the '%s' method.\",\n\t_errShouldNotImp[] = \"should NOT have implemented the '%s' method.\",\n\t_errLeftUndone[] = \"method '%s' not implemented\",\n\t_errBadSel[] = \"method %s given invalid selector %s\",\n\t_errDoesntRecognize[] = \"does not recognize selector %c%s\";\n\n\n@implementation Object\n\n\n+ (id)initialize\n{\n\treturn self; \n}\n\n- (id)awake\n{\n\treturn self; \n}\n\n+ (id)poseAs: aFactory\n{ \n\treturn class_poseAs(self, aFactory); \n}\n\n+ (id)new\n{\n\tid newObject = (*_alloc)((Class)self, 0);\n\tClass metaClass = self->ISA();\n\tif (class_getVersion(metaClass) > 1)\n\t    return [newObject init];\n\telse\n\t    return newObject;\n}\n\n+ (id)alloc\n{\n\treturn (*_zoneAlloc)((Class)self, 0, malloc_default_zone()); \n}\n\n+ (id)allocFromZone:(void *) z\n{\n\treturn (*_zoneAlloc)((Class)self, 0, z); \n}\n\n- (id)init\n{\n    return self;\n}\n\n- (const char *)name\n{\n\treturn class_getName(isa); \n}\n\n+ (const char *)name\n{\n\treturn class_getName((Class)self); \n}\n\n- (unsigned)hash\n{\n\treturn (unsigned)(((uintptr_t)self) >> 2);\n}\n\n- (BOOL)isEqual:anObject\n{\n\treturn anObject == self; \n}\n\n- (id)free\n{ \n\treturn (*_dealloc)(self); \n}\n\n+ (id)free\n{\n\treturn nil; \n}\n\n- (id)self\n{\n\treturn self; \n}\n\n\n-(id)class\n{\n\treturn (id)isa; \n}\n\n+ (id)class\n{\n\treturn self;\n}\n\n- (void *)zone\n{\n\tvoid *z = malloc_zone_from_ptr(self);\n\treturn z ? z : malloc_default_zone();\n}\n\n+ (id)superclass\n{ \n\treturn self->superclass; \n}\n\n- (id)superclass\n{ \n\treturn isa->superclass; \n}\n\n+ (int) version\n{\n\treturn class_getVersion((Class)self);\n}\n\n+ (id)setVersion: (int) aVersion\n{\n        class_setVersion((Class)self, aVersion);\n\treturn self;\n}\n\n- (BOOL)isKindOf:aClass\n{\n\tClass cls;\n\tfor (cls = isa; cls; cls = cls->superclass) \n\t\tif (cls == (Class)aClass)\n\t\t\treturn YES;\n\treturn NO;\n}\n\n- (BOOL)isMemberOf:aClass\n{\n\treturn isa == (Class)aClass;\n}\n\n- (BOOL)isKindOfClassNamed:(const char *)aClassName\n{\n\tClass cls;\n\tfor (cls = isa; cls; cls = cls->superclass) \n\t\tif (strcmp(aClassName, class_getName(cls)) == 0)\n\t\t\treturn YES;\n\treturn NO;\n}\n\n- (BOOL)isMemberOfClassNamed:(const char *)aClassName\n{\n\treturn strcmp(aClassName, class_getName(isa)) == 0;\n}\n\n+ (BOOL)instancesRespondTo:(SEL)aSelector\n{\n\treturn class_respondsToMethod((Class)self, aSelector);\n}\n\n- (BOOL)respondsTo:(SEL)aSelector\n{\n\treturn class_respondsToMethod(isa, aSelector);\n}\n\n- (id)copy\n{\n\treturn [self copyFromZone: [self zone]];\n}\n\n- (id)copyFromZone:(void *)z\n{\n\treturn (*_zoneCopy)(self, 0, z); \n}\n\n- (IMP)methodFor:(SEL)aSelector\n{\n\treturn class_lookupMethod(isa, aSelector);\n}\n\n+ (IMP)instanceMethodFor:(SEL)aSelector\n{\n\treturn class_lookupMethod(self, aSelector);\n}\n\n- (id)perform:(SEL)aSelector\n{ \n\tif (aSelector)\n\t\treturn ((id(*)(id, SEL))objc_msgSend)(self, aSelector); \n\telse\n\t\treturn [self error:_errBadSel, sel_getName(_cmd), aSelector];\n}\n\n- (id)perform:(SEL)aSelector with:anObject\n{\n\tif (aSelector)\n\t\treturn ((id(*)(id, SEL, id))objc_msgSend)(self, aSelector, anObject); \n\telse\n\t\treturn [self error:_errBadSel, sel_getName(_cmd), aSelector];\n}\n\n- (id)perform:(SEL)aSelector with:obj1 with:obj2\n{\n\tif (aSelector)\n\t\treturn ((id(*)(id, SEL, id, id))objc_msgSend)(self, aSelector, obj1, obj2); \n\telse\n\t\treturn [self error:_errBadSel, sel_getName(_cmd), aSelector];\n}\n\n- (id)subclassResponsibility:(SEL)aSelector\n{\n\treturn [self error:_errShouldHaveImp, sel_getName(aSelector)];\n}\n\n- (id)notImplemented:(SEL)aSelector\n{\n\treturn [self error:_errLeftUndone, sel_getName(aSelector)];\n}\n\n- (id)doesNotRecognize:(SEL)aMessage\n{\n\treturn [self error:_errDoesntRecognize, \n\t\tclass_isMetaClass(isa) ? '+' : '-', sel_getName(aMessage)];\n}\n\n- (id)error:(const char *)aCStr, ... \n{\n\tva_list ap;\n\tva_start(ap,aCStr); \n\t(*_error)(self, aCStr, ap); \n\t_objc_error (self, aCStr, ap);\t/* In case (*_error)() returns. */\n\tva_end(ap);\n        return nil;\n}\n\n- (void) printForDebugger:(void *)stream\n{\n}\n\n- (id)write:(void *) stream\n{\n\treturn self;\n}\n\n- (id)read:(void *) stream\n{\n\treturn self;\n}\n\n- (id)forward: (SEL) sel : (marg_list) args\n{\n    return [self doesNotRecognize: sel];\n}\n\n/* this method is not part of the published API */\n\n- (unsigned)methodArgSize:(SEL)sel\n{\n    Method\tmethod = class_getInstanceMethod((Class)isa, sel);\n    if (! method) return 0;\n    return method_getSizeOfArguments(method);\n}\n\n- (id)performv: (SEL) sel : (marg_list) args\n{\n    unsigned\tsize;\n\n    // Messages to nil object always return nil\n    if (! self) return nil;\n\n    // Calculate size of the marg_list from the method's\n    // signature.  This looks for the method in self\n    // and its superclasses.\n    size = [self methodArgSize: sel];\n\n    // If neither self nor its superclasses implement\n    // it, forward the message because self might know\n    // someone who does.  This is a \"chained\" forward...\n    if (! size) return [self forward: sel: args];\n\n    // Message self with the specified selector and arguments\n    return objc_msgSendv (self, sel, size, args); \n}\n\n/* Testing protocol conformance */\n\n- (BOOL) conformsTo: (Protocol *)aProtocolObj\n{\n  return [(id)isa conformsTo:aProtocolObj];\n}\n\n+ (BOOL) conformsTo: (Protocol *)aProtocolObj\n{\n  Class cls;\n  for (cls = self; cls; cls = cls->superclass)\n    {\n      if (class_conformsToProtocol(cls, aProtocolObj)) return YES;\n    }\n  return NO;\n}\n\n\n/* Looking up information for a method */\n\n- (struct objc_method_description *) descriptionForMethod:(SEL)aSelector\n{\n  Class cls;\n  struct objc_method_description *m;\n\n  /* Look in the protocols first. */\n  for (cls = isa; cls; cls = cls->superclass)\n    {\n      if (cls->ISA()->version >= 3)\n        {\n\t  struct objc_protocol_list *protocols = \n              (struct objc_protocol_list *)cls->protocols;\n  \n\t  while (protocols)\n\t    {\n\t      int i;\n\n\t      for (i = 0; i < protocols->count; i++)\n\t\t{\n\t\t  Protocol *p = protocols->list[i];\n\n\t\t  if (class_isMetaClass(cls))\n\t\t    m = [p descriptionForClassMethod:aSelector];\n\t\t  else\n\t\t    m = [p descriptionForInstanceMethod:aSelector];\n\n\t\t  if (m) {\n\t\t      return m;\n\t\t  }\n\t\t}\n  \n\t      if (cls->ISA()->version <= 4)\n\t\tbreak;\n  \n\t      protocols = protocols->next;\n\t    }\n\t}\n    }\n\n  /* Then try the class implementations. */\n    for (cls = isa; cls; cls = cls->superclass) {\n        void *iterator = 0;\n\tint i;\n        struct objc_method_list *mlist;\n        while ( (mlist = class_nextMethodList( cls, &iterator )) ) {\n            for (i = 0; i < mlist->method_count; i++)\n                if (mlist->method_list[i].method_name == aSelector) {\n\t\t    m = (struct objc_method_description *)&mlist->method_list[i];\n                    return m;\n\t\t}\n        }\n    }\n  return 0;\n}\n\n+ (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSelector\n{\n  Class cls;\n\n  /* Look in the protocols first. */\n  for (cls = self; cls; cls = cls->superclass)\n    {\n      if (cls->ISA()->version >= 3)\n        {\n\t  struct objc_protocol_list *protocols = \n              (struct objc_protocol_list *)cls->protocols;\n  \n\t  while (protocols)\n\t    {\n\t      int i;\n\n\t      for (i = 0; i < protocols->count; i++)\n\t\t{\n\t\t  Protocol *p = protocols->list[i];\n\t\t  struct objc_method_description *m;\n\n\t\t  if ((m = [p descriptionForInstanceMethod:aSelector]))\n\t\t    return m;\n\t\t}\n  \n\t      if (cls->ISA()->version <= 4)\n\t\tbreak;\n  \n\t      protocols = protocols->next;\n\t    }\n\t}\n    }\n\n  /* Then try the class implementations. */\n    for (cls = self; cls; cls = cls->superclass) {\n        void *iterator = 0;\n\tint i;\n        struct objc_method_list *mlist;\n        while ( (mlist = class_nextMethodList( cls, &iterator )) ) {\n            for (i = 0; i < mlist->method_count; i++)\n                if (mlist->method_list[i].method_name == aSelector) {\n\t\t    struct objc_method_description *m;\n\t\t    m = (struct objc_method_description *)&mlist->method_list[i];\n                    return m;\n\t\t}\n        }\n    }\n  return 0;\n}\n\n\n/* Obsolete methods (for binary compatibility only). */\n\n+ (id)superClass\n{\n\treturn [self superclass];\n}\n\n- (id)superClass\n{\n\treturn [self superclass];\n}\n\n- (BOOL)isKindOfGivenName:(const char *)aClassName\n{\n\treturn [self isKindOfClassNamed: aClassName];\n}\n\n- (BOOL)isMemberOfGivenName:(const char *)aClassName\n{\n\treturn [self isMemberOfClassNamed: aClassName];\n}\n\n- (struct objc_method_description *) methodDescFor:(SEL)aSelector\n{\n  return [self descriptionForMethod: aSelector];\n}\n\n+ (struct objc_method_description *) instanceMethodDescFor:(SEL)aSelector\n{\n  return [self descriptionForInstanceMethod: aSelector];\n}\n\n- (id)findClass:(const char *)aClassName\n{\n\treturn objc_lookUpClass(aClassName);\n}\n\n- (id)shouldNotImplement:(SEL)aSelector\n{\n\treturn [self error:_errShouldNotImp, sel_getName(aSelector)];\n}\n\n\n@end\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/OldClasses.subproj/List.h",
    "content": "/*\n * Copyright (c) 1999-2002, 2005-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\n    List.h\n    Copyright 1988-1996 NeXT Software, Inc.\n\n    DEFINED AS:\tA common class\n    HEADER FILES:\tobjc/List.h\n\n*/\n\n#ifndef _OBJC_LIST_H_\n#define _OBJC_LIST_H_\n\n#if __OBJC__  &&  !__OBJC2__  &&  !__cplusplus  &&  !__has_feature(objc_arc)\n\n#include <objc/Object.h>\n#include <Availability.h>\n\nDEPRECATED_ATTRIBUTE\n@interface List : Object\n{\n@public\n    id \t\t*dataPtr  DEPRECATED_ATTRIBUTE;\t/* data of the List object */\n    unsigned \tnumElements  DEPRECATED_ATTRIBUTE;\t/* Actual number of elements */\n    unsigned \tmaxElements  DEPRECATED_ATTRIBUTE;\t/* Total allocated elements */\n}\n\n/* Creating, freeing */\n\n- (id)free  DEPRECATED_ATTRIBUTE;\n- (id)freeObjects  DEPRECATED_ATTRIBUTE;\n- (id)copyFromZone:(void *)z  DEPRECATED_ATTRIBUTE;\n  \n/* Initializing */\n\n- (id)init  DEPRECATED_ATTRIBUTE;\n- (id)initCount:(unsigned)numSlots  DEPRECATED_ATTRIBUTE;\n\n/* Comparing two lists */\n\n- (BOOL)isEqual: anObject  DEPRECATED_ATTRIBUTE;\n  \n/* Managing the storage capacity */\n\n- (unsigned)capacity  DEPRECATED_ATTRIBUTE;\n- (id)setAvailableCapacity:(unsigned)numSlots  DEPRECATED_ATTRIBUTE;\n\n/* Manipulating objects by index */\n\n- (unsigned)count  DEPRECATED_ATTRIBUTE;\n- (id)objectAt:(unsigned)index  DEPRECATED_ATTRIBUTE;\n- (id)lastObject  DEPRECATED_ATTRIBUTE;\n- (id)addObject:anObject  DEPRECATED_ATTRIBUTE;\n- (id)insertObject:anObject at:(unsigned)index  DEPRECATED_ATTRIBUTE;\n- (id)removeObjectAt:(unsigned)index  DEPRECATED_ATTRIBUTE;\n- (id)removeLastObject  DEPRECATED_ATTRIBUTE;\n- (id)replaceObjectAt:(unsigned)index with:newObject  DEPRECATED_ATTRIBUTE;\n- (id)appendList: (List *)otherList  DEPRECATED_ATTRIBUTE;\n\n/* Manipulating objects by id */\n\n- (unsigned)indexOf:anObject  DEPRECATED_ATTRIBUTE;\n- (id)addObjectIfAbsent:anObject  DEPRECATED_ATTRIBUTE;\n- (id)removeObject:anObject  DEPRECATED_ATTRIBUTE;\n- (id)replaceObject:anObject with:newObject  DEPRECATED_ATTRIBUTE;\n\n/* Emptying the list */\n\n- (id)empty  DEPRECATED_ATTRIBUTE;\n\n/* Sending messages to elements of the list */\n\n- (id)makeObjectsPerform:(SEL)aSelector  DEPRECATED_ATTRIBUTE;\n- (id)makeObjectsPerform:(SEL)aSelector with:anObject  DEPRECATED_ATTRIBUTE;\n\n/*\n * The following new... methods are now obsolete.  They remain in this \n * interface file for backward compatibility only.  Use Object's alloc method \n * and the init... methods defined in this class instead.\n */\n\n+ (id)new  DEPRECATED_ATTRIBUTE;\n+ (id)newCount:(unsigned)numSlots  DEPRECATED_ATTRIBUTE;\n\n@end\n\ntypedef struct {\n    @defs(List);\n} NXListId  DEPRECATED_ATTRIBUTE;\n\n#define NX_ADDRESS(x) (((NXListId *)(x))->dataPtr)\n\n#define NX_NOT_IN_LIST\t0xffffffff\n\n#endif\n\n#endif /* _OBJC_LIST_H_ */\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/OldClasses.subproj/List.m",
    "content": "/*\n * Copyright (c) 1999-2001, 2005-2006 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\n\tList.m\n  \tCopyright 1988-1996 NeXT Software, Inc.\n\tWritten by: Bryan Yamamoto\n\tResponsibility: Bertrand Serlet\n*/\n\n#ifndef __OBJC2__\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <objc/List.h>\n\n#define DATASIZE(count) ((count) * sizeof(id))\n\n@implementation  List\n\n+ (id)initialize\n{\n    [self setVersion: 1];\n    return self;\n}\n\n- (id)initCount:(unsigned)numSlots\n{\n    maxElements = numSlots;\n    if (maxElements) \n\tdataPtr = (id *)malloc(DATASIZE(maxElements));\n    return self;\n}\n\n+ (id)newCount:(unsigned)numSlots\n{\n    return [[self alloc] initCount:numSlots];\n}\n\n+ (id)new\n{\n    return [self newCount:0];\n}\n\n- (id)init\n{\n    return [self initCount:0];\n}\n\n- (id)free\n{\n    free(dataPtr);\n    return [super free];\n}\n\n- (id)freeObjects\n{\n    id element;\n    while ((element = [self removeLastObject]))\n\t[element free];\n    return self;\n}\n\n- (id)copyFromZone:(void *)z\n{\n    List\t*new = [[[self class] alloc] initCount: numElements];\n    new->numElements = numElements;\n    bcopy ((const char*)dataPtr, (char*)new->dataPtr, DATASIZE(numElements));\n    return new;\n}\n\n- (BOOL) isEqual: anObject\n{\n    List\t*other;\n    if (! [anObject isKindOf: [self class]]) return NO;\n    other = (List *) anObject;\n    return (numElements == other->numElements) \n    \t&& (bcmp ((const char*)dataPtr, (const char*)other->dataPtr, DATASIZE(numElements)) == 0);\n}\n\n- (unsigned)capacity\n{\n    return maxElements;\n}\n\n- (unsigned)count\n{\n    return numElements;\n}\n\n- (id)objectAt:(unsigned)index\n{\n    if (index >= numElements)\n\treturn nil;\n    return dataPtr[index];\n}\n\n- (unsigned)indexOf:anObject\n{\n    register id *this = dataPtr;\n    register id *last = this + numElements;\n    while (this < last) {\n        if (*this == anObject)\n\t    return this - dataPtr;\n\tthis++;\n    }\n    return NX_NOT_IN_LIST;\n}\n\n- (id)lastObject\n{\n    if (! numElements)\n\treturn nil;\n    return dataPtr[numElements - 1];\n}\n\n- (id)setAvailableCapacity:(unsigned)numSlots\n{\n    volatile id *tempDataPtr;\n    if (numSlots < numElements) return nil;\n    tempDataPtr = (id *) realloc (dataPtr, DATASIZE(numSlots));\n    dataPtr = (id *)tempDataPtr;\n    maxElements = numSlots;\n    return self;\n}\n\n- (id)insertObject:anObject at:(unsigned)index\n{\n    register id *this, *last, *prev;\n    if (! anObject) return nil;\n    if (index > numElements)\n        return nil;\n    if ((numElements + 1) > maxElements) {\n    volatile id *tempDataPtr;\n\t/* we double the capacity, also a good size for malloc */\n\tmaxElements += maxElements + 1;\n\ttempDataPtr = (id *) realloc (dataPtr, DATASIZE(maxElements));\n\tdataPtr = (id*)tempDataPtr;\n    }\n    this = dataPtr + numElements;\n    prev = this - 1;\n    last = dataPtr + index;\n    while (this > last) \n\t*this-- = *prev--;\n    *last = anObject;\n    numElements++;\n    return self;\n}\n\n- (id)addObject:anObject\n{\n    return [self insertObject:anObject at:numElements];\n    \n}\n\n\n- (id)addObjectIfAbsent:anObject\n{\n    register id *this, *last;\n    if (! anObject) return nil;\n    this = dataPtr;\n    last = dataPtr + numElements;\n    while (this < last) {\n        if (*this == anObject)\n\t    return self;\n\tthis++;\n    }\n    return [self insertObject:anObject at:numElements];\n    \n}\n\n\n- (id)removeObjectAt:(unsigned)index\n{\n    register id *this, *last, *next;\n    id retval;\n    if (index >= numElements)\n        return nil;\n    this = dataPtr + index;\n    last = dataPtr + numElements;\n    next = this + 1;\n    retval = *this;\n    while (next < last)\n\t*this++ = *next++;\n    numElements--;\n    return retval;\n}\n\n- (id)removeObject:anObject\n{\n    register id *this, *last;\n    this = dataPtr;\n    last = dataPtr + numElements;\n    while (this < last) {\n\tif (*this == anObject)\n\t    return [self removeObjectAt:this - dataPtr];\n\tthis++;\n    }\n    return nil;\n}\n\n- (id)removeLastObject\n{\n    if (! numElements)\n\treturn nil;\n    return [self removeObjectAt: numElements - 1];\n}\n\n- (id)empty\n{\n    numElements = 0;\n    return self;\n}\n\n- (id)replaceObject:anObject with:newObject\n{\n    register id *this, *last;\n    if (! newObject)\n        return nil;\n    this = dataPtr;\n    last = dataPtr + numElements;\n    while (this < last) {\n\tif (*this == anObject) {\n\t    *this = newObject;\n\t    return anObject;\n\t}\n\tthis++;\n    }\n    return nil;\n}\n\n- (id)replaceObjectAt:(unsigned)index with:newObject\n{\n    register id *this;\n    id retval;\n    if (! newObject)\n        return nil;\n    if (index >= numElements)\n        return nil;\n    this = dataPtr + index;\n    retval = *this;\n    *this = newObject;\n    return retval;\n}\n\n- (id)makeObjectsPerform:(SEL)aSelector\n{\n    unsigned\tcount = numElements;\n    while (count--)\n\t[dataPtr[count] perform: aSelector];\n    return self;\n}\n\n- (id)makeObjectsPerform:(SEL)aSelector with:anObject\n{\n    unsigned\tcount = numElements;\n    while (count--)\n\t[dataPtr[count] perform: aSelector with: anObject];\n    return self;\n}\n\n-(id)appendList: (List *)otherList\n{\n    unsigned i, count;\n    \n    for (i = 0, count = [otherList count]; i < count; i++)\n\t[self addObject: [otherList objectAt: i]];\n    return self;\n}\n\n@end\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/Protocol.h",
    "content": "/*\n * Copyright (c) 1999-2003, 2006-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\n\tProtocol.h\n\tCopyright 1991-1996 NeXT Software, Inc.\n*/\n\n#ifndef _OBJC_PROTOCOL_H_\n#define _OBJC_PROTOCOL_H_\n\n#if !__OBJC__\n\n// typedef Protocol is here:\n#include <objc/runtime.h>\n\n\n#elif __OBJC2__\n\n#include <objc/NSObject.h>\n\n// All methods of class Protocol are unavailable. \n// Use the functions in objc/runtime.h instead.\n\nOBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)\n@interface Protocol : NSObject\n@end\n\n\n#else\n\n#include <objc/Object.h>\n\nOBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)\n@interface Protocol : Object\n{\n@private\n    char *protocol_name OBJC2_UNAVAILABLE;\n    struct objc_protocol_list *protocol_list OBJC2_UNAVAILABLE;\n    struct objc_method_description_list *instance_methods OBJC2_UNAVAILABLE;\n    struct objc_method_description_list *class_methods OBJC2_UNAVAILABLE;\n}\n\n/* Obtaining attributes intrinsic to the protocol */\n\n- (const char *)name OBJC2_UNAVAILABLE;\n\n/* Testing protocol conformance */\n\n- (BOOL) conformsTo: (Protocol *)aProtocolObject OBJC2_UNAVAILABLE;\n\n/* Looking up information specific to a protocol */\n\n- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel\n    __OSX_DEPRECATED(10.0, 10.5, \"use protocol_getMethodDescription instead\") \n    __IOS_DEPRECATED(2.0, 2.0, \"use protocol_getMethodDescription instead\") \n    __TVOS_DEPRECATED(9.0, 9.0, \"use protocol_getMethodDescription instead\") \n    __WATCHOS_DEPRECATED(1.0, 1.0, \"use protocol_getMethodDescription instead\")\n    __BRIDGEOS_DEPRECATED(2.0, 2.0, \"use protocol_getMethodDescription instead\");\n- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel \n    __OSX_DEPRECATED(10.0, 10.5, \"use protocol_getMethodDescription instead\") \n    __IOS_DEPRECATED(2.0, 2.0, \"use protocol_getMethodDescription instead\") \n    __TVOS_DEPRECATED(9.0, 9.0, \"use protocol_getMethodDescription instead\") \n    __WATCHOS_DEPRECATED(1.0, 1.0, \"use protocol_getMethodDescription instead\")\n    __BRIDGEOS_DEPRECATED(2.0, 2.0, \"use protocol_getMethodDescription instead\");\n\n@end\n\n#endif\n\n#endif /* _OBJC_PROTOCOL_H_ */\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/Protocol.mm",
    "content": "/*\n * Copyright (c) 1999-2001, 2005-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\n\tProtocol.h\n\tCopyright 1991-1996 NeXT Software, Inc.\n*/\n\n#include \"objc-private.h\"\n\n#undef id\n#undef Class\n\n#include <stdlib.h>\n#include <string.h>\n#include <mach-o/dyld.h>\n#include <mach-o/ldsyms.h>\n\n#include \"Protocol.h\"\n#include \"NSObject.h\"\n\n// __IncompleteProtocol is used as the return type of objc_allocateProtocol().\n\n// Old ABI uses NSObject as the superclass even though Protocol uses Object\n// because the R/R implementation for class Protocol is added at runtime\n// by CF, so __IncompleteProtocol would be left without an R/R implementation \n// otherwise, which would break ARC.\n\n@interface __IncompleteProtocol : NSObject @end\n@implementation __IncompleteProtocol \n#if __OBJC2__\n// fixme hack - make __IncompleteProtocol a non-lazy class\n+ (void) load { } \n#endif\n@end\n\n\n@implementation Protocol \n\n#if __OBJC2__\n// fixme hack - make Protocol a non-lazy class\n+ (void) load { } \n#endif\n\n\n- (BOOL) conformsTo: (Protocol *)aProtocolObj\n{\n    return protocol_conformsToProtocol(self, aProtocolObj);\n}\n\n- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel\n{\n#if !__OBJC2__\n    return lookup_protocol_method((struct old_protocol *)self, aSel, \n                                  YES/*required*/, YES/*instance*/, \n                                  YES/*recursive*/);\n#else\n    return method_getDescription(protocol_getMethod((struct protocol_t *)self, \n                                                     aSel, YES, YES, YES));\n#endif\n}\n\n- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel\n{\n#if !__OBJC2__\n    return lookup_protocol_method((struct old_protocol *)self, aSel, \n                                  YES/*required*/, NO/*instance*/, \n                                  YES/*recursive*/);\n#else\n    return method_getDescription(protocol_getMethod((struct protocol_t *)self, \n                                                    aSel, YES, NO, YES));\n#endif\n}\n\n- (const char *)name\n{\n    return protocol_getName(self);\n}\n\n- (BOOL)isEqual:other\n{\n#if __OBJC2__\n    // check isKindOf:\n    Class cls;\n    Class protoClass = objc_getClass(\"Protocol\");\n    for (cls = object_getClass(other); cls; cls = cls->superclass) {\n        if (cls == protoClass) break;\n    }\n    if (!cls) return NO;\n    // check equality\n    return protocol_isEqual(self, other);\n#else\n    return [other isKindOf:[Protocol class]] && [self conformsTo: other] && [other conformsTo: self];\n#endif\n}\n\n#if __OBJC2__\n- (NSUInteger)hash\n{\n    return 23;\n}\n#else\n- (unsigned)hash\n{\n    return 23;\n}\n#endif\n\n@end\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/arm64-asm.h",
    "content": "/*\n * @APPLE_LICENSE_HEADER_START@\n * \n * Copyright (c) 2018 Apple Inc.  All Rights Reserved.\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/********************************************************************\n * \n *  arm64-asm.h - asm tools for arm64/arm64_32 and ROP/JOP\n *\n ********************************************************************/\n\n#if __arm64__\n\n#if __LP64__\n// true arm64\n\n#define SUPPORT_TAGGED_POINTERS 1\n#define PTR .quad\n#define PTRSIZE 8\n#define PTRSHIFT 3  // 1<<PTRSHIFT == PTRSIZE\n// \"p\" registers are pointer-sized\n#define UXTP UXTX\n#define p0  x0\n#define p1  x1\n#define p2  x2\n#define p3  x3\n#define p4  x4\n#define p5  x5\n#define p6  x6\n#define p7  x7\n#define p8  x8\n#define p9  x9\n#define p10 x10\n#define p11 x11\n#define p12 x12\n#define p13 x13\n#define p14 x14\n#define p15 x15\n#define p16 x16\n#define p17 x17\n\n// true arm64\n#else\n// arm64_32\n\n#define SUPPORT_TAGGED_POINTERS 0\n#define PTR .long\n#define PTRSIZE 4\n#define PTRSHIFT 2  // 1<<PTRSHIFT == PTRSIZE\n// \"p\" registers are pointer-sized\n#define UXTP UXTW\n#define p0  w0\n#define p1  w1\n#define p2  w2\n#define p3  w3\n#define p4  w4\n#define p5  w5\n#define p6  w6\n#define p7  w7\n#define p8  w8\n#define p9  w9\n#define p10 w10\n#define p11 w11\n#define p12 w12\n#define p13 w13\n#define p14 w14\n#define p15 w15\n#define p16 w16\n#define p17 w17\n\n// arm64_32\n#endif\n\n\n#if __has_feature(ptrauth_returns)\n// ROP\n#   define SignLR pacibsp\n#   define AuthenticateLR autibsp\n#else\n// not ROP\n#   define SignLR\n#   define AuthenticateLR\n#endif\n\n#if __has_feature(ptrauth_calls)\n// JOP\n\n.macro TailCallFunctionPointer\n\t// $0 = function pointer value\n\tbraaz\t$0\n.endmacro\n\n.macro TailCallCachedImp\n\t// $0 = cached imp, $1 = address of cached imp\n\tbrab\t$0, $1\n.endmacro\n\n.macro TailCallMethodListImp\n\t// $0 = method list imp, $1 = address of method list imp\n\tbraa\t$0, $1\n.endmacro\n\n.macro TailCallBlockInvoke\n\t// $0 = invoke function, $1 = address of invoke function\n\tbraa\t$0, $1\n.endmacro\n\n.macro AuthAndResignAsIMP\n\t// $0 = cached imp, $1 = address of cached imp\n\tautib\t$0, $1\t\t// authenticate cached imp\n\tpaciza\t$0\t\t// resign cached imp as IMP\n.endmacro\n\n// JOP\n#else\n// not JOP\n\n.macro TailCallFunctionPointer\n\t// $0 = function pointer value\n\tbr\t$0\n.endmacro\n\n.macro TailCallCachedImp\n\t// $0 = cached imp, $1 = address of cached imp\n\tbr\t$0\n.endmacro\n\n.macro TailCallMethodListImp\n\t// $0 = method list imp, $1 = address of method list imp\n\tbr\t$0\n.endmacro\n\n.macro TailCallBlockInvoke\n\t// $0 = invoke function, $1 = address of invoke function\n\tbr\t$0\n.endmacro\n\n.macro AuthAndResignAsIMP\n\t// empty\n.endmacro\t\n\n// not JOP\n#endif\n\n#define TailCallBlockInvoke TailCallMethodListImp\n\n\n// __arm64__\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/hashtable.h",
    "content": "#include <objc/hashtable2.h>\n\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/hashtable2.h",
    "content": "/*\n * Copyright (c) 1999-2006 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\n    hashtable2.h\n    Scalable hash table.\n    Copyright 1989-1996 NeXT Software, Inc.\n*/\n\n#ifndef _OBJC_LITTLE_HASHTABLE_H_\n#define _OBJC_LITTLE_HASHTABLE_H_\n\n#ifndef _OBJC_PRIVATE_H_\n#   define OBJC_HASH_AVAILABILITY                             \\\n    __OSX_DEPRECATED(10.0, 10.1, \"NXHashTable is deprecated\") \\\n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE                      \\\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE\n#else\n#   define OBJC_HASH_AVAILABILITY\n#endif\n\n#include <objc/objc.h>\n#include <stdint.h>\n#include <TargetConditionals.h>\n\n__BEGIN_DECLS\n\n/*************************************************************************\n *\tHash tables of arbitrary data\n *************************************************************************/\n\n/* This module allows hashing of arbitrary data.  Such data must be pointers or integers, and client is responsible for allocating/deallocating this data.  A deallocation call-back is provided.\nThe objective C class HashTable is preferred when dealing with (key, values) associations because it is easier to use in that situation.\nAs well-behaved scalable data structures, hash tables double in size when they start becoming full, thus guaranteeing both average constant time access and linear size. */\n\ntypedef struct {\n    uintptr_t\t(* _Nonnull hash)(const void * _Nullable info,\n                                  const void * _Nullable data);\n    int\t\t(* _Nonnull isEqual)(const void * _Nullable info,\n                                     const void * _Nullable data1,\n                                     const void * _Nullable data2);\n    void\t(* _Nonnull free)(const void * _Nullable info,\n                                  void * _Nullable data);\n    int\t\tstyle; /* reserved for future expansion; currently 0 */\n    } NXHashTablePrototype;\n    \n/* the info argument allows a certain generality, such as freeing according to some owner information */\n/* invariants assumed by the implementation: \n\t1 - data1 = data2 => hash(data1) = hash(data2)\n\t    when data varies over time, hash(data) must remain invariant\n\t\t    e.g. if data hashes over a string key, the string must not be changed\n\t2- isEqual (data1, data2) => data1= data2\n */\n\ntypedef struct {\n    const NXHashTablePrototype\t* _Nonnull prototype OBJC_HASH_AVAILABILITY;\n    unsigned\t\t\tcount OBJC_HASH_AVAILABILITY;\n    unsigned\t\t\tnbBuckets OBJC_HASH_AVAILABILITY;\n    void\t\t\t* _Nullable buckets OBJC_HASH_AVAILABILITY;\n    const void\t\t\t* _Nullable info OBJC_HASH_AVAILABILITY;\n   } NXHashTable OBJC_HASH_AVAILABILITY;\n    /* private data structure; may change */\n    \nOBJC_EXPORT NXHashTable * _Nonnull\nNXCreateHashTableFromZone (NXHashTablePrototype prototype, unsigned capacity,\n                           const void * _Nullable info, void * _Nullable z)\n    OBJC_HASH_AVAILABILITY;\n\nOBJC_EXPORT NXHashTable * _Nonnull\nNXCreateHashTable (NXHashTablePrototype prototype, unsigned capacity,\n                   const void * _Nullable info)\n    OBJC_HASH_AVAILABILITY;\n    /* if hash is 0, pointer hash is assumed */\n    /* if isEqual is 0, pointer equality is assumed */\n    /* if free is 0, elements are not freed */\n    /* capacity is only a hint; 0 creates a small table */\n    /* info allows call backs to be very general */\n\nOBJC_EXPORT void\nNXFreeHashTable (NXHashTable * _Nonnull table)\n    OBJC_HASH_AVAILABILITY;\n    /* calls free for each data, and recovers table */\n\t\nOBJC_EXPORT void\nNXEmptyHashTable (NXHashTable * _Nonnull table)\n    OBJC_HASH_AVAILABILITY;\n    /* does not deallocate table nor data; keeps current capacity */\n\nOBJC_EXPORT void\nNXResetHashTable (NXHashTable * _Nonnull table)\n    OBJC_HASH_AVAILABILITY;\n    /* frees each entry; keeps current capacity */\n\nOBJC_EXPORT BOOL\nNXCompareHashTables (NXHashTable * _Nonnull table1,\n                     NXHashTable * _Nonnull table2)\n    OBJC_HASH_AVAILABILITY;\n    /* Returns YES if the two sets are equal (each member of table1 in table2, and table have same size) */\n\nOBJC_EXPORT NXHashTable * _Nonnull \nNXCopyHashTable (NXHashTable * _Nonnull table)\n    OBJC_HASH_AVAILABILITY;\n    /* makes a fresh table, copying data pointers, not data itself.  */\n\t\nOBJC_EXPORT unsigned\nNXCountHashTable (NXHashTable * _Nonnull table)\n    OBJC_HASH_AVAILABILITY;\n    /* current number of data in table */\n\t\nOBJC_EXPORT int\nNXHashMember (NXHashTable * _Nonnull table, const void * _Nullable data)\n    OBJC_HASH_AVAILABILITY;\n    /* returns non-0 iff data is present in table.\n    Example of use when the hashed data is a struct containing the key,\n    and when the callee only has a key:\n\tMyStruct\tpseudo;\n\tpseudo.key = myKey;\n\treturn NXHashMember (myTable, &pseudo)\n    */\n\t\nOBJC_EXPORT void * _Nullable\nNXHashGet (NXHashTable * _Nonnull table, const void * _Nullable data)\n    OBJC_HASH_AVAILABILITY;\n    /* return original table data or NULL.\n    Example of use when the hashed data is a struct containing the key,\n    and when the callee only has a key:\n\tMyStruct\tpseudo;\n\tMyStruct\t*original;\n\tpseudo.key = myKey;\n\toriginal = NXHashGet (myTable, &pseudo)\n    */\n\t\nOBJC_EXPORT void * _Nullable \nNXHashInsert (NXHashTable * _Nonnull table, const void * _Nullable data)\n    OBJC_HASH_AVAILABILITY;\n    /* previous data or NULL is returned. */\n\t\nOBJC_EXPORT void * _Nullable\nNXHashInsertIfAbsent (NXHashTable * _Nonnull table, const void * _Nullable data)\n    OBJC_HASH_AVAILABILITY;\n    /* If data already in table, returns the one in table\n    else adds argument to table and returns argument. */\n\nOBJC_EXPORT void * _Nullable\nNXHashRemove (NXHashTable * _Nonnull table, const void * _Nullable data)\n    OBJC_HASH_AVAILABILITY;\n    /* previous data or NULL is returned */\n\t\n/* Iteration over all elements of a table consists in setting up an iteration state and then to progress until all entries have been visited.  An example of use for counting elements in a table is:\n    unsigned\tcount = 0;\n    MyData\t*data;\n    NXHashState\tstate = NXInitHashState(table);\n    while (NXNextHashState(table, &state, &data)) {\n\tcount++;\n    }\n*/\n\ntypedef struct {int i; int j;} NXHashState OBJC_HASH_AVAILABILITY;\n    /* callers should not rely on actual contents of the struct */\n\nOBJC_EXPORT NXHashState\nNXInitHashState(NXHashTable * _Nonnull table)\n    OBJC_HASH_AVAILABILITY;\n\nOBJC_EXPORT int\nNXNextHashState(NXHashTable * _Nonnull table, NXHashState * _Nonnull state,\n                void * _Nullable * _Nonnull data) OBJC_HASH_AVAILABILITY;\n    /* returns 0 when all elements have been visited */\n\n/*************************************************************************\n *\tConveniences for writing hash, isEqual and free functions\n *\tand common prototypes\n *************************************************************************/\n\nOBJC_EXPORT uintptr_t\nNXPtrHash(const void * _Nullable info, const void * _Nullable data)\n    OBJC_HASH_AVAILABILITY;\n    /* scrambles the address bits; info unused */\n\nOBJC_EXPORT uintptr_t\nNXStrHash(const void * _Nullable info, const void * _Nullable data)\n    OBJC_HASH_AVAILABILITY;\n    /* string hashing; info unused */\n\nOBJC_EXPORT int\nNXPtrIsEqual(const void * _Nullable info, const void * _Nullable data1,\n             const void * _Nullable data2)\n    OBJC_HASH_AVAILABILITY;\n    /* pointer comparison; info unused */\n\nOBJC_EXPORT int\nNXStrIsEqual(const void * _Nullable info, const void * _Nullable data1,\n             const void * _Nullable data2)\n    OBJC_HASH_AVAILABILITY;\n    /* string comparison; NULL ok; info unused */\n\nOBJC_EXPORT void\nNXNoEffectFree(const void * _Nullable info, void * _Nullable data)\n    OBJC_HASH_AVAILABILITY;\n    /* no effect; info unused */\n\nOBJC_EXPORT void\nNXReallyFree(const void * _Nullable info, void * _Nullable data)\n    OBJC_HASH_AVAILABILITY;\n    /* frees it; info unused */\n\n/* The two following prototypes are useful for manipulating set of pointers or set of strings; For them free is defined as NXNoEffectFree */\nOBJC_EXPORT const NXHashTablePrototype NXPtrPrototype\n    OBJC_HASH_AVAILABILITY;\n    /* prototype when data is a pointer (void *) */\n\nOBJC_EXPORT const NXHashTablePrototype NXStrPrototype\n    OBJC_HASH_AVAILABILITY;\n    /* prototype when data is a string (char *) */\n\n/* following prototypes help describe mappings where the key is the first element of a struct and is either a pointer or a string.\nFor example NXStrStructKeyPrototype can be used to hash pointers to Example, where Example is:\n\ttypedef struct {\n\t    char\t*key;\n\t    int\t\tdata1;\n\t    ...\n\t    } Example\n    \nFor the following prototypes, free is defined as NXReallyFree.\n */\nOBJC_EXPORT const NXHashTablePrototype NXPtrStructKeyPrototype\n    OBJC_HASH_AVAILABILITY;\nOBJC_EXPORT const NXHashTablePrototype NXStrStructKeyPrototype\n    OBJC_HASH_AVAILABILITY;\n\n\n#if !__OBJC2__  &&  !TARGET_OS_WIN32\n\n/*************************************************************************\n *\tUnique strings and buffers\n *************************************************************************/\n\n/* Unique strings allows C users to enjoy the benefits of Lisp's atoms:\nA unique string is a string that is allocated once for all (never de-allocated) and that has only one representant (thus allowing comparison with == instead of strcmp).  A unique string should never be modified (and in fact some memory protection is done to ensure that).  In order to more explicitly insist on the fact that the string has been uniqued, a synonym of (const char *) has been added, NXAtom. */\n\ntypedef const char *NXAtom OBJC_HASH_AVAILABILITY;\n\nOBJC_EXPORT NXAtom _Nullable\nNXUniqueString(const char * _Nullable buffer)\n    OBJC_HASH_AVAILABILITY;\n    /* assumes that buffer is \\0 terminated, and returns\n     a previously created string or a new string that is a copy of buffer.\n    If NULL is passed returns NULL.\n    Returned string should never be modified.  To ensure this invariant,\n    allocations are made in a special read only zone. */\n\t\nOBJC_EXPORT NXAtom _Nonnull\nNXUniqueStringWithLength(const char * _Nullable buffer, int length)\n    OBJC_HASH_AVAILABILITY;\n    /* assumes that buffer is a non NULL buffer of at least \n    length characters.  Returns a previously created string or \n    a new string that is a copy of buffer. \n    If buffer contains \\0, string will be truncated.\n    As for NXUniqueString, returned string should never be modified.  */\n\t\nOBJC_EXPORT NXAtom _Nullable\nNXUniqueStringNoCopy(const char * _Nullable string)\n    OBJC_HASH_AVAILABILITY;\n    /* If there is already a unique string equal to string, returns the original.  \n    Otherwise, string is entered in the table, without making a copy.  Argument should then never be modified.  */\n\t\nOBJC_EXPORT char * _Nullable\nNXCopyStringBuffer(const char * _Nullable buffer)\n    OBJC_HASH_AVAILABILITY;\n    /* given a buffer, allocates a new string copy of buffer.  \n    Buffer should be \\0 terminated; returned string is \\0 terminated. */\n\nOBJC_EXPORT char * _Nullable\nNXCopyStringBufferFromZone(const char * _Nullable buffer, void * _Nullable z)\n    OBJC_HASH_AVAILABILITY;\n    /* given a buffer, allocates a new string copy of buffer.  \n    Buffer should be \\0 terminated; returned string is \\0 terminated. */\n\n#endif\n\n__END_DECLS\n\n#endif /* _OBJC_LITTLE_HASHTABLE_H_ */\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/hashtable2.mm",
    "content": "/*\n * Copyright (c) 1999-2008 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\n\thashtable2.m\n  \tCopyright 1989-1996 NeXT Software, Inc.\n\tCreated by Bertrand Serlet, Feb 89\n */\n\n#include \"objc-private.h\"\n#include \"hashtable2.h\"\n\n/* In order to improve efficiency, buckets contain a pointer to an array or directly the data when the array size is 1 */\ntypedef union {\n    const void\t*one;\n    const void\t**many;\n    } oneOrMany;\n    /* an optimization consists of storing directly data when count = 1 */\n    \ntypedef struct\t{\n    unsigned \tcount; \n    oneOrMany\telements;\n    } HashBucket;\n    /* private data structure; may change */\n    \n/*************************************************************************\n *\n *\tMacros and utilities\n *\t\n *************************************************************************/\n\n#define\tPTRSIZE\t\tsizeof(void *)\n\n#if !SUPPORT_ZONES\n#   define\tDEFAULT_ZONE\t NULL\n#   define\tZONE_FROM_PTR(p) NULL\n#   define\tALLOCTABLE(z)\t((NXHashTable *) malloc (sizeof (NXHashTable)))\n#   define\tALLOCBUCKETS(z,nb)((HashBucket *) calloc (nb, sizeof (HashBucket)))\n/* Return interior pointer so a table of classes doesn't look like objects */\n#   define\tALLOCPAIRS(z,nb) (1+(const void **) calloc (nb+1, sizeof (void *)))\n#   define\tFREEPAIRS(p) (free((void*)(-1+p)))\n#else\n#   define\tDEFAULT_ZONE\t malloc_default_zone()\n#   define\tZONE_FROM_PTR(p) malloc_zone_from_ptr(p)\n#   define\tALLOCTABLE(z)\t((NXHashTable *) malloc_zone_malloc ((malloc_zone_t *)z,sizeof (NXHashTable)))\n#   define\tALLOCBUCKETS(z,nb)((HashBucket *) malloc_zone_calloc ((malloc_zone_t *)z, nb, sizeof (HashBucket)))\n/* Return interior pointer so a table of classes doesn't look like objects */\n#   define\tALLOCPAIRS(z,nb) (1+(const void **) malloc_zone_calloc ((malloc_zone_t *)z, nb+1, sizeof (void *)))\n#   define\tFREEPAIRS(p) (free((void*)(-1+p)))\n#endif\n\n#if !SUPPORT_MOD\n    /* nbBuckets must be a power of 2 */\n#   define BUCKETOF(table, data) (((HashBucket *)table->buckets)+((*table->prototype->hash)(table->info, data) & (table->nbBuckets-1)))\n#   define GOOD_CAPACITY(c) (c <= 1 ? 1 : 1 << (log2u (c-1)+1))\n#   define MORE_CAPACITY(b) (b*2)\n#else\n    /* iff necessary this modulo can be optimized since the nbBuckets is of the form 2**n-1 */\n#   define\tBUCKETOF(table, data) (((HashBucket *)table->buckets)+((*table->prototype->hash)(table->info, data) % table->nbBuckets))\n#   define GOOD_CAPACITY(c) (exp2m1u (log2u (c)+1))\n#   define MORE_CAPACITY(b) (b*2+1)\n#endif\n\n#define ISEQUAL(table, data1, data2) ((data1 == data2) || (*table->prototype->isEqual)(table->info, data1, data2))\n\t/* beware of double evaluation */\n\t\n/*************************************************************************\n *\n *\tGlobal data and bootstrap\n *\t\n *************************************************************************/\n \nstatic int isEqualPrototype (const void *info, const void *data1, const void *data2) {\n    NXHashTablePrototype\t*proto1 = (NXHashTablePrototype *) data1;\n    NXHashTablePrototype\t*proto2 = (NXHashTablePrototype *) data2;\n    \n    return (proto1->hash == proto2->hash) && (proto1->isEqual == proto2->isEqual) && (proto1->free == proto2->free) && (proto1->style == proto2->style);\n    };\n    \nstatic uintptr_t hashPrototype (const void *info, const void *data) {\n    NXHashTablePrototype\t*proto = (NXHashTablePrototype *) data;\n    \n    return NXPtrHash(info, (void*)proto->hash) ^ NXPtrHash(info, (void*)proto->isEqual) ^ NXPtrHash(info, (void*)proto->free) ^ (uintptr_t) proto->style;\n    };\n\nvoid NXNoEffectFree (const void *info, void *data) {};\n\nstatic NXHashTablePrototype protoPrototype = {\n    hashPrototype, isEqualPrototype, NXNoEffectFree, 0\n    };\n\nstatic NXHashTable *prototypes = NULL;\n\t/* table of all prototypes */\n\nstatic void bootstrap (void) {\n    free(malloc(8));\n    prototypes = ALLOCTABLE (DEFAULT_ZONE);\n    prototypes->prototype = &protoPrototype; \n    prototypes->count = 1;\n    prototypes->nbBuckets = 1; /* has to be 1 so that the right bucket is 0 */\n    prototypes->buckets = ALLOCBUCKETS(DEFAULT_ZONE, 1);\n    prototypes->info = NULL;\n    ((HashBucket *) prototypes->buckets)[0].count = 1;\n    ((HashBucket *) prototypes->buckets)[0].elements.one = &protoPrototype;\n    };\n\nint NXPtrIsEqual (const void *info, const void *data1, const void *data2) {\n    return data1 == data2;\n    };\n\n/*************************************************************************\n *\n *\tOn z'y va\n *\t\n *************************************************************************/\n\nNXHashTable *NXCreateHashTable (NXHashTablePrototype prototype, unsigned capacity, const void *info) {\n    return NXCreateHashTableFromZone(prototype, capacity, info, DEFAULT_ZONE);\n}\n\nNXHashTable *NXCreateHashTableFromZone (NXHashTablePrototype prototype, unsigned capacity, const void *info, void *z) {\n    NXHashTable\t\t\t*table;\n    NXHashTablePrototype\t*proto;\n    \n    table = ALLOCTABLE(z);\n    if (! prototypes) bootstrap ();\n    if (! prototype.hash) prototype.hash = NXPtrHash;\n    if (! prototype.isEqual) prototype.isEqual = NXPtrIsEqual;\n    if (! prototype.free) prototype.free = NXNoEffectFree;\n    if (prototype.style) {\n\t_objc_inform (\"*** NXCreateHashTable: invalid style\\n\");\n\treturn NULL;\n\t};\n    proto = (NXHashTablePrototype *)NXHashGet (prototypes, &prototype); \n    if (! proto) {\n\tproto\n            = (NXHashTablePrototype *) malloc(sizeof (NXHashTablePrototype));\n\tbcopy ((const char*)&prototype, (char*)proto, sizeof (NXHashTablePrototype));\n    \t(void) NXHashInsert (prototypes, proto);\n\tproto = (NXHashTablePrototype *)NXHashGet (prototypes, &prototype);\n\tif (! proto) {\n\t    _objc_inform (\"*** NXCreateHashTable: bug\\n\");\n\t    return NULL;\n\t    };\n\t};\n    table->prototype = proto; table->count = 0; table->info = info;\n    table->nbBuckets = GOOD_CAPACITY(capacity);\n    table->buckets = ALLOCBUCKETS(z, table->nbBuckets);\n    return table;\n    }\n\nstatic void freeBucketPairs (void (*freeProc)(const void *info, void *data), HashBucket bucket, const void *info) {\n    unsigned\tj = bucket.count;\n    const void\t**pairs;\n    \n    if (j == 1) {\n\t(*freeProc) (info, (void *) bucket.elements.one);\n\treturn;\n\t};\n    pairs = bucket.elements.many;\n    while (j--) {\n\t(*freeProc) (info, (void *) *pairs);\n\tpairs ++;\n\t};\n    FREEPAIRS (bucket.elements.many);\n    };\n    \nstatic void freeBuckets (NXHashTable *table, int freeObjects) {\n    unsigned\t\ti = table->nbBuckets;\n    HashBucket\t\t*buckets = (HashBucket *) table->buckets;\n    \n    while (i--) {\n\tif (buckets->count) {\n\t    freeBucketPairs ((freeObjects) ? table->prototype->free : NXNoEffectFree, *buckets, table->info);\n\t    buckets->count = 0;\n\t    buckets->elements.one = NULL;\n\t    };\n\tbuckets++;\n\t};\n    };\n    \nvoid NXFreeHashTable (NXHashTable *table) {\n    freeBuckets (table, YES);\n    free (table->buckets);\n    free (table);\n    };\n    \nvoid NXEmptyHashTable (NXHashTable *table) {\n    freeBuckets (table, NO);\n    table->count = 0;\n    }\n\nvoid NXResetHashTable (NXHashTable *table) {\n    freeBuckets (table, YES);\n    table->count = 0;\n}\n\nBOOL NXCompareHashTables (NXHashTable *table1, NXHashTable *table2) {\n    if (table1 == table2) return YES;\n    if (NXCountHashTable (table1) != NXCountHashTable (table2)) return NO;\n    else {\n\tvoid\t\t*data;\n\tNXHashState\tstate = NXInitHashState (table1);\n\twhile (NXNextHashState (table1, &state, &data)) {\n\t    if (! NXHashMember (table2, data)) return NO;\n\t}\n\treturn YES;\n    }\n}\n\nNXHashTable *NXCopyHashTable (NXHashTable *table) {\n    NXHashTable\t\t*newt;\n    NXHashState\t\tstate = NXInitHashState (table);\n    void\t\t*data;\n    __unused void\t*z = ZONE_FROM_PTR(table);\n    \n    newt = ALLOCTABLE(z);\n    newt->prototype = table->prototype; newt->count = 0;\n    newt->info = table->info;\n    newt->nbBuckets = table->nbBuckets;\n    newt->buckets = ALLOCBUCKETS(z, newt->nbBuckets);\n    while (NXNextHashState (table, &state, &data))\n        NXHashInsert (newt, data);\n    return newt;\n    }\n\nunsigned NXCountHashTable (NXHashTable *table) {\n    return table->count;\n    }\n\nint NXHashMember (NXHashTable *table, const void *data) {\n    HashBucket\t*bucket = BUCKETOF(table, data);\n    unsigned\tj = bucket->count;\n    const void\t**pairs;\n    \n    if (! j) return 0;\n    if (j == 1) {\n    \treturn ISEQUAL(table, data, bucket->elements.one);\n\t};\n    pairs = bucket->elements.many;\n    while (j--) {\n\t/* we don't cache isEqual because lists are short */\n    \tif (ISEQUAL(table, data, *pairs)) return 1; \n\tpairs ++;\n\t};\n    return 0;\n    }\n\nvoid *NXHashGet (NXHashTable *table, const void *data) {\n    HashBucket\t*bucket = BUCKETOF(table, data);\n    unsigned\tj = bucket->count;\n    const void\t**pairs;\n    \n    if (! j) return NULL;\n    if (j == 1) {\n    \treturn ISEQUAL(table, data, bucket->elements.one)\n\t    ? (void *) bucket->elements.one : NULL; \n\t};\n    pairs = bucket->elements.many;\n    while (j--) {\n\t/* we don't cache isEqual because lists are short */\n    \tif (ISEQUAL(table, data, *pairs)) return (void *) *pairs; \n\tpairs ++;\n\t};\n    return NULL;\n    }\n\nunsigned _NXHashCapacity (NXHashTable *table) {\n    return table->nbBuckets;\n    }\n\nvoid _NXHashRehashToCapacity (NXHashTable *table, unsigned newCapacity) {\n    /* Rehash: we create a pseudo table pointing really to the old guys,\n    extend self, copy the old pairs, and free the pseudo table */\n    NXHashTable\t*old;\n    NXHashState\tstate;\n    void\t*aux;\n    __unused void *z = ZONE_FROM_PTR(table);\n    \n    old = ALLOCTABLE(z);\n    old->prototype = table->prototype; old->count = table->count; \n    old->nbBuckets = table->nbBuckets; old->buckets = table->buckets;\n    table->nbBuckets = newCapacity;\n    table->count = 0; table->buckets = ALLOCBUCKETS(z, table->nbBuckets);\n    state = NXInitHashState (old);\n    while (NXNextHashState (old, &state, &aux))\n\t(void) NXHashInsert (table, aux);\n    freeBuckets (old, NO);\n    if (old->count != table->count)\n\t_objc_inform(\"*** hashtable: count differs after rehashing; probably indicates a broken invariant: there are x and y such as isEqual(x, y) is TRUE but hash(x) != hash (y)\\n\");\n    free (old->buckets); \n    free (old);\n    }\n\nstatic void _NXHashRehash (NXHashTable *table) {\n    _NXHashRehashToCapacity (table, MORE_CAPACITY(table->nbBuckets));\n    }\n\nvoid *NXHashInsert (NXHashTable *table, const void *data) {\n    HashBucket\t*bucket = BUCKETOF(table, data);\n    unsigned\tj = bucket->count;\n    const void\t**pairs;\n    const void\t**newt;\n    __unused void *z = ZONE_FROM_PTR(table);\n    \n    if (! j) {\n\tbucket->count++; bucket->elements.one = data; \n\ttable->count++; \n\treturn NULL;\n\t};\n    if (j == 1) {\n    \tif (ISEQUAL(table, data, bucket->elements.one)) {\n\t    const void\t*old = bucket->elements.one;\n\t    bucket->elements.one = data;\n\t    return (void *) old;\n\t    };\n\tnewt = ALLOCPAIRS(z, 2);\n\tnewt[1] = bucket->elements.one;\n\t*newt = data;\n\tbucket->count++; bucket->elements.many = newt; \n\ttable->count++; \n\tif (table->count > table->nbBuckets) _NXHashRehash (table);\n\treturn NULL;\n\t};\n    pairs = bucket->elements.many;\n    while (j--) {\n\t/* we don't cache isEqual because lists are short */\n    \tif (ISEQUAL(table, data, *pairs)) {\n\t    const void\t*old = *pairs;\n\t    *pairs = data;\n\t    return (void *) old;\n\t    };\n\tpairs ++;\n\t};\n    /* we enlarge this bucket; and put new data in front */\n    newt = ALLOCPAIRS(z, bucket->count+1);\n    if (bucket->count) bcopy ((const char*)bucket->elements.many, (char*)(newt+1), bucket->count * PTRSIZE);\n    *newt = data;\n    FREEPAIRS (bucket->elements.many);\n    bucket->count++; bucket->elements.many = newt; \n    table->count++; \n    if (table->count > table->nbBuckets) _NXHashRehash (table);\n    return NULL;\n    }\n\nvoid *NXHashInsertIfAbsent (NXHashTable *table, const void *data) {\n    HashBucket\t*bucket = BUCKETOF(table, data);\n    unsigned\tj = bucket->count;\n    const void\t**pairs;\n    const void\t**newt;\n    __unused void *z = ZONE_FROM_PTR(table);\n    \n    if (! j) {\n\tbucket->count++; bucket->elements.one = data; \n\ttable->count++; \n\treturn (void *) data;\n\t};\n    if (j == 1) {\n    \tif (ISEQUAL(table, data, bucket->elements.one))\n\t    return (void *) bucket->elements.one;\n\tnewt = ALLOCPAIRS(z, 2);\n\tnewt[1] = bucket->elements.one;\n\t*newt = data;\n\tbucket->count++; bucket->elements.many = newt; \n\ttable->count++; \n\tif (table->count > table->nbBuckets) _NXHashRehash (table);\n\treturn (void *) data;\n\t};\n    pairs = bucket->elements.many;\n    while (j--) {\n\t/* we don't cache isEqual because lists are short */\n    \tif (ISEQUAL(table, data, *pairs))\n\t    return (void *) *pairs;\n\tpairs ++;\n\t};\n    /* we enlarge this bucket; and put new data in front */\n    newt = ALLOCPAIRS(z, bucket->count+1);\n    if (bucket->count) bcopy ((const char*)bucket->elements.many, (char*)(newt+1), bucket->count * PTRSIZE);\n    *newt = data;\n    FREEPAIRS (bucket->elements.many);\n    bucket->count++; bucket->elements.many = newt; \n    table->count++; \n    if (table->count > table->nbBuckets) _NXHashRehash (table);\n    return (void *) data;\n    }\n\nvoid *NXHashRemove (NXHashTable *table, const void *data) {\n    HashBucket\t*bucket = BUCKETOF(table, data);\n    unsigned\tj = bucket->count;\n    const void\t**pairs;\n    const void\t**newt;\n    __unused void *z = ZONE_FROM_PTR(table);\n    \n    if (! j) return NULL;\n    if (j == 1) {\n\tif (! ISEQUAL(table, data, bucket->elements.one)) return NULL;\n\tdata = bucket->elements.one;\n\ttable->count--; bucket->count--; bucket->elements.one = NULL;\n\treturn (void *) data;\n\t};\n    pairs = bucket->elements.many;\n    if (j == 2) {\n    \tif (ISEQUAL(table, data, pairs[0])) {\n\t    bucket->elements.one = pairs[1]; data = pairs[0];\n\t    }\n\telse if (ISEQUAL(table, data, pairs[1])) {\n\t    bucket->elements.one = pairs[0]; data = pairs[1];\n\t    }\n\telse return NULL;\n\tFREEPAIRS (pairs);\n\ttable->count--; bucket->count--;\n\treturn (void *) data;\n\t};\n    while (j--) {\n    \tif (ISEQUAL(table, data, *pairs)) {\n\t    data = *pairs;\n\t    /* we shrink this bucket */\n\t    newt = (bucket->count-1) \n\t\t? ALLOCPAIRS(z, bucket->count-1) : NULL;\n\t    if (bucket->count-1 != j)\n\t\t    bcopy ((const char*)bucket->elements.many, (char*)newt, PTRSIZE*(bucket->count-j-1));\n\t    if (j)\n\t\t    bcopy ((const char*)(bucket->elements.many + bucket->count-j), (char*)(newt+bucket->count-j-1), PTRSIZE*j);\n\t    FREEPAIRS (bucket->elements.many);\n\t    table->count--; bucket->count--; bucket->elements.many = newt;\n\t    return (void *) data;\n\t    };\n\tpairs ++;\n\t};\n    return NULL;\n    }\n\nNXHashState NXInitHashState (NXHashTable *table) {\n    NXHashState\tstate;\n    \n    state.i = table->nbBuckets;\n    state.j = 0;\n    return state;\n    };\n    \nint NXNextHashState (NXHashTable *table, NXHashState *state, void **data) {\n    HashBucket\t\t*buckets = (HashBucket *) table->buckets;\n    \n    while (state->j == 0) {\n\tif (state->i == 0) return NO;\n\tstate->i--; state->j = buckets[state->i].count;\n\t}\n    state->j--;\n    buckets += state->i;\n    *data = (void *) ((buckets->count == 1) \n    \t\t? buckets->elements.one : buckets->elements.many[state->j]);\n    return YES;\n    };\n\n/*************************************************************************\n *\n *\tConveniences\n *\t\n *************************************************************************/\n\nuintptr_t NXPtrHash (const void *info, const void *data) {\n    return (((uintptr_t) data) >> 16) ^ ((uintptr_t) data);\n    };\n    \nuintptr_t NXStrHash (const void *info, const void *data) {\n    uintptr_t\thash = 0;\n    unsigned char\t*s = (unsigned char *) data;\n    /* unsigned to avoid a sign-extend */\n    /* unroll the loop */\n    if (s) for (; ; ) { \n\tif (*s == '\\0') break;\n\thash ^= (uintptr_t) *s++;\n\tif (*s == '\\0') break;\n\thash ^= (uintptr_t) *s++ << 8;\n\tif (*s == '\\0') break;\n\thash ^= (uintptr_t) *s++ << 16;\n\tif (*s == '\\0') break;\n\thash ^= (uintptr_t) *s++ << 24;\n\t}\n    return hash;\n    };\n    \nint NXStrIsEqual (const void *info, const void *data1, const void *data2) {\n    if (data1 == data2) return YES;\n    if (! data1) return ! strlen ((char *) data2);\n    if (! data2) return ! strlen ((char *) data1);\n    if (((char *) data1)[0] != ((char *) data2)[0]) return NO;\n    return (strcmp ((char *) data1, (char *) data2)) ? NO : YES;\n    };\n    \nvoid NXReallyFree (const void *info, void *data) {\n    free (data);\n    };\n\n/* All the following functions are really private, made non-static only for the benefit of shlibs */\nstatic uintptr_t hashPtrStructKey (const void *info, const void *data) {\n    return NXPtrHash(info, *((void **) data));\n    };\n\nstatic int isEqualPtrStructKey (const void *info, const void *data1, const void *data2) {\n    return NXPtrIsEqual (info, *((void **) data1), *((void **) data2));\n    };\n\nstatic uintptr_t hashStrStructKey (const void *info, const void *data) {\n    return NXStrHash(info, *((char **) data));\n    };\n\nstatic int isEqualStrStructKey (const void *info, const void *data1, const void *data2) {\n    return NXStrIsEqual (info, *((char **) data1), *((char **) data2));\n    };\n\nconst NXHashTablePrototype NXPtrPrototype = {\n    NXPtrHash, NXPtrIsEqual, NXNoEffectFree, 0\n    };\n\nconst NXHashTablePrototype NXStrPrototype = {\n    NXStrHash, NXStrIsEqual, NXNoEffectFree, 0\n    };\n\nconst NXHashTablePrototype NXPtrStructKeyPrototype = {\n    hashPtrStructKey, isEqualPtrStructKey, NXReallyFree, 0\n    };\n\nconst NXHashTablePrototype NXStrStructKeyPrototype = {\n    hashStrStructKey, isEqualStrStructKey, NXReallyFree, 0\n    };\n\n/*************************************************************************\n *\n *\tUnique strings\n *\t\n *************************************************************************/\n\n#if !__OBJC2__  &&  !TARGET_OS_WIN32\n\n/* the implementation could be made faster at the expense of memory if the size of the strings were kept around */\nstatic NXHashTable *uniqueStrings = NULL;\n\n/* this is based on most apps using a few K of strings, and an average string size of 15 using sqrt(2*dataAlloced*perChunkOverhead) */\n#define CHUNK_SIZE\t360\n\nstatic int accessUniqueString = 0;\n\nstatic char\t\t*z = NULL;\nstatic size_t\tzSize = 0;\nmutex_t\t\tNXUniqueStringLock;\n\nstatic const char *CopyIntoReadOnly (const char *str) {\n    size_t\tlen = strlen (str) + 1;\n    char\t*result;\n    \n    if (len > CHUNK_SIZE/2) {\t/* dont let big strings waste space */\n\tresult = (char *)malloc (len);\n\tbcopy (str, result, len);\n\treturn result;\n    }\n\n    mutex_locker_t lock(NXUniqueStringLock);\n    if (zSize < len) {\n\tzSize = CHUNK_SIZE *((len + CHUNK_SIZE - 1) / CHUNK_SIZE);\n\t/* not enough room, we try to allocate.  If no room left, too bad */\n\tz = (char *)malloc (zSize);\n\t};\n    \n    result = z;\n    bcopy (str, result, len);\n    z += len;\n    zSize -= len;\n    return result;\n    };\n    \nNXAtom NXUniqueString (const char *buffer) {\n    const char\t*previous;\n    \n    if (! buffer) return buffer;\n    accessUniqueString++;\n    if (! uniqueStrings)\n    \tuniqueStrings = NXCreateHashTable (NXStrPrototype, 0, NULL);\n    previous = (const char *) NXHashGet (uniqueStrings, buffer);\n    if (previous) return previous;\n    previous = CopyIntoReadOnly (buffer);\n    if (NXHashInsert (uniqueStrings, previous)) {\n\t_objc_inform (\"*** NXUniqueString: invariant broken\\n\");\n\treturn NULL;\n\t};\n    return previous;\n    };\n\nNXAtom NXUniqueStringNoCopy (const char *string) {\n    accessUniqueString++;\n    if (! uniqueStrings)\n    \tuniqueStrings = NXCreateHashTable (NXStrPrototype, 0, NULL);\n    return (const char *) NXHashInsertIfAbsent (uniqueStrings, string);\n    };\n\n#define BUF_SIZE\t256\n\nNXAtom NXUniqueStringWithLength (const char *buffer, int length) {\n    NXAtom\tatom;\n    char\t*nullTermStr;\n    char\tstackBuf[BUF_SIZE];\n\n    if (length+1 > BUF_SIZE)\n\tnullTermStr = (char *)malloc (length+1);\n    else\n\tnullTermStr = stackBuf;\n    bcopy (buffer, nullTermStr, length);\n    nullTermStr[length] = '\\0';\n    atom = NXUniqueString (nullTermStr);\n    if (length+1 > BUF_SIZE)\n\tfree (nullTermStr);\n    return atom;\n    };\n\nchar *NXCopyStringBufferFromZone (const char *str, void *zone) {\n#if !SUPPORT_ZONES\n    return strdup(str);\n#else\n    return strcpy ((char *) malloc_zone_malloc((malloc_zone_t *)zone, strlen (str) + 1), str);\n#endif\n    };\n    \nchar *NXCopyStringBuffer (const char *str) {\n    return strdup(str);\n    };\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/isa.h",
    "content": "/*\n * @APPLE_LICENSE_HEADER_START@\n * \n * Copyright (c) 2018 Apple Inc.  All Rights Reserved.\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/********************************************************************\n * \n *  isa.h - Definitions of isa fields for C and assembly code.\n *\n ********************************************************************/\n\n#ifndef _OBJC_ISA_H_\n#define _OBJC_ISA_H_\n\n#include \"objc-config.h\"\n\n\n#if (!SUPPORT_NONPOINTER_ISA && !SUPPORT_PACKED_ISA && !SUPPORT_INDEXED_ISA) ||\\\n    ( SUPPORT_NONPOINTER_ISA &&  SUPPORT_PACKED_ISA && !SUPPORT_INDEXED_ISA) ||\\\n    ( SUPPORT_NONPOINTER_ISA && !SUPPORT_PACKED_ISA &&  SUPPORT_INDEXED_ISA)\n    // good config\n#else\n#   error bad config\n#endif\n\n\n#if SUPPORT_PACKED_ISA\n\n    // extra_rc must be the MSB-most field (so it matches carry/overflow flags)\n    // nonpointer must be the LSB (fixme or get rid of it)\n    // shiftcls must occupy the same bits that a real class pointer would\n    // bits + RC_ONE is equivalent to extra_rc + 1\n    // RC_HALF is the high bit of extra_rc (i.e. half of its range)\n\n    // future expansion:\n    // uintptr_t fast_rr : 1;     // no r/r overrides\n    // uintptr_t lock : 2;        // lock for atomic property, @synch\n    // uintptr_t extraBytes : 1;  // allocated with extra bytes\n\n# if __arm64__\n#   define ISA_MASK        0x0000000ffffffff8ULL\n#   define ISA_MAGIC_MASK  0x000003f000000001ULL\n#   define ISA_MAGIC_VALUE 0x000001a000000001ULL\n#   define ISA_BITFIELD                                                      \\\n      uintptr_t nonpointer        : 1;                                       \\\n      uintptr_t has_assoc         : 1;                                       \\\n      uintptr_t has_cxx_dtor      : 1;                                       \\\n      uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \\\n      uintptr_t magic             : 6;                                       \\\n      uintptr_t weakly_referenced : 1;                                       \\\n      uintptr_t deallocating      : 1;                                       \\\n      uintptr_t has_sidetable_rc  : 1;                                       \\\n      uintptr_t extra_rc          : 19\n#   define RC_ONE   (1ULL<<45)\n#   define RC_HALF  (1ULL<<18)\n\n# elif __x86_64__\n#   define ISA_MASK        0x00007ffffffffff8ULL\n#   define ISA_MAGIC_MASK  0x001f800000000001ULL\n#   define ISA_MAGIC_VALUE 0x001d800000000001ULL\n#   define ISA_BITFIELD                                                        \\\n      uintptr_t nonpointer        : 1;                                         \\\n      uintptr_t has_assoc         : 1;                                         \\\n      uintptr_t has_cxx_dtor      : 1;                                         \\\n      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \\\n      uintptr_t magic             : 6;                                         \\\n      uintptr_t weakly_referenced : 1;                                         \\\n      uintptr_t deallocating      : 1;                                         \\\n      uintptr_t has_sidetable_rc  : 1;                                         \\\n      uintptr_t extra_rc          : 8\n#   define RC_ONE   (1ULL<<56)\n#   define RC_HALF  (1ULL<<7)\n\n# else\n#   error unknown architecture for packed isa\n# endif\n\n// SUPPORT_PACKED_ISA\n#endif\n\n\n#if SUPPORT_INDEXED_ISA\n\n# if  __ARM_ARCH_7K__ >= 2  ||  (__arm64__ && !__LP64__)\n    // armv7k or arm64_32\n\n#   define ISA_INDEX_IS_NPI_BIT  0\n#   define ISA_INDEX_IS_NPI_MASK 0x00000001\n#   define ISA_INDEX_MASK        0x0001FFFC\n#   define ISA_INDEX_SHIFT       2\n#   define ISA_INDEX_BITS        15\n#   define ISA_INDEX_COUNT       (1 << ISA_INDEX_BITS)\n#   define ISA_INDEX_MAGIC_MASK  0x001E0001\n#   define ISA_INDEX_MAGIC_VALUE 0x001C0001\n#   define ISA_BITFIELD                         \\\n      uintptr_t nonpointer        : 1;          \\\n      uintptr_t has_assoc         : 1;          \\\n      uintptr_t indexcls          : 15;         \\\n      uintptr_t magic             : 4;          \\\n      uintptr_t has_cxx_dtor      : 1;          \\\n      uintptr_t weakly_referenced : 1;          \\\n      uintptr_t deallocating      : 1;          \\\n      uintptr_t has_sidetable_rc  : 1;          \\\n      uintptr_t extra_rc          : 7\n#   define RC_ONE   (1ULL<<25)\n#   define RC_HALF  (1ULL<<6)\n\n# else\n#   error unknown architecture for indexed isa\n# endif\n\n// SUPPORT_INDEXED_ISA\n#endif\n\n\n// _OBJC_ISA_H_\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/llvm-AlignOf.h",
    "content": "//===--- AlignOf.h - Portable calculation of type alignment -----*- C++ -*-===//\n//\n//                     The LLVM Compiler Infrastructure\n//\n// This file is distributed under the University of Illinois Open Source\n// License. See LICENSE.TXT for details.\n//\n//===----------------------------------------------------------------------===//\n//\n// This file defines the AlignOf function that computes alignments for\n// arbitrary types.\n//\n//===----------------------------------------------------------------------===//\n\n// Taken from llvmCore-3425.0.31.\n\n#ifndef LLVM_SUPPORT_ALIGNOF_H\n#define LLVM_SUPPORT_ALIGNOF_H\n\n#include <cstddef>\n\nnamespace objc {\n\ntemplate <typename T>\nstruct AlignmentCalcImpl {\n  char x;\n  T t;\nprivate:\n  AlignmentCalcImpl() {} // Never instantiate.\n};\n\n/// AlignOf - A templated class that contains an enum value representing\n///  the alignment of the template argument.  For example,\n///  AlignOf<int>::Alignment represents the alignment of type \"int\".  The\n///  alignment calculated is the minimum alignment, and not necessarily\n///  the \"desired\" alignment returned by GCC's __alignof__ (for example).  Note\n///  that because the alignment is an enum value, it can be used as a\n///  compile-time constant (e.g., for template instantiation).\ntemplate <typename T>\nstruct AlignOf {\n  enum { Alignment =\n         static_cast<unsigned int>(sizeof(AlignmentCalcImpl<T>) - sizeof(T)) };\n\n  enum { Alignment_GreaterEqual_2Bytes = Alignment >= 2 ? 1 : 0 };\n  enum { Alignment_GreaterEqual_4Bytes = Alignment >= 4 ? 1 : 0 };\n  enum { Alignment_GreaterEqual_8Bytes = Alignment >= 8 ? 1 : 0 };\n  enum { Alignment_GreaterEqual_16Bytes = Alignment >= 16 ? 1 : 0 };\n\n  enum { Alignment_LessEqual_2Bytes = Alignment <= 2 ? 1 : 0 };\n  enum { Alignment_LessEqual_4Bytes = Alignment <= 4 ? 1 : 0 };\n  enum { Alignment_LessEqual_8Bytes = Alignment <= 8 ? 1 : 0 };\n  enum { Alignment_LessEqual_16Bytes = Alignment <= 16 ? 1 : 0 };\n\n};\n\n/// alignOf - A templated function that returns the minimum alignment of\n///  of a type.  This provides no extra functionality beyond the AlignOf\n///  class besides some cosmetic cleanliness.  Example usage:\n///  alignOf<int>() returns the alignment of an int.\ntemplate <typename T>\ninline unsigned alignOf() { return AlignOf<T>::Alignment; }\n\n\n/// \\brief Helper for building an aligned character array type.\n///\n/// This template is used to explicitly build up a collection of aligned\n/// character types. We have to build these up using a macro and explicit\n/// specialization to cope with old versions of MSVC and GCC where only an\n/// integer literal can be used to specify an alignment constraint. Once built\n/// up here, we can then begin to indirect between these using normal C++\n/// template parameters.\ntemplate <size_t Alignment> struct AlignedCharArrayImpl;\n\n// MSVC requires special handling here.\n#ifndef _MSC_VER\n\n#if __has_feature(cxx_alignas)\n#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \\\n  template <> struct AlignedCharArrayImpl<x> { \\\n    char aligned alignas(x); \\\n  }\n#elif defined(__GNUC__)\n#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \\\n  template <> struct AlignedCharArrayImpl<x> { \\\n    char aligned __attribute__((aligned(x))); \\\n  }\n#else\n# error No supported align as directive.\n#endif\n\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(1);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(2);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(4);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(8);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(512);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(1024);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(2048);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(4096);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(8192);\n\n#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT\n\n#else // _MSC_VER\n\n// We provide special variations of this template for the most common\n// alignments because __declspec(align(...)) doesn't actually work when it is\n// a member of a by-value function argument in MSVC, even if the alignment\n// request is something reasonably like 8-byte or 16-byte.\ntemplate <> struct AlignedCharArrayImpl<1> { char aligned; };\ntemplate <> struct AlignedCharArrayImpl<2> { short aligned; };\ntemplate <> struct AlignedCharArrayImpl<4> { int aligned; };\ntemplate <> struct AlignedCharArrayImpl<8> { double aligned; };\n\n#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \\\n  template <> struct AlignedCharArrayImpl<x> { \\\n    __declspec(align(x)) char aligned; \\\n  }\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(512);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(1024);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(2048);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(4096);\nLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(8192);\n// Any larger and MSVC complains.\n#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT\n\n#endif // _MSC_VER\n\n/// \\brief This union template exposes a suitably aligned and sized character\n/// array member which can hold elements of any of up to four types.\n///\n/// These types may be arrays, structs, or any other types. The goal is to\n/// produce a union type containing a character array which, when used, forms\n/// storage suitable to placement new any of these types over. Support for more\n/// than four types can be added at the cost of more boiler plate.\ntemplate <typename T1,\n          typename T2 = char, typename T3 = char, typename T4 = char>\nunion AlignedCharArrayUnion {\nprivate:\n  class AlignerImpl {\n    T1 t1; T2 t2; T3 t3; T4 t4;\n\n    AlignerImpl(); // Never defined or instantiated.\n  };\n  union SizerImpl {\n    char arr1[sizeof(T1)], arr2[sizeof(T2)], arr3[sizeof(T3)], arr4[sizeof(T4)];\n  };\n\npublic:\n  /// \\brief The character array buffer for use by clients.\n  ///\n  /// No other member of this union should be referenced. The exist purely to\n  /// constrain the layout of this character array.\n  char buffer[sizeof(SizerImpl)];\n\nprivate:\n  // Tests seem to indicate that both Clang and GCC will properly register the\n  // alignment of a struct containing an aligned member, and this alignment\n  // should carry over to the character array in the union.\n  AlignedCharArrayImpl<AlignOf<AlignerImpl>::Alignment> nonce_member;\n};\n\n} // end namespace objc\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/llvm-DenseMap.h",
    "content": "//===- llvm/ADT/DenseMap.h - Dense probed hash table ------------*- C++ -*-===//\n//\n//                     The LLVM Compiler Infrastructure\n//\n// This file is distributed under the University of Illinois Open Source\n// License. See LICENSE.TXT for details.\n//\n//===----------------------------------------------------------------------===//\n//\n// This file defines the DenseMap class.\n//\n//===----------------------------------------------------------------------===//\n\n// Taken from llvmCore-3425.0.31.\n\n#ifndef LLVM_ADT_DENSEMAP_H\n#define LLVM_ADT_DENSEMAP_H\n\n#include \"llvm-type_traits.h\"\n#include \"llvm-MathExtras.h\"\n#include \"llvm-AlignOf.h\"\n#include \"llvm-DenseMapInfo.h\"\n#include <algorithm>\n#include <iterator>\n#include <new>\n#include <utility>\n#include <cassert>\n#include <climits>\n#include <cstddef>\n#include <cstring>\n#include <TargetConditionals.h>\n\n#include \"objc-private.h\"\n\n// From llvm/Support/Compiler.h\n#define LLVM_USE_RVALUE_REFERENCES 1\n#define llvm_move(value) (::std::move(value))\n\n#define MIN_BUCKETS 4\n#define MIN_COMPACT 1024\n\n\nnamespace objc {\n\ntemplate<typename KeyT, typename ValueT,\n         typename KeyInfoT = DenseMapInfo<KeyT>,\n         bool IsConst = false>\nclass DenseMapIterator;\n\n// ZeroValuesArePurgeable=true is used by the refcount table.\n// A key/value pair with value==0 is not required to be stored \n//   in the refcount table; it could correctly be erased instead.\n// For performance, we do keep zero values in the table when the \n//   true refcount decreases to 1: this makes any future retain faster.\n// For memory size, we allow rehashes and table insertions to \n//   remove a zero value as if it were a tombstone.\n\ntemplate<typename DerivedT, \n         typename KeyT, typename ValueT, typename KeyInfoT, \n         bool ZeroValuesArePurgeable = false>\nclass DenseMapBase {\nprotected:\n  typedef std::pair<KeyT, ValueT> BucketT;\n\npublic:\n  typedef KeyT key_type;\n  typedef ValueT mapped_type;\n  typedef BucketT value_type;\n\n  typedef DenseMapIterator<KeyT, ValueT, KeyInfoT> iterator;\n  typedef DenseMapIterator<KeyT, ValueT,\n                           KeyInfoT, true> const_iterator;\n  inline iterator begin() {\n    // When the map is empty, avoid the overhead of AdvancePastEmptyBuckets().\n    return empty() ? end() : iterator(getBuckets(), getBucketsEnd());\n  }\n  inline iterator end() {\n    return iterator(getBucketsEnd(), getBucketsEnd(), true);\n  }\n  inline const_iterator begin() const {\n    return empty() ? end() : const_iterator(getBuckets(), getBucketsEnd());\n  }\n  inline const_iterator end() const {\n    return const_iterator(getBucketsEnd(), getBucketsEnd(), true);\n  }\n\n  bool empty() const { return getNumEntries() == 0; }\n  unsigned size() const { return getNumEntries(); }\n\n  /// Grow the densemap so that it has at least Size buckets. Does not shrink\n  void resize(size_t Size) {\n    if (Size > getNumBuckets())\n      grow(Size);\n  }\n\n  void clear() {\n    if (getNumEntries() == 0 && getNumTombstones() == 0) return;\n    \n    // If the capacity of the array is huge, and the # elements used is small,\n    // shrink the array.\n    if (getNumEntries() * 4 < getNumBuckets() && \n        getNumBuckets() > MIN_BUCKETS) {\n      shrink_and_clear();\n      return;\n    }\n\n    const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();\n    for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {\n      if (!KeyInfoT::isEqual(P->first, EmptyKey)) {\n        if (!KeyInfoT::isEqual(P->first, TombstoneKey)) {\n          P->second.~ValueT();\n          decrementNumEntries();\n        }\n        P->first = EmptyKey;\n      }\n    }\n    assert(getNumEntries() == 0 && \"Node count imbalance!\");\n    setNumTombstones(0);\n  }\n\n  /// count - Return true if the specified key is in the map.\n  bool count(const KeyT &Val) const {\n    const BucketT *TheBucket;\n    return LookupBucketFor(Val, TheBucket);\n  }\n\n  iterator find(const KeyT &Val) {\n    BucketT *TheBucket;\n    if (LookupBucketFor(Val, TheBucket))\n      return iterator(TheBucket, getBucketsEnd(), true);\n    return end();\n  }\n  const_iterator find(const KeyT &Val) const {\n    const BucketT *TheBucket;\n    if (LookupBucketFor(Val, TheBucket))\n      return const_iterator(TheBucket, getBucketsEnd(), true);\n    return end();\n  }\n\n  /// Alternate version of find() which allows a different, and possibly\n  /// less expensive, key type.\n  /// The DenseMapInfo is responsible for supplying methods\n  /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key\n  /// type used.\n  template<class LookupKeyT>\n  iterator find_as(const LookupKeyT &Val) {\n    BucketT *TheBucket;\n    if (LookupBucketFor(Val, TheBucket))\n      return iterator(TheBucket, getBucketsEnd(), true);\n    return end();\n  }\n  template<class LookupKeyT>\n  const_iterator find_as(const LookupKeyT &Val) const {\n    const BucketT *TheBucket;\n    if (LookupBucketFor(Val, TheBucket))\n      return const_iterator(TheBucket, getBucketsEnd(), true);\n    return end();\n  }\n\n  /// lookup - Return the entry for the specified key, or a default\n  /// constructed value if no such entry exists.\n  ValueT lookup(const KeyT &Val) const {\n    const BucketT *TheBucket;\n    if (LookupBucketFor(Val, TheBucket))\n      return TheBucket->second;\n    return ValueT();\n  }\n\n  // Inserts key,value pair into the map if the key isn't already in the map.\n  // If the key is already in the map, it returns false and doesn't update the\n  // value.\n  std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {\n    BucketT *TheBucket;\n    if (LookupBucketFor(KV.first, TheBucket))\n      return std::make_pair(iterator(TheBucket, getBucketsEnd(), true),\n                            false); // Already in map.\n\n    // Otherwise, insert the new element.\n    TheBucket = InsertIntoBucket(KV.first, KV.second, TheBucket);\n    return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), true);\n  }\n\n  /// insert - Range insertion of pairs.\n  template<typename InputIt>\n  void insert(InputIt I, InputIt E) {\n    for (; I != E; ++I)\n      insert(*I);\n  }\n\n  // Clear if empty.\n  // Shrink if at least 15/16 empty and larger than MIN_COMPACT.\n  void compact() {\n    if (getNumEntries() == 0) {\n      shrink_and_clear();\n    } \n    else if (getNumBuckets() / 16 > getNumEntries()  &&  \n             getNumBuckets() > MIN_COMPACT) \n    {\n      grow(getNumEntries() * 2);\n    }\n  }\n\n  bool erase(const KeyT &Val) {\n    BucketT *TheBucket;\n    if (!LookupBucketFor(Val, TheBucket))\n      return false; // not in map.\n\n    TheBucket->second.~ValueT();\n    TheBucket->first = getTombstoneKey();\n    decrementNumEntries();\n    incrementNumTombstones();\n    compact();\n    return true;\n  }\n  void erase(iterator I) {\n    BucketT *TheBucket = &*I;\n    TheBucket->second.~ValueT();\n    TheBucket->first = getTombstoneKey();\n    decrementNumEntries();\n    incrementNumTombstones();\n    compact();\n  }\n\n  value_type& FindAndConstruct(const KeyT &Key) {\n    BucketT *TheBucket;\n    if (LookupBucketFor(Key, TheBucket))\n      return *TheBucket;\n\n    return *InsertIntoBucket(Key, ValueT(), TheBucket);\n  }\n\n  ValueT &operator[](const KeyT &Key) {\n    return FindAndConstruct(Key).second;\n  }\n\n#if LLVM_USE_RVALUE_REFERENCES\n  value_type& FindAndConstruct(KeyT &&Key) {\n    BucketT *TheBucket;\n    if (LookupBucketFor(Key, TheBucket))\n      return *TheBucket;\n\n    return *InsertIntoBucket(Key, ValueT(), TheBucket);\n  }\n\n  ValueT &operator[](KeyT &&Key) {\n    return FindAndConstruct(Key).second;\n  }\n#endif\n\n  /// isPointerIntoBucketsArray - Return true if the specified pointer points\n  /// somewhere into the DenseMap's array of buckets (i.e. either to a key or\n  /// value in the DenseMap).\n  bool isPointerIntoBucketsArray(const void *Ptr) const {\n    return Ptr >= getBuckets() && Ptr < getBucketsEnd();\n  }\n\n  /// getPointerIntoBucketsArray() - Return an opaque pointer into the buckets\n  /// array.  In conjunction with the previous method, this can be used to\n  /// determine whether an insertion caused the DenseMap to reallocate.\n  const void *getPointerIntoBucketsArray() const { return getBuckets(); }\n\nprotected:\n  DenseMapBase() {}\n\n  void destroyAll() {\n    if (getNumBuckets() == 0) // Nothing to do.\n      return;\n\n    const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();\n    for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {\n      if (!KeyInfoT::isEqual(P->first, EmptyKey) &&\n          !KeyInfoT::isEqual(P->first, TombstoneKey))\n        P->second.~ValueT();\n      P->first.~KeyT();\n    }\n\n#ifndef NDEBUG\n      memset((void*)getBuckets(), 0x5a, sizeof(BucketT)*getNumBuckets());\n#endif\n    }\n\n  void initEmpty() {\n    setNumEntries(0);\n    setNumTombstones(0);\n\n    assert((getNumBuckets() & (getNumBuckets()-1)) == 0 &&\n           \"# initial buckets must be a power of two!\");\n    const KeyT EmptyKey = getEmptyKey();\n    for (BucketT *B = getBuckets(), *E = getBucketsEnd(); B != E; ++B)\n      new (&B->first) KeyT(EmptyKey);\n  }\n\n  void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) {\n    initEmpty();\n\n    // Insert all the old elements.\n    const KeyT EmptyKey = getEmptyKey();\n    const KeyT TombstoneKey = getTombstoneKey();\n    for (BucketT *B = OldBucketsBegin, *E = OldBucketsEnd; B != E; ++B) {\n      if (!KeyInfoT::isEqual(B->first, EmptyKey) &&\n          !KeyInfoT::isEqual(B->first, TombstoneKey) && \n          !(ZeroValuesArePurgeable && B->second == 0)) {\n        // Insert the key/value into the new table.\n        BucketT *DestBucket;\n        bool FoundVal = LookupBucketFor(B->first, DestBucket);\n        (void)FoundVal; // silence warning.\n        assert(!FoundVal && \"Key already in new map?\");\n        DestBucket->first = llvm_move(B->first);\n        new (&DestBucket->second) ValueT(llvm_move(B->second));\n        incrementNumEntries();\n        \n        // Free the value.\n        B->second.~ValueT();\n      }\n      B->first.~KeyT();\n    }\n\n#ifndef NDEBUG\n    if (OldBucketsBegin != OldBucketsEnd)\n      memset((void*)OldBucketsBegin, 0x5a,\n             sizeof(BucketT) * (OldBucketsEnd - OldBucketsBegin));\n#endif\n  }\n\n  template <typename OtherBaseT>\n  void copyFrom(const DenseMapBase<OtherBaseT, KeyT, ValueT, KeyInfoT>& other) {\n    assert(getNumBuckets() == other.getNumBuckets());\n\n    setNumEntries(other.getNumEntries());\n    setNumTombstones(other.getNumTombstones());\n\n    if (isPodLike<KeyT>::value && isPodLike<ValueT>::value)\n      memcpy(getBuckets(), other.getBuckets(),\n             getNumBuckets() * sizeof(BucketT));\n    else\n      for (size_t i = 0; i < getNumBuckets(); ++i) {\n        new (&getBuckets()[i].first) KeyT(other.getBuckets()[i].first);\n        if (!KeyInfoT::isEqual(getBuckets()[i].first, getEmptyKey()) &&\n            !KeyInfoT::isEqual(getBuckets()[i].first, getTombstoneKey()))\n          new (&getBuckets()[i].second) ValueT(other.getBuckets()[i].second);\n      }\n  }\n\n  void swap(DenseMapBase& RHS) {\n    std::swap(getNumEntries(), RHS.getNumEntries());\n    std::swap(getNumTombstones(), RHS.getNumTombstones());\n  }\n\n  static unsigned getHashValue(const KeyT &Val) {\n    return KeyInfoT::getHashValue(Val);\n  }\n  template<typename LookupKeyT>\n  static unsigned getHashValue(const LookupKeyT &Val) {\n    return KeyInfoT::getHashValue(Val);\n  }\n  static const KeyT getEmptyKey() {\n    return KeyInfoT::getEmptyKey();\n  }\n  static const KeyT getTombstoneKey() {\n    return KeyInfoT::getTombstoneKey();\n  }\n\nprivate:\n  unsigned getNumEntries() const {\n    return static_cast<const DerivedT *>(this)->getNumEntries();\n  }\n  void setNumEntries(unsigned Num) {\n    static_cast<DerivedT *>(this)->setNumEntries(Num);\n  }\n  void incrementNumEntries() {\n    setNumEntries(getNumEntries() + 1);\n  }\n  void decrementNumEntries() {\n    setNumEntries(getNumEntries() - 1);\n  }\n  unsigned getNumTombstones() const {\n    return static_cast<const DerivedT *>(this)->getNumTombstones();\n  }\n  void setNumTombstones(unsigned Num) {\n    static_cast<DerivedT *>(this)->setNumTombstones(Num);\n  }\n  void incrementNumTombstones() {\n    setNumTombstones(getNumTombstones() + 1);\n  }\n  void decrementNumTombstones() {\n    setNumTombstones(getNumTombstones() - 1);\n  }\n  const BucketT *getBuckets() const {\n    return static_cast<const DerivedT *>(this)->getBuckets();\n  }\n  BucketT *getBuckets() {\n    return static_cast<DerivedT *>(this)->getBuckets();\n  }\n  unsigned getNumBuckets() const {\n    return static_cast<const DerivedT *>(this)->getNumBuckets();\n  }\n  BucketT *getBucketsEnd() {\n    return getBuckets() + getNumBuckets();\n  }\n  const BucketT *getBucketsEnd() const {\n    return getBuckets() + getNumBuckets();\n  }\n\n  void grow(unsigned AtLeast) {\n    static_cast<DerivedT *>(this)->grow(AtLeast);\n  }\n\n  void shrink_and_clear() {\n    static_cast<DerivedT *>(this)->shrink_and_clear();\n  }\n\n\n  BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value,\n                            BucketT *TheBucket) {\n    TheBucket = InsertIntoBucketImpl(Key, TheBucket);\n\n    TheBucket->first = Key;\n    new (&TheBucket->second) ValueT(Value);\n    return TheBucket;\n  }\n\n#if LLVM_USE_RVALUE_REFERENCES\n  BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value,\n                            BucketT *TheBucket) {\n    TheBucket = InsertIntoBucketImpl(Key, TheBucket);\n\n    TheBucket->first = Key;\n    new (&TheBucket->second) ValueT(std::move(Value));\n    return TheBucket;\n  }\n\n  BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, BucketT *TheBucket) {\n    TheBucket = InsertIntoBucketImpl(Key, TheBucket);\n\n    TheBucket->first = std::move(Key);\n    new (&TheBucket->second) ValueT(std::move(Value));\n    return TheBucket;\n  }\n#endif\n\n  BucketT *InsertIntoBucketImpl(const KeyT &Key, BucketT *TheBucket) {\n    // If the load of the hash table is more than 3/4, grow the table. \n    // If fewer than 1/8 of the buckets are empty (meaning that many are \n    // filled with tombstones), rehash the table without growing.\n    //\n    // The later case is tricky.  For example, if we had one empty bucket with\n    // tons of tombstones, failing lookups (e.g. for insertion) would have to\n    // probe almost the entire table until it found the empty bucket.  If the\n    // table completely filled with tombstones, no lookup would ever succeed,\n    // causing infinite loops in lookup.\n    unsigned NewNumEntries = getNumEntries() + 1;\n    unsigned NumBuckets = getNumBuckets();\n    if (NewNumEntries*4 >= NumBuckets*3) {\n      this->grow(NumBuckets * 2);\n      LookupBucketFor(Key, TheBucket);\n      NumBuckets = getNumBuckets();\n    }\n    if (NumBuckets-(NewNumEntries+getNumTombstones()) <= NumBuckets/8) {\n      this->grow(NumBuckets);\n      LookupBucketFor(Key, TheBucket);\n    }\n    assert(TheBucket);\n\n    // Only update the state after we've grown our bucket space appropriately\n    // so that when growing buckets we have self-consistent entry count.\n    // If we are writing over a tombstone or zero value, remember this.\n    if (KeyInfoT::isEqual(TheBucket->first, getEmptyKey())) {\n      // Replacing an empty bucket.\n      incrementNumEntries();      \n    }\n    else if (KeyInfoT::isEqual(TheBucket->first, getTombstoneKey())) {\n      // Replacing a tombstone.\n      incrementNumEntries();\n      decrementNumTombstones();\n    }\n    else if (ZeroValuesArePurgeable  &&  TheBucket->second == 0) {\n      // Purging a zero. No accounting changes.\n      TheBucket->second.~ValueT();\n    } else {\n      // Updating an existing entry. No accounting changes.\n    }\n\n    return TheBucket;\n  }\n\n  /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in\n  /// FoundBucket.  If the bucket contains the key and a value, this returns\n  /// true, otherwise it returns a bucket with an empty marker or tombstone \n  /// or zero value and returns false.\n  template<typename LookupKeyT>\n  bool LookupBucketFor(const LookupKeyT &Val,\n                       const BucketT *&FoundBucket) const {\n    const BucketT *BucketsPtr = getBuckets();\n    const unsigned NumBuckets = getNumBuckets();\n\n    if (NumBuckets == 0) {\n      FoundBucket = 0;\n      return false;\n    }\n\n    // FoundTombstone - Keep track of whether we find a tombstone or zero value while probing.\n    const BucketT *FoundTombstone = 0;\n    const KeyT EmptyKey = getEmptyKey();\n    const KeyT TombstoneKey = getTombstoneKey();\n    assert(!KeyInfoT::isEqual(Val, EmptyKey) &&\n           !KeyInfoT::isEqual(Val, TombstoneKey) &&\n           \"Empty/Tombstone value shouldn't be inserted into map!\");\n\n    unsigned BucketNo = getHashValue(Val) & (NumBuckets-1);\n    unsigned ProbeAmt = 1;\n    while (1) {\n      const BucketT *ThisBucket = BucketsPtr + BucketNo;\n      // Found Val's bucket?  If so, return it.\n      if (KeyInfoT::isEqual(Val, ThisBucket->first)) {\n        FoundBucket = ThisBucket;\n        return true;\n      }\n\n      // If we found an empty bucket, the key doesn't exist in the set.\n      // Insert it and return the default value.\n      if (KeyInfoT::isEqual(ThisBucket->first, EmptyKey)) {\n        // If we've already seen a tombstone while probing, fill it in instead\n        // of the empty bucket we eventually probed to.\n        if (FoundTombstone) ThisBucket = FoundTombstone;\n        FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;\n        return false;\n      }\n\n      // If this is a tombstone, remember it.  If Val ends up not in the map, we\n      // prefer to return it than something that would require more probing.\n      // Ditto for zero values.\n      if (KeyInfoT::isEqual(ThisBucket->first, TombstoneKey) && !FoundTombstone)\n        FoundTombstone = ThisBucket;  // Remember the first tombstone found.\n      if (ZeroValuesArePurgeable  && \n          ThisBucket->second == 0  &&  !FoundTombstone) \n        FoundTombstone = ThisBucket;\n\n      // Otherwise, it's a hash collision or a tombstone, continue quadratic\n      // probing.\n      if (ProbeAmt > NumBuckets) {\n          // No empty buckets in table. Die.\n          _objc_fatal(\"Hash table corrupted. This is probably a memory error \"\n                      \"somewhere. (table at %p, buckets at %p (%zu bytes), \"\n                      \"%u buckets, %u entries, %u tombstones, \"\n                      \"data %p %p %p %p)\", \n                      this, BucketsPtr, malloc_size(BucketsPtr), \n                      NumBuckets, getNumEntries(), getNumTombstones(), \n                      ((void**)BucketsPtr)[0], ((void**)BucketsPtr)[1], \n                      ((void**)BucketsPtr)[2], ((void**)BucketsPtr)[3]);\n      }\n      BucketNo += ProbeAmt++;\n      BucketNo&= (NumBuckets-1);\n    }\n  }\n\n  template <typename LookupKeyT>\n  bool LookupBucketFor(const LookupKeyT &Val, BucketT *&FoundBucket) {\n    const BucketT *ConstFoundBucket;\n    bool Result = const_cast<const DenseMapBase *>(this)\n      ->LookupBucketFor(Val, ConstFoundBucket);\n    FoundBucket = const_cast<BucketT *>(ConstFoundBucket);\n    return Result;\n  }\n\npublic:\n  /// Return the approximate size (in bytes) of the actual map.\n  /// This is just the raw memory used by DenseMap.\n  /// If entries are pointers to objects, the size of the referenced objects\n  /// are not included.\n  size_t getMemorySize() const {\n    return getNumBuckets() * sizeof(BucketT);\n  }\n};\n\ntemplate<typename KeyT, typename ValueT,\n         bool ZeroValuesArePurgeable = false, \n         typename KeyInfoT = DenseMapInfo<KeyT> >\nclass DenseMap\n    : public DenseMapBase<DenseMap<KeyT, ValueT, ZeroValuesArePurgeable, KeyInfoT>,\n                          KeyT, ValueT, KeyInfoT, ZeroValuesArePurgeable> {\n  // Lift some types from the dependent base class into this class for\n  // simplicity of referring to them.\n  typedef DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, ZeroValuesArePurgeable> BaseT;\n  typedef typename BaseT::BucketT BucketT;\n  friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, ZeroValuesArePurgeable>;\n\n  BucketT *Buckets;\n  unsigned NumEntries;\n  unsigned NumTombstones;\n  unsigned NumBuckets;\n\npublic:\n  explicit DenseMap(unsigned NumInitBuckets = 0) {\n    init(NumInitBuckets);\n  }\n\n  DenseMap(const DenseMap &other) {\n    init(0);\n    copyFrom(other);\n  }\n\n#if LLVM_USE_RVALUE_REFERENCES\n  DenseMap(DenseMap &&other) {\n    init(0);\n    swap(other);\n  }\n#endif\n\n  template<typename InputIt>\n  DenseMap(const InputIt &I, const InputIt &E) {\n    init(NextPowerOf2(std::distance(I, E)));\n    this->insert(I, E);\n  }\n\n  ~DenseMap() {\n    this->destroyAll();\n    operator delete(Buckets);\n  }\n\n  void swap(DenseMap& RHS) {\n    std::swap(Buckets, RHS.Buckets);\n    std::swap(NumEntries, RHS.NumEntries);\n    std::swap(NumTombstones, RHS.NumTombstones);\n    std::swap(NumBuckets, RHS.NumBuckets);\n  }\n\n  DenseMap& operator=(const DenseMap& other) {\n    copyFrom(other);\n    return *this;\n  }\n\n#if LLVM_USE_RVALUE_REFERENCES\n  DenseMap& operator=(DenseMap &&other) {\n    this->destroyAll();\n    operator delete(Buckets);\n    init(0);\n    swap(other);\n    return *this;\n  }\n#endif\n\n  void copyFrom(const DenseMap& other) {\n    this->destroyAll();\n    operator delete(Buckets);\n    if (allocateBuckets(other.NumBuckets)) {\n      this->BaseT::copyFrom(other);\n    } else {\n      NumEntries = 0;\n      NumTombstones = 0;\n    }\n  }\n\n  void init(unsigned InitBuckets) {\n    if (allocateBuckets(InitBuckets)) {\n      this->BaseT::initEmpty();\n    } else {\n      NumEntries = 0;\n      NumTombstones = 0;\n    }\n  }\n\n  void grow(unsigned AtLeast) {\n    unsigned OldNumBuckets = NumBuckets;\n    BucketT *OldBuckets = Buckets;\n\n    allocateBuckets(std::max<unsigned>(MIN_BUCKETS, NextPowerOf2(AtLeast)));\n    assert(Buckets);\n    if (!OldBuckets) {\n      this->BaseT::initEmpty();\n      return;\n    }\n\n    this->moveFromOldBuckets(OldBuckets, OldBuckets+OldNumBuckets);\n\n    // Free the old table.\n    operator delete(OldBuckets);\n  }\n\n  void shrink_and_clear() {\n    unsigned OldNumEntries = NumEntries;\n    this->destroyAll();\n\n    // Reduce the number of buckets.\n    unsigned NewNumBuckets = 0;\n    if (OldNumEntries)\n      NewNumBuckets = std::max(MIN_BUCKETS, 1 << (Log2_32_Ceil(OldNumEntries) + 1));\n    if (NewNumBuckets == NumBuckets) {\n      this->BaseT::initEmpty();\n      return;\n    }\n\n    operator delete(Buckets);\n    init(NewNumBuckets);\n  }\n\nprivate:\n  unsigned getNumEntries() const {\n    return NumEntries;\n  }\n  void setNumEntries(unsigned Num) {\n    NumEntries = Num;\n  }\n\n  unsigned getNumTombstones() const {\n    return NumTombstones;\n  }\n  void setNumTombstones(unsigned Num) {\n    NumTombstones = Num;\n  }\n\n  BucketT *getBuckets() const {\n    return Buckets;\n  }\n\n  unsigned getNumBuckets() const {\n    return NumBuckets;\n  }\n\n  bool allocateBuckets(unsigned Num) {\n    NumBuckets = Num;\n    if (NumBuckets == 0) {\n      Buckets = 0;\n      return false;\n    }\n\n    Buckets = static_cast<BucketT*>(operator new(sizeof(BucketT)*NumBuckets));\n    return true;\n  }\n};\n\ntemplate<typename KeyT, typename ValueT,\n         unsigned InlineBuckets = 4,\n         bool ZeroValuesArePurgeable = false, \n         typename KeyInfoT = DenseMapInfo<KeyT> >\nclass SmallDenseMap\n    : public DenseMapBase<SmallDenseMap<KeyT, ValueT, InlineBuckets, ZeroValuesArePurgeable, KeyInfoT>,\n                          KeyT, ValueT, KeyInfoT, ZeroValuesArePurgeable> {\n  // Lift some types from the dependent base class into this class for\n  // simplicity of referring to them.\n  typedef DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, ZeroValuesArePurgeable> BaseT;\n  typedef typename BaseT::BucketT BucketT;\n  friend class DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, ZeroValuesArePurgeable>;\n\n  unsigned Small : 1;\n  unsigned NumEntries : 31;\n  unsigned NumTombstones;\n\n  struct LargeRep {\n    BucketT *Buckets;\n    unsigned NumBuckets;\n  };\n\n  /// A \"union\" of an inline bucket array and the struct representing\n  /// a large bucket. This union will be discriminated by the 'Small' bit.\n  AlignedCharArrayUnion<BucketT[InlineBuckets], LargeRep> storage;\n\npublic:\n  explicit SmallDenseMap(unsigned NumInitBuckets = 0) {\n    init(NumInitBuckets);\n  }\n\n  SmallDenseMap(const SmallDenseMap &other) {\n    init(0);\n    copyFrom(other);\n  }\n\n#if LLVM_USE_RVALUE_REFERENCES\n  SmallDenseMap(SmallDenseMap &&other) {\n    init(0);\n    swap(other);\n  }\n#endif\n\n  template<typename InputIt>\n  SmallDenseMap(const InputIt &I, const InputIt &E) {\n    init(NextPowerOf2(std::distance(I, E)));\n    this->insert(I, E);\n  }\n\n  ~SmallDenseMap() {\n    this->destroyAll();\n    deallocateBuckets();\n  }\n\n  void swap(SmallDenseMap& RHS) {\n    unsigned TmpNumEntries = RHS.NumEntries;\n    RHS.NumEntries = NumEntries;\n    NumEntries = TmpNumEntries;\n    std::swap(NumTombstones, RHS.NumTombstones);\n\n    const KeyT EmptyKey = this->getEmptyKey();\n    const KeyT TombstoneKey = this->getTombstoneKey();\n    if (Small && RHS.Small) {\n      // If we're swapping inline bucket arrays, we have to cope with some of\n      // the tricky bits of DenseMap's storage system: the buckets are not\n      // fully initialized. Thus we swap every key, but we may have\n      // a one-directional move of the value.\n      for (unsigned i = 0, e = InlineBuckets; i != e; ++i) {\n        BucketT *LHSB = &getInlineBuckets()[i],\n                *RHSB = &RHS.getInlineBuckets()[i];\n        bool hasLHSValue = (!KeyInfoT::isEqual(LHSB->first, EmptyKey) &&\n                            !KeyInfoT::isEqual(LHSB->first, TombstoneKey));\n        bool hasRHSValue = (!KeyInfoT::isEqual(RHSB->first, EmptyKey) &&\n                            !KeyInfoT::isEqual(RHSB->first, TombstoneKey));\n        if (hasLHSValue && hasRHSValue) {\n          // Swap together if we can...\n          std::swap(*LHSB, *RHSB);\n          continue;\n        }\n        // Swap separately and handle any assymetry.\n        std::swap(LHSB->first, RHSB->first);\n        if (hasLHSValue) {\n          new (&RHSB->second) ValueT(llvm_move(LHSB->second));\n          LHSB->second.~ValueT();\n        } else if (hasRHSValue) {\n          new (&LHSB->second) ValueT(llvm_move(RHSB->second));\n          RHSB->second.~ValueT();\n        }\n      }\n      return;\n    }\n    if (!Small && !RHS.Small) {\n      std::swap(getLargeRep()->Buckets, RHS.getLargeRep()->Buckets);\n      std::swap(getLargeRep()->NumBuckets, RHS.getLargeRep()->NumBuckets);\n      return;\n    }\n\n    SmallDenseMap &SmallSide = Small ? *this : RHS;\n    SmallDenseMap &LargeSide = Small ? RHS : *this;\n\n    // First stash the large side's rep and move the small side across.\n    LargeRep TmpRep = llvm_move(*LargeSide.getLargeRep());\n    LargeSide.getLargeRep()->~LargeRep();\n    LargeSide.Small = true;\n    // This is similar to the standard move-from-old-buckets, but the bucket\n    // count hasn't actually rotated in this case. So we have to carefully\n    // move construct the keys and values into their new locations, but there\n    // is no need to re-hash things.\n    for (unsigned i = 0, e = InlineBuckets; i != e; ++i) {\n      BucketT *NewB = &LargeSide.getInlineBuckets()[i],\n              *OldB = &SmallSide.getInlineBuckets()[i];\n      new (&NewB->first) KeyT(llvm_move(OldB->first));\n      OldB->first.~KeyT();\n      if (!KeyInfoT::isEqual(NewB->first, EmptyKey) &&\n          !KeyInfoT::isEqual(NewB->first, TombstoneKey)) {\n        new (&NewB->second) ValueT(llvm_move(OldB->second));\n        OldB->second.~ValueT();\n      }\n    }\n\n    // The hard part of moving the small buckets across is done, just move\n    // the TmpRep into its new home.\n    SmallSide.Small = false;\n    new (SmallSide.getLargeRep()) LargeRep(llvm_move(TmpRep));\n  }\n\n  SmallDenseMap& operator=(const SmallDenseMap& other) {\n    copyFrom(other);\n    return *this;\n  }\n\n#if LLVM_USE_RVALUE_REFERENCES\n  SmallDenseMap& operator=(SmallDenseMap &&other) {\n    this->destroyAll();\n    deallocateBuckets();\n    init(0);\n    swap(other);\n    return *this;\n  }\n#endif\n\n  void copyFrom(const SmallDenseMap& other) {\n    this->destroyAll();\n    deallocateBuckets();\n    Small = true;\n    if (other.getNumBuckets() > InlineBuckets) {\n      Small = false;\n      allocateBuckets(other.getNumBuckets());\n    }\n    this->BaseT::copyFrom(other);\n  }\n\n  void init(unsigned InitBuckets) {\n    Small = true;\n    if (InitBuckets > InlineBuckets) {\n      Small = false;\n      new (getLargeRep()) LargeRep(allocateBuckets(InitBuckets));\n    }\n    this->BaseT::initEmpty();\n  }\n\n  void grow(unsigned AtLeast) {\n    if (AtLeast > InlineBuckets)\n      AtLeast = std::max<unsigned>(MIN_BUCKETS, NextPowerOf2(AtLeast));\n\n    if (Small) {\n      if (AtLeast <= InlineBuckets)\n        return; // Nothing to do.\n\n      // First move the inline buckets into a temporary storage.\n      AlignedCharArrayUnion<BucketT[InlineBuckets]> TmpStorage;\n      BucketT *TmpBegin = reinterpret_cast<BucketT *>(TmpStorage.buffer);\n      BucketT *TmpEnd = TmpBegin;\n\n      // Loop over the buckets, moving non-empty, non-tombstones into the\n      // temporary storage. Have the loop move the TmpEnd forward as it goes.\n      const KeyT EmptyKey = this->getEmptyKey();\n      const KeyT TombstoneKey = this->getTombstoneKey();\n      for (BucketT *P = getBuckets(), *E = P + InlineBuckets; P != E; ++P) {\n        if (!KeyInfoT::isEqual(P->first, EmptyKey) &&\n            !KeyInfoT::isEqual(P->first, TombstoneKey)) {\n          assert(size_t(TmpEnd - TmpBegin) < InlineBuckets &&\n                 \"Too many inline buckets!\");\n          new (&TmpEnd->first) KeyT(llvm_move(P->first));\n          new (&TmpEnd->second) ValueT(llvm_move(P->second));\n          ++TmpEnd;\n          P->second.~ValueT();\n        }\n        P->first.~KeyT();\n      }\n\n      // Now make this map use the large rep, and move all the entries back\n      // into it.\n      Small = false;\n      new (getLargeRep()) LargeRep(allocateBuckets(AtLeast));\n      this->moveFromOldBuckets(TmpBegin, TmpEnd);\n      return;\n    }\n\n    LargeRep OldRep = llvm_move(*getLargeRep());\n    getLargeRep()->~LargeRep();\n    if (AtLeast <= InlineBuckets) {\n      Small = true;\n    } else {\n      new (getLargeRep()) LargeRep(allocateBuckets(AtLeast));\n    }\n\n    this->moveFromOldBuckets(OldRep.Buckets, OldRep.Buckets+OldRep.NumBuckets);\n\n    // Free the old table.\n    operator delete(OldRep.Buckets);\n  }\n\n  void shrink_and_clear() {\n    unsigned OldSize = this->size();\n    this->destroyAll();\n\n    // Reduce the number of buckets.\n    unsigned NewNumBuckets = 0;\n    if (OldSize) {\n      NewNumBuckets = 1 << (Log2_32_Ceil(OldSize) + 1);\n      if (NewNumBuckets > InlineBuckets && NewNumBuckets < MIN_BUCKETS)\n        NewNumBuckets = MIN_BUCKETS;\n    }\n    if ((Small && NewNumBuckets <= InlineBuckets) ||\n        (!Small && NewNumBuckets == getLargeRep()->NumBuckets)) {\n      this->BaseT::initEmpty();\n      return;\n    }\n\n    deallocateBuckets();\n    init(NewNumBuckets);\n  }\n\nprivate:\n  unsigned getNumEntries() const {\n    return NumEntries;\n  }\n  void setNumEntries(unsigned Num) {\n    assert(Num < INT_MAX && \"Cannot support more than INT_MAX entries\");\n    NumEntries = Num;\n  }\n\n  unsigned getNumTombstones() const {\n    return NumTombstones;\n  }\n  void setNumTombstones(unsigned Num) {\n    NumTombstones = Num;\n  }\n\n  const BucketT *getInlineBuckets() const {\n    assert(Small);\n    // Note that this cast does not violate aliasing rules as we assert that\n    // the memory's dynamic type is the small, inline bucket buffer, and the\n    // 'storage.buffer' static type is 'char *'.\n    return reinterpret_cast<const BucketT *>(storage.buffer);\n  }\n  BucketT *getInlineBuckets() {\n    return const_cast<BucketT *>(\n      const_cast<const SmallDenseMap *>(this)->getInlineBuckets());\n  }\n  const LargeRep *getLargeRep() const {\n    assert(!Small);\n    // Note, same rule about aliasing as with getInlineBuckets.\n    return reinterpret_cast<const LargeRep *>(storage.buffer);\n  }\n  LargeRep *getLargeRep() {\n    return const_cast<LargeRep *>(\n      const_cast<const SmallDenseMap *>(this)->getLargeRep());\n  }\n\n  const BucketT *getBuckets() const {\n    return Small ? getInlineBuckets() : getLargeRep()->Buckets;\n  }\n  BucketT *getBuckets() {\n    return const_cast<BucketT *>(\n      const_cast<const SmallDenseMap *>(this)->getBuckets());\n  }\n  unsigned getNumBuckets() const {\n    return Small ? InlineBuckets : getLargeRep()->NumBuckets;\n  }\n\n  void deallocateBuckets() {\n    if (Small)\n      return;\n\n    operator delete(getLargeRep()->Buckets);\n    getLargeRep()->~LargeRep();\n  }\n\n  LargeRep allocateBuckets(unsigned Num) {\n    assert(Num > InlineBuckets && \"Must allocate more buckets than are inline\");\n    LargeRep Rep = {\n      static_cast<BucketT*>(operator new(sizeof(BucketT) * Num)), Num\n};\n    return Rep;\n  }\n};\n\ntemplate<typename KeyT, typename ValueT,\n         typename KeyInfoT, bool IsConst>\nclass DenseMapIterator {\n  typedef std::pair<KeyT, ValueT> Bucket;\n  typedef DenseMapIterator<KeyT, ValueT,\n                           KeyInfoT, true> ConstIterator;\n  friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, true>;\npublic:\n  typedef ptrdiff_t difference_type;\n  typedef typename conditional<IsConst, const Bucket, Bucket>::type value_type;\n  typedef value_type *pointer;\n  typedef value_type &reference;\n  typedef std::forward_iterator_tag iterator_category;\nprivate:\n  pointer Ptr, End;\npublic:\n  DenseMapIterator() : Ptr(0), End(0) {}\n\n  DenseMapIterator(pointer Pos, pointer E, bool NoAdvance = false)\n    : Ptr(Pos), End(E) {\n    if (!NoAdvance) AdvancePastEmptyBuckets();\n  }\n\n  // If IsConst is true this is a converting constructor from iterator to\n  // const_iterator and the default copy constructor is used.\n  // Otherwise this is a copy constructor for iterator.\n  DenseMapIterator(const DenseMapIterator<KeyT, ValueT,\n                                          KeyInfoT, false>& I)\n    : Ptr(I.Ptr), End(I.End) {}\n\n  reference operator*() const {\n    return *Ptr;\n  }\n  pointer operator->() const {\n    return Ptr;\n  }\n\n  bool operator==(const ConstIterator &RHS) const {\n    return Ptr == RHS.operator->();\n  }\n  bool operator!=(const ConstIterator &RHS) const {\n    return Ptr != RHS.operator->();\n  }\n\n  inline DenseMapIterator& operator++() {  // Preincrement\n    ++Ptr;\n    AdvancePastEmptyBuckets();\n    return *this;\n  }\n  DenseMapIterator operator++(int) {  // Postincrement\n    DenseMapIterator tmp = *this; ++*this; return tmp;\n  }\n\nprivate:\n  void AdvancePastEmptyBuckets() {\n    const KeyT Empty = KeyInfoT::getEmptyKey();\n    const KeyT Tombstone = KeyInfoT::getTombstoneKey();\n\n    while (Ptr != End &&\n           (KeyInfoT::isEqual(Ptr->first, Empty) ||\n            KeyInfoT::isEqual(Ptr->first, Tombstone)))\n      ++Ptr;\n  }\n};\n\n} // end namespace objc\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/llvm-DenseMapInfo.h",
    "content": "//===- llvm/ADT/DenseMapInfo.h - Type traits for DenseMap -------*- C++ -*-===//\n//\n//                     The LLVM Compiler Infrastructure\n//\n// This file is distributed under the University of Illinois Open Source\n// License. See LICENSE.TXT for details.\n//\n//===----------------------------------------------------------------------===//\n//\n// This file defines DenseMapInfo traits for DenseMap.\n//\n//===----------------------------------------------------------------------===//\n\n// Taken from llvmCore-3425.0.31.\n\n#ifndef LLVM_ADT_DENSEMAPINFO_H\n#define LLVM_ADT_DENSEMAPINFO_H\n\n#include \"objc-private.h\"\n#include \"llvm-type_traits.h\"\n\nnamespace objc {\n\ntemplate<typename T>\nstruct DenseMapInfo {\n  //static inline T getEmptyKey();\n  //static inline T getTombstoneKey();\n  //static unsigned getHashValue(const T &Val);\n  //static bool isEqual(const T &LHS, const T &RHS);\n};\n\n// Provide DenseMapInfo for all pointers.\ntemplate<typename T>\nstruct DenseMapInfo<T*> {\n  static inline T* getEmptyKey() {\n    uintptr_t Val = static_cast<uintptr_t>(-1);\n    return reinterpret_cast<T*>(Val);\n  }\n  static inline T* getTombstoneKey() {\n    uintptr_t Val = static_cast<uintptr_t>(-2);\n    return reinterpret_cast<T*>(Val);\n  }\n  static unsigned getHashValue(const T *PtrVal) {\n      return ptr_hash((uintptr_t)PtrVal);\n  }\n  static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; }\n};\n\n// Provide DenseMapInfo for disguised pointers.\ntemplate<typename T>\nstruct DenseMapInfo<DisguisedPtr<T>> {\n  static inline DisguisedPtr<T> getEmptyKey() {\n    return DisguisedPtr<T>((T*)(uintptr_t)-1);\n  }\n  static inline DisguisedPtr<T> getTombstoneKey() {\n    return DisguisedPtr<T>((T*)(uintptr_t)-2);\n  }\n  static unsigned getHashValue(const T *PtrVal) {\n      return ptr_hash((uintptr_t)PtrVal);\n  }\n  static bool isEqual(const DisguisedPtr<T> &LHS, const DisguisedPtr<T> &RHS) {\n      return LHS == RHS; \n  }\n};\n\n// Provide DenseMapInfo for cstrings.\ntemplate<> struct DenseMapInfo<const char*> {\n  static inline const char* getEmptyKey() { \n    return reinterpret_cast<const char *>((intptr_t)-1); \n  }\n  static inline const char* getTombstoneKey() { \n    return reinterpret_cast<const char *>((intptr_t)-2); \n  }\n  static unsigned getHashValue(const char* const &Val) { \n    return _objc_strhash(Val); \n  }\n  static bool isEqual(const char* const &LHS, const char* const &RHS) {\n    return 0 == strcmp(LHS, RHS);\n  }\n};\n\n// Provide DenseMapInfo for chars.\ntemplate<> struct DenseMapInfo<char> {\n  static inline char getEmptyKey() { return ~0; }\n  static inline char getTombstoneKey() { return ~0 - 1; }\n  static unsigned getHashValue(const char& Val) { return Val * 37U; }\n  static bool isEqual(const char &LHS, const char &RHS) {\n    return LHS == RHS;\n  }\n};\n  \n// Provide DenseMapInfo for unsigned ints.\ntemplate<> struct DenseMapInfo<unsigned> {\n  static inline unsigned getEmptyKey() { return ~0U; }\n  static inline unsigned getTombstoneKey() { return ~0U - 1; }\n  static unsigned getHashValue(const unsigned& Val) { return Val * 37U; }\n  static bool isEqual(const unsigned& LHS, const unsigned& RHS) {\n    return LHS == RHS;\n  }\n};\n\n// Provide DenseMapInfo for unsigned longs.\ntemplate<> struct DenseMapInfo<unsigned long> {\n  static inline unsigned long getEmptyKey() { return ~0UL; }\n  static inline unsigned long getTombstoneKey() { return ~0UL - 1L; }\n  static unsigned getHashValue(const unsigned long& Val) {\n    return (unsigned)(Val * 37UL);\n  }\n  static bool isEqual(const unsigned long& LHS, const unsigned long& RHS) {\n    return LHS == RHS;\n  }\n};\n\n// Provide DenseMapInfo for unsigned long longs.\ntemplate<> struct DenseMapInfo<unsigned long long> {\n  static inline unsigned long long getEmptyKey() { return ~0ULL; }\n  static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; }\n  static unsigned getHashValue(const unsigned long long& Val) {\n    return (unsigned)(Val * 37ULL);\n  }\n  static bool isEqual(const unsigned long long& LHS,\n                      const unsigned long long& RHS) {\n    return LHS == RHS;\n  }\n};\n\n// Provide DenseMapInfo for ints.\ntemplate<> struct DenseMapInfo<int> {\n  static inline int getEmptyKey() { return 0x7fffffff; }\n  static inline int getTombstoneKey() { return -0x7fffffff - 1; }\n  static unsigned getHashValue(const int& Val) { return (unsigned)(Val * 37U); }\n  static bool isEqual(const int& LHS, const int& RHS) {\n    return LHS == RHS;\n  }\n};\n\n// Provide DenseMapInfo for longs.\ntemplate<> struct DenseMapInfo<long> {\n  static inline long getEmptyKey() {\n    return (1UL << (sizeof(long) * 8 - 1)) - 1UL;\n  }\n  static inline long getTombstoneKey() { return getEmptyKey() - 1L; }\n  static unsigned getHashValue(const long& Val) {\n    return (unsigned)(Val * 37UL);\n  }\n  static bool isEqual(const long& LHS, const long& RHS) {\n    return LHS == RHS;\n  }\n};\n\n// Provide DenseMapInfo for long longs.\ntemplate<> struct DenseMapInfo<long long> {\n  static inline long long getEmptyKey() { return 0x7fffffffffffffffLL; }\n  static inline long long getTombstoneKey() { return -0x7fffffffffffffffLL-1; }\n  static unsigned getHashValue(const long long& Val) {\n    return (unsigned)(Val * 37ULL);\n  }\n  static bool isEqual(const long long& LHS,\n                      const long long& RHS) {\n    return LHS == RHS;\n  }\n};\n\n// Provide DenseMapInfo for all pairs whose members have info.\ntemplate<typename T, typename U>\nstruct DenseMapInfo<std::pair<T, U> > {\n  typedef std::pair<T, U> Pair;\n  typedef DenseMapInfo<T> FirstInfo;\n  typedef DenseMapInfo<U> SecondInfo;\n\n  static inline Pair getEmptyKey() {\n    return std::make_pair(FirstInfo::getEmptyKey(),\n                          SecondInfo::getEmptyKey());\n  }\n  static inline Pair getTombstoneKey() {\n    return std::make_pair(FirstInfo::getTombstoneKey(),\n                          SecondInfo::getTombstoneKey());\n  }\n  static unsigned getHashValue(const Pair& PairVal) {\n    uint64_t key = (uint64_t)FirstInfo::getHashValue(PairVal.first) << 32\n          | (uint64_t)SecondInfo::getHashValue(PairVal.second);\n    key += ~(key << 32);\n    key ^= (key >> 22);\n    key += ~(key << 13);\n    key ^= (key >> 8);\n    key += (key << 3);\n    key ^= (key >> 15);\n    key += ~(key << 27);\n    key ^= (key >> 31);\n    return (unsigned)key;\n  }\n  static bool isEqual(const Pair &LHS, const Pair &RHS) {\n    return FirstInfo::isEqual(LHS.first, RHS.first) &&\n           SecondInfo::isEqual(LHS.second, RHS.second);\n  }\n};\n\n} // end namespace objc\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/llvm-MathExtras.h",
    "content": "//===-- llvm/Support/MathExtras.h - Useful math functions -------*- C++ -*-===//\n//\n//                     The LLVM Compiler Infrastructure\n//\n// This file is distributed under the University of Illinois Open Source\n// License. See LICENSE.TXT for details.\n//\n//===----------------------------------------------------------------------===//\n//\n// This file contains some functions that are useful for math stuff.\n//\n//===----------------------------------------------------------------------===//\n\n// Taken from llvmCore-3425.0.31.\n\n#ifndef LLVM_SUPPORT_MATHEXTRAS_H\n#define LLVM_SUPPORT_MATHEXTRAS_H\n\nnamespace objc {\n\n// NOTE: The following support functions use the _32/_64 extensions instead of\n// type overloading so that signed and unsigned integers can be used without\n// ambiguity.\n\n/// Hi_32 - This function returns the high 32 bits of a 64 bit value.\ninline uint32_t Hi_32(uint64_t Value) {\n  return static_cast<uint32_t>(Value >> 32);\n}\n\n/// Lo_32 - This function returns the low 32 bits of a 64 bit value.\ninline uint32_t Lo_32(uint64_t Value) {\n  return static_cast<uint32_t>(Value);\n}\n\n/// isInt - Checks if an integer fits into the given bit width.\ntemplate<unsigned N>\ninline bool isInt(int64_t x) {\n  return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1)));\n}\n// Template specializations to get better code for common cases.\ntemplate<>\ninline bool isInt<8>(int64_t x) {\n  return static_cast<int8_t>(x) == x;\n}\ntemplate<>\ninline bool isInt<16>(int64_t x) {\n  return static_cast<int16_t>(x) == x;\n}\ntemplate<>\ninline bool isInt<32>(int64_t x) {\n  return static_cast<int32_t>(x) == x;\n}\n\n/// isShiftedInt<N,S> - Checks if a signed integer is an N bit number shifted\n///                     left by S.\ntemplate<unsigned N, unsigned S>\ninline bool isShiftedInt(int64_t x) {\n  return isInt<N+S>(x) && (x % (1<<S) == 0);\n}\n\n/// isUInt - Checks if an unsigned integer fits into the given bit width.\ntemplate<unsigned N>\ninline bool isUInt(uint64_t x) {\n  return N >= 64 || x < (UINT64_C(1)<<N);\n}\n// Template specializations to get better code for common cases.\ntemplate<>\ninline bool isUInt<8>(uint64_t x) {\n  return static_cast<uint8_t>(x) == x;\n}\ntemplate<>\ninline bool isUInt<16>(uint64_t x) {\n  return static_cast<uint16_t>(x) == x;\n}\ntemplate<>\ninline bool isUInt<32>(uint64_t x) {\n  return static_cast<uint32_t>(x) == x;\n}\n\n/// isShiftedUInt<N,S> - Checks if a unsigned integer is an N bit number shifted\n///                     left by S.\ntemplate<unsigned N, unsigned S>\ninline bool isShiftedUInt(uint64_t x) {\n  return isUInt<N+S>(x) && (x % (1<<S) == 0);\n}\n\n/// isUIntN - Checks if an unsigned integer fits into the given (dynamic)\n/// bit width.\ninline bool isUIntN(unsigned N, uint64_t x) {\n  return x == (x & (~0ULL >> (64 - N)));\n}\n\n/// isIntN - Checks if an signed integer fits into the given (dynamic)\n/// bit width.\ninline bool isIntN(unsigned N, int64_t x) {\n  return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1)));\n}\n\n/// isMask_32 - This function returns true if the argument is a sequence of ones\n/// starting at the least significant bit with the remainder zero (32 bit\n/// version).   Ex. isMask_32(0x0000FFFFU) == true.\ninline bool isMask_32(uint32_t Value) {\n  return Value && ((Value + 1) & Value) == 0;\n}\n\n/// isMask_64 - This function returns true if the argument is a sequence of ones\n/// starting at the least significant bit with the remainder zero (64 bit\n/// version).\ninline bool isMask_64(uint64_t Value) {\n  return Value && ((Value + 1) & Value) == 0;\n}\n\n/// isShiftedMask_32 - This function returns true if the argument contains a\n/// sequence of ones with the remainder zero (32 bit version.)\n/// Ex. isShiftedMask_32(0x0000FF00U) == true.\ninline bool isShiftedMask_32(uint32_t Value) {\n  return isMask_32((Value - 1) | Value);\n}\n\n/// isShiftedMask_64 - This function returns true if the argument contains a\n/// sequence of ones with the remainder zero (64 bit version.)\ninline bool isShiftedMask_64(uint64_t Value) {\n  return isMask_64((Value - 1) | Value);\n}\n\n/// isPowerOf2_32 - This function returns true if the argument is a power of\n/// two > 0. Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)\ninline bool isPowerOf2_32(uint32_t Value) {\n  return Value && !(Value & (Value - 1));\n}\n\n/// isPowerOf2_64 - This function returns true if the argument is a power of two\n/// > 0 (64 bit edition.)\ninline bool isPowerOf2_64(uint64_t Value) {\n  return Value && !(Value & (Value - int64_t(1L)));\n}\n\n/// CountLeadingZeros_32 - this function performs the platform optimal form of\n/// counting the number of zeros from the most significant bit to the first one\n/// bit.  Ex. CountLeadingZeros_32(0x00F000FF) == 8.\n/// Returns 32 if the word is zero.\ninline unsigned CountLeadingZeros_32(uint32_t Value) {\n  unsigned Count; // result\n#if __GNUC__ >= 4\n  // PowerPC is defined for __builtin_clz(0)\n#if !defined(__ppc__) && !defined(__ppc64__)\n  if (!Value) return 32;\n#endif\n  Count = __builtin_clz(Value);\n#else\n  if (!Value) return 32;\n  Count = 0;\n  // bisection method for count leading zeros\n  for (unsigned Shift = 32 >> 1; Shift; Shift >>= 1) {\n    uint32_t Tmp = Value >> Shift;\n    if (Tmp) {\n      Value = Tmp;\n    } else {\n      Count |= Shift;\n    }\n  }\n#endif\n  return Count;\n}\n\n/// CountLeadingOnes_32 - this function performs the operation of\n/// counting the number of ones from the most significant bit to the first zero\n/// bit.  Ex. CountLeadingOnes_32(0xFF0FFF00) == 8.\n/// Returns 32 if the word is all ones.\ninline unsigned CountLeadingOnes_32(uint32_t Value) {\n  return CountLeadingZeros_32(~Value);\n}\n\n/// CountLeadingZeros_64 - This function performs the platform optimal form\n/// of counting the number of zeros from the most significant bit to the first\n/// one bit (64 bit edition.)\n/// Returns 64 if the word is zero.\ninline unsigned CountLeadingZeros_64(uint64_t Value) {\n  unsigned Count; // result\n#if __GNUC__ >= 4\n  // PowerPC is defined for __builtin_clzll(0)\n#if !defined(__ppc__) && !defined(__ppc64__)\n  if (!Value) return 64;\n#endif\n  Count = __builtin_clzll(Value);\n#else\n  if (sizeof(long) == sizeof(int64_t)) {\n    if (!Value) return 64;\n    Count = 0;\n    // bisection method for count leading zeros\n    for (unsigned Shift = 64 >> 1; Shift; Shift >>= 1) {\n      uint64_t Tmp = Value >> Shift;\n      if (Tmp) {\n        Value = Tmp;\n      } else {\n        Count |= Shift;\n      }\n    }\n  } else {\n    // get hi portion\n    uint32_t Hi = Hi_32(Value);\n\n    // if some bits in hi portion\n    if (Hi) {\n        // leading zeros in hi portion plus all bits in lo portion\n        Count = CountLeadingZeros_32(Hi);\n    } else {\n        // get lo portion\n        uint32_t Lo = Lo_32(Value);\n        // same as 32 bit value\n        Count = CountLeadingZeros_32(Lo)+32;\n    }\n  }\n#endif\n  return Count;\n}\n\n/// CountLeadingOnes_64 - This function performs the operation\n/// of counting the number of ones from the most significant bit to the first\n/// zero bit (64 bit edition.)\n/// Returns 64 if the word is all ones.\ninline unsigned CountLeadingOnes_64(uint64_t Value) {\n  return CountLeadingZeros_64(~Value);\n}\n\n/// CountTrailingZeros_32 - this function performs the platform optimal form of\n/// counting the number of zeros from the least significant bit to the first one\n/// bit.  Ex. CountTrailingZeros_32(0xFF00FF00) == 8.\n/// Returns 32 if the word is zero.\ninline unsigned CountTrailingZeros_32(uint32_t Value) {\n#if __GNUC__ >= 4\n  return Value ? __builtin_ctz(Value) : 32;\n#else\n  static const unsigned Mod37BitPosition[] = {\n    32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13,\n    4, 7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9,\n    5, 20, 8, 19, 18\n  };\n  return Mod37BitPosition[(-Value & Value) % 37];\n#endif\n}\n\n/// CountTrailingOnes_32 - this function performs the operation of\n/// counting the number of ones from the least significant bit to the first zero\n/// bit.  Ex. CountTrailingOnes_32(0x00FF00FF) == 8.\n/// Returns 32 if the word is all ones.\ninline unsigned CountTrailingOnes_32(uint32_t Value) {\n  return CountTrailingZeros_32(~Value);\n}\n\n/// CountTrailingZeros_64 - This function performs the platform optimal form\n/// of counting the number of zeros from the least significant bit to the first\n/// one bit (64 bit edition.)\n/// Returns 64 if the word is zero.\ninline unsigned CountTrailingZeros_64(uint64_t Value) {\n#if __GNUC__ >= 4\n  return Value ? __builtin_ctzll(Value) : 64;\n#else\n  static const unsigned Mod67Position[] = {\n    64, 0, 1, 39, 2, 15, 40, 23, 3, 12, 16, 59, 41, 19, 24, 54,\n    4, 64, 13, 10, 17, 62, 60, 28, 42, 30, 20, 51, 25, 44, 55,\n    47, 5, 32, 65, 38, 14, 22, 11, 58, 18, 53, 63, 9, 61, 27,\n    29, 50, 43, 46, 31, 37, 21, 57, 52, 8, 26, 49, 45, 36, 56,\n    7, 48, 35, 6, 34, 33, 0\n  };\n  return Mod67Position[(-Value & Value) % 67];\n#endif\n}\n\n/// CountTrailingOnes_64 - This function performs the operation\n/// of counting the number of ones from the least significant bit to the first\n/// zero bit (64 bit edition.)\n/// Returns 64 if the word is all ones.\ninline unsigned CountTrailingOnes_64(uint64_t Value) {\n  return CountTrailingZeros_64(~Value);\n}\n\n/// CountPopulation_32 - this function counts the number of set bits in a value.\n/// Ex. CountPopulation(0xF000F000) = 8\n/// Returns 0 if the word is zero.\ninline unsigned CountPopulation_32(uint32_t Value) {\n#if __GNUC__ >= 4\n  return __builtin_popcount(Value);\n#else\n  uint32_t v = Value - ((Value >> 1) & 0x55555555);\n  v = (v & 0x33333333) + ((v >> 2) & 0x33333333);\n  return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;\n#endif\n}\n\n/// CountPopulation_64 - this function counts the number of set bits in a value,\n/// (64 bit edition.)\ninline unsigned CountPopulation_64(uint64_t Value) {\n#if __GNUC__ >= 4\n  return __builtin_popcountll(Value);\n#else\n  uint64_t v = Value - ((Value >> 1) & 0x5555555555555555ULL);\n  v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL);\n  v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL;\n  return unsigned((uint64_t)(v * 0x0101010101010101ULL) >> 56);\n#endif\n}\n\n/// Log2_32 - This function returns the floor log base 2 of the specified value,\n/// -1 if the value is zero. (32 bit edition.)\n/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2\ninline unsigned Log2_32(uint32_t Value) {\n  return 31 - CountLeadingZeros_32(Value);\n}\n\n/// Log2_64 - This function returns the floor log base 2 of the specified value,\n/// -1 if the value is zero. (64 bit edition.)\ninline unsigned Log2_64(uint64_t Value) {\n  return 63 - CountLeadingZeros_64(Value);\n}\n\n/// Log2_32_Ceil - This function returns the ceil log base 2 of the specified\n/// value, 32 if the value is zero. (32 bit edition).\n/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3\ninline unsigned Log2_32_Ceil(uint32_t Value) {\n  return 32-CountLeadingZeros_32(Value-1);\n}\n\n/// Log2_64_Ceil - This function returns the ceil log base 2 of the specified\n/// value, 64 if the value is zero. (64 bit edition.)\ninline unsigned Log2_64_Ceil(uint64_t Value) {\n  return 64-CountLeadingZeros_64(Value-1);\n}\n\n/// GreatestCommonDivisor64 - Return the greatest common divisor of the two\n/// values using Euclid's algorithm.\ninline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {\n  while (B) {\n    uint64_t T = B;\n    B = A % B;\n    A = T;\n  }\n  return A;\n}\n\n/// BitsToDouble - This function takes a 64-bit integer and returns the bit\n/// equivalent double.\ninline double BitsToDouble(uint64_t Bits) {\n  union {\n    uint64_t L;\n    double D;\n  } T;\n  T.L = Bits;\n  return T.D;\n}\n\n/// BitsToFloat - This function takes a 32-bit integer and returns the bit\n/// equivalent float.\ninline float BitsToFloat(uint32_t Bits) {\n  union {\n    uint32_t I;\n    float F;\n  } T;\n  T.I = Bits;\n  return T.F;\n}\n\n/// DoubleToBits - This function takes a double and returns the bit\n/// equivalent 64-bit integer.  Note that copying doubles around\n/// changes the bits of NaNs on some hosts, notably x86, so this\n/// routine cannot be used if these bits are needed.\ninline uint64_t DoubleToBits(double Double) {\n  union {\n    uint64_t L;\n    double D;\n  } T;\n  T.D = Double;\n  return T.L;\n}\n\n/// FloatToBits - This function takes a float and returns the bit\n/// equivalent 32-bit integer.  Note that copying floats around\n/// changes the bits of NaNs on some hosts, notably x86, so this\n/// routine cannot be used if these bits are needed.\ninline uint32_t FloatToBits(float Float) {\n  union {\n    uint32_t I;\n    float F;\n  } T;\n  T.F = Float;\n  return T.I;\n}\n\n/// Platform-independent wrappers for the C99 isnan() function.\nint IsNAN(float f);\nint IsNAN(double d);\n\n/// Platform-independent wrappers for the C99 isinf() function.\nint IsInf(float f);\nint IsInf(double d);\n\n/// MinAlign - A and B are either alignments or offsets.  Return the minimum\n/// alignment that may be assumed after adding the two together.\ninline uint64_t MinAlign(uint64_t A, uint64_t B) {\n  // The largest power of 2 that divides both A and B.\n  return (A | B) & -(A | B);\n}\n\n/// NextPowerOf2 - Returns the next power of two (in 64-bits)\n/// that is strictly greater than A.  Returns zero on overflow.\ninline uint64_t NextPowerOf2(uint64_t A) {\n  A |= (A >> 1);\n  A |= (A >> 2);\n  A |= (A >> 4);\n  A |= (A >> 8);\n  A |= (A >> 16);\n  A |= (A >> 32);\n  return A + 1;\n}\n\n/// NextPowerOf2 - Returns the next power of two (in 32-bits)\n/// that is strictly greater than A.  Returns zero on overflow.\ninline uint32_t NextPowerOf2(uint32_t A) {\n  A |= (A >> 1);\n  A |= (A >> 2);\n  A |= (A >> 4);\n  A |= (A >> 8);\n  A |= (A >> 16);\n  return A + 1;\n}\n\n/// Returns the next integer (mod 2**64) that is greater than or equal to\n/// \\p Value and is a multiple of \\p Align. \\p Align must be non-zero.\n///\n/// Examples:\n/// \\code\n///   RoundUpToAlignment(5, 8) = 8\n///   RoundUpToAlignment(17, 8) = 24\n///   RoundUpToAlignment(~0LL, 8) = 0\n/// \\endcode\ninline uint64_t RoundUpToAlignment(uint64_t Value, uint64_t Align) {\n  return ((Value + Align - 1) / Align) * Align;\n}\n\n/// Returns the offset to the next integer (mod 2**64) that is greater than\n/// or equal to \\p Value and is a multiple of \\p Align. \\p Align must be\n/// non-zero.\ninline uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align) {\n  return RoundUpToAlignment(Value, Align) - Value;\n}\n\n/// abs64 - absolute value of a 64-bit int.  Not all environments support\n/// \"abs\" on whatever their name for the 64-bit int type is.  The absolute\n/// value of the largest negative number is undefined, as with \"abs\".\ninline int64_t abs64(int64_t x) {\n  return (x < 0) ? -x : x;\n}\n\n/// SignExtend32 - Sign extend B-bit number x to 32-bit int.\n/// Usage int32_t r = SignExtend32<5>(x);\ntemplate <unsigned B> inline int32_t SignExtend32(uint32_t x) {\n  return int32_t(x << (32 - B)) >> (32 - B);\n}\n\n/// \\brief Sign extend number in the bottom B bits of X to a 32-bit int.\n/// Requires 0 < B <= 32.\ninline int32_t SignExtend32(uint32_t X, unsigned B) {\n  return int32_t(X << (32 - B)) >> (32 - B);\n}\n\n/// SignExtend64 - Sign extend B-bit number x to 64-bit int.\n/// Usage int64_t r = SignExtend64<5>(x);\ntemplate <unsigned B> inline int64_t SignExtend64(uint64_t x) {\n  return int64_t(x << (64 - B)) >> (64 - B);\n}\n\n/// \\brief Sign extend number in the bottom B bits of X to a 64-bit int.\n/// Requires 0 < B <= 64.\ninline int64_t SignExtend64(uint64_t X, unsigned B) {\n  return int64_t(X << (64 - B)) >> (64 - B);\n}\n\n} // End llvm namespace\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/llvm-type_traits.h",
    "content": "//===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===//\n//\n//                     The LLVM Compiler Infrastructure\n//\n// This file is distributed under the University of Illinois Open Source\n// License. See LICENSE.TXT for details.\n//\n//===----------------------------------------------------------------------===//\n//\n// This file provides a template class that determines if a type is a class or\n// not. The basic mechanism, based on using the pointer to member function of\n// a zero argument to a function was \"boosted\" from the boost type_traits\n// library. See http://www.boost.org/ for all the gory details.\n//\n//===----------------------------------------------------------------------===//\n\n// Taken from llvmCore-3425.0.31.\n\n#ifndef LLVM_SUPPORT_TYPE_TRAITS_H\n#define LLVM_SUPPORT_TYPE_TRAITS_H\n\n#include <cstddef>\n#include <utility>\n\n#ifndef __has_feature\n#define LLVM_DEFINED_HAS_FEATURE\n#define __has_feature(x) 0\n#endif\n\n// This is actually the conforming implementation which works with abstract\n// classes.  However, enough compilers have trouble with it that most will use\n// the one in boost/type_traits/object_traits.hpp. This implementation actually\n// works with VC7.0, but other interactions seem to fail when we use it.\n\nnamespace objc {\n  \nnamespace dont_use\n{\n    // These two functions should never be used. They are helpers to\n    // the is_class template below. They cannot be located inside\n    // is_class because doing so causes at least GCC to think that\n    // the value of the \"value\" enumerator is not constant. Placing\n    // them out here (for some strange reason) allows the sizeof\n    // operator against them to magically be constant. This is\n    // important to make the is_class<T>::value idiom zero cost. it\n    // evaluates to a constant 1 or 0 depending on whether the\n    // parameter T is a class or not (respectively).\n    template<typename T> char is_class_helper(void(T::*)());\n    template<typename T> double is_class_helper(...);\n}\n\ntemplate <typename T>\nstruct is_class\n{\n  // is_class<> metafunction due to Paul Mensonides (leavings@attbi.com). For\n  // more details:\n  // http://groups.google.com/groups?hl=en&selm=000001c1cc83%24e154d5e0%247772e50c%40c161550a&rnum=1\npublic:\n  static const bool value =\n      sizeof(char) == sizeof(dont_use::is_class_helper<T>(0));\n};\n  \n  \n/// isPodLike - This is a type trait that is used to determine whether a given\n/// type can be copied around with memcpy instead of running ctors etc.\ntemplate <typename T>\nstruct isPodLike {\n#if __has_feature(is_trivially_copyable)\n  // If the compiler supports the is_trivially_copyable trait use it, as it\n  // matches the definition of isPodLike closely.\n  static const bool value = __is_trivially_copyable(T);\n#else\n  // If we don't know anything else, we can (at least) assume that all non-class\n  // types are PODs.\n  static const bool value = !is_class<T>::value;\n#endif\n};\n\n// std::pair's are pod-like if their elements are.\ntemplate<typename T, typename U>\nstruct isPodLike<std::pair<T, U> > {\n  static const bool value = isPodLike<T>::value && isPodLike<U>::value;\n};\n  \n\ntemplate <class T, T v>\nstruct integral_constant {\n  typedef T value_type;\n  static const value_type value = v;\n  typedef integral_constant<T,v> type;\n  operator value_type() { return value; }\n};\n\ntypedef integral_constant<bool, true> true_type;\ntypedef integral_constant<bool, false> false_type;\n\n/// \\brief Metafunction that determines whether the two given types are \n/// equivalent.\ntemplate<typename T, typename U> struct is_same       : public false_type {};\ntemplate<typename T>             struct is_same<T, T> : public true_type {};\n\n/// \\brief Metafunction that removes const qualification from a type.\ntemplate <typename T> struct remove_const          { typedef T type; };\ntemplate <typename T> struct remove_const<const T> { typedef T type; };\n\n/// \\brief Metafunction that removes volatile qualification from a type.\ntemplate <typename T> struct remove_volatile             { typedef T type; };\ntemplate <typename T> struct remove_volatile<volatile T> { typedef T type; };\n\n/// \\brief Metafunction that removes both const and volatile qualification from\n/// a type.\ntemplate <typename T> struct remove_cv {\n  typedef typename remove_const<typename remove_volatile<T>::type>::type type;\n};\n\n/// \\brief Helper to implement is_integral metafunction.\ntemplate <typename T> struct is_integral_impl           : false_type {};\ntemplate <> struct is_integral_impl<         bool>      : true_type {};\ntemplate <> struct is_integral_impl<         char>      : true_type {};\ntemplate <> struct is_integral_impl<  signed char>      : true_type {};\ntemplate <> struct is_integral_impl<unsigned char>      : true_type {};\ntemplate <> struct is_integral_impl<         wchar_t>   : true_type {};\ntemplate <> struct is_integral_impl<         short>     : true_type {};\ntemplate <> struct is_integral_impl<unsigned short>     : true_type {};\ntemplate <> struct is_integral_impl<         int>       : true_type {};\ntemplate <> struct is_integral_impl<unsigned int>       : true_type {};\ntemplate <> struct is_integral_impl<         long>      : true_type {};\ntemplate <> struct is_integral_impl<unsigned long>      : true_type {};\ntemplate <> struct is_integral_impl<         long long> : true_type {};\ntemplate <> struct is_integral_impl<unsigned long long> : true_type {};\n\n/// \\brief Metafunction that determines whether the given type is an integral\n/// type.\ntemplate <typename T>\nstruct is_integral : is_integral_impl<T> {};\n\n/// \\brief Metafunction to remove reference from a type.\ntemplate <typename T> struct remove_reference { typedef T type; };\ntemplate <typename T> struct remove_reference<T&> { typedef T type; };\n\n/// \\brief Metafunction that determines whether the given type is a pointer\n/// type.\ntemplate <typename T> struct is_pointer : false_type {};\ntemplate <typename T> struct is_pointer<T*> : true_type {};\ntemplate <typename T> struct is_pointer<T* const> : true_type {};\ntemplate <typename T> struct is_pointer<T* volatile> : true_type {};\ntemplate <typename T> struct is_pointer<T* const volatile> : true_type {};\n\n/// \\brief Metafunction that determines whether the given type is either an\n/// integral type or an enumeration type.\n///\n/// Note that this accepts potentially more integral types than we whitelist\n/// above for is_integral because it is based on merely being convertible\n/// implicitly to an integral type.\ntemplate <typename T> class is_integral_or_enum {\n  // Provide an overload which can be called with anything implicitly\n  // convertible to an unsigned long long. This should catch integer types and\n  // enumeration types at least. We blacklist classes with conversion operators\n  // below.\n  static double check_int_convertible(unsigned long long);\n  static char check_int_convertible(...);\n\n  typedef typename remove_reference<T>::type UnderlyingT;\n  static UnderlyingT &nonce_instance;\n\npublic:\n  static const bool\n    value = (!is_class<UnderlyingT>::value && !is_pointer<UnderlyingT>::value &&\n             !is_same<UnderlyingT, float>::value &&\n             !is_same<UnderlyingT, double>::value &&\n             sizeof(char) != sizeof(check_int_convertible(nonce_instance)));\n};\n\n// enable_if_c - Enable/disable a template based on a metafunction\ntemplate<bool Cond, typename T = void>\nstruct enable_if_c {\n  typedef T type;\n};\n\ntemplate<typename T> struct enable_if_c<false, T> { };\n  \n// enable_if - Enable/disable a template based on a metafunction\ntemplate<typename Cond, typename T = void>\nstruct enable_if : public enable_if_c<Cond::value, T> { };\n\nnamespace dont_use {\n  template<typename Base> char base_of_helper(const volatile Base*);\n  template<typename Base> double base_of_helper(...);\n}\n\n/// is_base_of - Metafunction to determine whether one type is a base class of\n/// (or identical to) another type.\ntemplate<typename Base, typename Derived>\nstruct is_base_of {\n  static const bool value \n    = is_class<Base>::value && is_class<Derived>::value &&\n      sizeof(char) == sizeof(dont_use::base_of_helper<Base>((Derived*)0));\n};\n\n// remove_pointer - Metafunction to turn Foo* into Foo.  Defined in\n// C++0x [meta.trans.ptr].\ntemplate <typename T> struct remove_pointer { typedef T type; };\ntemplate <typename T> struct remove_pointer<T*> { typedef T type; };\ntemplate <typename T> struct remove_pointer<T*const> { typedef T type; };\ntemplate <typename T> struct remove_pointer<T*volatile> { typedef T type; };\ntemplate <typename T> struct remove_pointer<T*const volatile> {\n    typedef T type; };\n\ntemplate <bool, typename T, typename F>\nstruct conditional { typedef T type; };\n\ntemplate <typename T, typename F>\nstruct conditional<false, T, F> { typedef F type; };\n\n}\n\n#ifdef LLVM_DEFINED_HAS_FEATURE\n#undef __has_feature\n#endif\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/maptable.h",
    "content": "/*\n * Copyright (c) 1999-2003, 2006-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\tmaptable.h\n\tScalable hash table of mappings.\n\tBertrand, August 1990\n\tCopyright 1990-1996 NeXT Software, Inc.\n*/\n\n#ifndef _OBJC_MAPTABLE_H_\n#define _OBJC_MAPTABLE_H_\n\n#ifndef _OBJC_PRIVATE_H_\n#   define OBJC_MAP_AVAILABILITY                             \\\n    __OSX_DEPRECATED(10.0, 10.1, \"NXMapTable is deprecated\") \\\n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE                     \\\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE\n#else\n#   define OBJC_MAP_AVAILABILITY\n#endif\n\n#include <objc/objc.h>\n\n__BEGIN_DECLS\n\n/***************\tDefinitions\t\t***************/\n\n    /* This module allows hashing of arbitrary associations [key -> value].  Keys and values must be pointers or integers, and client is responsible for allocating/deallocating this data.  A deallocation call-back is provided.\n    NX_MAPNOTAKEY (-1) is used internally as a marker, and therefore keys must always be different from -1.\n    As well-behaved scalable data structures, hash tables double in size when they start becoming full, thus guaranteeing both average constant time access and linear size. */\n\ntypedef struct _NXMapTable {\n    /* private data structure; may change */\n    const struct _NXMapTablePrototype\t* _Nonnull prototype;\n    unsigned\tcount;\n    unsigned\tnbBucketsMinusOne;\n    void\t* _Nullable buckets;\n} NXMapTable OBJC_MAP_AVAILABILITY;\n\ntypedef struct _NXMapTablePrototype {\n    unsigned\t(* _Nonnull hash)(NXMapTable * _Nonnull,\n                                  const void * _Nullable key);\n    int\t\t(* _Nonnull isEqual)(NXMapTable * _Nonnull,\n                                     const void * _Nullable key1,\n                                     const void * _Nullable key2);\n    void\t(* _Nonnull free)(NXMapTable * _Nonnull,\n                                  void * _Nullable key,\n                                  void * _Nullable value);\n    int\t\tstyle; /* reserved for future expansion; currently 0 */\n} NXMapTablePrototype OBJC_MAP_AVAILABILITY;\n    \n    /* invariants assumed by the implementation: \n\tA - key != -1\n\tB - key1 == key2 => hash(key1) == hash(key2)\n\t    when key varies over time, hash(key) must remain invariant\n\t    e.g. if string key, the string must not be changed\n\tC - isEqual(key1, key2) => key1 == key2\n    */\n\n#define NX_MAPNOTAKEY\t((void * _Nonnull)(-1))\n\n/***************\tFunctions\t\t***************/\n\nOBJC_EXPORT NXMapTable * _Nonnull\nNXCreateMapTableFromZone(NXMapTablePrototype prototype,\n                         unsigned capacity, void * _Nullable z)\n    OBJC_MAP_AVAILABILITY;\n\nOBJC_EXPORT NXMapTable * _Nonnull\nNXCreateMapTable(NXMapTablePrototype prototype, unsigned capacity)\n    OBJC_MAP_AVAILABILITY;\n    /* capacity is only a hint; 0 creates a small table */\n\nOBJC_EXPORT void\nNXFreeMapTable(NXMapTable * _Nonnull table)\n    OBJC_MAP_AVAILABILITY;\n    /* call free for each pair, and recovers table */\n\t\nOBJC_EXPORT void\nNXResetMapTable(NXMapTable * _Nonnull table)\n    OBJC_MAP_AVAILABILITY;\n    /* free each pair; keep current capacity */\n\nOBJC_EXPORT BOOL\nNXCompareMapTables(NXMapTable * _Nonnull table1, NXMapTable * _Nonnull table2)\n    OBJC_MAP_AVAILABILITY;\n    /* Returns YES if the two sets are equal (each member of table1 in table2, and table have same size) */\n\nOBJC_EXPORT unsigned\nNXCountMapTable(NXMapTable * _Nonnull table)\n    OBJC_MAP_AVAILABILITY;\n    /* current number of data in table */\n\t\nOBJC_EXPORT void * _Nullable\nNXMapMember(NXMapTable * _Nonnull table, const void * _Nullable key,\n            void * _Nullable * _Nonnull value) OBJC_MAP_AVAILABILITY;\n    /* return original table key or NX_MAPNOTAKEY.  If key is found, value is set */\n\t\nOBJC_EXPORT void * _Nullable\nNXMapGet(NXMapTable * _Nonnull table, const void * _Nullable key)\n    OBJC_MAP_AVAILABILITY;\n    /* return original corresponding value or NULL.  When NULL need be stored as value, NXMapMember can be used to test for presence */\n\t\nOBJC_EXPORT void * _Nullable\nNXMapInsert(NXMapTable * _Nonnull table, const void * _Nullable key,\n            const void * _Nullable value)\n    OBJC_MAP_AVAILABILITY;\n    /* override preexisting pair; Return previous value or NULL. */\n\t\nOBJC_EXPORT void * _Nullable\nNXMapRemove(NXMapTable * _Nonnull table, const void * _Nullable key)\n    OBJC_MAP_AVAILABILITY;\n    /* previous value or NULL is returned */\n\t\n/* Iteration over all elements of a table consists in setting up an iteration state and then to progress until all entries have been visited.  An example of use for counting elements in a table is:\n    unsigned\tcount = 0;\n    const MyKey\t*key;\n    const MyValue\t*value;\n    NXMapState\tstate = NXInitMapState(table);\n    while(NXNextMapState(table, &state, &key, &value)) {\n\tcount++;\n    }\n*/\n\ntypedef struct {int index;} NXMapState OBJC_MAP_AVAILABILITY;\n    /* callers should not rely on actual contents of the struct */\n\nOBJC_EXPORT NXMapState\nNXInitMapState(NXMapTable * _Nonnull table)\n    OBJC_MAP_AVAILABILITY;\n\nOBJC_EXPORT int\nNXNextMapState(NXMapTable * _Nonnull table, NXMapState * _Nonnull state,\n               const void * _Nullable * _Nonnull key,\n               const void * _Nullable * _Nonnull value)\n    OBJC_MAP_AVAILABILITY;\n    /* returns 0 when all elements have been visited */\n\n/***************\tConveniences\t\t***************/\n\nOBJC_EXPORT const NXMapTablePrototype NXPtrValueMapPrototype\n    OBJC_MAP_AVAILABILITY;\n    /* hashing is pointer/integer hashing;\n      isEqual is identity;\n      free is no-op. */\nOBJC_EXPORT const NXMapTablePrototype NXStrValueMapPrototype\n    OBJC_MAP_AVAILABILITY;\n    /* hashing is string hashing;\n      isEqual is strcmp;\n      free is no-op. */\nOBJC_EXPORT const NXMapTablePrototype NXObjectMapPrototype\n    OBJC2_UNAVAILABLE;\n    /* for objects; uses methods: hash, isEqual:, free, all for key. */\n\n__END_DECLS\n\n#endif /* _OBJC_MAPTABLE_H_ */\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/maptable.mm",
    "content": "/*\n * Copyright (c) 1999-2003, 2005-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\tmaptable.m\n  \tCopyright 1990-1996 NeXT Software, Inc.\n\tCreated by Bertrand Serlet, August 1990\n */\n\n\n#include <string.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#include \"objc-private.h\"\n#include \"maptable.h\"\n#include \"hashtable2.h\"\n\n\n/******\t\tMacros and utilities\t****************************/\n\n#if defined(DEBUG)\n    #define INLINE\t\n#else\n    #define INLINE inline\n#endif\n\ntypedef struct _MapPair {\n    const void\t*key;\n    const void\t*value;\n} MapPair;\n\nstatic INLINE unsigned xorHash(unsigned hash) { \n    unsigned xored = (hash & 0xffff) ^ (hash >> 16);\n    return ((xored * 65521) + hash);\n}\n\nstatic INLINE unsigned bucketOf(NXMapTable *table, const void *key) {\n    unsigned\thash = (table->prototype->hash)(table, key);\n    return hash & table->nbBucketsMinusOne;\n}\n\nstatic INLINE int isEqual(NXMapTable *table, const void *key1, const void *key2) {\n    return (key1 == key2) ? 1 : (table->prototype->isEqual)(table, key1, key2);\n}\n\nstatic INLINE unsigned nextIndex(NXMapTable *table, unsigned index) {\n    return (index + 1) & table->nbBucketsMinusOne;\n}\n\nstatic INLINE void *allocBuckets(void *z, unsigned nb) {\n    MapPair\t*pairs = 1+(MapPair *)malloc_zone_malloc((malloc_zone_t *)z, ((nb+1) * sizeof(MapPair)));\n    MapPair\t*pair = pairs;\n    while (nb--) { pair->key = NX_MAPNOTAKEY; pair->value = NULL; pair++; }\n    return pairs;\n}\n\nstatic INLINE void freeBuckets(void *p) {\n    free(-1+(MapPair *)p);\n}\n\n/*****\t\tGlobal data and bootstrap\t**********************/\n\nstatic int isEqualPrototype (const void *info, const void *data1, const void *data2) {\n    NXHashTablePrototype        *proto1 = (NXHashTablePrototype *) data1;\n    NXHashTablePrototype        *proto2 = (NXHashTablePrototype *) data2;\n\n    return (proto1->hash == proto2->hash) && (proto1->isEqual == proto2->isEqual) && (proto1->free == proto2->free) && (proto1->style == proto2->style);\n    };\n\nstatic uintptr_t hashPrototype (const void *info, const void *data) {\n    NXHashTablePrototype        *proto = (NXHashTablePrototype *) data;\n\n    return NXPtrHash(info, (void*)proto->hash) ^ NXPtrHash(info, (void*)proto->isEqual) ^ NXPtrHash(info, (void*)proto->free) ^ (uintptr_t) proto->style;\n    };\n\nstatic NXHashTablePrototype protoPrototype = {\n    hashPrototype, isEqualPrototype, NXNoEffectFree, 0\n};\n\nstatic NXHashTable *prototypes = NULL;\n\t/* table of all prototypes */\n\n/****\t\tFundamentals Operations\t\t\t**************/\n\nNXMapTable *NXCreateMapTableFromZone(NXMapTablePrototype prototype, unsigned capacity, void *z) {\n    NXMapTable\t\t\t*table = (NXMapTable *)malloc_zone_malloc((malloc_zone_t *)z, sizeof(NXMapTable));\n    NXMapTablePrototype\t\t*proto;\n    if (! prototypes) prototypes = NXCreateHashTable(protoPrototype, 0, NULL);\n    if (! prototype.hash || ! prototype.isEqual || ! prototype.free || prototype.style) {\n\t_objc_inform(\"*** NXCreateMapTable: invalid creation parameters\\n\");\n\treturn NULL;\n    }\n    proto = (NXMapTablePrototype *)NXHashGet(prototypes, &prototype); \n    if (! proto) {\n\tproto = (NXMapTablePrototype *)malloc(sizeof(NXMapTablePrototype));\n\t*proto = prototype;\n    \t(void)NXHashInsert(prototypes, proto);\n    }\n    table->prototype = proto; table->count = 0;\n    table->nbBucketsMinusOne = exp2u(log2u(capacity)+1) - 1;\n    table->buckets = allocBuckets(z, table->nbBucketsMinusOne + 1);\n    return table;\n}\n\nNXMapTable *NXCreateMapTable(NXMapTablePrototype prototype, unsigned capacity) {\n    return NXCreateMapTableFromZone(prototype, capacity, malloc_default_zone());\n}\n\nvoid NXFreeMapTable(NXMapTable *table) {\n    NXResetMapTable(table);\n    freeBuckets(table->buckets);\n    free(table);\n}\n\nvoid NXResetMapTable(NXMapTable *table) {\n    MapPair\t*pairs = (MapPair *)table->buckets;\n    void\t(*freeProc)(struct _NXMapTable *, void *, void *) = table->prototype->free;\n    unsigned\tindex = table->nbBucketsMinusOne + 1;\n    while (index--) {\n\tif (pairs->key != NX_MAPNOTAKEY) {\n\t    freeProc(table, (void *)pairs->key, (void *)pairs->value);\n\t    pairs->key = NX_MAPNOTAKEY; pairs->value = NULL;\n\t}\n\tpairs++;\n    }\n    table->count = 0;\n}\n\nBOOL NXCompareMapTables(NXMapTable *table1, NXMapTable *table2) {\n    if (table1 == table2) return YES;\n    if (table1->count != table2->count) return NO;\n    else {\n\tconst void *key;\n\tconst void *value;\n\tNXMapState\tstate = NXInitMapState(table1);\n\twhile (NXNextMapState(table1, &state, &key, &value)) {\n\t    if (NXMapMember(table2, key, (void**)&value) == NX_MAPNOTAKEY) return NO;\n\t}\n\treturn YES;\n    }\n}\n\nunsigned NXCountMapTable(NXMapTable *table) { return table->count; }\n\n#if __x86_64__\nextern \"C\" void __NXMAPTABLE_CORRUPTED__\n(const void *table, const void *buckets, uint64_t count,\n uint64_t nbBucketsMinusOne, uint64_t badkeys, uint64_t index,\n uint64_t index2, uint64_t pairIndexes, const void *key1,\n const void *value1, const void *key2, const void *value2,\n const void *key3, const void *value3);\n\nstatic int _mapStrIsEqual(NXMapTable *table, const void *key1, const void *key2);\n\nasm(\"\\n .text\"\n    \"\\n .private_extern ___NXMAPTABLE_CORRUPTED__\"\n    \"\\n ___NXMAPTABLE_CORRUPTED__:\"\n    // push a frame for the unwinder to see\n    \"\\n pushq %rbp\"\n    \"\\n mov %rsp, %rbp\"\n    // push register parameters to the stack in reverse order\n    \"\\n pushq %r9\"\n    \"\\n pushq %r8\"\n    \"\\n pushq %rcx\"\n    \"\\n pushq %rdx\"\n    \"\\n pushq %rsi\"\n    \"\\n pushq %rdi\"\n    // pop the pushed register parameters into their destinations\n    \"\\n popq %rax\"  // table\n    \"\\n popq %rbx\"  // buckets\n    \"\\n popq %rcx\"  // count\n    \"\\n popq %rdx\"  // nbBucketsMinusOne\n    \"\\n popq %rdi\"  // badkeys\n    \"\\n popq %rsi\"  // index\n    // read stack parameters into their destinations\n    \"\\n mov 0*8+16(%rbp), %r8\"   // index2\n    \"\\n mov 1*8+16(%rbp), %r9\"   // pairIndexes\n    \"\\n mov 2*8+16(%rbp), %r10\"  // key1\n    \"\\n mov 3*8+16(%rbp), %r11\"  // value1\n    \"\\n mov 4*8+16(%rbp), %r12\"  // key2\n    \"\\n mov 5*8+16(%rbp), %r13\"  // value2\n    \"\\n mov 6*8+16(%rbp), %r14\"  // key3\n    \"\\n mov 7*8+16(%rbp), %r15\"  // value3\n    \"\\n ud2\");\n#endif\n\n// Look for a particular case of data corruption (rdar://36373000)\n// and investigate it further before crashing.\nstatic void validateKey(NXMapTable *table, MapPair *pair,\n                        unsigned index, unsigned index2)\n{\n#if __x86_64__\n#   define BADKEY ((void * _Nonnull)(0xfffffffffffffffeULL))\n    if (pair->key != BADKEY  ||\n        table->prototype->isEqual != _mapStrIsEqual)\n    {\n        return;\n    }\n\n    _objc_inform_now_and_on_crash\n        (\"NXMapTable %p (%p) has invalid key/value pair %p->%p (%p)\",\n         table, table->buckets, pair->key, pair->value, pair);\n    _objc_inform_now_and_on_crash\n        (\"table %p, buckets %p, count %u, nbNucketsMinusOne %u, \"\n         \"prototype %p (hash %p, isEqual %p, free %p)\",\n         table, table->buckets, table->count, table->nbBucketsMinusOne,\n         table->prototype, table->prototype->hash, table->prototype->isEqual,\n         table->prototype->free);\n\n    // Count the number of bad keys in the table.\n    MapPair *pairs = (MapPair *)table->buckets;\n    unsigned badKeys = 0;\n    for (unsigned i = 0; i < table->nbBucketsMinusOne+1; i++) {\n        if (pairs[i].key == BADKEY) badKeys++;\n    }\n\n    _objc_inform_now_and_on_crash(\"%u invalid keys in table\", badKeys);\n\n    // Record some additional key pairs for posterity.\n    unsigned pair2Index = nextIndex(table, index);\n    unsigned pair3Index = nextIndex(table, pair2Index);\n    MapPair *pair2 = pairs + pair2Index;\n    MapPair *pair3 = pairs + pair3Index;\n    uint64_t pairIndexes = ((uint64_t)pair2Index << 32) | pair3Index;\n\n    // Save a bunch of values to registers so we can see them in the crash log.\n    __NXMAPTABLE_CORRUPTED__\n        (// rax, rbx, rcx, rdx\n         table, table->buckets, table->count, table->nbBucketsMinusOne,\n         // rdi, rsi, skip rbp, skip rsp\n         badKeys, index,\n         // r8, r9, r10, r11\n         index2, pairIndexes, pair->key, pair->value,\n         // r12, r13, r14, r15\n         pair2->key, pair2->value, pair3->key, pair3->value);\n#endif\n}\n\nstatic INLINE void *_NXMapMember(NXMapTable *table, const void *key, void **value) {\n    MapPair\t*pairs = (MapPair *)table->buckets;\n    unsigned\tindex = bucketOf(table, key);\n    MapPair\t*pair = pairs + index;\n    if (pair->key == NX_MAPNOTAKEY) return NX_MAPNOTAKEY;\n    validateKey(table, pair, index, index);\n\n    if (isEqual(table, pair->key, key)) {\n\t*value = (void *)pair->value;\n\treturn (void *)pair->key;\n    } else {\n\tunsigned\tindex2 = index;\n\twhile ((index2 = nextIndex(table, index2)) != index) {\n\t    pair = pairs + index2;\n\t    if (pair->key == NX_MAPNOTAKEY) return NX_MAPNOTAKEY;\n\t    validateKey(table, pair, index, index2);\n\t    if (isEqual(table, pair->key, key)) {\n\t    \t*value = (void *)pair->value;\n\t\treturn (void *)pair->key;\n\t    }\n\t}\n\treturn NX_MAPNOTAKEY;\n    }\n}\n\nvoid *NXMapMember(NXMapTable *table, const void *key, void **value) {\n    return _NXMapMember(table, key, value);\n}\n\nvoid *NXMapGet(NXMapTable *table, const void *key) {\n    void\t*value;\n    return (_NXMapMember(table, key, &value) != NX_MAPNOTAKEY) ? value : NULL;\n}\n\nstatic void _NXMapRehash(NXMapTable *table) {\n    MapPair\t*pairs = (MapPair *)table->buckets;\n    MapPair\t*pair = pairs;\n    unsigned\tnumBuckets = table->nbBucketsMinusOne + 1;\n    unsigned\tindex = numBuckets;\n    unsigned\toldCount = table->count;\n    \n    table->nbBucketsMinusOne = 2 * numBuckets - 1;\n    table->count = 0; \n    table->buckets = allocBuckets(malloc_zone_from_ptr(table), table->nbBucketsMinusOne + 1);\n    while (index--) {\n\tif (pair->key != NX_MAPNOTAKEY) {\n\t    (void)NXMapInsert(table, pair->key, pair->value);\n\t}\n\tpair++;\n    }\n    if (oldCount != table->count)\n\t_objc_inform(\"*** maptable: count differs after rehashing; probably indicates a broken invariant: there are x and y such as isEqual(x, y) is TRUE but hash(x) != hash (y)\\n\");\n    freeBuckets(pairs);\n}\n\nvoid *NXMapInsert(NXMapTable *table, const void *key, const void *value) {\n    MapPair\t*pairs = (MapPair *)table->buckets;\n    unsigned\tindex = bucketOf(table, key);\n    MapPair\t*pair = pairs + index;\n    if (key == NX_MAPNOTAKEY) {\n\t_objc_inform(\"*** NXMapInsert: invalid key: -1\\n\");\n\treturn NULL;\n    }\n\n    unsigned numBuckets = table->nbBucketsMinusOne + 1;\n\n    if (pair->key == NX_MAPNOTAKEY) {\n\tpair->key = key; pair->value = value;\n\ttable->count++;\n\tif (table->count * 4 > numBuckets * 3) _NXMapRehash(table);\n\treturn NULL;\n    }\n    \n    if (isEqual(table, pair->key, key)) {\n\tconst void\t*old = pair->value;\n\tif (old != value) pair->value = value;/* avoid writing unless needed! */\n\treturn (void *)old;\n    } else if (table->count == numBuckets) {\n\t/* no room: rehash and retry */\n\t_NXMapRehash(table);\n\treturn NXMapInsert(table, key, value);\n    } else {\n\tunsigned\tindex2 = index;\n\twhile ((index2 = nextIndex(table, index2)) != index) {\n\t    pair = pairs + index2;\n\t    if (pair->key == NX_MAPNOTAKEY) {\n\t\tpair->key = key; pair->value = value;\n\t\ttable->count++;\n\t\tif (table->count * 4 > numBuckets * 3) _NXMapRehash(table);\n\t\treturn NULL;\n\t    }\n\t    if (isEqual(table, pair->key, key)) {\n\t\tconst void\t*old = pair->value;\n\t\tif (old != value) pair->value = value;/* avoid writing unless needed! */\n\t\treturn (void *)old;\n\t    }\n\t}\n\t/* no room: can't happen! */\n\t_objc_inform(\"**** NXMapInsert: bug\\n\");\n\treturn NULL;\n    }\n}\n\nstatic int mapRemove = 0;\n\nvoid *NXMapRemove(NXMapTable *table, const void *key) {\n    MapPair\t*pairs = (MapPair *)table->buckets;\n    unsigned\tindex = bucketOf(table, key);\n    MapPair\t*pair = pairs + index;\n    unsigned\tchain = 1; /* number of non-nil pairs in a row */\n    int\t\tfound = 0;\n    const void\t*old = NULL;\n    if (pair->key == NX_MAPNOTAKEY) return NULL;\n    mapRemove ++;\n    /* compute chain */\n    {\n\tunsigned\tindex2 = index;\n\tif (isEqual(table, pair->key, key)) {found ++; old = pair->value; }\n\twhile ((index2 = nextIndex(table, index2)) != index) {\n\t    pair = pairs + index2;\n\t    if (pair->key == NX_MAPNOTAKEY) break;\n\t    if (isEqual(table, pair->key, key)) {found ++; old = pair->value; }\n\t    chain++;\n\t}\n    }\n    if (! found) return NULL;\n    if (found != 1) _objc_inform(\"**** NXMapRemove: incorrect table\\n\");\n    /* remove then reinsert */\n    {\n\tMapPair\tbuffer[16];\n\tMapPair\t*aux = (chain > 16) ? (MapPair *)malloc(sizeof(MapPair)*(chain-1)) : buffer;\n\tunsigned\tauxnb = 0;\n\tint\tnb = chain;\n\tunsigned\tindex2 = index;\n\twhile (nb--) {\n\t    pair = pairs + index2;\n\t    if (! isEqual(table, pair->key, key)) aux[auxnb++] = *pair;\n\t    pair->key = NX_MAPNOTAKEY; pair->value = NULL;\n\t    index2 = nextIndex(table, index2);\n\t}\n\ttable->count -= chain;\n\tif (auxnb != chain-1) _objc_inform(\"**** NXMapRemove: bug\\n\");\n\twhile (auxnb--) NXMapInsert(table, aux[auxnb].key, aux[auxnb].value);\n\tif (chain > 16) free(aux);\n    }\n    return (void *)old;\n}\n\nNXMapState NXInitMapState(NXMapTable *table) {\n    NXMapState\tstate;\n    state.index = table->nbBucketsMinusOne + 1;\n    return state;\n}\n    \nint NXNextMapState(NXMapTable *table, NXMapState *state, const void **key, const void **value) {\n    MapPair\t*pairs = (MapPair *)table->buckets;\n    while (state->index--) {\n\tMapPair\t*pair = pairs + state->index;\n\tif (pair->key != NX_MAPNOTAKEY) {\n\t    *key = pair->key; *value = pair->value;\n\t    return YES;\n\t}\n    }\n    return NO;\n}\n\n\n/***********************************************************************\n* NXMapKeyCopyingInsert\n* Like NXMapInsert, but strdups the key if necessary.\n* Used to prevent stale pointers when bundles are unloaded.\n**********************************************************************/\nvoid *NXMapKeyCopyingInsert(NXMapTable *table, const void *key, const void *value)\n{\n    void *realKey; \n    void *realValue = NULL;\n\n    if ((realKey = NXMapMember(table, key, &realValue)) != NX_MAPNOTAKEY) {\n        // key DOES exist in table - use table's key for insertion\n    } else {\n        // key DOES NOT exist in table - copy the new key before insertion\n        realKey = (void *)strdupIfMutable((char *)key);\n    }\n    return NXMapInsert(table, realKey, value);\n}\n\n\n/***********************************************************************\n* NXMapKeyFreeingRemove\n* Like NXMapRemove, but frees the existing key if necessary.\n* Used to prevent stale pointers when bundles are unloaded.\n**********************************************************************/\nvoid *NXMapKeyFreeingRemove(NXMapTable *table, const void *key)\n{\n    void *realKey;\n    void *realValue = NULL;\n\n    if ((realKey = NXMapMember(table, key, &realValue)) != NX_MAPNOTAKEY) {\n        // key DOES exist in table - remove pair and free key\n        realValue = NXMapRemove(table, realKey);\n        // free the key from the table, not necessarily the one given\n        freeIfMutable((char *)realKey); \n        return realValue;\n    } else {\n        // key DOES NOT exist in table - nothing to do\n        return NULL;\n    }\n}\n\n\n/****\t\tConveniences\t\t*************************************/\n\nstatic unsigned _mapPtrHash(NXMapTable *table, const void *key) {\n#ifdef __LP64__\n    return (unsigned)(((uintptr_t)key) >> 3);\n#else\n    return ((uintptr_t)key) >> 2;\n#endif\n}\n    \nstatic unsigned _mapStrHash(NXMapTable *table, const void *key) {\n    unsigned\t\thash = 0;\n    unsigned char\t*s = (unsigned char *)key;\n    /* unsigned to avoid a sign-extend */\n    /* unroll the loop */\n    if (s) for (; ; ) { \n\tif (*s == '\\0') break;\n\thash ^= *s++;\n\tif (*s == '\\0') break;\n\thash ^= *s++ << 8;\n\tif (*s == '\\0') break;\n\thash ^= *s++ << 16;\n\tif (*s == '\\0') break;\n\thash ^= *s++ << 24;\n    }\n    return xorHash(hash);\n}\n    \nstatic int _mapPtrIsEqual(NXMapTable *table, const void *key1, const void *key2) {\n    return key1 == key2;\n}\n\nstatic int _mapStrIsEqual(NXMapTable *table, const void *key1, const void *key2) {\n    if (key1 == key2) return YES;\n    if (! key1) return ! strlen ((char *) key2);\n    if (! key2) return ! strlen ((char *) key1);\n    if (((char *) key1)[0] != ((char *) key2)[0]) return NO;\n    return (strcmp((char *) key1, (char *) key2)) ? NO : YES;\n}\n    \nstatic void _mapNoFree(NXMapTable *table, void *key, void *value) {}\n\nconst NXMapTablePrototype NXPtrValueMapPrototype = {\n    _mapPtrHash, _mapPtrIsEqual, _mapNoFree, 0\n};\n\nconst NXMapTablePrototype NXStrValueMapPrototype = {\n    _mapStrHash, _mapStrIsEqual, _mapNoFree, 0\n};\n\n\n#if !__OBJC2__  &&  !TARGET_OS_WIN32\n\n/* This only works with class Object, which is unavailable. */\n\n/* Method prototypes */\n@interface DoesNotExist\n+ (id)class;\n+ (id)initialize;\n- (id)description;\n- (const char *)UTF8String;\n- (unsigned long)hash;\n- (BOOL)isEqual:(id)object;\n- (void)free;\n@end\n\nstatic unsigned _mapObjectHash(NXMapTable *table, const void *key) {\n    return [(id)key hash];\n}\n    \nstatic int _mapObjectIsEqual(NXMapTable *table, const void *key1, const void *key2) {\n    return [(id)key1 isEqual:(id)key2];\n}\n\nstatic void _mapObjectFree(NXMapTable *table, void *key, void *value) {\n    [(id)key free];\n}\n\nconst NXMapTablePrototype NXObjectMapPrototype = {\n    _mapObjectHash, _mapObjectIsEqual, _mapObjectFree, 0\n};\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/message.h",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _OBJC_MESSAGE_H\n#define _OBJC_MESSAGE_H\n\n#include <objc/objc.h>\n#include <objc/runtime.h>\n\n#ifndef OBJC_SUPER\n#define OBJC_SUPER\n\n/// Specifies the superclass of an instance. \nstruct objc_super {\n    /// Specifies an instance of a class.\n    __unsafe_unretained _Nonnull id receiver;\n\n    /// Specifies the particular superclass of the instance to message. \n#if !defined(__cplusplus)  &&  !__OBJC2__\n    /* For compatibility with old objc-runtime.h header */\n    __unsafe_unretained _Nonnull Class class;\n#else\n    __unsafe_unretained _Nonnull Class super_class;\n#endif\n    /* super_class is the first class to search */\n};\n#endif\n\n\n/* Basic Messaging Primitives\n *\n * On some architectures, use objc_msgSend_stret for some struct return types.\n * On some architectures, use objc_msgSend_fpret for some float return types.\n * On some architectures, use objc_msgSend_fp2ret for some float return types.\n *\n * These functions must be cast to an appropriate function pointer type \n * before being called. \n */\n#if !OBJC_OLD_DISPATCH_PROTOTYPES\nOBJC_EXPORT void\nobjc_msgSend(void /* id self, SEL op, ... */ )\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ )\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n#else\n/** \n * Sends a message with a simple return value to an instance of a class.\n * \n * @param self A pointer to the instance of the class that is to receive the message.\n * @param op The selector of the method that handles the message.\n * @param ... \n *   A variable argument list containing the arguments to the method.\n * \n * @return The return value of the method.\n * \n * @note When it encounters a method call, the compiler generates a call to one of the\n *  functions \\c objc_msgSend, \\c objc_msgSend_stret, \\c objc_msgSendSuper, or \\c objc_msgSendSuper_stret.\n *  Messages sent to an object’s superclass (using the \\c super keyword) are sent using \\c objc_msgSendSuper; \n *  other messages are sent using \\c objc_msgSend. Methods that have data structures as return values\n *  are sent using \\c objc_msgSendSuper_stret and \\c objc_msgSend_stret.\n */\nOBJC_EXPORT id _Nullable\nobjc_msgSend(id _Nullable self, SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n/** \n * Sends a message with a simple return value to the superclass of an instance of a class.\n * \n * @param super A pointer to an \\c objc_super data structure. Pass values identifying the\n *  context the message was sent to, including the instance of the class that is to receive the\n *  message and the superclass at which to start searching for the method implementation.\n * @param op A pointer of type SEL. Pass the selector of the method that will handle the message.\n * @param ...\n *   A variable argument list containing the arguments to the method.\n * \n * @return The return value of the method identified by \\e op.\n * \n * @see objc_msgSend\n */\nOBJC_EXPORT id _Nullable\nobjc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n#endif\n\n\n/* Struct-returning Messaging Primitives\n *\n * Use these functions to call methods that return structs on the stack. \n * On some architectures, some structures are returned in registers. \n * Consult your local function call ABI documentation for details.\n * \n * These functions must be cast to an appropriate function pointer type \n * before being called. \n */\n#if !OBJC_OLD_DISPATCH_PROTOTYPES\nOBJC_EXPORT void\nobjc_msgSend_stret(void /* id self, SEL op, ... */ )\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n\nOBJC_EXPORT void\nobjc_msgSendSuper_stret(void /* struct objc_super *super, SEL op, ... */ )\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n#else\n/** \n * Sends a message with a data-structure return value to an instance of a class.\n * \n * @see objc_msgSend\n */\nOBJC_EXPORT void\nobjc_msgSend_stret(id _Nullable self, SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n\n/** \n * Sends a message with a data-structure return value to the superclass of an instance of a class.\n * \n * @see objc_msgSendSuper\n */\nOBJC_EXPORT void\nobjc_msgSendSuper_stret(struct objc_super * _Nonnull super,\n                        SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n#endif\n\n\n/* Floating-point-returning Messaging Primitives\n * \n * Use these functions to call methods that return floating-point values \n * on the stack. \n * Consult your local function call ABI documentation for details.\n * \n * arm:    objc_msgSend_fpret not used\n * i386:   objc_msgSend_fpret used for `float`, `double`, `long double`.\n * x86-64: objc_msgSend_fpret used for `long double`.\n *\n * arm:    objc_msgSend_fp2ret not used\n * i386:   objc_msgSend_fp2ret not used\n * x86-64: objc_msgSend_fp2ret used for `_Complex long double`.\n *\n * These functions must be cast to an appropriate function pointer type \n * before being called. \n */\n#if !OBJC_OLD_DISPATCH_PROTOTYPES\n\n# if defined(__i386__)\n\nOBJC_EXPORT void\nobjc_msgSend_fpret(void /* id self, SEL op, ... */ )\n    OBJC_AVAILABLE(10.4, 2.0, 9.0, 1.0, 2.0);\n\n# elif defined(__x86_64__)\n\nOBJC_EXPORT void\nobjc_msgSend_fpret(void /* id self, SEL op, ... */ )\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_msgSend_fp2ret(void /* id self, SEL op, ... */ )\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n# endif\n\n// !OBJC_OLD_DISPATCH_PROTOTYPES\n#else\n// OBJC_OLD_DISPATCH_PROTOTYPES\n# if defined(__i386__)\n\n/** \n * Sends a message with a floating-point return value to an instance of a class.\n * \n * @see objc_msgSend\n * @note On the i386 platform, the ABI for functions returning a floating-point value is\n *  incompatible with that for functions returning an integral type. On the i386 platform, therefore, \n *  you must use \\c objc_msgSend_fpret for functions returning non-integral type. For \\c float or \n *  \\c long \\c double return types, cast the function to an appropriate function pointer type first.\n */\nOBJC_EXPORT double\nobjc_msgSend_fpret(id _Nullable self, SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.4, 2.0, 9.0, 1.0, 2.0);\n\n/* Use objc_msgSendSuper() for fp-returning messages to super. */\n/* See also objc_msgSendv_fpret() below. */\n\n# elif defined(__x86_64__)\n/** \n * Sends a message with a floating-point return value to an instance of a class.\n * \n * @see objc_msgSend\n */\nOBJC_EXPORT long double\nobjc_msgSend_fpret(id _Nullable self, SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n#  if __STDC_VERSION__ >= 199901L\nOBJC_EXPORT _Complex long double\nobjc_msgSend_fp2ret(id _Nullable self, SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n#  else\nOBJC_EXPORT void objc_msgSend_fp2ret(id _Nullable self, SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n#  endif\n\n/* Use objc_msgSendSuper() for fp-returning messages to super. */\n/* See also objc_msgSendv_fpret() below. */\n\n# endif\n\n// OBJC_OLD_DISPATCH_PROTOTYPES\n#endif\n\n\n/* Direct Method Invocation Primitives\n * Use these functions to call the implementation of a given Method.\n * This is faster than calling method_getImplementation() and method_getName().\n *\n * The receiver must not be nil.\n *\n * These functions must be cast to an appropriate function pointer type \n * before being called. \n */\n#if !OBJC_OLD_DISPATCH_PROTOTYPES\nOBJC_EXPORT void\nmethod_invoke(void /* id receiver, Method m, ... */ ) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nmethod_invoke_stret(void /* id receiver, Method m, ... */ ) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n#else\nOBJC_EXPORT id _Nullable\nmethod_invoke(id _Nullable receiver, Method _Nonnull m, ...) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nmethod_invoke_stret(id _Nullable receiver, Method _Nonnull m, ...) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n#endif\n\n\n/* Message Forwarding Primitives\n * Use these functions to forward a message as if the receiver did not \n * respond to it. \n *\n * The receiver must not be nil.\n * \n * class_getMethodImplementation() may return (IMP)_objc_msgForward.\n * class_getMethodImplementation_stret() may return (IMP)_objc_msgForward_stret\n * \n * These functions must be cast to an appropriate function pointer type \n * before being called. \n *\n * Before Mac OS X 10.6, _objc_msgForward must not be called directly \n * but may be compared to other IMP values.\n */\n#if !OBJC_OLD_DISPATCH_PROTOTYPES\nOBJC_EXPORT void\n_objc_msgForward(void /* id receiver, SEL sel, ... */ ) \n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\n_objc_msgForward_stret(void /* id receiver, SEL sel, ... */ ) \n    OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n#else\nOBJC_EXPORT id _Nullable\n_objc_msgForward(id _Nonnull receiver, SEL _Nonnull sel, ...) \n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\n_objc_msgForward_stret(id _Nonnull receiver, SEL _Nonnull sel, ...) \n    OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n#endif\n\n\n/* Variable-argument Messaging Primitives\n *\n * Use these functions to call methods with a list of arguments, such \n * as the one passed to forward:: .\n *\n * The contents of the argument list are architecture-specific. \n * Consult your local function call ABI documentation for details.\n * \n * These functions must be cast to an appropriate function pointer type \n * before being called, except for objc_msgSendv_stret() which must not \n * be cast to a struct-returning type.\n */\n\ntypedef void* marg_list;\n\nOBJC_EXPORT id _Nullable\nobjc_msgSendv(id _Nullable self, SEL _Nonnull op, size_t arg_size,\n              marg_list _Nonnull arg_frame)\n    OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT void\nobjc_msgSendv_stret(void * _Nonnull stretAddr, id _Nullable self,\n                    SEL _Nonnull op, size_t arg_size,\n                    marg_list _Nullable arg_frame)\n    OBJC2_UNAVAILABLE;\n/* Note that objc_msgSendv_stret() does not return a structure type, \n * and should not be cast to do so. This is unlike objc_msgSend_stret() \n * and objc_msgSendSuper_stret().\n */\n#if defined(__i386__)\nOBJC_EXPORT double\nobjc_msgSendv_fpret(id _Nullable self, SEL _Nonnull op,\n                    unsigned arg_size, marg_list _Nullable arg_frame)\n    OBJC2_UNAVAILABLE;\n#endif\n\n\n/* The following marg_list macros are of marginal utility. They\n * are included for compatibility with the old objc-class.h header. */\n\n#if !__OBJC2__\n\n#define marg_prearg_size\t0\n\n#define marg_malloc(margs, method) \\\n\tdo { \\\n\t\tmargs = (marg_list *)malloc (marg_prearg_size + ((7 + method_getSizeOfArguments(method)) & ~7)); \\\n\t} while (0)\n\n#define marg_free(margs) \\\n\tdo { \\\n\t\tfree(margs); \\\n\t} while (0)\n\t\n#define marg_adjustedOffset(method, offset) \\\n\t(marg_prearg_size + offset)\n\n#define marg_getRef(margs, offset, type) \\\n\t( (type *)((char *)margs + marg_adjustedOffset(method,offset) ) )\n\n#define marg_getValue(margs, offset, type) \\\n\t( *marg_getRef(margs, offset, type) )\n\n#define marg_setValue(margs, offset, type, value) \\\n\t( marg_getValue(margs, offset, type) = (value) )\n\n#endif\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-abi.h",
    "content": "/*\n * Copyright (c) 2009 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n\n#ifndef _OBJC_ABI_H\n#define _OBJC_ABI_H\n\n/* \n * WARNING  DANGER  HAZARD  BEWARE  EEK\n * \n * Everything in this file is for Apple Internal use only.\n * These will change in arbitrary OS updates and in unpredictable ways.\n * When your program breaks, you get to keep both pieces.\n */\n\n/*\n * objc-abi.h: Declarations for functions used by compiler codegen.\n */\n\n#include <malloc/malloc.h>\n#include <TargetConditionals.h>\n#include <objc/objc.h>\n#include <objc/runtime.h>\n#include <objc/message.h>\n\n/* Linker metadata symbols */\n\n// NSObject was in Foundation/CF on macOS < 10.8.\n#if TARGET_OS_OSX\n#if __OBJC2__\n\nOBJC_EXPORT const char __objc_nsobject_class_10_5\n    __asm__(\"$ld$hide$os10.5$_OBJC_CLASS_$_NSObject\");\nOBJC_EXPORT const char __objc_nsobject_class_10_6\n    __asm__(\"$ld$hide$os10.6$_OBJC_CLASS_$_NSObject\");\nOBJC_EXPORT const char __objc_nsobject_class_10_7\n    __asm__(\"$ld$hide$os10.7$_OBJC_CLASS_$_NSObject\");\n\nOBJC_EXPORT const char __objc_nsobject_metaclass_10_5\n    __asm__(\"$ld$hide$os10.5$_OBJC_METACLASS_$_NSObject\");\nOBJC_EXPORT const char __objc_nsobject_metaclass_10_6\n    __asm__(\"$ld$hide$os10.6$_OBJC_METACLASS_$_NSObject\");\nOBJC_EXPORT const char __objc_nsobject_metaclass_10_7\n    __asm__(\"$ld$hide$os10.7$_OBJC_METACLASS_$_NSObject\");\n\nOBJC_EXPORT const char __objc_nsobject_isa_10_5\n    __asm__(\"$ld$hide$os10.5$_OBJC_IVAR_$_NSObject.isa\");\nOBJC_EXPORT const char __objc_nsobject_isa_10_6\n    __asm__(\"$ld$hide$os10.6$_OBJC_IVAR_$_NSObject.isa\");\nOBJC_EXPORT const char __objc_nsobject_isa_10_7\n    __asm__(\"$ld$hide$os10.7$_OBJC_IVAR_$_NSObject.isa\");\n\n#else\n\nOBJC_EXPORT const char __objc_nsobject_class_10_5\n    __asm__(\"$ld$hide$os10.5$.objc_class_name_NSObject\");\nOBJC_EXPORT const char __objc_nsobject_class_10_6\n    __asm__(\"$ld$hide$os10.6$.objc_class_name_NSObject\");\nOBJC_EXPORT const char __objc_nsobject_class_10_7\n    __asm__(\"$ld$hide$os10.7$.objc_class_name_NSObject\");\n\n#endif\n#endif\n\n/* Runtime startup. */\n\n// Old static initializer. Used by old crt1.o and old bug workarounds.\nOBJC_EXPORT void\n_objcInit(void)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/* Images */\n\n// Description of an Objective-C image.\n// __DATA,__objc_imageinfo stores one of these.\ntypedef struct objc_image_info {\n    uint32_t version; // currently 0\n    uint32_t flags;\n\n#if __cplusplus >= 201103L\n  private:\n    enum : uint32_t {\n        IsReplacement       = 1<<0,  // used for Fix&Continue, now ignored\n        SupportsGC          = 1<<1,  // image supports GC\n        RequiresGC          = 1<<2,  // image requires GC\n        OptimizedByDyld     = 1<<3,  // image is from an optimized shared cache\n        CorrectedSynthesize = 1<<4,  // used for an old workaround, now ignored\n        IsSimulated         = 1<<5,  // image compiled for a simulator platform\n        HasCategoryClassProperties  = 1<<6,  // class properties in category_t\n\n        SwiftVersionMaskShift = 8,\n        SwiftVersionMask    = 0xff << SwiftVersionMaskShift  // Swift ABI version\n\n    };\n   public:\n    enum : uint32_t {\n        SwiftVersion1   = 1,\n        SwiftVersion1_2 = 2,\n        SwiftVersion2   = 3,\n        SwiftVersion3   = 4\n    };\n\n  public:\n    bool isReplacement()   const { return flags & IsReplacement; }\n    bool supportsGC()      const { return flags & SupportsGC; }\n    bool requiresGC()      const { return flags & RequiresGC; }\n    bool optimizedByDyld() const { return flags & OptimizedByDyld; }\n    bool hasCategoryClassProperties() const { return flags & HasCategoryClassProperties; }\n    bool containsSwift()   const { return (flags & SwiftVersionMask) != 0; }\n    uint32_t swiftVersion() const { return (flags & SwiftVersionMask) >> SwiftVersionMaskShift; }\n#endif\n} objc_image_info;\n\n/* \nIsReplacement:\n   Once used for Fix&Continue in old OS X object files (not final linked images)\n   Not currently used.\n\nSupportsGC:\n   App: GC is required. Framework: GC is supported but not required.\n\nRequiresGC:\n   Framework: GC is required.\n\nOptimizedByDyld:\n   Assorted metadata precooked in the dyld shared cache.\n   Never set for images outside the shared cache file itself.\n\nCorrectedSynthesize:\n   Once used on old iOS to mark images that did not have a particular \n   miscompile. Not used by the runtime.\n\nIsSimulated:\n   Image was compiled for a simulator platform. Not used by the runtime.\n\nHasClassProperties:\n   New ABI: category_t.classProperties fields are present.\n   Old ABI: Set by some compilers. Not used by the runtime.\n*/\n\n\n/* Properties */\n\n// Read or write an object property. Not all object properties use these.\nOBJC_EXPORT id _Nullable\nobjc_getProperty(id _Nullable self, SEL _Nonnull _cmd,\n                 ptrdiff_t offset, BOOL atomic)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_setProperty(id _Nullable self, SEL _Nonnull _cmd, ptrdiff_t offset,\n                 id _Nullable newValue, BOOL atomic, signed char shouldCopy)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_setProperty_atomic(id _Nullable self, SEL _Nonnull _cmd,\n                        id _Nullable newValue, ptrdiff_t offset)\n    OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_setProperty_nonatomic(id _Nullable self, SEL _Nonnull _cmd,\n                           id _Nullable newValue, ptrdiff_t offset)\n    OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_setProperty_atomic_copy(id _Nullable self, SEL _Nonnull _cmd,\n                             id _Nullable newValue, ptrdiff_t offset)\n    OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_setProperty_nonatomic_copy(id _Nullable self, SEL _Nonnull _cmd,\n                                id _Nullable newValue, ptrdiff_t offset)\n    OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);\n\n\n// Read or write a non-object property. Not all uses are C structs, \n// and not all C struct properties use this.\nOBJC_EXPORT void\nobjc_copyStruct(void * _Nonnull dest, const void * _Nonnull src,\n                ptrdiff_t size, BOOL atomic, BOOL hasStrong)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n// Perform a copy of a C++ object using striped locks. Used by non-POD C++ typed atomic properties.\nOBJC_EXPORT void\nobjc_copyCppObjectAtomic(void * _Nonnull dest, const void * _Nonnull src,\n                         void (* _Nonnull copyHelper)\n                           (void * _Nonnull dest, const void * _Nonnull source))\n    OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);\n\n/* Classes. */\n#if __OBJC2__\nOBJC_EXPORT IMP _Nonnull _objc_empty_vtable\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n#endif\nOBJC_EXPORT struct objc_cache _objc_empty_cache\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n\n/* Messages */\n\n#if __OBJC2__\n// objc_msgSendSuper2() takes the current search class, not its superclass.\nOBJC_EXPORT id _Nullable\nobjc_msgSendSuper2(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.6, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_msgSendSuper2_stret(struct objc_super * _Nonnull super,\n                         SEL _Nonnull op,...)\n    OBJC_AVAILABLE(10.6, 2.0, 9.0, 1.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n\n// objc_msgSend_noarg() may be faster for methods with no additional arguments.\nOBJC_EXPORT id _Nullable\nobjc_msgSend_noarg(id _Nullable self, SEL _Nonnull _cmd)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n#endif\n\n#if __OBJC2__\n// Debug messengers. Messengers used by the compiler have a debug flavor that \n// may perform extra sanity checking. \n// Old objc_msgSendSuper() does not have a debug version; this is OBJC2 only.\n// *_fixup() do not have debug versions; use non-fixup only for debug mode.\nOBJC_EXPORT id _Nullable\nobjc_msgSend_debug(id _Nullable self, SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT id _Nullable\nobjc_msgSendSuper2_debug(struct objc_super * _Nonnull super,\n                         SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_msgSend_stret_debug(id _Nullable self, SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n\nOBJC_EXPORT void\nobjc_msgSendSuper2_stret_debug(struct objc_super * _Nonnull super,\n                               SEL _Nonnull op,...)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n\n# if defined(__i386__)\nOBJC_EXPORT double\nobjc_msgSend_fpret_debug(id _Nullable self, SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n# elif defined(__x86_64__)\nOBJC_EXPORT long double\nobjc_msgSend_fpret_debug(id _Nullable self, SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n#  if __STDC_VERSION__ >= 199901L\nOBJC_EXPORT _Complex long double\nobjc_msgSend_fp2ret_debug(id _Nullable self, SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n#  else\nOBJC_EXPORT void\nobjc_msgSend_fp2ret_debug(id _Nullable self, SEL _Nonnull op, ...)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n#  endif\n# endif\n\n#endif\n\n#if __OBJC2__\n// Lookup messengers.\n// These are not callable C functions. Do not call them directly.\n// The caller should set the method parameters, call objc_msgLookup(), \n// then immediately call the returned IMP.\n// \n// Generic ABI:\n// - Callee-saved registers are preserved.\n// - Receiver and selector registers may be modified. These values must \n//   be passed to the called IMP. Other parameter registers are preserved.\n// - Caller-saved non-parameter registers are not preserved. Some of \n//   these registers are used to pass data from objc_msgLookup() to \n//   the called IMP and must not be disturbed by the caller.\n// - Red zone is not preserved.\n// See each architecture's implementation for details.\n\nOBJC_EXPORT void\nobjc_msgLookup(void)\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\nOBJC_EXPORT void\nobjc_msgLookupSuper2(void)\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\nOBJC_EXPORT void\nobjc_msgLookup_stret(void)\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n\nOBJC_EXPORT void\nobjc_msgLookupSuper2_stret(void)\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n\n# if defined(__i386__)\nOBJC_EXPORT void\nobjc_msgLookup_fpret(void)\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\n# elif defined(__x86_64__)\nOBJC_EXPORT void\nobjc_msgLookup_fpret(void)\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\nOBJC_EXPORT void\nobjc_msgLookup_fp2ret(void)\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n# endif\n\n#endif\n\n#if (TARGET_OS_OSX || TARGET_OS_SIMULATOR)  &&  defined(__x86_64__)\n// objc_msgSend_fixup() was used for vtable-dispatchable call sites.\n// The symbols remain exported on macOS for binary compatibility.\n// The symbols can probably be removed from iOS simulator but we haven't tried.\nOBJC_EXPORT void\nobjc_msgSend_fixup(void)\n    __OSX_DEPRECATED(10.5, 10.8, \"fixup dispatch is no longer optimized\");\n\nOBJC_EXPORT void\nobjc_msgSend_stret_fixup(void)\n    __OSX_DEPRECATED(10.5, 10.8, \"fixup dispatch is no longer optimized\");\n\nOBJC_EXPORT void\nobjc_msgSendSuper2_fixup(void)\n    __OSX_DEPRECATED(10.5, 10.8, \"fixup dispatch is no longer optimized\");\n\nOBJC_EXPORT void\nobjc_msgSendSuper2_stret_fixup(void)\n    __OSX_DEPRECATED(10.5, 10.8, \"fixup dispatch is no longer optimized\");\n\nOBJC_EXPORT void\nobjc_msgSend_fpret_fixup(void)\n    __OSX_DEPRECATED(10.5, 10.8, \"fixup dispatch is no longer optimized\");\n\nOBJC_EXPORT void\nobjc_msgSend_fp2ret_fixup(void)\n    __OSX_DEPRECATED(10.5, 10.8, \"fixup dispatch is no longer optimized\");\n#endif\n\n/* C++-compatible exception handling. */\n#if __OBJC2__\n\n// Vtable for C++ exception typeinfo for Objective-C types.\nOBJC_EXPORT const void * _Nullable objc_ehtype_vtable[]\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n// C++ exception typeinfo for type `id`.\nOBJC_EXPORT struct objc_typeinfo OBJC_EHTYPE_id\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n// Exception personality function for Objective-C and Objective-C++ code.\nstruct _Unwind_Exception;\nstruct _Unwind_Context;\nOBJC_EXPORT int\n__objc_personality_v0(int version,\n                      int actions,\n                      uint64_t exceptionClass,\n                      struct _Unwind_Exception * _Nonnull exceptionObject,\n                      struct _Unwind_Context * _Nonnull context)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n#endif\n\n/* ARC */\n\nOBJC_EXPORT id _Nullable\nobjc_retainBlock(id _Nullable)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\n\n/* Non-pointer isa */\n\n#if __OBJC2__\n\n// Extract class pointer from an isa field.\n    \n#if TARGET_OS_SIMULATOR && !TARGET_OS_IOSMAC\n    // No simulators use nonpointer isa yet.\n    \n#elif __LP64__\n#   define OBJC_HAVE_NONPOINTER_ISA 1\n#   define OBJC_HAVE_PACKED_NONPOINTER_ISA 1\n\n// Packed-isa version. This one is used directly by Swift code.\n// (Class)(isa & (uintptr_t)&objc_absolute_packed_isa_class_mask) == class ptr\nOBJC_EXPORT const struct { char c; } objc_absolute_packed_isa_class_mask\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\n#elif (__ARM_ARCH_7K__ >= 2  ||  (__arm64__ && !__LP64__))\n#   define OBJC_HAVE_NONPOINTER_ISA 1\n#   define OBJC_HAVE_INDEXED_NONPOINTER_ISA 1\n\n// Indexed-isa version.\n// if (isa & (uintptr_t)&objc_absolute_indexed_isa_magic_mask == (uintptr_t)&objc_absolute_indexed_isa_magic_value) {\n//     uintptr_t index = (isa & (uintptr_t)&objc_absolute_indexed_isa_index_mask) >> (uintptr_t)&objc_absolute_indexed_isa_index_shift;\n//     cls = objc_indexed_classes[index];\n// } else\n//     cls = (Class)isa;\n// }\nOBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_magic_mask\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\nOBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_magic_value\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\nOBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_index_mask\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\nOBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_index_shift\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\n#endif\n\n#endif\n\n\n/* Object class */\n\n// This symbol might be required for binary compatibility, so we\n// declare it here where TAPI will see it.\n#if __OBJC__  &&  __OBJC2__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wobjc-interface-ivars\"\n#if !defined(OBJC_DECLARE_SYMBOLS)\n__OSX_AVAILABLE(10.0)\n__IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n__WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE\n#endif\nOBJC_ROOT_CLASS\n@interface Object {\n    Class isa;\n}\n@end\n#pragma clang diagnostic pop\n#endif\n\n\n// _OBJC_ABI_H\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-accessors.mm",
    "content": "/*\n * Copyright (c) 2006-2008 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include <string.h>\n#include <stddef.h>\n\n#include <libkern/OSAtomic.h>\n\n#include \"objc-private.h\"\n#include \"runtime.h\"\n\n// stub interface declarations to make compiler happy.\n\n@interface __NSCopyable\n- (id)copyWithZone:(void *)zone;\n@end\n\n@interface __NSMutableCopyable\n- (id)mutableCopyWithZone:(void *)zone;\n@end\n\nStripedMap<spinlock_t> PropertyLocks;\nStripedMap<spinlock_t> StructLocks;\nStripedMap<spinlock_t> CppObjectLocks;\n\n#define MUTABLE_COPY 2\n\nid objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {\n    if (offset == 0) {\n        return object_getClass(self);\n    }\n\n    // Retain release world\n    id *slot = (id*) ((char*)self + offset);\n    if (!atomic) return *slot;\n        \n    // Atomic retain release world\n    spinlock_t& slotlock = PropertyLocks[slot];\n    slotlock.lock();\n    id value = objc_retain(*slot);\n    slotlock.unlock();\n    \n    // for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.\n    return objc_autoreleaseReturnValue(value);\n}\n\n\nstatic inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) __attribute__((always_inline));\n\nstatic inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)\n{\n    if (offset == 0) {\n        object_setClass(self, newValue);\n        return;\n    }\n\n    id oldValue;\n    id *slot = (id*) ((char*)self + offset);\n\n    if (copy) {\n        newValue = [newValue copyWithZone:nil];\n    } else if (mutableCopy) {\n        newValue = [newValue mutableCopyWithZone:nil];\n    } else {\n        if (*slot == newValue) return;\n        newValue = objc_retain(newValue);\n    }\n\n    if (!atomic) {\n        oldValue = *slot;\n        *slot = newValue;\n    } else {\n        spinlock_t& slotlock = PropertyLocks[slot];\n        slotlock.lock();\n        oldValue = *slot;\n        *slot = newValue;        \n        slotlock.unlock();\n    }\n\n    objc_release(oldValue);\n}\n\nvoid objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy) \n{\n    bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);\n    bool mutableCopy = (shouldCopy == MUTABLE_COPY);\n    reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);\n}\n\nvoid objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)\n{\n    reallySetProperty(self, _cmd, newValue, offset, true, false, false);\n}\n\nvoid objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)\n{\n    reallySetProperty(self, _cmd, newValue, offset, false, false, false);\n}\n\n\nvoid objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)\n{\n    reallySetProperty(self, _cmd, newValue, offset, true, true, false);\n}\n\nvoid objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)\n{\n    reallySetProperty(self, _cmd, newValue, offset, false, true, false);\n}\n\n\n// This entry point was designed wrong.  When used as a getter, src needs to be locked so that\n// if simultaneously used for a setter then there would be contention on src.\n// So we need two locks - one of which will be contended.\nvoid objc_copyStruct(void *dest, const void *src, ptrdiff_t size, BOOL atomic, BOOL hasStrong __unused) {\n    spinlock_t *srcLock = nil;\n    spinlock_t *dstLock = nil;\n    if (atomic) {\n        srcLock = &StructLocks[src];\n        dstLock = &StructLocks[dest];\n        spinlock_t::lockTwo(srcLock, dstLock);\n    }\n\n    memmove(dest, src, size);\n\n    if (atomic) {\n        spinlock_t::unlockTwo(srcLock, dstLock);\n    }\n}\n\nvoid objc_copyCppObjectAtomic(void *dest, const void *src, void (*copyHelper) (void *dest, const void *source)) {\n    spinlock_t *srcLock = &CppObjectLocks[src];\n    spinlock_t *dstLock = &CppObjectLocks[dest];\n    spinlock_t::lockTwo(srcLock, dstLock);\n\n    // let C++ code perform the actual copy.\n    copyHelper(dest, src);\n    \n    spinlock_t::unlockTwo(srcLock, dstLock);\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-api.h",
    "content": "/*\n * Copyright (c) 1999-2006 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n// Copyright 1988-1996 NeXT Software, Inc.\n\n#ifndef _OBJC_OBJC_API_H_\n#define _OBJC_OBJC_API_H_\n\n#include <Availability.h>\n#include <AvailabilityMacros.h>\n#include <TargetConditionals.h>\n#include <sys/types.h>\n\n#ifndef __has_feature\n#   define __has_feature(x) 0\n#endif\n\n#ifndef __has_extension\n#   define __has_extension __has_feature\n#endif\n\n#ifndef __has_attribute\n#   define __has_attribute(x) 0\n#endif\n\n#if !__has_feature(nullability)\n#   ifndef _Nullable\n#       define _Nullable\n#   endif\n#   ifndef _Nonnull\n#       define _Nonnull\n#   endif\n#   ifndef _Null_unspecified\n#       define _Null_unspecified\n#   endif\n#endif\n\n#ifndef __APPLE_BLEACH_SDK__\n# if __has_feature(attribute_availability_bridgeos)\n#   ifndef __BRIDGEOS_AVAILABLE\n#       define __BRIDGEOS_AVAILABLE(_vers) __OS_AVAILABILITY(bridgeos,introduced=_vers)\n#   endif\n#   ifndef __BRIDGEOS_DEPRECATED\n#       define __BRIDGEOS_DEPRECATED(_start, _dep, _msg) __BRIDGEOS_AVAILABLE(_start) __OS_AVAILABILITY_MSG(bridgeos,deprecated=_dep,_msg)\n#   endif\n#   ifndef __BRIDGEOS_UNAVAILABLE\n#       define __BRIDGEOS_UNAVAILABLE __OS_AVAILABILITY(bridgeos,unavailable)\n#   endif\n# else\n#   ifndef __BRIDGEOS_AVAILABLE\n#       define __BRIDGEOS_AVAILABLE(_vers)\n#   endif\n#   ifndef __BRIDGEOS_DEPRECATED\n#       define __BRIDGEOS_DEPRECATED(_start, _dep, _msg)\n#   endif\n#   ifndef __BRIDGEOS_UNAVAILABLE\n#       define __BRIDGEOS_UNAVAILABLE\n#   endif\n# endif\n#endif\n\n/*\n * OBJC_API_VERSION 0 or undef: Tiger and earlier API only\n * OBJC_API_VERSION 2: Leopard and later API available\n */\n#if !defined(OBJC_API_VERSION)\n#   if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)  &&  __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_5\n#       define OBJC_API_VERSION 0\n#   else\n#       define OBJC_API_VERSION 2\n#   endif\n#endif\n\n\n/*\n * OBJC_NO_GC 1: GC is not supported\n * OBJC_NO_GC undef: GC is supported. This SDK no longer supports this mode.\n *\n * OBJC_NO_GC_API undef: Libraries must export any symbols that \n *                       dual-mode code may links to.\n * OBJC_NO_GC_API 1: Libraries need not export GC-related symbols.\n */\n#if defined(__OBJC_GC__)\n#   error Objective-C garbage collection is not supported.\n#elif TARGET_OS_OSX\n    /* GC is unsupported. GC API symbols are exported. */\n#   define OBJC_NO_GC 1\n#   undef  OBJC_NO_GC_API\n#else\n    /* GC is unsupported. GC API symbols are not exported. */\n#   define OBJC_NO_GC 1\n#   define OBJC_NO_GC_API 1\n#endif\n\n\n/* NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER == 1 \n * marks -[NSObject init] as a designated initializer. */\n#if !defined(NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER)\n#   define NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER 1\n#endif\n\n\n/* OBJC_OLD_DISPATCH_PROTOTYPES == 0 enforces the rule that the dispatch \n * functions must be cast to an appropriate function pointer type. */\n#if !defined(OBJC_OLD_DISPATCH_PROTOTYPES)\n#   if __swift__\n        // Existing Swift code expects IMP to be Comparable.\n        // Variadic IMP is comparable via OpaquePointer; non-variadic IMP isn't.\n#       define OBJC_OLD_DISPATCH_PROTOTYPES 1\n#   else\n#       define OBJC_OLD_DISPATCH_PROTOTYPES 1\n#   endif\n#endif\n\n\n/* OBJC_AVAILABLE: shorthand for all-OS availability */\n#if !defined(OBJC_AVAILABLE)\n#   define OBJC_AVAILABLE(x, i, t, w, b)                            \\\n        __OSX_AVAILABLE(x)  __IOS_AVAILABLE(i)  __TVOS_AVAILABLE(t) \\\n        __WATCHOS_AVAILABLE(w)  __BRIDGEOS_AVAILABLE(b)\n#endif\n\n\n/* OBJC_ISA_AVAILABILITY: `isa` will be deprecated or unavailable \n * in the future */\n#if !defined(OBJC_ISA_AVAILABILITY)\n#   if __OBJC2__\n#       define OBJC_ISA_AVAILABILITY  __attribute__((deprecated))\n#   else\n#       define OBJC_ISA_AVAILABILITY  /* still available */\n#   endif\n#endif\n\n\n/* OBJC2_UNAVAILABLE: unavailable in objc 2.0, deprecated in Leopard */\n#if !defined(OBJC2_UNAVAILABLE)\n#   if __OBJC2__\n#       define OBJC2_UNAVAILABLE UNAVAILABLE_ATTRIBUTE\n#   else\n        /* plain C code also falls here, but this is close enough */\n#       define OBJC2_UNAVAILABLE                                       \\\n            __OSX_DEPRECATED(10.5, 10.5, \"not available in __OBJC2__\") \\\n            __IOS_DEPRECATED(2.0, 2.0, \"not available in __OBJC2__\")   \\\n            __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE\n#   endif\n#endif\n\n/* OBJC_UNAVAILABLE: unavailable, with a message where supported */\n#if !defined(OBJC_UNAVAILABLE)\n#   if __has_extension(attribute_unavailable_with_message)\n#       define OBJC_UNAVAILABLE(_msg) __attribute__((unavailable(_msg)))\n#   else\n#       define OBJC_UNAVAILABLE(_msg) __attribute__((unavailable))\n#   endif\n#endif\n\n/* OBJC_DEPRECATED: deprecated, with a message where supported */\n#if !defined(OBJC_DEPRECATED)\n#   if __has_extension(attribute_deprecated_with_message)\n#       define OBJC_DEPRECATED(_msg) __attribute__((deprecated(_msg)))\n#   else\n#       define OBJC_DEPRECATED(_msg) __attribute__((deprecated))\n#   endif\n#endif\n\n/* OBJC_ARC_UNAVAILABLE: unavailable with -fobjc-arc */\n#if !defined(OBJC_ARC_UNAVAILABLE)\n#   if __has_feature(objc_arc)\n#       define OBJC_ARC_UNAVAILABLE OBJC_UNAVAILABLE(\"not available in automatic reference counting mode\")\n#   else\n#       define OBJC_ARC_UNAVAILABLE\n#   endif\n#endif\n\n/* OBJC_SWIFT_UNAVAILABLE: unavailable in Swift */\n#if !defined(OBJC_SWIFT_UNAVAILABLE)\n#   if __has_feature(attribute_availability_swift)\n#       define OBJC_SWIFT_UNAVAILABLE(_msg) __attribute__((availability(swift, unavailable, message=_msg)))\n#   else\n#       define OBJC_SWIFT_UNAVAILABLE(_msg)\n#   endif\n#endif\n\n/* OBJC_ARM64_UNAVAILABLE: unavailable on arm64 (i.e. stret dispatch) */\n#if !defined(OBJC_ARM64_UNAVAILABLE)\n#   if defined(__arm64__)\n#       define OBJC_ARM64_UNAVAILABLE OBJC_UNAVAILABLE(\"not available in arm64\")\n#   else\n#       define OBJC_ARM64_UNAVAILABLE \n#   endif\n#endif\n\n/* OBJC_GC_UNAVAILABLE: unavailable with -fobjc-gc or -fobjc-gc-only */\n#if !defined(OBJC_GC_UNAVAILABLE)\n#   define OBJC_GC_UNAVAILABLE\n#endif\n\n#if !defined(OBJC_EXTERN)\n#   if defined(__cplusplus)\n#       define OBJC_EXTERN extern \"C\" \n#   else\n#       define OBJC_EXTERN extern\n#   endif\n#endif\n\n#if !defined(OBJC_VISIBLE)\n#   if TARGET_OS_WIN32\n#       if defined(BUILDING_OBJC)\n#           define OBJC_VISIBLE __declspec(dllexport)\n#       else\n#           define OBJC_VISIBLE __declspec(dllimport)\n#       endif\n#   else\n#       define OBJC_VISIBLE  __attribute__((visibility(\"default\")))\n#   endif\n#endif\n\n#if !defined(OBJC_EXPORT)\n#   define OBJC_EXPORT  OBJC_EXTERN OBJC_VISIBLE\n#endif\n\n#if !defined(OBJC_IMPORT)\n#   define OBJC_IMPORT extern\n#endif\n\n#if !defined(OBJC_ROOT_CLASS)\n#   if __has_attribute(objc_root_class)\n#       define OBJC_ROOT_CLASS __attribute__((objc_root_class))\n#   else\n#       define OBJC_ROOT_CLASS\n#   endif\n#endif\n\n#ifndef __DARWIN_NULL\n#define __DARWIN_NULL NULL\n#endif\n\n#if !defined(OBJC_INLINE)\n#   define OBJC_INLINE __inline\n#endif\n\n// Declares an enum type or option bits type as appropriate for each language.\n#if (__cplusplus && __cplusplus >= 201103L && (__has_extension(cxx_strong_enums) || __has_feature(objc_fixed_enum))) || (!__cplusplus && __has_feature(objc_fixed_enum))\n#define OBJC_ENUM(_type, _name) enum _name : _type _name; enum _name : _type\n#if (__cplusplus)\n#define OBJC_OPTIONS(_type, _name) _type _name; enum : _type\n#else\n#define OBJC_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type\n#endif\n#else\n#define OBJC_ENUM(_type, _name) _type _name; enum\n#define OBJC_OPTIONS(_type, _name) _type _name; enum\n#endif\n\n#if !defined(OBJC_RETURNS_RETAINED)\n#   if __OBJC__ && __has_attribute(ns_returns_retained)\n#       define OBJC_RETURNS_RETAINED __attribute__((ns_returns_retained))\n#   else\n#       define OBJC_RETURNS_RETAINED\n#   endif\n#endif\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-auto.h",
    "content": "/*\n * Copyright (c) 2004-2007 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _OBJC_AUTO_H_\n#define _OBJC_AUTO_H_\n\n#include <objc/objc.h>\n#include <malloc/malloc.h>\n#include <stdint.h>\n#include <stddef.h>\n#include <string.h>\n#include <Availability.h>\n#include <TargetConditionals.h>\n\n#include <sys/types.h>\n#include <libkern/OSAtomic.h>\n\n\n// Define OBJC_SILENCE_GC_DEPRECATIONS=1 to temporarily \n// silence deprecation warnings for GC functions.\n\n#if OBJC_SILENCE_GC_DEPRECATIONS\n#   define OBJC_GC_DEPRECATED(message)\n#elif __has_extension(attribute_deprecated_with_message)\n#   define OBJC_GC_DEPRECATED(message) __attribute__((deprecated(message \". Define OBJC_SILENCE_GC_DEPRECATIONS=1 to temporarily silence this diagnostic.\")))\n#else\n#   define OBJC_GC_DEPRECATED(message) __attribute__((deprecated))\n#endif\n\n\nenum {\n    OBJC_RATIO_COLLECTION        = (0 << 0),\n    OBJC_GENERATIONAL_COLLECTION = (1 << 0),\n    OBJC_FULL_COLLECTION         = (2 << 0),\n    OBJC_EXHAUSTIVE_COLLECTION   = (3 << 0),\n    \n    OBJC_COLLECT_IF_NEEDED       = (1 << 3),\n    OBJC_WAIT_UNTIL_DONE         = (1 << 4)\n};\n\nenum {\n    OBJC_CLEAR_RESIDENT_STACK = (1 << 0)\n};\n\n\n#if !defined(OBJC_NO_GC)  ||  \\\n    (OBJC_DECLARE_SYMBOLS && !defined(OBJC_NO_GC_API))\n\n\n/* Out-of-line declarations */\n\nOBJC_EXPORT void objc_collect(unsigned long options)\n    __OSX_DEPRECATED(10.6, 10.8, \"it does nothing\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT BOOL objc_collectingEnabled(void)\n    __OSX_DEPRECATED(10.5, 10.8, \"it always returns NO\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT malloc_zone_t *objc_collectableZone(void) \n    __OSX_DEPRECATED(10.7, 10.8, \"it always returns nil\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT void objc_setCollectionThreshold(size_t threshold)\n    __OSX_DEPRECATED(10.5, 10.8, \"it does nothing\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT void objc_setCollectionRatio(size_t ratio)\n    __OSX_DEPRECATED(10.5, 10.8, \"it does nothing\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation) \n    __OSX_DEPRECATED(10.6, 10.8, \"use OSAtomicCompareAndSwapPtr instead\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE;\nOBJC_EXPORT BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation) \n    __OSX_DEPRECATED(10.6, 10.8, \"use OSAtomicCompareAndSwapPtrBarrier instead\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE;\nOBJC_EXPORT BOOL objc_atomicCompareAndSwapGlobal(id predicate, id replacement, volatile id *objectLocation)\n    __OSX_DEPRECATED(10.6, 10.8, \"use OSAtomicCompareAndSwapPtr instead\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE;\nOBJC_EXPORT BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate, id replacement, volatile id *objectLocation)\n    __OSX_DEPRECATED(10.6, 10.8, \"use OSAtomicCompareAndSwapPtrBarrier instead\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE;\nOBJC_EXPORT BOOL objc_atomicCompareAndSwapInstanceVariable(id predicate, id replacement, volatile id *objectLocation)\n    __OSX_DEPRECATED(10.6, 10.8, \"use OSAtomicCompareAndSwapPtr instead\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE;\nOBJC_EXPORT BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replacement, volatile id *objectLocation)\n    __OSX_DEPRECATED(10.6, 10.8, \"use OSAtomicCompareAndSwapPtrBarrier instead\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE;\nOBJC_EXPORT id objc_assign_strongCast(id val, id *dest)\n    __OSX_DEPRECATED(10.4, 10.8, \"use a simple assignment instead\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT id objc_assign_global(id val, id *dest)\n    __OSX_DEPRECATED(10.4, 10.8, \"use a simple assignment instead\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT id objc_assign_threadlocal(id val, id *dest)\n    __OSX_DEPRECATED(10.7, 10.8, \"use a simple assignment instead\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT id objc_assign_ivar(id value, id dest, ptrdiff_t offset)\n    __OSX_DEPRECATED(10.4, 10.8, \"use a simple assignment instead\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT void *objc_memmove_collectable(void *dst, const void *src, size_t size)\n    __OSX_DEPRECATED(10.4, 10.8, \"use memmove instead\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT id objc_read_weak(id *location)\n    __OSX_DEPRECATED(10.5, 10.8, \"use a simple read instead, or convert to zeroing __weak\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT id objc_assign_weak(id value, id *location)\n    __OSX_DEPRECATED(10.5, 10.8, \"use a simple assignment instead, or convert to zeroing __weak\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT void objc_registerThreadWithCollector(void)\n    __OSX_DEPRECATED(10.6, 10.8, \"it does nothing\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT void objc_unregisterThreadWithCollector(void)\n    __OSX_DEPRECATED(10.6, 10.8, \"it does nothing\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT void objc_assertRegisteredThreadWithCollector(void)\n    __OSX_DEPRECATED(10.6, 10.8, \"it does nothing\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT void objc_clear_stack(unsigned long options)\n    __OSX_DEPRECATED(10.5, 10.8, \"it does nothing\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT BOOL objc_is_finalized(void *ptr)\n    __OSX_DEPRECATED(10.4, 10.8, \"it always returns NO\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT void objc_finalizeOnMainThread(Class cls)\n    __OSX_DEPRECATED(10.5, 10.5, \"it does nothing\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT BOOL objc_collecting_enabled(void)\n    __OSX_DEPRECATED(10.4, 10.5, \"it always returns NO\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT void objc_set_collection_threshold(size_t threshold)\n    __OSX_DEPRECATED(10.4, 10.5, \"it does nothing\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT void objc_set_collection_ratio(size_t ratio)\n    __OSX_DEPRECATED(10.4, 10.5, \"it does nothing\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT void objc_start_collector_thread(void)\n    __OSX_DEPRECATED(10.4, 10.5, \"it does nothing\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT void objc_startCollectorThread(void)\n    __OSX_DEPRECATED(10.5, 10.7, \"it does nothing\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\nOBJC_EXPORT id objc_allocate_object(Class cls, int extra)\n    __OSX_DEPRECATED(10.4, 10.4, \"use class_createInstance instead\") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\n\n/* !defined(OBJC_NO_GC) */\n#else\n/* defined(OBJC_NO_GC) */\n\n\n/* Inline declarations */\n\nOBJC_GC_DEPRECATED(\"it does nothing\")\nstatic OBJC_INLINE void objc_collect(unsigned long options __unused) { }\nOBJC_GC_DEPRECATED(\"it always returns NO\")\nstatic OBJC_INLINE BOOL objc_collectingEnabled(void) { return NO; }\n#if TARGET_OS_OSX\nOBJC_GC_DEPRECATED(\"it always returns nil\")\nstatic OBJC_INLINE malloc_zone_t *objc_collectableZone(void) { return nil; }\n#endif\nOBJC_GC_DEPRECATED(\"it does nothing\")\nstatic OBJC_INLINE void objc_setCollectionThreshold(size_t threshold __unused) { }\nOBJC_GC_DEPRECATED(\"it does nothing\")\nstatic OBJC_INLINE void objc_setCollectionRatio(size_t ratio __unused) { }\nOBJC_GC_DEPRECATED(\"it does nothing\")\nstatic OBJC_INLINE void objc_startCollectorThread(void) { }\n\n#if __has_feature(objc_arc)\n\n/* Covers for GC memory operations are unavailable in ARC */\n\n#else\n\nOBJC_GC_DEPRECATED(\"use OSAtomicCompareAndSwapPtr instead\")\nstatic OBJC_INLINE BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation) \n    { return OSAtomicCompareAndSwapPtr((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); }\n\nOBJC_GC_DEPRECATED(\"use OSAtomicCompareAndSwapPtrBarrier instead\")\nstatic OBJC_INLINE BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation) \n    { return OSAtomicCompareAndSwapPtrBarrier((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); }\n\nOBJC_GC_DEPRECATED(\"use OSAtomicCompareAndSwapPtr instead\")\nstatic OBJC_INLINE BOOL objc_atomicCompareAndSwapGlobal(id predicate, id replacement, volatile id *objectLocation) \n    { return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); }\n\nOBJC_GC_DEPRECATED(\"use OSAtomicCompareAndSwapPtrBarrier instead\")\nstatic OBJC_INLINE BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate, id replacement, volatile id *objectLocation) \n    { return objc_atomicCompareAndSwapPtrBarrier(predicate, replacement, objectLocation); }\n\nOBJC_GC_DEPRECATED(\"use OSAtomicCompareAndSwapPtr instead\")\nstatic OBJC_INLINE BOOL objc_atomicCompareAndSwapInstanceVariable(id predicate, id replacement, volatile id *objectLocation) \n    { return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); }\n\nOBJC_GC_DEPRECATED(\"use OSAtomicCompareAndSwapPtrBarrier instead\")\nstatic OBJC_INLINE BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replacement, volatile id *objectLocation) \n    { return objc_atomicCompareAndSwapPtrBarrier(predicate, replacement, objectLocation); }\n\n\nOBJC_GC_DEPRECATED(\"use a simple assignment instead\")\nstatic OBJC_INLINE id objc_assign_strongCast(id val, id *dest) \n    { return (*dest = val); }\n\nOBJC_GC_DEPRECATED(\"use a simple assignment instead\")\nstatic OBJC_INLINE id objc_assign_global(id val, id *dest) \n    { return (*dest = val); }\n\nOBJC_GC_DEPRECATED(\"use a simple assignment instead\")\nstatic OBJC_INLINE id objc_assign_threadlocal(id val, id *dest) \n    { return (*dest = val); }\n\nOBJC_GC_DEPRECATED(\"use a simple assignment instead\")\nstatic OBJC_INLINE id objc_assign_ivar(id val, id dest, ptrdiff_t offset) \n    { return (*(id*)((intptr_t)(char *)dest+offset) = val); }\n\nOBJC_GC_DEPRECATED(\"use a simple read instead, or convert to zeroing __weak\")\nstatic OBJC_INLINE id objc_read_weak(id *location) \n    { return *location; }\n\nOBJC_GC_DEPRECATED(\"use a simple assignment instead, or convert to zeroing __weak\")\nstatic OBJC_INLINE id objc_assign_weak(id value, id *location) \n    { return (*location = value); }\n\n/* MRC */\n#endif\n\nOBJC_GC_DEPRECATED(\"use memmove instead\")\nstatic OBJC_INLINE void *objc_memmove_collectable(void *dst, const void *src, size_t size) \n    { return memmove(dst, src, size); }\n\nOBJC_GC_DEPRECATED(\"it does nothing\")\nstatic OBJC_INLINE void objc_finalizeOnMainThread(Class cls __unused) { }\nOBJC_GC_DEPRECATED(\"it always returns NO\")\nstatic OBJC_INLINE BOOL objc_is_finalized(void *ptr __unused) { return NO; }\nOBJC_GC_DEPRECATED(\"it does nothing\")\nstatic OBJC_INLINE void objc_clear_stack(unsigned long options __unused) { }\nOBJC_GC_DEPRECATED(\"it always returns NO\")\nstatic OBJC_INLINE BOOL objc_collecting_enabled(void) { return NO; }\nOBJC_GC_DEPRECATED(\"it does nothing\")\nstatic OBJC_INLINE void objc_set_collection_threshold(size_t threshold __unused) { } \nOBJC_GC_DEPRECATED(\"it does nothing\")\nstatic OBJC_INLINE void objc_set_collection_ratio(size_t ratio __unused) { } \nOBJC_GC_DEPRECATED(\"it does nothing\")\nstatic OBJC_INLINE void objc_start_collector_thread(void) { }\n\n#if __has_feature(objc_arc)\nextern id objc_allocate_object(Class cls, int extra) UNAVAILABLE_ATTRIBUTE;\n#else\nOBJC_EXPORT id class_createInstance(Class cls, size_t extraBytes)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\nOBJC_GC_DEPRECATED(\"use class_createInstance instead\")\nstatic OBJC_INLINE id objc_allocate_object(Class cls, int extra) \n    { return class_createInstance(cls, (size_t)extra); }\n#endif\n\nOBJC_GC_DEPRECATED(\"it does nothing\")\nstatic OBJC_INLINE void objc_registerThreadWithCollector() { }\nOBJC_GC_DEPRECATED(\"it does nothing\")\nstatic OBJC_INLINE void objc_unregisterThreadWithCollector() { }\nOBJC_GC_DEPRECATED(\"it does nothing\")\nstatic OBJC_INLINE void objc_assertRegisteredThreadWithCollector() { }\n\n/* defined(OBJC_NO_GC) */\n#endif\n\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-auto.mm",
    "content": "/*\n * Copyright (c) 2004-2007 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#define OBJC_DECLARE_SYMBOLS 1\n#include \"objc-private.h\"\n#include \"objc-auto.h\"\n\n// GC is no longer supported.\n\n#if OBJC_NO_GC_API\n\n// No GC and no GC symbols needed. We're done here.\n# if SUPPORT_GC_COMPAT\n#   error inconsistent config settings\n# endif\n\n#else\n\n// No GC but we do need to export GC symbols.\n\n# if !SUPPORT_GC_COMPAT\n#   error inconsistent config settings\n# endif\n\nvoid objc_collect(unsigned long options __unused) { }\nBOOL objc_collectingEnabled(void) { return NO; }\nvoid objc_setCollectionThreshold(size_t threshold __unused) { }\nvoid objc_setCollectionRatio(size_t ratio __unused) { }\nvoid objc_startCollectorThread(void) { }\n\n#if TARGET_OS_WIN32\nBOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation) \n    { void *original = InterlockedCompareExchangePointer((void * volatile *)objectLocation, (void *)replacement, (void *)predicate); return (original == predicate); }\n\nBOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation) \n    { void *original = InterlockedCompareExchangePointer((void * volatile *)objectLocation, (void *)replacement, (void *)predicate); return (original == predicate); }\n#else\nBOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation) \n    { return OSAtomicCompareAndSwapPtr((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); }\n\nBOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation) \n    { return OSAtomicCompareAndSwapPtrBarrier((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); }\n#endif\n\nBOOL objc_atomicCompareAndSwapGlobal(id predicate, id replacement, volatile id *objectLocation) \n    { return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); }\n\nBOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate, id replacement, volatile id *objectLocation) \n    { return objc_atomicCompareAndSwapPtrBarrier(predicate, replacement, objectLocation); }\n\nBOOL objc_atomicCompareAndSwapInstanceVariable(id predicate, id replacement, volatile id *objectLocation) \n    { return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); }\n\nBOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replacement, volatile id *objectLocation) \n    { return objc_atomicCompareAndSwapPtrBarrier(predicate, replacement, objectLocation); }\n\nid objc_assign_strongCast(id val, id *dest) \n    { return (*dest = val); }\n\nid objc_assign_global(id val, id *dest) \n    { return (*dest = val); }\n\nid objc_assign_threadlocal(id val, id *dest)\n    { return (*dest = val); }\n\nid objc_assign_ivar(id val, id dest, ptrdiff_t offset) \n    { return (*(id*)((char *)dest+offset) = val); }\n\nid objc_read_weak(id *location) \n    { return *location; }\n\nid objc_assign_weak(id value, id *location) \n    { return (*location = value); }\n\nvoid *objc_memmove_collectable(void *dst, const void *src, size_t size) \n    { return memmove(dst, src, size); }\n\nvoid objc_finalizeOnMainThread(Class cls __unused) { }\nBOOL objc_is_finalized(void *ptr __unused) { return NO; }\nvoid objc_clear_stack(unsigned long options __unused) { }\n\nBOOL objc_collecting_enabled(void) { return NO; }\nvoid objc_set_collection_threshold(size_t threshold __unused) { } \nvoid objc_set_collection_ratio(size_t ratio __unused) { } \nvoid objc_start_collector_thread(void) { }\n\nid objc_allocate_object(Class cls, int extra) \n    { return class_createInstance(cls, extra); }\n\nvoid objc_registerThreadWithCollector() { }\nvoid objc_unregisterThreadWithCollector() { }\nvoid objc_assertRegisteredThreadWithCollector() { }\n\nmalloc_zone_t* objc_collect_init(int(*callback)() __unused) { return nil; }\nmalloc_zone_t* objc_collectableZone() { return nil; }\n\nBOOL objc_isAuto(id object __unused) { return NO; }\nBOOL objc_dumpHeap(char *filename __unused, unsigned long length __unused)\n    { return NO; }\n\n// not OBJC_NO_GC_API\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-block-trampolines.h",
    "content": "/*\n * Copyright (c) 2018 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n\n#ifndef _OBJC_TRAMPOLINES_H\n#define _OBJC_TRAMPOLINES_H\n\n/* \n * WARNING  DANGER  HAZARD  BEWARE  EEK\n * \n * Everything in this file is for Apple Internal use only.\n * These will change in arbitrary OS updates and in unpredictable ways.\n * When your program breaks, you get to keep both pieces.\n */\n\n/*\n * objc-block-trampolines.h: Symbols for IMP block trampolines\n */\n\n#include <objc/objc-api.h>\n\nOBJC_EXPORT const char _objc_blockTrampolineImpl\n    OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);\n\nOBJC_EXPORT const char _objc_blockTrampolineStart\n    OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);\n\nOBJC_EXPORT const char _objc_blockTrampolineLast\n    OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);\n\n\nOBJC_EXPORT const char _objc_blockTrampolineImpl_stret\nOBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0)\n    OBJC_ARM64_UNAVAILABLE;\n\nOBJC_EXPORT const char _objc_blockTrampolineStart_stret\nOBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0)\n    OBJC_ARM64_UNAVAILABLE;\n\nOBJC_EXPORT const char _objc_blockTrampolineLast_stret\nOBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0)\n    OBJC_ARM64_UNAVAILABLE;\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-block-trampolines.mm",
    "content": "/*\n * Copyright (c) 2010 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/***********************************************************************\n * objc-block-trampolines.m\n * Author:\tb.bum\n *\n **********************************************************************/\n\n/***********************************************************************\n * Imports.\n **********************************************************************/\n#include \"objc-private.h\"\n#include \"runtime.h\"\n\n#include <Block.h>\n#include <Block_private.h>\n#include <mach/mach.h>\n#include <objc/objc-block-trampolines.h>\n\n// fixme C++ compilers don't implemement memory_order_consume efficiently.\n// Use memory_order_relaxed and cross our fingers.\n#define MEMORY_ORDER_CONSUME std::memory_order_relaxed\n\n// 8 bytes of text and data per trampoline on all architectures.\n#define SLOT_SIZE 8\n\n// The trampolines are defined in assembly files in libobjc-trampolines.dylib.\n// We can't link to libobjc-trampolines.dylib directly because\n// for security reasons it isn't in the dyld shared cache.\n\n// Trampoline addresses are lazily looked up.\n// All of them are hidden behind a single atomic pointer for lock-free init.\n\n#ifdef __PTRAUTH_INTRINSICS__\n#   define TrampolinePtrauth __ptrauth(ptrauth_key_function_pointer, 1, 0x3af1)\n#else\n#   define TrampolinePtrauth\n#endif\n\nclass TrampolinePointerWrapper {\n    struct TrampolinePointers {\n        class TrampolineAddress {\n            const void * TrampolinePtrauth storage;\n\n        public:\n            TrampolineAddress(void *dylib, const char *name) {\n#define PREFIX \"_objc_blockTrampoline\"\n                char symbol[strlen(PREFIX) + strlen(name) + 1];\n                strcpy(symbol, PREFIX);\n                strcat(symbol, name);\n                // dlsym() from a text segment returns a signed pointer\n                // Authenticate it manually and let the compiler re-sign it.\n                storage = ptrauth_auth_data(dlsym(dylib, symbol),\n                                            ptrauth_key_function_pointer, 0);\n                if (!storage) {\n                    _objc_fatal(\"couldn't dlsym %s\", symbol);\n                }\n            }\n\n            uintptr_t address() {\n                return (uintptr_t)(void*)storage;\n            }\n        };\n\n        TrampolineAddress impl;   // trampoline header code\n        TrampolineAddress start;  // first trampoline\n#if DEBUG\n        // These symbols are only used in assertions.\n        // fixme might be able to move the assertions to libobjc-trampolines itself\n        TrampolineAddress last;    // start of the last trampoline\n        // We don't use the address after the last trampoline because that\n        // address might be in a different section, and then dlsym() would not\n        // sign it as a function pointer.\n# if SUPPORT_STRET\n        TrampolineAddress impl_stret;\n        TrampolineAddress start_stret;\n        TrampolineAddress last_stret;\n# endif\n#endif\n\n        uintptr_t textSegment;\n        uintptr_t textSegmentSize;\n\n        void check() {\n#if DEBUG\n            assert(impl.address() == textSegment + PAGE_MAX_SIZE);\n            assert(impl.address() % PAGE_SIZE == 0);  // not PAGE_MAX_SIZE\n            assert(impl.address() + PAGE_MAX_SIZE ==\n                   last.address() + SLOT_SIZE);\n            assert(last.address()+8 < textSegment + textSegmentSize);\n            assert((last.address() - start.address()) % SLOT_SIZE == 0);\n# if SUPPORT_STRET\n            assert(impl_stret.address() == textSegment + 2*PAGE_MAX_SIZE);\n            assert(impl_stret.address() % PAGE_SIZE == 0);  // not PAGE_MAX_SIZE\n            assert(impl_stret.address() + PAGE_MAX_SIZE ==\n                   last_stret.address() + SLOT_SIZE);\n            assert(start.address() - impl.address() ==\n                   start_stret.address() - impl_stret.address());\n            assert(last_stret.address() + SLOT_SIZE <\n                   textSegment + textSegmentSize);\n            assert((last_stret.address() - start_stret.address())\n                   % SLOT_SIZE == 0);\n# endif\n#endif\n        }\n\n\n        TrampolinePointers(void *dylib)\n            : impl(dylib, \"Impl\")\n            , start(dylib, \"Start\")\n#if DEBUG\n            , last(dylib, \"Last\")\n# if SUPPORT_STRET\n            , impl_stret(dylib, \"Impl_stret\")\n            , start_stret(dylib, \"Start_stret\")\n            , last_stret(dylib, \"Last_stret\")\n# endif\n#endif\n        {\n            const auto *mh =\n                dyld_image_header_containing_address((void *)impl.address());\n            unsigned long size = 0;\n            textSegment = (uintptr_t)\n                getsegmentdata((headerType *)mh, \"__TEXT\", &size);\n            textSegmentSize = size;\n\n            check();\n        }\n    };\n\n    std::atomic<TrampolinePointers *> trampolines{nil};\n\n    TrampolinePointers *get() {\n        return trampolines.load(MEMORY_ORDER_CONSUME);\n    }\n\npublic:\n    void Initialize() {\n        if (get()) return;\n\n        // This code may be called concurrently.\n        // In the worst case we perform extra dyld operations.\n        void *dylib = dlopen(\"/usr/lib/libobjc-trampolines.dylib\",\n                             RTLD_NOW | RTLD_LOCAL | RTLD_FIRST);\n        if (!dylib) {\n            _objc_fatal(\"couldn't dlopen libobjc-trampolines.dylib\");\n        }\n\n        auto t = new TrampolinePointers(dylib);\n        TrampolinePointers *old = nil;\n        if (! trampolines.compare_exchange_strong(old, t, memory_order_release))\n        {\n            delete t;  // Lost an initialization race.\n        }\n    }\n\n    uintptr_t textSegment() { return get()->textSegment; }\n    uintptr_t textSegmentSize() { return get()->textSegmentSize; }\n\n    uintptr_t impl() { return get()->impl.address(); }\n    uintptr_t start() { return get()->start.address(); }\n};\n\nstatic TrampolinePointerWrapper Trampolines;\n\n// argument mode identifier\ntypedef enum {\n    ReturnValueInRegisterArgumentMode,\n#if SUPPORT_STRET\n    ReturnValueOnStackArgumentMode,\n#endif\n    \n    ArgumentModeCount\n} ArgumentMode;\n\n// We must take care with our data layout on architectures that support \n// multiple page sizes.\n// \n// The trampoline template in __TEXT is sized and aligned with PAGE_MAX_SIZE.\n// On some platforms this requires additional linker flags.\n// \n// When we allocate a page group, we use PAGE_MAX_SIZE size. \n// This allows trampoline code to find its data by subtracting PAGE_MAX_SIZE.\n// \n// When we allocate a page group, we use the process's page alignment. \n// This simplifies allocation because we don't need to force greater than \n// default alignment when running with small pages, but it also means \n// the trampoline code MUST NOT look for its data by masking with PAGE_MAX_MASK.\n\nstruct TrampolineBlockPageGroup\n{\n    TrampolineBlockPageGroup *nextPageGroup; // linked list of all pages\n    TrampolineBlockPageGroup *nextAvailablePage; // linked list of pages with available slots\n    \n    uintptr_t nextAvailable; // index of next available slot, endIndex() if no more available\n    \n    // Payload data: block pointers and free list.\n    // Bytes parallel with trampoline header code are the fields above or unused\n    // uint8_t payloads[PAGE_MAX_SIZE - sizeof(TrampolineBlockPageGroup)] \n\n    // Code: Mach-O header, then trampoline header followed by trampolines.\n    // On platforms with struct return we have non-stret trampolines and\n    //     stret trampolines. The stret and non-stret trampolines at a given\n    //     index share the same data page.\n    // uint8_t macho[PAGE_MAX_SIZE];\n    // uint8_t trampolines[ArgumentModeCount][PAGE_MAX_SIZE];\n    \n    // Per-trampoline block data format:\n    // initial value is 0 while page data is filled sequentially \n    // when filled, value is reference to Block_copy()d block\n    // when empty, value is index of next available slot OR 0 if never used yet\n    \n    union Payload {\n        id block;\n        uintptr_t nextAvailable;  // free list\n    };\n    \n    static uintptr_t headerSize() {\n        return (uintptr_t) (Trampolines.start() - Trampolines.impl());\n    }\n    \n    static uintptr_t slotSize() {\n        return SLOT_SIZE;\n    }\n\n    static uintptr_t startIndex() {\n        // headerSize is assumed to be slot-aligned\n        return headerSize() / slotSize();\n    }\n\n    static uintptr_t endIndex() {\n        return (uintptr_t)PAGE_MAX_SIZE / slotSize();\n    }\n\n    static bool validIndex(uintptr_t index) {\n        return (index >= startIndex() && index < endIndex());\n    }\n\n    Payload *payload(uintptr_t index) {\n        assert(validIndex(index));\n        return (Payload *)((char *)this + index*slotSize());\n    }\n\n    uintptr_t trampolinesForMode(int aMode) {\n        // Skip over data page and Mach-O page.\n        return (uintptr_t)this + PAGE_MAX_SIZE * (2 + aMode);\n    }\n    \n    IMP trampoline(int aMode, uintptr_t index) {\n        assert(validIndex(index));\n        char *base = (char *)trampolinesForMode(aMode);\n        char *imp = base + index*slotSize();\n#if __arm__\n        imp++;  // trampoline is Thumb instructions\n#endif\n#if __has_feature(ptrauth_calls)\n        imp = ptrauth_sign_unauthenticated(imp,\n                                           ptrauth_key_function_pointer, 0);\n#endif\n        return (IMP)imp;\n    }\n\n    uintptr_t indexForTrampoline(uintptr_t tramp) {\n        for (int aMode = 0; aMode < ArgumentModeCount; aMode++) {\n            uintptr_t base  = trampolinesForMode(aMode);\n            uintptr_t start = base + startIndex() * slotSize();\n            uintptr_t end   = base + endIndex() * slotSize();\n            if (tramp >= start  &&  tramp < end) {\n                return (uintptr_t)(tramp - base) / slotSize();\n            }\n        }\n        return 0;\n    }\n\n    static void check() {\n        assert(TrampolineBlockPageGroup::headerSize() >= sizeof(TrampolineBlockPageGroup));\n        assert(TrampolineBlockPageGroup::headerSize() % TrampolineBlockPageGroup::slotSize() == 0);\n    }\n\n};\n\nstatic TrampolineBlockPageGroup *HeadPageGroup;\n\n#pragma mark Utility Functions\n\n#if !__OBJC2__\n#define runtimeLock classLock\n#endif\n\n#pragma mark Trampoline Management Functions\nstatic TrampolineBlockPageGroup *_allocateTrampolinesAndData()\n{\n    runtimeLock.assertLocked();\n\n    vm_address_t dataAddress;\n    \n    TrampolineBlockPageGroup::check();\n\n    // Our final mapping will look roughly like this:\n    //   r/w data\n    //   r/o text mapped from libobjc-trampolines.dylib\n    // with fixed offsets from the text to the data embedded in the text.\n    //\n    // More precisely it will look like this:\n    //   1 page r/w data\n    //   1 page libobjc-trampolines.dylib Mach-O header\n    //   N pages trampoline code, one for each ArgumentMode\n    //   M pages for the rest of libobjc-trampolines' TEXT segment.\n    // The kernel requires that we remap the entire TEXT segment every time.\n    // We assume that our code begins on the second TEXT page, but are robust\n    // against other additions to the end of the TEXT segment.\n\n    assert(HeadPageGroup == nil  ||  HeadPageGroup->nextAvailablePage == nil);\n\n    auto textSource = Trampolines.textSegment();\n    auto textSourceSize = Trampolines.textSegmentSize();\n    auto dataSize = PAGE_MAX_SIZE;\n\n    // Allocate a single contiguous region big enough to hold data+text.\n    kern_return_t result;\n    result = vm_allocate(mach_task_self(), &dataAddress,\n                         dataSize + textSourceSize,\n                         VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_FOUNDATION));\n    if (result != KERN_SUCCESS) {\n        _objc_fatal(\"vm_allocate trampolines failed (%d)\", result);\n    }\n\n    // Remap libobjc-trampolines' TEXT segment atop all\n    // but the first of the pages we just allocated:\n    vm_address_t textDest = dataAddress + dataSize;\n    vm_prot_t currentProtection, maxProtection;\n    result = vm_remap(mach_task_self(), &textDest,\n                      textSourceSize,\n                      0, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,\n                      mach_task_self(), textSource, TRUE, \n                      &currentProtection, &maxProtection, VM_INHERIT_SHARE);\n    if (result != KERN_SUCCESS) {\n        _objc_fatal(\"vm_remap trampolines failed (%d)\", result);\n    }\n\n    TrampolineBlockPageGroup *pageGroup = (TrampolineBlockPageGroup *) dataAddress;\n    pageGroup->nextAvailable = pageGroup->startIndex();\n    pageGroup->nextPageGroup = nil;\n    pageGroup->nextAvailablePage = nil;\n    \n    if (HeadPageGroup) {\n        TrampolineBlockPageGroup *lastPageGroup = HeadPageGroup;\n        while(lastPageGroup->nextPageGroup) {\n            lastPageGroup = lastPageGroup->nextPageGroup;\n        }\n        lastPageGroup->nextPageGroup = pageGroup;\n        HeadPageGroup->nextAvailablePage = pageGroup;\n    } else {\n        HeadPageGroup = pageGroup;\n    }\n    \n    return pageGroup;\n}\n\nstatic TrampolineBlockPageGroup *\ngetOrAllocatePageGroupWithNextAvailable() \n{\n    runtimeLock.assertLocked();\n    \n    if (!HeadPageGroup)\n        return _allocateTrampolinesAndData();\n    \n    // make sure head page is filled first\n    if (HeadPageGroup->nextAvailable != HeadPageGroup->endIndex())\n        return HeadPageGroup;\n    \n    if (HeadPageGroup->nextAvailablePage) // check if there is a page w/a hole\n        return HeadPageGroup->nextAvailablePage;\n    \n    return _allocateTrampolinesAndData(); // tack on a new one\n}\n\nstatic TrampolineBlockPageGroup *\npageAndIndexContainingIMP(IMP anImp, uintptr_t *outIndex) \n{\n    runtimeLock.assertLocked();\n\n    // Authenticate as a function pointer, returning an un-signed address.\n    uintptr_t trampAddress =\n            (uintptr_t)ptrauth_auth_data((const char *)anImp,\n                                         ptrauth_key_function_pointer, 0);\n\n    for (TrampolineBlockPageGroup *pageGroup = HeadPageGroup; \n         pageGroup;\n         pageGroup = pageGroup->nextPageGroup)\n    {\n        uintptr_t index = pageGroup->indexForTrampoline(trampAddress);\n        if (index) {\n            if (outIndex) *outIndex = index;\n            return pageGroup;\n        }\n    }\n    \n    return nil;\n}\n\n\nstatic ArgumentMode \nargumentModeForBlock(id block) \n{\n    ArgumentMode aMode = ReturnValueInRegisterArgumentMode;\n\n#if SUPPORT_STRET\n    if (_Block_has_signature(block) && _Block_use_stret(block))\n        aMode = ReturnValueOnStackArgumentMode;\n#else\n    assert(! (_Block_has_signature(block) && _Block_use_stret(block)));\n#endif\n    \n    return aMode;\n}\n\n\n// `block` must already have been copied \nIMP \n_imp_implementationWithBlockNoCopy(id block)\n{\n    runtimeLock.assertLocked();\n\n    TrampolineBlockPageGroup *pageGroup = \n        getOrAllocatePageGroupWithNextAvailable();\n\n    uintptr_t index = pageGroup->nextAvailable;\n    assert(index >= pageGroup->startIndex()  &&  index < pageGroup->endIndex());\n    TrampolineBlockPageGroup::Payload *payload = pageGroup->payload(index);\n    \n    uintptr_t nextAvailableIndex = payload->nextAvailable;\n    if (nextAvailableIndex == 0) {\n        // First time through (unused slots are zero). Fill sequentially.\n        // If the page is now full this will now be endIndex(), handled below.\n        nextAvailableIndex = index + 1;\n    }\n    pageGroup->nextAvailable = nextAvailableIndex;\n    if (nextAvailableIndex == pageGroup->endIndex()) {\n        // PageGroup is now full (free list or wilderness exhausted)\n        // Remove from available page linked list\n        TrampolineBlockPageGroup *iterator = HeadPageGroup;\n        while(iterator && (iterator->nextAvailablePage != pageGroup)) {\n            iterator = iterator->nextAvailablePage;\n        }\n        if (iterator) {\n            iterator->nextAvailablePage = pageGroup->nextAvailablePage;\n            pageGroup->nextAvailablePage = nil;\n        }\n    }\n    \n    payload->block = block;\n    return pageGroup->trampoline(argumentModeForBlock(block), index);\n}\n\n\n#pragma mark Public API\nIMP imp_implementationWithBlock(id block) \n{\n    // Block object must be copied outside runtimeLock\n    // because it performs arbitrary work.\n    block = Block_copy(block);\n\n    // Trampolines must be initialized outside runtimeLock\n    // because it calls dlopen().\n    Trampolines.Initialize();\n    \n    mutex_locker_t lock(runtimeLock);\n\n    return _imp_implementationWithBlockNoCopy(block);\n}\n\n\nid imp_getBlock(IMP anImp) {\n    uintptr_t index;\n    TrampolineBlockPageGroup *pageGroup;\n    \n    if (!anImp) return nil;\n    \n    mutex_locker_t lock(runtimeLock);\n    \n    pageGroup = pageAndIndexContainingIMP(anImp, &index);\n    \n    if (!pageGroup) {\n        return nil;\n    }\n\n    TrampolineBlockPageGroup::Payload *payload = pageGroup->payload(index);\n    \n    if (payload->nextAvailable <= TrampolineBlockPageGroup::endIndex()) {\n        // unallocated\n        return nil;\n    }\n    \n    return payload->block;\n}\n\nBOOL imp_removeBlock(IMP anImp) {\n    \n    if (!anImp) return NO;\n\n    id block;\n    \n    {\n        mutex_locker_t lock(runtimeLock);\n    \n        uintptr_t index;\n        TrampolineBlockPageGroup *pageGroup =\n            pageAndIndexContainingIMP(anImp, &index);\n        \n        if (!pageGroup) {\n            return NO;\n        }\n        \n        TrampolineBlockPageGroup::Payload *payload = pageGroup->payload(index);\n        block = payload->block;\n        // block is released below, outside the lock\n        \n        payload->nextAvailable = pageGroup->nextAvailable;\n        pageGroup->nextAvailable = index;\n        \n        // make sure this page is on available linked list\n        TrampolineBlockPageGroup *pageGroupIterator = HeadPageGroup;\n        \n        // see if page is the next available page for any existing pages\n        while (pageGroupIterator->nextAvailablePage && \n               pageGroupIterator->nextAvailablePage != pageGroup)\n        {\n            pageGroupIterator = pageGroupIterator->nextAvailablePage;\n        }\n        \n        if (! pageGroupIterator->nextAvailablePage) {\n            // if iteration stopped because nextAvail was nil\n            // add to end of list.\n            pageGroupIterator->nextAvailablePage = pageGroup;\n            pageGroup->nextAvailablePage = nil;\n        }\n    }\n\n    // do this AFTER dropping the lock\n    Block_release(block);\n    return YES;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-blocktramps-arm.s",
    "content": "#if __arm__\n\t\n#include <arm/arch.h>\n#include <mach/vm_param.h>\n\n.syntax unified\n\n.text\n.globl __objc_blockTrampolineImpl\n.globl __objc_blockTrampolineStart\n.globl __objc_blockTrampolineLast\n\n// Trampoline machinery assumes the trampolines are Thumb function pointers\n#if !__thumb2__\n#   error sorry\n#endif\n\n.thumb\n\n// Exported symbols are not marked as functions.\n// The trampoline construction code assumes that the Thumb bit is not set.\n.thumb_func L__objc_blockTrampolineImpl_func\n\n.align PAGE_MAX_SHIFT\n__objc_blockTrampolineImpl:\nL__objc_blockTrampolineImpl_func:\n\t/*\n\t r0 == self\n\t r12 == pc of trampoline's first instruction + PC bias\n\t lr == original return address\n\t */\n\n\tmov  r1, r0                   // _cmd = self\n\n\t// Trampoline's data is one page before the trampoline text.\n\t// Also correct PC bias of 4 bytes.\n\tsub  r12, # 2*PAGE_MAX_SIZE\n\tldr  r0, [r12, #-4]          // self = block object\n\tldr  pc, [r0, #12]           // tail call block->invoke\n\t// not reached\n\n\t// Align trampolines to 8 bytes\n.align 3\n\t\n.macro TrampolineEntry\n\tmov r12, pc\n\tb L__objc_blockTrampolineImpl_func\n.align 3\n.endmacro\n\n.macro TrampolineEntryX16\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\t\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\t\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\t\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n.endmacro\n\n.macro TrampolineEntryX256\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\t\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\t\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\t\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n.endmacro\n\n__objc_blockTrampolineStart:\n\t// 2048-2 trampolines to fill 16K page\n\tTrampolineEntryX256\n\tTrampolineEntryX256\n\tTrampolineEntryX256\n\tTrampolineEntryX256\n\n\tTrampolineEntryX256\n\tTrampolineEntryX256\n\tTrampolineEntryX256\n\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\n\tTrampolineEntry\n__objc_blockTrampolineLast:\n\tTrampolineEntry\n\t// TrampolineEntry\n\t// TrampolineEntry\n\n\n\n.text\n.globl __objc_blockTrampolineImpl_stret\n.globl __objc_blockTrampolineStart_stret\n.globl __objc_blockTrampolineLast_stret\n\n// Trampoline machinery assumes the trampolines are Thumb function pointers\n#if !__thumb2__\n#   error sorry\n#endif\n\n.thumb\n\n// Exported symbols are not marked as functions.\n// The trampoline construction code assumes that the Thumb bit is not set.\n.thumb_func L__objc_blockTrampolineImpl_stret_func\n\n.align PAGE_MAX_SHIFT\n__objc_blockTrampolineImpl_stret:\nL__objc_blockTrampolineImpl_stret_func:\n\t/*\n\t r1 == self\n\t r12 == pc of trampoline's first instruction + PC bias\n\t lr == original return address\n\t */\n\n\tmov  r2, r1                   // _cmd = self\n\n\t// Trampoline's data is one page before the trampoline text.\n\t// Also correct PC bias of 4 bytes.\n\tsub  r12, # 3*PAGE_MAX_SIZE\n\tldr  r1, [r12, #-4]          // self = block object\n\tldr  pc, [r1, #12]           // tail call block->invoke\n\t// not reached\n\n\t// Align trampolines to 8 bytes\n.align 3\n\t\n.macro TrampolineEntry_stret\n\tmov r12, pc\n\tb L__objc_blockTrampolineImpl_stret_func\n.align 3\n.endmacro\n\n.macro TrampolineEntryX16_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\t\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\t\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\t\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n.endmacro\n\n.macro TrampolineEntryX256_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\t\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\t\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\t\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n.endmacro\n\n__objc_blockTrampolineStart_stret:\n\t// 2048-2 trampolines to fill 16K page\n\tTrampolineEntryX256_stret\n\tTrampolineEntryX256_stret\n\tTrampolineEntryX256_stret\n\tTrampolineEntryX256_stret\n\n\tTrampolineEntryX256_stret\n\tTrampolineEntryX256_stret\n\tTrampolineEntryX256_stret\n\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\tTrampolineEntryX16_stret\n\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\tTrampolineEntry_stret\n\n\tTrampolineEntry_stret\n__objc_blockTrampolineLast_stret:\n\tTrampolineEntry_stret\n\t// TrampolineEntry_stret\n\t// TrampolineEntry_stret\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-blocktramps-arm64.s",
    "content": "#if __arm64__\n\n#include <mach/vm_param.h>\n#include \"arm64-asm.h\"\n\n// Offset of block->invoke field.\n#if __LP64__\n    // true arm64\n#   define BLOCK_INVOKE 16\n#else\n    // arm64_32\n#   define BLOCK_INVOKE 12\n#endif\n\n.text\n.globl __objc_blockTrampolineImpl\n.globl __objc_blockTrampolineStart\n.globl __objc_blockTrampolineLast\n\t\n.align PAGE_MAX_SHIFT\n__objc_blockTrampolineImpl:\nL_objc_blockTrampolineImpl:\n\t/*\n\t x0  == self\n\t x17 == address of called trampoline's data (2 pages before its code)\n\t lr  == original return address\n\t */\n\n\tmov  x1, x0                  // _cmd = self\n\tldr  p0, [x17]               // self = block object\n\tadd  p15, p0, #BLOCK_INVOKE  // x15 = &block->invoke\n\tldr  p16, [x15]              // x16 = block->invoke\n\tTailCallBlockInvoke x16, x15\n\n\t// pad up to TrampolineBlockPagePair header size\n\tnop\n\t\n.macro TrampolineEntry\n\t// load address of trampoline data (two pages before this instruction)\n\tadr  x17, -2*PAGE_MAX_SIZE\n\tb    L_objc_blockTrampolineImpl\n.endmacro\n\n.macro TrampolineEntryX16\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\t\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\t\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\t\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n.endmacro\n\n.macro TrampolineEntryX256\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\t\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\t\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\t\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n.endmacro\n\t\n.align 3\n__objc_blockTrampolineStart:\n\t// 2048-3 trampolines to fill 16K page\n\tTrampolineEntryX256\n\tTrampolineEntryX256\n\tTrampolineEntryX256\n\tTrampolineEntryX256\n\n\tTrampolineEntryX256\n\tTrampolineEntryX256\n\tTrampolineEntryX256\n\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\tTrampolineEntryX16\n\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\tTrampolineEntry\n\n__objc_blockTrampolineLast:\n\tTrampolineEntry\n\t// TrampolineEntry\n\t// TrampolineEntry\n\t// TrampolineEntry\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-blocktramps-i386.s",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifdef __i386__\n\n#include <mach/vm_param.h>\n\t\n.text\n.globl __objc_blockTrampolineImpl\n.globl __objc_blockTrampolineStart\n.globl __objc_blockTrampolineLast\n\n.align PAGE_SHIFT\n__objc_blockTrampolineImpl:\n    popl %eax\n    andl $0xFFFFFFF8, %eax\n    subl $ 2*PAGE_SIZE, %eax\n    movl 4(%esp), %ecx // self -> ecx\n    movl %ecx, 8(%esp) // ecx -> _cmd\n    movl (%eax), %ecx // blockPtr -> ecx\n    movl %ecx, 4(%esp) // ecx -> self\n    jmp  *12(%ecx) // tail to block->invoke\n\n.macro TrampolineEntry\n    call __objc_blockTrampolineImpl\n    nop\n    nop\n    nop\n.endmacro\n\n.align 5\n__objc_blockTrampolineStart:\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n__objc_blockTrampolineLast:\n    TrampolineEntry\n\n\n.text\n.globl __objc_blockTrampolineImpl_stret\n.globl __objc_blockTrampolineStart_stret\n.globl __objc_blockTrampolineLast_stret\n\n.align PAGE_SHIFT\n__objc_blockTrampolineImpl_stret:\n    popl %eax\n    andl $0xFFFFFFF8, %eax\n    subl $ 3*PAGE_SIZE, %eax\n    movl 8(%esp), %ecx // self -> ecx\n    movl %ecx, 12(%esp) // ecx -> _cmd\n    movl (%eax), %ecx // blockPtr -> ecx\n    movl %ecx, 8(%esp) // ecx -> self\n    jmp  *12(%ecx) // tail to block->invoke\n\n.macro TrampolineEntry_stret\n    call __objc_blockTrampolineImpl_stret\n    nop\n    nop\n    nop\n.endmacro\n\n.align 5\n__objc_blockTrampolineStart_stret:\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n__objc_blockTrampolineLast_stret:\n    TrampolineEntry_stret\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-blocktramps-x86_64.s",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifdef __x86_64__\n\n#include <mach/vm_param.h>\n\n.text\n.globl __objc_blockTrampolineImpl\n.globl __objc_blockTrampolineStart\n.globl __objc_blockTrampolineLast\n\n.align PAGE_SHIFT\n__objc_blockTrampolineImpl:\n    popq %r10\n    andq $0xFFFFFFFFFFFFFFF8, %r10\n    subq $ 2*PAGE_SIZE, %r10\n    movq %rdi, %rsi // arg1 -> arg2\n    movq (%r10), %rdi // block -> arg1\n    jmp  *16(%rdi)\n\n.macro TrampolineEntry\n    callq __objc_blockTrampolineImpl\n    nop\n    nop\n    nop\n.endmacro\n\n.align 5\n__objc_blockTrampolineStart:\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n    TrampolineEntry\n__objc_blockTrampolineLast:\n    TrampolineEntry\n\n\n.text\n.globl __objc_blockTrampolineImpl_stret\n.globl __objc_blockTrampolineStart_stret\n.globl __objc_blockTrampolineLast_stret\n\n.align PAGE_SHIFT\n__objc_blockTrampolineImpl_stret:\n    popq %r10\n    andq $0xFFFFFFFFFFFFFFF8, %r10\n    subq $ 3*PAGE_SIZE, %r10\n    // %rdi -- first arg -- is address of return value's space. Don't mess with it.\n    movq %rsi, %rdx // arg2 -> arg3\n    movq (%r10), %rsi // block -> arg2\n    jmp  *16(%rsi)\n\n.macro TrampolineEntry_stret\n    callq __objc_blockTrampolineImpl_stret\n    nop\n    nop\n    nop\n.endmacro\n\n.align 5\n__objc_blockTrampolineStart_stret:\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n    TrampolineEntry_stret\n__objc_blockTrampolineLast_stret:\n    TrampolineEntry_stret\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-cache-old.h",
    "content": "/*\n * Copyright (c) 2012 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _OBJC_CACHE_OLD_H\n#define _OBJC_CACHE_OLD_H\n\n#include \"objc-private.h\"\n\n__BEGIN_DECLS\n\nextern IMP _cache_getImp(Class cls, SEL sel);\nextern Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_internal_imp);\n\nextern void flush_cache(Class cls);\nextern bool _cache_fill(Class cls, Method meth, SEL sel);\nextern void _cache_addForwardEntry(Class cls, SEL sel);\nextern IMP  _cache_addIgnoredEntry(Class cls, SEL sel);\nextern void _cache_free(Cache cache);\nextern void _cache_collect(bool collectALot);\n\n__END_DECLS\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-cache-old.mm",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-cache.m\n* Method cache management\n* Cache flushing\n* Cache garbage collection\n* Cache instrumentation\n* Dedicated allocator for large caches\n**********************************************************************/\n\n\n/***********************************************************************\n * Method cache locking (GrP 2001-1-14)\n *\n * For speed, objc_msgSend does not acquire any locks when it reads \n * method caches. Instead, all cache changes are performed so that any \n * objc_msgSend running concurrently with the cache mutator will not \n * crash or hang or get an incorrect result from the cache. \n *\n * When cache memory becomes unused (e.g. the old cache after cache \n * expansion), it is not immediately freed, because a concurrent \n * objc_msgSend could still be using it. Instead, the memory is \n * disconnected from the data structures and placed on a garbage list. \n * The memory is now only accessible to instances of objc_msgSend that \n * were running when the memory was disconnected; any further calls to \n * objc_msgSend will not see the garbage memory because the other data \n * structures don't point to it anymore. The collecting_in_critical\n * function checks the PC of all threads and returns FALSE when all threads \n * are found to be outside objc_msgSend. This means any call to objc_msgSend \n * that could have had access to the garbage has finished or moved past the \n * cache lookup stage, so it is safe to free the memory.\n *\n * All functions that modify cache data or structures must acquire the \n * cacheUpdateLock to prevent interference from concurrent modifications.\n * The function that frees cache garbage must acquire the cacheUpdateLock \n * and use collecting_in_critical() to flush out cache readers.\n * The cacheUpdateLock is also used to protect the custom allocator used \n * for large method cache blocks.\n *\n * Cache readers (PC-checked by collecting_in_critical())\n * objc_msgSend*\n * _cache_getImp\n * _cache_getMethod\n *\n * Cache writers (hold cacheUpdateLock while reading or writing; not PC-checked)\n * _cache_fill         (acquires lock)\n * _cache_expand       (only called from cache_fill)\n * _cache_create       (only called from cache_expand)\n * bcopy               (only called from instrumented cache_expand)\n * flush_caches        (acquires lock)\n * _cache_flush        (only called from cache_fill and flush_caches)\n * _cache_collect_free (only called from cache_expand and cache_flush)\n *\n * UNPROTECTED cache readers (NOT thread-safe; used for debug info only)\n * _cache_print\n * _class_printMethodCaches\n * _class_printDuplicateCacheEntries\n * _class_printMethodCacheStatistics\n *\n * _class_lookupMethodAndLoadCache is a special case. It may read a \n * method triplet out of one cache and store it in another cache. This \n * is unsafe if the method triplet is a forward:: entry, because the \n * triplet itself could be freed unless _class_lookupMethodAndLoadCache \n * were PC-checked or used a lock. Additionally, storing the method \n * triplet in both caches would result in double-freeing if both caches \n * were flushed or expanded. The solution is for _cache_getMethod to \n * ignore all entries whose implementation is _objc_msgForward_impcache, \n * so _class_lookupMethodAndLoadCache cannot look at a forward:: entry\n * unsafely or place it in multiple caches.\n ***********************************************************************/\n\n#if !__OBJC2__\n\n#include \"objc-private.h\"\n#include \"objc-cache-old.h\"\n#include \"hashtable2.h\"\n\ntypedef struct {\n    SEL name;     // same layout as struct old_method\n    void *unused;\n    IMP imp;  // same layout as struct old_method\n} cache_entry;\n\n\n/* When _class_slow_grow is non-zero, any given cache is actually grown\n * only on the odd-numbered times it becomes full; on the even-numbered\n * times, it is simply emptied and re-used.  When this flag is zero,\n * caches are grown every time. */\nstatic const int _class_slow_grow = 1;\n\n/* For min cache size: clear_cache=1, slow_grow=1\n   For max cache size: clear_cache=0, slow_grow=0 */\n\n/* Initial cache bucket count. INIT_CACHE_SIZE must be a power of two. */\nenum {\n    INIT_CACHE_SIZE_LOG2 = 2,\n    INIT_CACHE_SIZE      = (1 << INIT_CACHE_SIZE_LOG2)\n};\n\n\n/* Amount of space required for `count` hash table buckets, knowing that\n * one entry is embedded in the cache structure itself. */\n#define TABLE_SIZE(count)  ((count - 1) * sizeof(cache_entry *))\n\n\n#if !TARGET_OS_WIN32\n#   define CACHE_ALLOCATOR\n#endif\n\n/* Custom cache allocator parameters.\n * CACHE_REGION_SIZE must be a multiple of CACHE_QUANTUM. */\n#define CACHE_ALLOCATOR_MIN 512\n#define CACHE_QUANTUM (CACHE_ALLOCATOR_MIN+sizeof(struct objc_cache)-sizeof(cache_entry*))\n#define CACHE_REGION_SIZE ((128*1024 / CACHE_QUANTUM) * CACHE_QUANTUM)\n// #define CACHE_REGION_SIZE ((256*1024 / CACHE_QUANTUM) * CACHE_QUANTUM)\n\nstatic uintptr_t cache_allocator_mask_for_size(size_t size)\n{\n    return (size - sizeof(struct objc_cache)) / sizeof(cache_entry *);\n}\n\nstatic size_t cache_allocator_size_for_mask(uintptr_t mask)\n{\n    size_t requested = sizeof(struct objc_cache) + TABLE_SIZE(mask+1);\n    size_t actual = CACHE_QUANTUM;\n    while (actual < requested) actual += CACHE_QUANTUM;\n    return actual;\n}\n\n\n/* Cache instrumentation data. Immediately follows the cache block itself. */\n#ifdef OBJC_INSTRUMENTED\ntypedef struct\n{\n    unsigned int hitCount;           // cache lookup success tally\n    unsigned int hitProbes;          // sum entries checked to hit\n    unsigned int maxHitProbes;       // max entries checked to hit\n    unsigned int missCount;          // cache lookup no-find tally\n    unsigned int missProbes;         // sum entries checked to miss\n    unsigned int maxMissProbes;      // max entries checked to miss\n    unsigned int flushCount;         // cache flush tally\n    unsigned int flushedEntries;     // sum cache entries flushed\n    unsigned int maxFlushedEntries;  // max cache entries flushed\n} CacheInstrumentation;\n\n#define CACHE_INSTRUMENTATION(cache)  (CacheInstrumentation *) &cache->buckets[cache->mask + 1];\n#endif\n\n/* Cache filling and flushing instrumentation */\n\nstatic int totalCacheFills = 0;\n\n#ifdef OBJC_INSTRUMENTED\nunsigned int LinearFlushCachesCount              = 0;\nunsigned int LinearFlushCachesVisitedCount       = 0;\nunsigned int MaxLinearFlushCachesVisitedCount    = 0;\nunsigned int NonlinearFlushCachesCount           = 0;\nunsigned int NonlinearFlushCachesClassCount      = 0;\nunsigned int NonlinearFlushCachesVisitedCount    = 0;\nunsigned int MaxNonlinearFlushCachesVisitedCount = 0;\nunsigned int IdealFlushCachesCount               = 0;\nunsigned int MaxIdealFlushCachesCount            = 0;\n#endif\n\n\n/***********************************************************************\n* A static empty cache.  All classes initially point at this cache.\n* When the first message is sent it misses in the cache, and when\n* the cache is grown it checks for this case and uses malloc rather\n* than realloc.  This avoids the need to check for NULL caches in the\n* messenger.\n***********************************************************************/\n\nstruct objc_cache _objc_empty_cache =\n{\n    0,        // mask\n    0,        // occupied\n    { NULL }  // buckets\n};\n#ifdef OBJC_INSTRUMENTED\nCacheInstrumentation emptyCacheInstrumentation = {0};\n#endif\n\n\n/* Local prototypes */\n\nstatic bool _cache_isEmpty(Cache cache);\nstatic Cache _cache_malloc(uintptr_t slotCount);\nstatic Cache _cache_create(Class cls);\nstatic Cache _cache_expand(Class cls);\n\nstatic int _collecting_in_critical(void);\nstatic void _garbage_make_room(void);\nstatic void _cache_collect_free(void *data, size_t size);\n\n#if defined(CACHE_ALLOCATOR)\nstatic bool cache_allocator_is_block(void *block);\nstatic Cache cache_allocator_calloc(size_t size);\nstatic void cache_allocator_free(void *block);\n#endif\n\n/***********************************************************************\n* Cache statistics for OBJC_PRINT_CACHE_SETUP\n**********************************************************************/\nstatic unsigned int cache_counts[16];\nstatic size_t cache_allocations;\nstatic size_t cache_collections;\nstatic size_t cache_allocator_regions;\n\nstatic size_t log2u(size_t x)\n{\n    unsigned int log;\n\n    log = 0;\n    while (x >>= 1)\n        log += 1;\n\n    return log;\n}\n\n\n/***********************************************************************\n* _cache_isEmpty.\n* Returns YES if the given cache is some empty cache.\n* Empty caches should never be allocated on the heap.\n**********************************************************************/\nstatic bool _cache_isEmpty(Cache cache)\n{\n    return (cache == NULL  ||  cache == (Cache)&_objc_empty_cache  ||  cache->mask == 0);\n}\n\n\n/***********************************************************************\n* _cache_malloc.\n*\n* Called from _cache_create() and cache_expand()\n* Cache locks: cacheUpdateLock must be held by the caller.\n**********************************************************************/\nstatic Cache _cache_malloc(uintptr_t slotCount)\n{\n    Cache new_cache;\n    size_t size;\n\n    cacheUpdateLock.assertLocked();\n\n    // Allocate table (why not check for failure?)\n    size = sizeof(struct objc_cache) + TABLE_SIZE(slotCount);\n#if defined(OBJC_INSTRUMENTED)\n    // Custom cache allocator can't handle instrumentation.\n    size += sizeof(CacheInstrumentation);\n    new_cache = calloc(size, 1);\n    new_cache->mask = slotCount - 1;\n#elif !defined(CACHE_ALLOCATOR)\n    // fixme cache allocator implementation isn't 64-bit clean\n    new_cache = calloc(size, 1);\n    new_cache->mask = (unsigned int)(slotCount - 1);\n#else\n    if (size < CACHE_ALLOCATOR_MIN) {\n        new_cache = (Cache)calloc(size, 1);\n        new_cache->mask = slotCount - 1;\n        // occupied and buckets and instrumentation are all zero\n    } else {\n        new_cache = cache_allocator_calloc(size);\n        // mask is already set\n        // occupied and buckets and instrumentation are all zero\n    }\n#endif\n\n    if (PrintCaches) {\n        size_t bucket = log2u(slotCount);\n        if (bucket < sizeof(cache_counts) / sizeof(cache_counts[0])) {\n            cache_counts[bucket]++;\n        }\n        cache_allocations++;\n    }\n\n    return new_cache;\n}\n\n/***********************************************************************\n* _cache_free_block.\n*\n* Called from _cache_free() and _cache_collect_free().\n* block may be a cache or a forward:: entry.\n* If block is a cache, forward:: entries it points to will NOT be freed.\n* Cache locks: cacheUpdateLock must be held by the caller.\n**********************************************************************/\nstatic inline int isPowerOf2(unsigned long l) { return 1 == __builtin_popcountl(l); }\nstatic void _cache_free_block(void *block)\n{\n    cacheUpdateLock.assertLocked();\n\n#if !TARGET_OS_WIN32\n    if (PrintCaches) {\n        Cache cache = (Cache)block;\n        size_t slotCount = cache->mask + 1;\n        if (isPowerOf2(slotCount)) {\n            size_t bucket = log2u(slotCount);\n            if (bucket < sizeof(cache_counts) / sizeof(cache_counts[0])) {\n                cache_counts[bucket]--;\n            }\n        }\n    }\n#endif\n\n#if defined(CACHE_ALLOCATOR)\n    if (cache_allocator_is_block(block)) {\n        cache_allocator_free(block);\n    } else \n#endif\n    {\n        free(block);\n    }\n}\n\n\n/***********************************************************************\n* _cache_free.\n*\n* Called from _objc_remove_classes_in_image().\n* forward:: entries in the cache ARE freed.\n* Cache locks: cacheUpdateLock must NOT be held by the caller.\n**********************************************************************/\nvoid _cache_free(Cache cache)\n{\n    unsigned int i;\n\n    mutex_locker_t lock(cacheUpdateLock);\n\n    for (i = 0; i < cache->mask + 1; i++) {\n        cache_entry *entry = (cache_entry *)cache->buckets[i];\n        if (entry  &&  entry->imp == _objc_msgForward_impcache) {\n            _cache_free_block(entry);\n        }\n    }\n    \n    _cache_free_block(cache);\n}\n\n\n/***********************************************************************\n* _cache_create.\n*\n* Called from _cache_expand().\n* Cache locks: cacheUpdateLock must be held by the caller.\n**********************************************************************/\nstatic Cache _cache_create(Class cls)\n{\n    Cache new_cache;\n\n    cacheUpdateLock.assertLocked();\n\n    // Allocate new cache block\n    new_cache = _cache_malloc(INIT_CACHE_SIZE);\n\n    // Install the cache\n    cls->cache = new_cache;\n\n    // Clear the grow flag so that we will re-use the current storage,\n    // rather than actually grow the cache, when expanding the cache\n    // for the first time\n    if (_class_slow_grow) {\n        cls->setShouldGrowCache(false);\n    }\n\n    // Return our creation\n    return new_cache;\n}\n\n\n/***********************************************************************\n* _cache_expand.\n*\n* Called from _cache_fill ()\n* Cache locks: cacheUpdateLock must be held by the caller.\n**********************************************************************/\nstatic Cache _cache_expand(Class cls)\n{\n    Cache old_cache;\n    Cache new_cache;\n    uintptr_t slotCount;\n    uintptr_t index;\n\n    cacheUpdateLock.assertLocked();\n\n    // First growth goes from empty cache to a real one\n    old_cache = cls->cache;\n    if (_cache_isEmpty(old_cache))\n        return _cache_create (cls);\n\n    if (_class_slow_grow) {\n        // Cache grows every other time only.\n        if (cls->shouldGrowCache()) {\n            // Grow the cache this time. Don't grow next time.\n            cls->setShouldGrowCache(false);\n        } \n        else {\n            // Reuse the current cache storage this time. Do grow next time.\n            cls->setShouldGrowCache(true);\n\n            // Clear the valid-entry counter\n            old_cache->occupied = 0;\n\n            // Invalidate all the cache entries\n            for (index = 0; index < old_cache->mask + 1; index += 1)\n            {\n                // Remember what this entry was, so we can possibly\n                // deallocate it after the bucket has been invalidated\n                cache_entry *oldEntry = (cache_entry *)old_cache->buckets[index];\n                \n                // Skip invalid entry\n                if (!oldEntry)\n                    continue;\n\n                // Invalidate this entry\n                old_cache->buckets[index] = NULL;\n\n                // Deallocate \"forward::\" entry\n                if (oldEntry->imp == _objc_msgForward_impcache) {\n                    _cache_collect_free (oldEntry, sizeof(cache_entry));\n                }\n            }\n\n            // Return the same old cache, freshly emptied\n            return old_cache;\n        }\n    }\n\n    // Double the cache size\n    slotCount = (old_cache->mask + 1) << 1;\n\n    new_cache = _cache_malloc(slotCount);\n\n#ifdef OBJC_INSTRUMENTED\n    // Propagate the instrumentation data\n    {\n        CacheInstrumentation *oldCacheData;\n        CacheInstrumentation *newCacheData;\n\n        oldCacheData = CACHE_INSTRUMENTATION(old_cache);\n        newCacheData = CACHE_INSTRUMENTATION(new_cache);\n        bcopy ((const char *)oldCacheData, (char *)newCacheData, sizeof(CacheInstrumentation));\n    }\n#endif\n\n    // Deallocate \"forward::\" entries from the old cache\n    for (index = 0; index < old_cache->mask + 1; index++) {\n        cache_entry *entry = (cache_entry *)old_cache->buckets[index];\n        if (entry && entry->imp == _objc_msgForward_impcache) {\n            _cache_collect_free (entry, sizeof(cache_entry));\n        }\n    }\n\n    // Install new cache\n    cls->cache = new_cache;\n\n    // Deallocate old cache, try freeing all the garbage\n    _cache_collect_free (old_cache, old_cache->mask * sizeof(cache_entry *));\n    _cache_collect(false);\n\n    return new_cache;\n}\n\n\n/***********************************************************************\n* _cache_fill.  Add the specified method to the specified class' cache.\n* Returns NO if the cache entry wasn't added: cache was busy, \n*  class is still being initialized, new entry is a duplicate.\n*\n* Called only from _class_lookupMethodAndLoadCache and\n* class_respondsToMethod and _cache_addForwardEntry.\n*\n* Cache locks: cacheUpdateLock must not be held.\n**********************************************************************/\nbool _cache_fill(Class cls, Method smt, SEL sel)\n{\n    uintptr_t newOccupied;\n    uintptr_t index;\n    cache_entry **buckets;\n    cache_entry *entry;\n    Cache cache;\n\n    cacheUpdateLock.assertUnlocked();\n\n    // Never cache before +initialize is done\n    if (!cls->isInitialized()) {\n        return NO;\n    }\n\n    // Keep tally of cache additions\n    totalCacheFills += 1;\n\n    mutex_locker_t lock(cacheUpdateLock);\n\n    entry = (cache_entry *)smt;\n\n    cache = cls->cache;\n\n    // Make sure the entry wasn't added to the cache by some other thread \n    // before we grabbed the cacheUpdateLock.\n    // Don't use _cache_getMethod() because _cache_getMethod() doesn't \n    // return forward:: entries.\n    if (_cache_getImp(cls, sel)) {\n        return NO; // entry is already cached, didn't add new one\n    }\n\n    // Use the cache as-is if it is less than 3/4 full\n    newOccupied = cache->occupied + 1;\n    if ((newOccupied * 4) <= (cache->mask + 1) * 3) {\n        // Cache is less than 3/4 full.\n        cache->occupied = (unsigned int)newOccupied;\n    } else {\n        // Cache is too full. Expand it.\n        cache = _cache_expand (cls);\n\n        // Account for the addition\n        cache->occupied += 1;\n    }\n\n    // Scan for the first unused slot and insert there.\n    // There is guaranteed to be an empty slot because the \n    // minimum size is 4 and we resized at 3/4 full.\n    buckets = (cache_entry **)cache->buckets;\n    for (index = CACHE_HASH(sel, cache->mask); \n         buckets[index] != NULL; \n         index = (index+1) & cache->mask)\n    {\n        // empty\n    }\n    buckets[index] = entry;\n\n    return YES; // successfully added new cache entry\n}\n\n\n/***********************************************************************\n* _cache_addForwardEntry\n* Add a forward:: entry  for the given selector to cls's method cache.\n* Does nothing if the cache addition fails for any reason.\n* Called from class_respondsToMethod and _class_lookupMethodAndLoadCache.\n* Cache locks: cacheUpdateLock must not be held.\n**********************************************************************/\nvoid _cache_addForwardEntry(Class cls, SEL sel)\n{\n    cache_entry *smt;\n  \n    smt = (cache_entry *)malloc(sizeof(cache_entry));\n    smt->name = sel;\n    smt->imp = _objc_msgForward_impcache;\n    if (! _cache_fill(cls, (Method)smt, sel)) {  // fixme hack\n        // Entry not added to cache. Don't leak the method struct.\n        free(smt);\n    }\n}\n\n\n/***********************************************************************\n* _cache_flush.  Invalidate all valid entries in the given class' cache.\n*\n* Called from flush_caches() and _cache_fill()\n* Cache locks: cacheUpdateLock must be held by the caller.\n**********************************************************************/\nvoid _cache_flush(Class cls)\n{\n    Cache cache;\n    unsigned int index;\n\n    cacheUpdateLock.assertLocked();\n\n    // Locate cache.  Ignore unused cache.\n    cache = cls->cache;\n    if (_cache_isEmpty(cache)) return;\n\n#ifdef OBJC_INSTRUMENTED\n    {\n        CacheInstrumentation *cacheData;\n\n        // Tally this flush\n        cacheData = CACHE_INSTRUMENTATION(cache);\n        cacheData->flushCount += 1;\n        cacheData->flushedEntries += cache->occupied;\n        if (cache->occupied > cacheData->maxFlushedEntries)\n            cacheData->maxFlushedEntries = cache->occupied;\n    }\n#endif\n\n    // Traverse the cache\n    for (index = 0; index <= cache->mask; index += 1)\n    {\n        // Remember what this entry was, so we can possibly\n        // deallocate it after the bucket has been invalidated\n        cache_entry *oldEntry = (cache_entry *)cache->buckets[index];\n\n        // Invalidate this entry\n        cache->buckets[index] = NULL;\n\n        // Deallocate \"forward::\" entry\n        if (oldEntry && oldEntry->imp == _objc_msgForward_impcache)\n            _cache_collect_free (oldEntry, sizeof(cache_entry));\n    }\n\n    // Clear the valid-entry counter\n    cache->occupied = 0;\n}\n\n\n/***********************************************************************\n* flush_cache.  Flushes the instance method cache for class cls only.\n* Use flush_caches() if cls might have in-use subclasses.\n**********************************************************************/\nvoid flush_cache(Class cls)\n{\n    if (cls) {\n        mutex_locker_t lock(cacheUpdateLock);\n        _cache_flush(cls);\n    }\n}\n\n\n/***********************************************************************\n* cache collection.\n**********************************************************************/\n\n#if !TARGET_OS_WIN32\n\n// A sentinel (magic value) to report bad thread_get_state status.\n// Must not be a valid PC.\n// Must not be zero - thread_get_state() on a new thread returns PC == 0.\n#define PC_SENTINEL  1\n\n// UNIX03 compliance hack (4508809)\n#if !__DARWIN_UNIX03\n#define __srr0 srr0\n#define __eip eip\n#endif\n\nstatic uintptr_t _get_pc_for_thread(thread_t thread)\n#if defined(__i386__)\n{\n    i386_thread_state_t state;\n    unsigned int count = i386_THREAD_STATE_COUNT;\n    kern_return_t okay = thread_get_state (thread, i386_THREAD_STATE, (thread_state_t)&state, &count);\n    return (okay == KERN_SUCCESS) ? state.__eip : PC_SENTINEL;\n}\n#elif defined(__x86_64__)\n{\n    x86_thread_state64_t\t\t\tstate;\n    unsigned int count = x86_THREAD_STATE64_COUNT;\n    kern_return_t okay = thread_get_state (thread, x86_THREAD_STATE64, (thread_state_t)&state, &count);\n    return (okay == KERN_SUCCESS) ? state.__rip : PC_SENTINEL;\n}\n#elif defined(__arm__)\n{\n    arm_thread_state_t state;\n    unsigned int count = ARM_THREAD_STATE_COUNT;\n    kern_return_t okay = thread_get_state (thread, ARM_THREAD_STATE, (thread_state_t)&state, &count);\n    return (okay == KERN_SUCCESS) ? state.__pc : PC_SENTINEL;\n}\n#else\n{\n#error _get_pc_for_thread () not implemented for this architecture\n}\n#endif\n\n#endif\n\n/***********************************************************************\n* _collecting_in_critical.\n* Returns TRUE if some thread is currently executing a cache-reading \n* function. Collection of cache garbage is not allowed when a cache-\n* reading function is in progress because it might still be using \n* the garbage memory.\n**********************************************************************/\nextern \"C\" uintptr_t objc_entryPoints[];\nextern \"C\" uintptr_t objc_exitPoints[];\n\nstatic int _collecting_in_critical(void)\n{\n#if TARGET_OS_WIN32\n    return TRUE;\n#else\n    thread_act_port_array_t threads;\n    unsigned number;\n    unsigned count;\n    kern_return_t ret;\n    int result;\n\n    mach_port_t mythread = pthread_mach_thread_np(pthread_self());\n\n    // Get a list of all the threads in the current task\n    ret = task_threads (mach_task_self (), &threads, &number);\n    if (ret != KERN_SUCCESS)\n    {\n        _objc_fatal(\"task_thread failed (result %d)\\n\", ret);\n    }\n\n    // Check whether any thread is in the cache lookup code\n    result = FALSE;\n    for (count = 0; count < number; count++)\n    {\n        int region;\n        uintptr_t pc;\n\n        // Don't bother checking ourselves\n        if (threads[count] == mythread)\n            continue;\n\n        // Find out where thread is executing\n        pc = _get_pc_for_thread (threads[count]);\n\n        // Check for bad status, and if so, assume the worse (can't collect)\n        if (pc == PC_SENTINEL)\n        {\n            result = TRUE;\n            goto done;\n        }\n        \n        // Check whether it is in the cache lookup code\n        for (region = 0; objc_entryPoints[region] != 0; region++)\n        {\n            if ((pc >= objc_entryPoints[region]) &&\n                (pc <= objc_exitPoints[region])) \n            {\n                result = TRUE;\n                goto done;\n            }\n        }\n    }\n\n done:\n    // Deallocate the port rights for the threads\n    for (count = 0; count < number; count++) {\n        mach_port_deallocate(mach_task_self (), threads[count]);\n    }\n\n    // Deallocate the thread list\n    vm_deallocate (mach_task_self (), (vm_address_t) threads, sizeof(threads[0]) * number);\n\n    // Return our finding\n    return result;\n#endif\n}\n\n\n/***********************************************************************\n* _garbage_make_room.  Ensure that there is enough room for at least\n* one more ref in the garbage.\n**********************************************************************/\n\n// amount of memory represented by all refs in the garbage\nstatic size_t garbage_byte_size = 0;\n\n// do not empty the garbage until garbage_byte_size gets at least this big\nstatic size_t garbage_threshold = 1024;\n\n// table of refs to free\nstatic void **garbage_refs = 0;\n\n// current number of refs in garbage_refs\nstatic size_t garbage_count = 0;\n\n// capacity of current garbage_refs\nstatic size_t garbage_max = 0;\n\n// capacity of initial garbage_refs\nenum {\n    INIT_GARBAGE_COUNT = 128\n};\n\nstatic void _garbage_make_room(void)\n{\n    static int first = 1;\n\n    // Create the collection table the first time it is needed\n    if (first)\n    {\n        first = 0;\n        garbage_refs = (void**)\n            malloc(INIT_GARBAGE_COUNT * sizeof(void *));\n        garbage_max = INIT_GARBAGE_COUNT;\n    }\n\n    // Double the table if it is full\n    else if (garbage_count == garbage_max)\n    {\n        garbage_refs = (void**)\n            realloc(garbage_refs, garbage_max * 2 * sizeof(void *));\n        garbage_max *= 2;\n    }\n}\n\n\n/***********************************************************************\n* _cache_collect_free.  Add the specified malloc'd memory to the list\n* of them to free at some later point.\n* size is used for the collection threshold. It does not have to be \n* precisely the block's size.\n* Cache locks: cacheUpdateLock must be held by the caller.\n**********************************************************************/\nstatic void _cache_collect_free(void *data, size_t size)\n{\n    cacheUpdateLock.assertLocked();\n\n    _garbage_make_room ();\n    garbage_byte_size += size;\n    garbage_refs[garbage_count++] = data;\n}\n\n\n/***********************************************************************\n* _cache_collect.  Try to free accumulated dead caches.\n* collectALot tries harder to free memory.\n* Cache locks: cacheUpdateLock must be held by the caller.\n**********************************************************************/\nvoid _cache_collect(bool collectALot)\n{\n    cacheUpdateLock.assertLocked();\n\n    // Done if the garbage is not full\n    if (garbage_byte_size < garbage_threshold  &&  !collectALot) {\n        return;\n    }\n\n    // Synchronize collection with objc_msgSend and other cache readers\n    if (!collectALot) {\n        if (_collecting_in_critical ()) {\n            // objc_msgSend (or other cache reader) is currently looking in\n            // the cache and might still be using some garbage.\n            if (PrintCaches) {\n                _objc_inform (\"CACHES: not collecting; \"\n                              \"objc_msgSend in progress\");\n            }\n            return;\n        }\n    } \n    else {\n        // No excuses.\n        while (_collecting_in_critical()) \n            ;\n    }\n\n    // No cache readers in progress - garbage is now deletable\n\n    // Log our progress\n    if (PrintCaches) {\n        cache_collections++;\n        _objc_inform (\"CACHES: COLLECTING %zu bytes (%zu regions, %zu allocations, %zu collections)\", garbage_byte_size, cache_allocator_regions, cache_allocations, cache_collections);\n    }\n    \n    // Dispose all refs now in the garbage\n    while (garbage_count--) {\n        _cache_free_block(garbage_refs[garbage_count]);\n    }\n    \n    // Clear the garbage count and total size indicator\n    garbage_count = 0;\n    garbage_byte_size = 0;\n\n    if (PrintCaches) {\n        size_t i;\n        size_t total = 0;\n        size_t ideal_total = 0;\n        size_t malloc_total = 0;\n        size_t local_total = 0;\n\n        for (i = 0; i < sizeof(cache_counts) / sizeof(cache_counts[0]); i++) {\n            int count = cache_counts[i];\n            int slots = 1 << i;\n            size_t size = sizeof(struct objc_cache) + TABLE_SIZE(slots);\n            size_t ideal = size;\n#if TARGET_OS_WIN32\n            size_t malloc = size;\n#else\n            size_t malloc = malloc_good_size(size);\n#endif\n            size_t local = size < CACHE_ALLOCATOR_MIN ? malloc : cache_allocator_size_for_mask(cache_allocator_mask_for_size(size));\n\n            if (!count) continue;\n\n            _objc_inform(\"CACHES: %4d slots: %4d caches, %6zu / %6zu / %6zu bytes ideal/malloc/local, %6zu / %6zu bytes wasted malloc/local\", slots, count, ideal*count, malloc*count, local*count, malloc*count-ideal*count, local*count-ideal*count);\n\n            total += count;\n            ideal_total += ideal*count;\n            malloc_total += malloc*count;\n            local_total += local*count;\n        }\n\n        _objc_inform(\"CACHES:      total: %4zu caches, %6zu / %6zu / %6zu bytes ideal/malloc/local, %6zu / %6zu bytes wasted malloc/local\", total, ideal_total, malloc_total, local_total, malloc_total-ideal_total, local_total-ideal_total);\n    }\n}\n\n\n\n\n\n#if defined(CACHE_ALLOCATOR)\n\n/***********************************************************************\n* Custom method cache allocator.\n* Method cache block sizes are 2^slots+2 words, which is a pessimal \n* case for the system allocator. It wastes 504 bytes per cache block \n* with 128 or more slots, which adds up to tens of KB for an AppKit process.\n* To save memory, the custom cache allocator below is used.\n* \n* The cache allocator uses 128 KB allocation regions. Few processes will \n* require a second region. Within a region, allocation is address-ordered \n* first fit.\n* \n* The cache allocator uses a quantum of 520.\n* Cache block ideal sizes: 520, 1032, 2056, 4104\n* Cache allocator sizes:   520, 1040, 2080, 4160\n*\n* Because all blocks are known to be genuine method caches, the ordinary \n* cache->mask and cache->occupied fields are used as block headers. \n* No out-of-band headers are maintained. The number of blocks will \n* almost always be fewer than 200, so for simplicity there is no free \n* list or other optimization.\n* \n* Block in use: mask != 0, occupied != -1 (mask indicates block size)\n* Block free:   mask != 0, occupied == -1 (mask is precisely block size)\n* \n* No cache allocator functions take any locks. Instead, the caller \n* must hold the cacheUpdateLock.\n* \n* fixme with 128 KB regions and 520 B min block size, an allocation\n* bitmap would be only 32 bytes - better than free list?\n**********************************************************************/\n\ntypedef struct cache_allocator_block {\n    uintptr_t size;\n    uintptr_t state;\n    struct cache_allocator_block *nextFree;\n} cache_allocator_block;\n\ntypedef struct cache_allocator_region {\n    cache_allocator_block *start;\n    cache_allocator_block *end;    // first non-block address\n    cache_allocator_block *freeList;\n    struct cache_allocator_region *next;\n} cache_allocator_region;\n\nstatic cache_allocator_region *cacheRegion = NULL;\n\n\n/***********************************************************************\n* cache_allocator_add_region\n* Allocates and returns a new region that can hold at least size \n*   bytes of large method caches. \n* The actual size will be rounded up to a CACHE_QUANTUM boundary, \n*   with a minimum of CACHE_REGION_SIZE. \n* The new region is lowest-priority for new allocations. Callers that \n*   know the other regions are already full should allocate directly \n*   into the returned region.\n**********************************************************************/\nstatic cache_allocator_region *cache_allocator_add_region(size_t size)\n{\n    vm_address_t addr;\n    cache_allocator_block *b;\n    cache_allocator_region **rgnP;\n    cache_allocator_region *newRegion = (cache_allocator_region *)\n        calloc(1, sizeof(cache_allocator_region));\n\n    // Round size up to quantum boundary, and apply the minimum size.\n    size += CACHE_QUANTUM - (size % CACHE_QUANTUM);\n    if (size < CACHE_REGION_SIZE) size = CACHE_REGION_SIZE;\n\n    // Allocate the region\n    addr = (vm_address_t)calloc(size, 1);\n    newRegion->start = (cache_allocator_block *)addr;\n    newRegion->end = (cache_allocator_block *)(addr + size);\n\n    // Mark the first block: free and covers the entire region\n    b = newRegion->start;\n    b->size = size;\n    b->state = (uintptr_t)-1;\n    b->nextFree = NULL;\n    newRegion->freeList = b;\n\n    // Add to end of the linked list of regions.\n    // Other regions should be re-used before this one is touched.\n    newRegion->next = NULL;\n    rgnP = &cacheRegion;\n    while (*rgnP) {\n        rgnP = &(**rgnP).next;\n    }\n    *rgnP = newRegion;\n\n    cache_allocator_regions++;\n\n    return newRegion;\n}\n\n\n/***********************************************************************\n* cache_allocator_coalesce\n* Attempts to coalesce a free block with the single free block following \n* it in the free list, if any.\n**********************************************************************/\nstatic void cache_allocator_coalesce(cache_allocator_block *block)\n{\n    if (block->size + (uintptr_t)block == (uintptr_t)block->nextFree) {\n        block->size += block->nextFree->size;\n        block->nextFree = block->nextFree->nextFree;\n    }\n}\n\n\n/***********************************************************************\n* cache_region_calloc\n* Attempt to allocate a size-byte block in the given region. \n* Allocation is first-fit. The free list is already fully coalesced.\n* Returns NULL if there is not enough room in the region for the block.\n**********************************************************************/\nstatic void *cache_region_calloc(cache_allocator_region *rgn, size_t size)\n{\n    cache_allocator_block **blockP;\n    uintptr_t mask;\n\n    // Save mask for allocated block, then round size \n    // up to CACHE_QUANTUM boundary\n    mask = cache_allocator_mask_for_size(size);\n    size = cache_allocator_size_for_mask(mask);\n\n    // Search the free list for a sufficiently large free block.\n\n    for (blockP = &rgn->freeList; \n         *blockP != NULL; \n         blockP = &(**blockP).nextFree) \n    {\n        cache_allocator_block *block = *blockP;\n        if (block->size < size) continue;  // not big enough\n\n        // block is now big enough. Allocate from it.\n\n        // Slice off unneeded fragment of block, if any, \n        // and reconnect the free list around block.\n        if (block->size - size >= CACHE_QUANTUM) {\n            cache_allocator_block *leftover = \n                (cache_allocator_block *)(size + (uintptr_t)block);\n            leftover->size = block->size - size;\n            leftover->state = (uintptr_t)-1;\n            leftover->nextFree = block->nextFree;\n            *blockP = leftover;\n        } else {\n            *blockP = block->nextFree;\n        }\n            \n        // block is now exactly the right size.\n\n        bzero(block, size);\n        block->size = mask;  // Cache->mask\n        block->state = 0;    // Cache->occupied\n\n        return block;\n    }\n\n    // No room in this region.\n    return NULL;\n}\n\n\n/***********************************************************************\n* cache_allocator_calloc\n* Custom allocator for large method caches (128+ slots)\n* The returned cache block already has cache->mask set. \n* cache->occupied and the cache contents are zero.\n* Cache locks: cacheUpdateLock must be held by the caller\n**********************************************************************/\nstatic Cache cache_allocator_calloc(size_t size)\n{\n    cache_allocator_region *rgn;\n\n    cacheUpdateLock.assertLocked();\n\n    for (rgn = cacheRegion; rgn != NULL; rgn = rgn->next) {\n        void *p = cache_region_calloc(rgn, size);\n        if (p) {\n            return (Cache)p;\n        }\n    }\n\n    // No regions or all regions full - make a region and try one more time\n    // In the unlikely case of a cache over 256KB, it will get its own region.\n    return (Cache)cache_region_calloc(cache_allocator_add_region(size), size);\n}\n\n\n/***********************************************************************\n* cache_allocator_region_for_block\n* Returns the cache allocator region that ptr points into, or NULL.\n**********************************************************************/\nstatic cache_allocator_region *cache_allocator_region_for_block(cache_allocator_block *block) \n{\n    cache_allocator_region *rgn;\n    for (rgn = cacheRegion; rgn != NULL; rgn = rgn->next) {\n        if (block >= rgn->start  &&  block < rgn->end) return rgn;\n    }\n    return NULL;\n}\n\n\n/***********************************************************************\n* cache_allocator_is_block\n* If ptr is a live block from the cache allocator, return YES\n* If ptr is a block from some other allocator, return NO.\n* If ptr is a dead block from the cache allocator, result is undefined.\n* Cache locks: cacheUpdateLock must be held by the caller\n**********************************************************************/\nstatic bool cache_allocator_is_block(void *ptr)\n{\n    cacheUpdateLock.assertLocked();\n    return (cache_allocator_region_for_block((cache_allocator_block *)ptr) != NULL);\n}\n\n/***********************************************************************\n* cache_allocator_free\n* Frees a block allocated by the cache allocator.\n* Cache locks: cacheUpdateLock must be held by the caller.\n**********************************************************************/\nstatic void cache_allocator_free(void *ptr)\n{\n    cache_allocator_block *dead = (cache_allocator_block *)ptr;\n    cache_allocator_block *cur;\n    cache_allocator_region *rgn;\n\n    cacheUpdateLock.assertLocked();\n\n    if (! (rgn = cache_allocator_region_for_block(dead))) {\n        // free of non-pointer\n        _objc_inform(\"cache_allocator_free of non-pointer %p\", dead);\n        return;\n    }    \n\n    dead->size = cache_allocator_size_for_mask(dead->size);\n    dead->state = (uintptr_t)-1;\n\n    if (!rgn->freeList  ||  rgn->freeList > dead) {\n        // dead block belongs at front of free list\n        dead->nextFree = rgn->freeList;\n        rgn->freeList = dead;\n        cache_allocator_coalesce(dead);\n        return;\n    }\n\n    // dead block belongs in the middle or end of free list\n    for (cur = rgn->freeList; cur != NULL; cur = cur->nextFree) {\n        cache_allocator_block *ahead = cur->nextFree;\n        \n        if (!ahead  ||  ahead > dead) {\n            // cur and ahead straddle dead, OR dead belongs at end of free list\n            cur->nextFree = dead;\n            dead->nextFree = ahead;\n            \n            // coalesce into dead first in case both succeed\n            cache_allocator_coalesce(dead);\n            cache_allocator_coalesce(cur);\n            return;\n        }\n    }\n\n    // uh-oh\n    _objc_inform(\"cache_allocator_free of non-pointer %p\", ptr);\n}\n\n// defined(CACHE_ALLOCATOR)\n#endif\n\n/***********************************************************************\n* Cache instrumentation and debugging\n**********************************************************************/\n\n#ifdef OBJC_INSTRUMENTED\nenum {\n    CACHE_HISTOGRAM_SIZE\t= 512\n};\n\nunsigned int\tCacheHitHistogram [CACHE_HISTOGRAM_SIZE];\nunsigned int\tCacheMissHistogram [CACHE_HISTOGRAM_SIZE];\n#endif\n\n\n/***********************************************************************\n* _cache_print.\n**********************************************************************/\nstatic void _cache_print(Cache cache)\n{\n    uintptr_t index;\n    uintptr_t count;\n\n    count = cache->mask + 1;\n    for (index = 0; index < count; index += 1) {\n        cache_entry *entry = (cache_entry *)cache->buckets[index];\n        if (entry) {\n            if (entry->imp == _objc_msgForward_impcache)\n                printf (\"does not recognize: \\n\");\n            printf (\"%s\\n\", sel_getName(entry->name));\n        }\n    }\n}\n\n\n/***********************************************************************\n* _class_printMethodCaches.\n**********************************************************************/\nvoid _class_printMethodCaches(Class cls)\n{\n    if (_cache_isEmpty(cls->cache)) {\n        printf(\"no instance-method cache for class %s\\n\",cls->nameForLogging());\n    } else {\n        printf(\"instance-method cache for class %s:\\n\", cls->nameForLogging());\n        _cache_print(cls->cache);\n    }\n\n    if (_cache_isEmpty(cls->ISA()->cache)) {\n        printf(\"no class-method cache for class %s\\n\", cls->nameForLogging());\n    } else {\n        printf (\"class-method cache for class %s:\\n\", cls->nameForLogging());\n        _cache_print(cls->ISA()->cache);\n    }\n}\n\n\n#if 0\n#warning fixme\n\n\n/***********************************************************************\n* _class_printDuplicateCacheEntries.\n**********************************************************************/\nvoid _class_printDuplicateCacheEntries(bool detail)\n{\n    NXHashState state;\n    Class cls;\n    unsigned int duplicates;\n    unsigned int index1;\n    unsigned int index2;\n    unsigned int mask;\n    unsigned int count;\n    unsigned int isMeta;\n    Cache cache;\n\n\n    printf (\"Checking for duplicate cache entries \\n\");\n\n    // Outermost loop - iterate over all classes\n    state = NXInitHashState (class_hash);\n    duplicates = 0;\n    while (NXNextHashState (class_hash, &state, (void **) &cls))\n    {\n        // Control loop - do given class' cache, then its isa's cache\n        for (isMeta = 0; isMeta <= 1; isMeta += 1)\n        {\n            // Select cache of interest and make sure it exists\n            cache = (isMeta ? cls->ISA : cls)->cache;\n            if (_cache_isEmpty(cache))\n                continue;\n\n            // Middle loop - check each entry in the given cache\n            mask  = cache->mask;\n            count = mask + 1;\n            for (index1 = 0; index1 < count; index1 += 1)\n            {\n                // Skip invalid entry\n                if (!cache->buckets[index1])\n                    continue;\n\n                // Inner loop - check that given entry matches no later entry\n                for (index2 = index1 + 1; index2 < count; index2 += 1)\n                {\n                    // Skip invalid entry\n                    if (!cache->buckets[index2])\n                        continue;\n\n                    // Check for duplication by method name comparison\n                    if (strcmp ((char *) cache->buckets[index1]->name),\n                                (char *) cache->buckets[index2]->name)) == 0)\n                    {\n                        if (detail)\n                            printf (\"%s %s\\n\", cls->nameForLogging(), sel_getName(cache->buckets[index1]->name));\n                        duplicates += 1;\n                        break;\n                    }\n                }\n            }\n        }\n    }\n\n    // Log the findings\n    printf (\"duplicates = %d\\n\", duplicates);\n    printf (\"total cache fills = %d\\n\", totalCacheFills);\n}\n\n\n/***********************************************************************\n* PrintCacheHeader.\n**********************************************************************/\nstatic void PrintCacheHeader(void)\n{\n#ifdef OBJC_INSTRUMENTED\n    printf (\"Cache  Cache  Slots  Avg    Max   AvgS  MaxS  AvgS  MaxS  TotalD   AvgD  MaxD  TotalD   AvgD  MaxD  TotD  AvgD  MaxD\\n\");\n    printf (\"Size   Count  Used   Used   Used  Hit   Hit   Miss  Miss  Hits     Prbs  Prbs  Misses   Prbs  Prbs  Flsh  Flsh  Flsh\\n\");\n    printf (\"-----  -----  -----  -----  ----  ----  ----  ----  ----  -------  ----  ----  -------  ----  ----  ----  ----  ----\\n\");\n#else\n    printf (\"Cache  Cache  Slots  Avg    Max   AvgS  MaxS  AvgS  MaxS\\n\");\n    printf (\"Size   Count  Used   Used   Used  Hit   Hit   Miss  Miss\\n\");\n    printf (\"-----  -----  -----  -----  ----  ----  ----  ----  ----\\n\");\n#endif\n}\n\n\n/***********************************************************************\n* PrintCacheInfo.\n**********************************************************************/\nstatic void PrintCacheInfo(unsigned int cacheSize,\n                           unsigned int cacheCount,\n                           unsigned int slotsUsed,\n                           float avgUsed, unsigned int maxUsed,\n                           float avgSHit, unsigned int maxSHit,\n                           float avgSMiss, unsigned int maxSMiss\n#ifdef OBJC_INSTRUMENTED\n                           , unsigned int totDHits,\n                           float avgDHit,\n                           unsigned int maxDHit,\n                           unsigned int totDMisses,\n                           float avgDMiss,\n                           unsigned int maxDMiss,\n                           unsigned int totDFlsh,\n                           float avgDFlsh,\n                           unsigned int maxDFlsh\n#endif\n                           )\n{\n#ifdef OBJC_INSTRUMENTED\n    printf (\"%5u  %5u  %5u  %5.1f  %4u  %4.1f  %4u  %4.1f  %4u  %7u  %4.1f  %4u  %7u  %4.1f  %4u  %4u  %4.1f  %4u\\n\",\n#else\n            printf (\"%5u  %5u  %5u  %5.1f  %4u  %4.1f  %4u  %4.1f  %4u\\n\",\n#endif\n                    cacheSize, cacheCount, slotsUsed, avgUsed, maxUsed, avgSHit, maxSHit, avgSMiss, maxSMiss\n#ifdef OBJC_INSTRUMENTED\n                    , totDHits, avgDHit, maxDHit, totDMisses, avgDMiss, maxDMiss, totDFlsh, avgDFlsh, maxDFlsh\n#endif\n                    );\n            \n}\n\n\n#ifdef OBJC_INSTRUMENTED\n/***********************************************************************\n* PrintCacheHistogram.  Show the non-zero entries from the specified\n* cache histogram.\n**********************************************************************/\nstatic void PrintCacheHistogram(char *title,\n                                unsigned int *firstEntry,\n                                unsigned int entryCount)\n{\n    unsigned int index;\n    unsigned int *thisEntry;\n\n    printf (\"%s\\n\", title);\n    printf (\"    Probes    Tally\\n\");\n    printf (\"    ------    -----\\n\");\n    for (index = 0, thisEntry = firstEntry;\n         index < entryCount;\n         index += 1, thisEntry += 1)\n    {\n        if (*thisEntry == 0)\n            continue;\n\n        printf (\"    %6d    %5d\\n\", index, *thisEntry);\n    }\n}\n#endif\n\n\n/***********************************************************************\n* _class_printMethodCacheStatistics.\n**********************************************************************/\n\n#define MAX_LOG2_SIZE   32\n#define MAX_CHAIN_SIZE  100\n\nvoid _class_printMethodCacheStatistics(void)\n{\n    unsigned int isMeta;\n    unsigned int index;\n    NXHashState state;\n    Class cls;\n    unsigned int totalChain;\n    unsigned int totalMissChain;\n    unsigned int maxChain;\n    unsigned int maxMissChain;\n    unsigned int classCount;\n    unsigned int negativeEntryCount;\n    unsigned int cacheExpandCount;\n    unsigned int cacheCountBySize[2][MAX_LOG2_SIZE]        = {{0}};\n    unsigned int totalEntriesBySize[2][MAX_LOG2_SIZE]      = {{0}};\n    unsigned int maxEntriesBySize[2][MAX_LOG2_SIZE]        = {{0}};\n    unsigned int totalChainBySize[2][MAX_LOG2_SIZE]        = {{0}};\n    unsigned int totalMissChainBySize[2][MAX_LOG2_SIZE]    = {{0}};\n    unsigned int totalMaxChainBySize[2][MAX_LOG2_SIZE]     = {{0}};\n    unsigned int totalMaxMissChainBySize[2][MAX_LOG2_SIZE] = {{0}};\n    unsigned int maxChainBySize[2][MAX_LOG2_SIZE]          = {{0}};\n    unsigned int maxMissChainBySize[2][MAX_LOG2_SIZE]      = {{0}};\n    unsigned int chainCount[MAX_CHAIN_SIZE]                = {0};\n    unsigned int missChainCount[MAX_CHAIN_SIZE]            = {0};\n#ifdef OBJC_INSTRUMENTED\n    unsigned int hitCountBySize[2][MAX_LOG2_SIZE]          = {{0}};\n    unsigned int hitProbesBySize[2][MAX_LOG2_SIZE]         = {{0}};\n    unsigned int maxHitProbesBySize[2][MAX_LOG2_SIZE]      = {{0}};\n    unsigned int missCountBySize[2][MAX_LOG2_SIZE]         = {{0}};\n    unsigned int missProbesBySize[2][MAX_LOG2_SIZE]        = {{0}};\n    unsigned int maxMissProbesBySize[2][MAX_LOG2_SIZE]     = {{0}};\n    unsigned int flushCountBySize[2][MAX_LOG2_SIZE]        = {{0}};\n    unsigned int flushedEntriesBySize[2][MAX_LOG2_SIZE]    = {{0}};\n    unsigned int maxFlushedEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};\n#endif\n\n    printf (\"Printing cache statistics\\n\");\n\n    // Outermost loop - iterate over all classes\n    state = NXInitHashState (class_hash);\n    classCount = 0;\n    negativeEntryCount = 0;\n    cacheExpandCount = 0;\n    while (NXNextHashState (class_hash, &state, (void **) &cls))\n    {\n        // Tally classes\n        classCount += 1;\n\n        // Control loop - do given class' cache, then its isa's cache\n        for (isMeta = 0; isMeta <= 1; isMeta += 1)\n        {\n            Cache cache;\n            unsigned int mask;\n            unsigned int log2Size;\n            unsigned int entryCount;\n\n            // Select cache of interest\n            cache = (isMeta ? cls->ISA : cls)->cache;\n\n            // Ignore empty cache... should we?\n            if (_cache_isEmpty(cache))\n                continue;\n\n            // Middle loop - do each entry in the given cache\n            mask = cache->mask;\n            entryCount = 0;\n            totalChain = 0;\n            totalMissChain = 0;\n            maxChain = 0;\n            maxMissChain = 0;\n            for (index = 0; index < mask + 1; index += 1)\n            {\n                cache_entry **buckets;\n                cache_entry *entry;\n                unsigned int hash;\n                unsigned int methodChain;\n                unsigned int methodMissChain;\n                unsigned int index2;\n\n                // If entry is invalid, the only item of\n                // interest is that future insert hashes\n                // to this entry can use it directly.\n                buckets = (cache_entry **)cache->buckets;\n                if (!buckets[index])\n                {\n                    missChainCount[0] += 1;\n                    continue;\n                }\n\n                entry = buckets[index];\n\n                // Tally valid entries\n                entryCount += 1;\n\n                // Tally \"forward::\" entries\n                if (entry->imp == _objc_msgForward_impcache)\n                    negativeEntryCount += 1;\n\n                // Calculate search distance (chain length) for this method\n                // The chain may wrap around to the beginning of the table.\n                hash = CACHE_HASH(entry->name, mask);\n                if (index >= hash) methodChain = index - hash;\n                else methodChain = (mask+1) + index - hash;\n\n                // Tally chains of this length\n                if (methodChain < MAX_CHAIN_SIZE)\n                    chainCount[methodChain] += 1;\n\n                // Keep sum of all chain lengths\n                totalChain += methodChain;\n\n                // Record greatest chain length\n                if (methodChain > maxChain)\n                    maxChain = methodChain;\n\n                // Calculate search distance for miss that hashes here\n                index2 = index;\n                while (buckets[index2])\n                {\n                    index2 += 1;\n                    index2 &= mask;\n                }\n                methodMissChain = ((index2 - index) & mask);\n\n                // Tally miss chains of this length\n                if (methodMissChain < MAX_CHAIN_SIZE)\n                    missChainCount[methodMissChain] += 1;\n\n                // Keep sum of all miss chain lengths in this class\n                totalMissChain += methodMissChain;\n\n                // Record greatest miss chain length\n                if (methodMissChain > maxMissChain)\n                    maxMissChain = methodMissChain;\n            }\n\n            // Factor this cache into statistics about caches of the same\n            // type and size (all caches are a power of two in size)\n            log2Size = log2u (mask + 1);\n            cacheCountBySize[isMeta][log2Size] += 1;\n            totalEntriesBySize[isMeta][log2Size] += entryCount;\n            if (entryCount > maxEntriesBySize[isMeta][log2Size])\n                maxEntriesBySize[isMeta][log2Size] = entryCount;\n            totalChainBySize[isMeta][log2Size] += totalChain;\n            totalMissChainBySize[isMeta][log2Size] += totalMissChain;\n            totalMaxChainBySize[isMeta][log2Size] += maxChain;\n            totalMaxMissChainBySize[isMeta][log2Size] += maxMissChain;\n            if (maxChain > maxChainBySize[isMeta][log2Size])\n                maxChainBySize[isMeta][log2Size] = maxChain;\n            if (maxMissChain > maxMissChainBySize[isMeta][log2Size])\n                maxMissChainBySize[isMeta][log2Size] = maxMissChain;\n#ifdef OBJC_INSTRUMENTED\n            {\n                CacheInstrumentation *cacheData;\n\n                cacheData = CACHE_INSTRUMENTATION(cache);\n                hitCountBySize[isMeta][log2Size] += cacheData->hitCount;\n                hitProbesBySize[isMeta][log2Size] += cacheData->hitProbes;\n                if (cacheData->maxHitProbes > maxHitProbesBySize[isMeta][log2Size])\n                    maxHitProbesBySize[isMeta][log2Size] = cacheData->maxHitProbes;\n                missCountBySize[isMeta][log2Size] += cacheData->missCount;\n                missProbesBySize[isMeta][log2Size] += cacheData->missProbes;\n                if (cacheData->maxMissProbes > maxMissProbesBySize[isMeta][log2Size])\n                    maxMissProbesBySize[isMeta][log2Size] = cacheData->maxMissProbes;\n                flushCountBySize[isMeta][log2Size] += cacheData->flushCount;\n                flushedEntriesBySize[isMeta][log2Size] += cacheData->flushedEntries;\n                if (cacheData->maxFlushedEntries > maxFlushedEntriesBySize[isMeta][log2Size])\n                    maxFlushedEntriesBySize[isMeta][log2Size] = cacheData->maxFlushedEntries;\n            }\n#endif\n            // Caches start with a power of two number of entries, and grow by doubling, so\n            // we can calculate the number of times this cache has expanded\n            cacheExpandCount += log2Size - INIT_CACHE_SIZE_LOG2;\n        }\n    }\n\n    {\n        unsigned int cacheCountByType[2] = {0};\n        unsigned int totalCacheCount     = 0;\n        unsigned int totalEntries        = 0;\n        unsigned int maxEntries          = 0;\n        unsigned int totalSlots          = 0;\n#ifdef OBJC_INSTRUMENTED\n        unsigned int totalHitCount       = 0;\n        unsigned int totalHitProbes      = 0;\n        unsigned int maxHitProbes        = 0;\n        unsigned int totalMissCount      = 0;\n        unsigned int totalMissProbes     = 0;\n        unsigned int maxMissProbes       = 0;\n        unsigned int totalFlushCount     = 0;\n        unsigned int totalFlushedEntries = 0;\n        unsigned int maxFlushedEntries   = 0;\n#endif\n\n        totalChain = 0;\n        maxChain = 0;\n        totalMissChain = 0;\n        maxMissChain = 0;\n\n        // Sum information over all caches\n        for (isMeta = 0; isMeta <= 1; isMeta += 1)\n        {\n            for (index = 0; index < MAX_LOG2_SIZE; index += 1)\n            {\n                cacheCountByType[isMeta] += cacheCountBySize[isMeta][index];\n                totalEntries += totalEntriesBySize[isMeta][index];\n                totalSlots += cacheCountBySize[isMeta][index] * (1 << index);\n                totalChain += totalChainBySize[isMeta][index];\n                if (maxEntriesBySize[isMeta][index] > maxEntries)\n                    maxEntries = maxEntriesBySize[isMeta][index];\n                if (maxChainBySize[isMeta][index] > maxChain)\n                    maxChain   = maxChainBySize[isMeta][index];\n                totalMissChain += totalMissChainBySize[isMeta][index];\n                if (maxMissChainBySize[isMeta][index] > maxMissChain)\n                    maxMissChain = maxMissChainBySize[isMeta][index];\n#ifdef OBJC_INSTRUMENTED\n                totalHitCount += hitCountBySize[isMeta][index];\n                totalHitProbes += hitProbesBySize[isMeta][index];\n                if (maxHitProbesBySize[isMeta][index] > maxHitProbes)\n                    maxHitProbes = maxHitProbesBySize[isMeta][index];\n                totalMissCount += missCountBySize[isMeta][index];\n                totalMissProbes += missProbesBySize[isMeta][index];\n                if (maxMissProbesBySize[isMeta][index] > maxMissProbes)\n                    maxMissProbes = maxMissProbesBySize[isMeta][index];\n                totalFlushCount += flushCountBySize[isMeta][index];\n                totalFlushedEntries += flushedEntriesBySize[isMeta][index];\n                if (maxFlushedEntriesBySize[isMeta][index] > maxFlushedEntries)\n                    maxFlushedEntries = maxFlushedEntriesBySize[isMeta][index];\n#endif\n            }\n\n            totalCacheCount += cacheCountByType[isMeta];\n        }\n\n        // Log our findings\n        printf (\"There are %u classes\\n\", classCount);\n\n        for (isMeta = 0; isMeta <= 1; isMeta += 1)\n        {\n            // Number of this type of class\n            printf    (\"\\nThere are %u %s-method caches, broken down by size (slot count):\\n\",\n                       cacheCountByType[isMeta],\n                       isMeta ? \"class\" : \"instance\");\n\n            // Print header\n            PrintCacheHeader ();\n\n            // Keep format consistent even if there are caches of this kind\n            if (cacheCountByType[isMeta] == 0)\n            {\n                printf (\"(none)\\n\");\n                continue;\n            }\n\n            // Usage information by cache size\n            for (index = 0; index < MAX_LOG2_SIZE; index += 1)\n            {\n                unsigned int cacheCount;\n                unsigned int cacheSlotCount;\n                unsigned int cacheEntryCount;\n\n                // Get number of caches of this type and size\n                cacheCount = cacheCountBySize[isMeta][index];\n                if (cacheCount == 0)\n                    continue;\n\n                // Get the cache slot count and the total number of valid entries\n                cacheSlotCount  = (1 << index);\n                cacheEntryCount = totalEntriesBySize[isMeta][index];\n\n                // Give the analysis\n                PrintCacheInfo (cacheSlotCount,\n                                cacheCount,\n                                cacheEntryCount,\n                                (float) cacheEntryCount / (float) cacheCount,\n                                maxEntriesBySize[isMeta][index],\n                                (float) totalChainBySize[isMeta][index] / (float) cacheEntryCount,\n                                maxChainBySize[isMeta][index],\n                                (float) totalMissChainBySize[isMeta][index] / (float) (cacheCount * cacheSlotCount),\n                                maxMissChainBySize[isMeta][index]\n#ifdef OBJC_INSTRUMENTED\n                                , hitCountBySize[isMeta][index],\n                                hitCountBySize[isMeta][index] ?\n                                (float) hitProbesBySize[isMeta][index] / (float) hitCountBySize[isMeta][index] : 0.0,\n                                maxHitProbesBySize[isMeta][index],\n                                missCountBySize[isMeta][index],\n                                missCountBySize[isMeta][index] ?\n                                (float) missProbesBySize[isMeta][index] / (float) missCountBySize[isMeta][index] : 0.0,\n                                maxMissProbesBySize[isMeta][index],\n                                flushCountBySize[isMeta][index],\n                                flushCountBySize[isMeta][index] ?\n                                (float) flushedEntriesBySize[isMeta][index] / (float) flushCountBySize[isMeta][index] : 0.0,\n                                maxFlushedEntriesBySize[isMeta][index]\n#endif\n                                );\n            }\n        }\n\n        // Give overall numbers\n        printf (\"\\nCumulative:\\n\");\n        PrintCacheHeader ();\n        PrintCacheInfo (totalSlots,\n                        totalCacheCount,\n                        totalEntries,\n                        (float) totalEntries / (float) totalCacheCount,\n                        maxEntries,\n                        (float) totalChain / (float) totalEntries,\n                        maxChain,\n                        (float) totalMissChain / (float) totalSlots,\n                        maxMissChain\n#ifdef OBJC_INSTRUMENTED\n                        , totalHitCount,\n                        totalHitCount ?\n                        (float) totalHitProbes / (float) totalHitCount : 0.0,\n                        maxHitProbes,\n                        totalMissCount,\n                        totalMissCount ?\n                        (float) totalMissProbes / (float) totalMissCount : 0.0,\n                        maxMissProbes,\n                        totalFlushCount,\n                        totalFlushCount ?\n                        (float) totalFlushedEntries / (float) totalFlushCount : 0.0,\n                        maxFlushedEntries\n#endif\n                        );\n\n        printf (\"\\nNumber of \\\"forward::\\\" entries: %d\\n\", negativeEntryCount);\n        printf (\"Number of cache expansions: %d\\n\", cacheExpandCount);\n#ifdef OBJC_INSTRUMENTED\n        printf (\"flush_caches:   total calls  total visits  average visits  max visits  total classes  visits/class\\n\");\n        printf (\"                -----------  ------------  --------------  ----------  -------------  -------------\\n\");\n        printf (\"  linear        %11u  %12u  %14.1f  %10u  %13u  %12.2f\\n\",\n                LinearFlushCachesCount,\n                LinearFlushCachesVisitedCount,\n                LinearFlushCachesCount ?\n                (float) LinearFlushCachesVisitedCount / (float) LinearFlushCachesCount : 0.0,\n                MaxLinearFlushCachesVisitedCount,\n                LinearFlushCachesVisitedCount,\n                1.0);\n        printf (\"  nonlinear     %11u  %12u  %14.1f  %10u  %13u  %12.2f\\n\",\n                NonlinearFlushCachesCount,\n                NonlinearFlushCachesVisitedCount,\n                NonlinearFlushCachesCount ?\n                (float) NonlinearFlushCachesVisitedCount / (float) NonlinearFlushCachesCount : 0.0,\n                MaxNonlinearFlushCachesVisitedCount,\n                NonlinearFlushCachesClassCount,\n                NonlinearFlushCachesClassCount ?\n                (float) NonlinearFlushCachesVisitedCount / (float) NonlinearFlushCachesClassCount : 0.0);\n        printf (\"  ideal         %11u  %12u  %14.1f  %10u  %13u  %12.2f\\n\",\n                LinearFlushCachesCount + NonlinearFlushCachesCount,\n                IdealFlushCachesCount,\n                LinearFlushCachesCount + NonlinearFlushCachesCount ?\n                (float) IdealFlushCachesCount / (float) (LinearFlushCachesCount + NonlinearFlushCachesCount) : 0.0,\n                MaxIdealFlushCachesCount,\n                LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount,\n                LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount ?\n                (float) IdealFlushCachesCount / (float) (LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount) : 0.0);\n\n        PrintCacheHistogram (\"\\nCache hit histogram:\",  &CacheHitHistogram[0],  CACHE_HISTOGRAM_SIZE);\n        PrintCacheHistogram (\"\\nCache miss histogram:\", &CacheMissHistogram[0], CACHE_HISTOGRAM_SIZE);\n#endif\n\n#if 0\n        printf (\"\\nLookup chains:\");\n        for (index = 0; index < MAX_CHAIN_SIZE; index += 1)\n        {\n            if (chainCount[index] != 0)\n                printf (\"  %u:%u\", index, chainCount[index]);\n        }\n\n        printf (\"\\nMiss chains:\");\n        for (index = 0; index < MAX_CHAIN_SIZE; index += 1)\n        {\n            if (missChainCount[index] != 0)\n                printf (\"  %u:%u\", index, missChainCount[index]);\n        }\n\n        printf (\"\\nTotal memory usage for cache data structures: %lu bytes\\n\",\n                totalCacheCount * (sizeof(struct objc_cache) - sizeof(cache_entry *)) +\n                totalSlots * sizeof(cache_entry *) +\n                negativeEntryCount * sizeof(cache_entry));\n#endif\n    }\n}\n\n#endif\n\n\n// !__OBJC2__\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-cache.h",
    "content": "\n#ifndef _OBJC_CACHE_H\n#define _OBJC_CACHE_H\n\n#include \"objc-private.h\"\n\n__BEGIN_DECLS\n\nextern IMP cache_getImp(Class cls, SEL sel);\n\nextern void cache_fill(Class cls, SEL sel, IMP imp, id receiver);\n\nextern void cache_erase_nolock(Class cls);\n\nextern void cache_delete(Class cls);\n\nextern void cache_collect(bool collectALot);\n\n__END_DECLS\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-cache.mm",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-cache.m\n* Method cache management\n* Cache flushing\n* Cache garbage collection\n* Cache instrumentation\n* Dedicated allocator for large caches\n**********************************************************************/\n\n\n/***********************************************************************\n * Method cache locking (GrP 2001-1-14)\n *\n * For speed, objc_msgSend does not acquire any locks when it reads \n * method caches. Instead, all cache changes are performed so that any \n * objc_msgSend running concurrently with the cache mutator will not \n * crash or hang or get an incorrect result from the cache. \n *\n * When cache memory becomes unused (e.g. the old cache after cache \n * expansion), it is not immediately freed, because a concurrent \n * objc_msgSend could still be using it. Instead, the memory is \n * disconnected from the data structures and placed on a garbage list. \n * The memory is now only accessible to instances of objc_msgSend that \n * were running when the memory was disconnected; any further calls to \n * objc_msgSend will not see the garbage memory because the other data \n * structures don't point to it anymore. The collecting_in_critical\n * function checks the PC of all threads and returns FALSE when all threads \n * are found to be outside objc_msgSend. This means any call to objc_msgSend \n * that could have had access to the garbage has finished or moved past the \n * cache lookup stage, so it is safe to free the memory.\n *\n * All functions that modify cache data or structures must acquire the \n * cacheUpdateLock to prevent interference from concurrent modifications.\n * The function that frees cache garbage must acquire the cacheUpdateLock \n * and use collecting_in_critical() to flush out cache readers.\n * The cacheUpdateLock is also used to protect the custom allocator used \n * for large method cache blocks.\n *\n * Cache readers (PC-checked by collecting_in_critical())\n * objc_msgSend*\n * cache_getImp\n *\n * Cache writers (hold cacheUpdateLock while reading or writing; not PC-checked)\n * cache_fill         (acquires lock)\n * cache_expand       (only called from cache_fill)\n * cache_create       (only called from cache_expand)\n * bcopy               (only called from instrumented cache_expand)\n * flush_caches        (acquires lock)\n * cache_flush        (only called from cache_fill and flush_caches)\n * cache_collect_free (only called from cache_expand and cache_flush)\n *\n * UNPROTECTED cache readers (NOT thread-safe; used for debug info only)\n * cache_print\n * _class_printMethodCaches\n * _class_printDuplicateCacheEntries\n * _class_printMethodCacheStatistics\n *\n ***********************************************************************/\n\n\n#if __OBJC2__\n\n#include \"objc-private.h\"\n#include \"objc-cache.h\"\n\n\n/* Initial cache bucket count. INIT_CACHE_SIZE must be a power of two. */\nenum {\n    INIT_CACHE_SIZE_LOG2 = 2,\n    INIT_CACHE_SIZE      = (1 << INIT_CACHE_SIZE_LOG2)\n};\n\nstatic void cache_collect_free(struct bucket_t *data, mask_t capacity);\nstatic int _collecting_in_critical(void);\nstatic void _garbage_make_room(void);\n\n\n/***********************************************************************\n* Cache statistics for OBJC_PRINT_CACHE_SETUP\n**********************************************************************/\nstatic unsigned int cache_counts[16];\nstatic size_t cache_allocations;\nstatic size_t cache_collections;\n\nstatic void recordNewCache(mask_t capacity)\n{\n    size_t bucket = log2u(capacity);\n    if (bucket < countof(cache_counts)) {\n        cache_counts[bucket]++;\n    }\n    cache_allocations++;\n}\n\nstatic void recordDeadCache(mask_t capacity)\n{\n    size_t bucket = log2u(capacity);\n    if (bucket < countof(cache_counts)) {\n        cache_counts[bucket]--;\n    }\n}\n\n/***********************************************************************\n* Pointers used by compiled class objects\n* These use asm to avoid conflicts with the compiler's internal declarations\n**********************************************************************/\n\n// EMPTY_BYTES includes space for a cache end marker bucket.\n// This end marker doesn't actually have the wrap-around pointer \n// because cache scans always find an empty bucket before they might wrap.\n// 1024 buckets is fairly common.\n#if DEBUG\n    // Use a smaller size to exercise heap-allocated empty caches.\n#   define EMPTY_BYTES ((8+1)*16)\n#else\n#   define EMPTY_BYTES ((1024+1)*16)\n#endif\n\n#define stringize(x) #x\n#define stringize2(x) stringize(x)\n\n// \"cache\" is cache->buckets; \"vtable\" is cache->mask/occupied\n// hack to avoid conflicts with compiler's internal declaration\nasm(\"\\n .section __TEXT,__const\"\n    \"\\n .globl __objc_empty_vtable\"\n    \"\\n .set __objc_empty_vtable, 0\"\n    \"\\n .globl __objc_empty_cache\"\n    \"\\n .align 3\"\n    \"\\n __objc_empty_cache: .space \" stringize2(EMPTY_BYTES)\n    );\n\n\n#if __arm__  ||  __x86_64__  ||  __i386__\n// objc_msgSend has few registers available.\n// Cache scan increments and wraps at special end-marking bucket.\n#define CACHE_END_MARKER 1\nstatic inline mask_t cache_next(mask_t i, mask_t mask) {\n    return (i+1) & mask;\n}\n\n#elif __arm64__\n// objc_msgSend has lots of registers available.\n// Cache scan decrements. No end marker needed.\n#define CACHE_END_MARKER 0\nstatic inline mask_t cache_next(mask_t i, mask_t mask) {\n    return i ? i-1 : mask;\n}\n\n#else\n#error unknown architecture\n#endif\n\n\n// copied from dispatch_atomic_maximally_synchronizing_barrier\n// fixme verify that this barrier hack does in fact work here\n#if __x86_64__\n#define mega_barrier() \\\n    do { unsigned long _clbr; __asm__ __volatile__( \\\n        \"cpuid\" \\\n        : \"=a\" (_clbr) : \"0\" (0) : \"rbx\", \"rcx\", \"rdx\", \"cc\", \"memory\" \\\n                                                    ); } while(0)\n\n#elif __i386__\n#define mega_barrier() \\\n    do { unsigned long _clbr; __asm__ __volatile__( \\\n        \"cpuid\" \\\n        : \"=a\" (_clbr) : \"0\" (0) : \"ebx\", \"ecx\", \"edx\", \"cc\", \"memory\" \\\n                                                    ); } while(0)\n\n#elif __arm__  ||  __arm64__\n#define mega_barrier() \\\n    __asm__ __volatile__( \\\n        \"dsb    ish\" \\\n        : : : \"memory\")\n\n#else\n#error unknown architecture\n#endif\n\n#if __arm64__\n\n// Pointer-size register prefix for inline asm\n# if __LP64__\n#   define p \"x\"  // true arm64\n# else\n#   define p \"w\"  // arm64_32\n# endif\n\n// Use atomic double-word instructions to update cache entries.\n// This requires cache buckets not cross cache line boundaries.\nstatic ALWAYS_INLINE void\nstp(uintptr_t onep, uintptr_t twop, void *destp)\n{\n    __asm__ (\"stp %\" p \"[one], %\" p \"[two], [%x[dest]]\"\n             : \"=m\" (((uintptr_t *)(destp))[0]),\n               \"=m\" (((uintptr_t *)(destp))[1])\n             : [one] \"r\" (onep),\n               [two] \"r\" (twop),\n               [dest] \"r\" (destp)\n             : /* no clobbers */\n             );\n}\n\nstatic ALWAYS_INLINE void __unused\nldp(uintptr_t& onep, uintptr_t& twop, const void *srcp)\n{\n    __asm__ (\"ldp %\" p \"[one], %\" p \"[two], [%x[src]]\"\n             : [one] \"=r\" (onep),\n               [two] \"=r\" (twop)\n             : \"m\" (((const uintptr_t *)(srcp))[0]),\n               \"m\" (((const uintptr_t *)(srcp))[1]),\n               [src] \"r\" (srcp)\n             : /* no clobbers */\n             );\n}\n\n#undef p\n#endif\n\n\n// Class points to cache. SEL is key. Cache buckets store SEL+IMP.\n// Caches are never built in the dyld shared cache.\n\nstatic inline mask_t cache_hash(cache_key_t key, mask_t mask) \n{\n    return (mask_t)(key & mask);\n}\n\ncache_t *getCache(Class cls) \n{\n    assert(cls);\n    return &cls->cache;\n}\n\ncache_key_t getKey(SEL sel) \n{\n    assert(sel);\n    return (cache_key_t)sel;\n}\n\n#if __arm64__\n\nvoid bucket_t::set(cache_key_t newKey, IMP newImp)\n{\n    assert(_key == 0  ||  _key == newKey);\n\n    static_assert(offsetof(bucket_t,_imp) == 0 && offsetof(bucket_t,_key) == sizeof(void *),\n                  \"bucket_t doesn't match arm64 bucket_t::set()\");\n\n#if __has_feature(ptrauth_calls)\n    // Authenticate as a C function pointer and re-sign for the cache bucket.\n    uintptr_t signedImp = _imp.prepareWrite(newImp);\n#else\n    // No function pointer signing.\n    uintptr_t signedImp = (uintptr_t)newImp;\n#endif\n\n    // Write to the bucket.\n    // LDP/STP guarantees that all observers get\n    // either imp/key or newImp/newKey\n    stp(signedImp, newKey, this);\n}\n\n#else\n\nvoid bucket_t::set(cache_key_t newKey, IMP newImp)\n{\n    assert(_key == 0  ||  _key == newKey);\n\n    // objc_msgSend uses key and imp with no locks.\n    // It is safe for objc_msgSend to see new imp but NULL key\n    // (It will get a cache miss but not dispatch to the wrong place.)\n    // It is unsafe for objc_msgSend to see old imp and new key.\n    // Therefore we write new imp, wait a lot, then write new key.\n    \n    _imp = newImp;\n    \n    if (_key != newKey) {\n        mega_barrier();\n        _key = newKey;\n    }\n}\n\n#endif\n\nvoid cache_t::setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask)\n{\n    // objc_msgSend uses mask and buckets with no locks.\n    // It is safe for objc_msgSend to see new buckets but old mask.\n    // (It will get a cache miss but not overrun the buckets' bounds).\n    // It is unsafe for objc_msgSend to see old buckets and new mask.\n    // Therefore we write new buckets, wait a lot, then write new mask.\n    // objc_msgSend reads mask first, then buckets.\n\n    // ensure other threads see buckets contents before buckets pointer\n    mega_barrier();\n\n    _buckets = newBuckets;\n    \n    // ensure other threads see new buckets before new mask\n    mega_barrier();\n    \n    _mask = newMask;\n    _occupied = 0;\n}\n\n\nstruct bucket_t *cache_t::buckets() \n{\n    return _buckets; \n}\n\nmask_t cache_t::mask() \n{\n    return _mask; \n}\n\nmask_t cache_t::occupied() \n{\n    return _occupied;\n}\n\nvoid cache_t::incrementOccupied() \n{\n    _occupied++;\n}\n\nvoid cache_t::initializeToEmpty()\n{\n    bzero(this, sizeof(*this));\n    _buckets = (bucket_t *)&_objc_empty_cache;\n}\n\n\nmask_t cache_t::capacity() \n{\n    return mask() ? mask()+1 : 0; \n}\n\n\n#if CACHE_END_MARKER\n\nsize_t cache_t::bytesForCapacity(uint32_t cap) \n{\n    // fixme put end marker inline when capacity+1 malloc is inefficient\n    return sizeof(bucket_t) * (cap + 1);\n}\n\nbucket_t *cache_t::endMarker(struct bucket_t *b, uint32_t cap) \n{\n    // bytesForCapacity() chooses whether the end marker is inline or not\n    return (bucket_t *)((uintptr_t)b + bytesForCapacity(cap)) - 1;\n}\n\nbucket_t *allocateBuckets(mask_t newCapacity)\n{\n    // Allocate one extra bucket to mark the end of the list.\n    // This can't overflow mask_t because newCapacity is a power of 2.\n    // fixme instead put the end mark inline when +1 is malloc-inefficient\n    bucket_t *newBuckets = (bucket_t *)\n        calloc(cache_t::bytesForCapacity(newCapacity), 1);\n\n    bucket_t *end = cache_t::endMarker(newBuckets, newCapacity);\n\n#if __arm__\n    // End marker's key is 1 and imp points BEFORE the first bucket.\n    // This saves an instruction in objc_msgSend.\n    end->setKey((cache_key_t)(uintptr_t)1);\n    end->setImp((IMP)(newBuckets - 1));\n#else\n    // End marker's key is 1 and imp points to the first bucket.\n    end->setKey((cache_key_t)(uintptr_t)1);\n    end->setImp((IMP)newBuckets);\n#endif\n    \n    if (PrintCaches) recordNewCache(newCapacity);\n\n    return newBuckets;\n}\n\n#else\n\nsize_t cache_t::bytesForCapacity(uint32_t cap) \n{\n    return sizeof(bucket_t) * cap;\n}\n\nbucket_t *allocateBuckets(mask_t newCapacity)\n{\n    if (PrintCaches) recordNewCache(newCapacity);\n\n    return (bucket_t *)calloc(cache_t::bytesForCapacity(newCapacity), 1);\n}\n\n#endif\n\n\nbucket_t *emptyBucketsForCapacity(mask_t capacity, bool allocate = true)\n{\n    cacheUpdateLock.assertLocked();\n\n    size_t bytes = cache_t::bytesForCapacity(capacity);\n\n    // Use _objc_empty_cache if the buckets is small enough.\n    if (bytes <= EMPTY_BYTES) {\n        return (bucket_t *)&_objc_empty_cache;\n    }\n\n    // Use shared empty buckets allocated on the heap.\n    static bucket_t **emptyBucketsList = nil;\n    static mask_t emptyBucketsListCount = 0;\n    \n    mask_t index = log2u(capacity);\n\n    if (index >= emptyBucketsListCount) {\n        if (!allocate) return nil;\n\n        mask_t newListCount = index + 1;\n        bucket_t *newBuckets = (bucket_t *)calloc(bytes, 1);\n        emptyBucketsList = (bucket_t**)\n            realloc(emptyBucketsList, newListCount * sizeof(bucket_t *));\n        // Share newBuckets for every un-allocated size smaller than index.\n        // The array is therefore always fully populated.\n        for (mask_t i = emptyBucketsListCount; i < newListCount; i++) {\n            emptyBucketsList[i] = newBuckets;\n        }\n        emptyBucketsListCount = newListCount;\n\n        if (PrintCaches) {\n            _objc_inform(\"CACHES: new empty buckets at %p (capacity %zu)\", \n                         newBuckets, (size_t)capacity);\n        }\n    }\n\n    return emptyBucketsList[index];\n}\n\n\nbool cache_t::isConstantEmptyCache()\n{\n    return \n        occupied() == 0  &&  \n        buckets() == emptyBucketsForCapacity(capacity(), false);\n}\n\nbool cache_t::canBeFreed()\n{\n    return !isConstantEmptyCache();\n}\n\n\nvoid cache_t::reallocate(mask_t oldCapacity, mask_t newCapacity)\n{\n    bool freeOld = canBeFreed();\n\n    bucket_t *oldBuckets = buckets();\n    bucket_t *newBuckets = allocateBuckets(newCapacity);\n\n    // Cache's old contents are not propagated. \n    // This is thought to save cache memory at the cost of extra cache fills.\n    // fixme re-measure this\n\n    assert(newCapacity > 0);\n    assert((uintptr_t)(mask_t)(newCapacity-1) == newCapacity-1);\n\n    setBucketsAndMask(newBuckets, newCapacity - 1);\n    \n    if (freeOld) {\n        cache_collect_free(oldBuckets, oldCapacity);\n        cache_collect(false);\n    }\n}\n\n\nvoid cache_t::bad_cache(id receiver, SEL sel, Class isa)\n{\n    // Log in separate steps in case the logging itself causes a crash.\n    _objc_inform_now_and_on_crash\n        (\"Method cache corrupted. This may be a message to an \"\n         \"invalid object, or a memory error somewhere else.\");\n    cache_t *cache = &isa->cache;\n    _objc_inform_now_and_on_crash\n        (\"%s %p, SEL %p, isa %p, cache %p, buckets %p, \"\n         \"mask 0x%x, occupied 0x%x\", \n         receiver ? \"receiver\" : \"unused\", receiver, \n         sel, isa, cache, cache->_buckets, \n         cache->_mask, cache->_occupied);\n    _objc_inform_now_and_on_crash\n        (\"%s %zu bytes, buckets %zu bytes\", \n         receiver ? \"receiver\" : \"unused\", malloc_size(receiver), \n         malloc_size(cache->_buckets));\n    _objc_inform_now_and_on_crash\n        (\"selector '%s'\", sel_getName(sel));\n    _objc_inform_now_and_on_crash\n        (\"isa '%s'\", isa->nameForLogging());\n    _objc_fatal\n        (\"Method cache corrupted. This may be a message to an \"\n         \"invalid object, or a memory error somewhere else.\");\n}\n\n\nbucket_t * cache_t::find(cache_key_t k, id receiver)\n{\n    assert(k != 0);\n\n    bucket_t *b = buckets();\n    mask_t m = mask();\n    mask_t begin = cache_hash(k, m);\n    mask_t i = begin;\n    do {\n        if (b[i].key() == 0  ||  b[i].key() == k) {\n            return &b[i];\n        }\n    } while ((i = cache_next(i, m)) != begin);\n\n    // hack\n    Class cls = (Class)((uintptr_t)this - offsetof(objc_class, cache));\n    cache_t::bad_cache(receiver, (SEL)k, cls);\n}\n\n\nvoid cache_t::expand()\n{\n    cacheUpdateLock.assertLocked();\n    \n    uint32_t oldCapacity = capacity();\n    uint32_t newCapacity = oldCapacity ? oldCapacity*2 : INIT_CACHE_SIZE;\n\n    if ((uint32_t)(mask_t)newCapacity != newCapacity) {\n        // mask overflow - can't grow further\n        // fixme this wastes one bit of mask\n        newCapacity = oldCapacity;\n    }\n\n    reallocate(oldCapacity, newCapacity);\n}\n\n\nstatic void cache_fill_nolock(Class cls, SEL sel, IMP imp, id receiver)\n{\n    cacheUpdateLock.assertLocked();\n\n    // Never cache before +initialize is done\n    if (!cls->isInitialized()) return;\n\n    // Make sure the entry wasn't added to the cache by some other thread \n    // before we grabbed the cacheUpdateLock.\n    if (cache_getImp(cls, sel)) return;\n\n    cache_t *cache = getCache(cls);\n    cache_key_t key = getKey(sel);\n\n    // Use the cache as-is if it is less than 3/4 full\n    mask_t newOccupied = cache->occupied() + 1;\n    mask_t capacity = cache->capacity();\n    if (cache->isConstantEmptyCache()) {\n        // Cache is read-only. Replace it.\n        cache->reallocate(capacity, capacity ?: INIT_CACHE_SIZE);\n    }\n    else if (newOccupied <= capacity / 4 * 3) {\n        // Cache is less than 3/4 full. Use it as-is.\n    }\n    else {\n        // Cache is too full. Expand it.\n        cache->expand();\n    }\n\n    // Scan for the first unused slot and insert there.\n    // There is guaranteed to be an empty slot because the \n    // minimum size is 4 and we resized at 3/4 full.\n    bucket_t *bucket = cache->find(key, receiver);\n    if (bucket->key() == 0) cache->incrementOccupied();\n    bucket->set(key, imp);\n}\n\nvoid cache_fill(Class cls, SEL sel, IMP imp, id receiver)\n{\n#if !DEBUG_TASK_THREADS\n    mutex_locker_t lock(cacheUpdateLock);\n    cache_fill_nolock(cls, sel, imp, receiver);\n#else\n    _collecting_in_critical();\n    return;\n#endif\n}\n\n\n// Reset this entire cache to the uncached lookup by reallocating it.\n// This must not shrink the cache - that breaks the lock-free scheme.\nvoid cache_erase_nolock(Class cls)\n{\n    cacheUpdateLock.assertLocked();\n\n    cache_t *cache = getCache(cls);\n\n    mask_t capacity = cache->capacity();\n    if (capacity > 0  &&  cache->occupied() > 0) {\n        auto oldBuckets = cache->buckets();\n        auto buckets = emptyBucketsForCapacity(capacity);\n        cache->setBucketsAndMask(buckets, capacity - 1); // also clears occupied\n\n        cache_collect_free(oldBuckets, capacity);\n        cache_collect(false);\n    }\n}\n\n\nvoid cache_delete(Class cls)\n{\n    mutex_locker_t lock(cacheUpdateLock);\n    if (cls->cache.canBeFreed()) {\n        if (PrintCaches) recordDeadCache(cls->cache.capacity());\n        free(cls->cache.buckets());\n    }\n}\n\n\n/***********************************************************************\n* cache collection.\n**********************************************************************/\n\n#if !TARGET_OS_WIN32\n\n// A sentinel (magic value) to report bad thread_get_state status.\n// Must not be a valid PC.\n// Must not be zero - thread_get_state() on a new thread returns PC == 0.\n#define PC_SENTINEL  1\n\nstatic uintptr_t _get_pc_for_thread(thread_t thread)\n#if defined(__i386__)\n{\n    i386_thread_state_t state;\n    unsigned int count = i386_THREAD_STATE_COUNT;\n    kern_return_t okay = thread_get_state (thread, i386_THREAD_STATE, (thread_state_t)&state, &count);\n    return (okay == KERN_SUCCESS) ? state.__eip : PC_SENTINEL;\n}\n#elif defined(__x86_64__)\n{\n    x86_thread_state64_t\t\t\tstate;\n    unsigned int count = x86_THREAD_STATE64_COUNT;\n    kern_return_t okay = thread_get_state (thread, x86_THREAD_STATE64, (thread_state_t)&state, &count);\n    return (okay == KERN_SUCCESS) ? state.__rip : PC_SENTINEL;\n}\n#elif defined(__arm__)\n{\n    arm_thread_state_t state;\n    unsigned int count = ARM_THREAD_STATE_COUNT;\n    kern_return_t okay = thread_get_state (thread, ARM_THREAD_STATE, (thread_state_t)&state, &count);\n    return (okay == KERN_SUCCESS) ? state.__pc : PC_SENTINEL;\n}\n#elif defined(__arm64__)\n{\n    arm_thread_state64_t state;\n    unsigned int count = ARM_THREAD_STATE64_COUNT;\n    kern_return_t okay = thread_get_state (thread, ARM_THREAD_STATE64, (thread_state_t)&state, &count);\n    return (okay == KERN_SUCCESS) ? arm_thread_state64_get_pc(state) : PC_SENTINEL;\n}\n#else\n{\n#error _get_pc_for_thread () not implemented for this architecture\n}\n#endif\n\n#endif\n\n/***********************************************************************\n* _collecting_in_critical.\n* Returns TRUE if some thread is currently executing a cache-reading \n* function. Collection of cache garbage is not allowed when a cache-\n* reading function is in progress because it might still be using \n* the garbage memory.\n**********************************************************************/\nextern \"C\" uintptr_t objc_entryPoints[];\nextern \"C\"  uintptr_t objc_exitPoints[];\n\nstatic int _collecting_in_critical(void)\n{\n#if TARGET_OS_WIN32\n    return TRUE;\n#else\n    thread_act_port_array_t threads;\n    unsigned number;\n    unsigned count;\n    kern_return_t ret;\n    int result;\n\n    mach_port_t mythread = pthread_mach_thread_np(pthread_self());\n\n    // Get a list of all the threads in the current task\n#if !DEBUG_TASK_THREADS\n    ret = task_threads(mach_task_self(), &threads, &number);\n#else\n    ret = objc_task_threads(mach_task_self(), &threads, &number);\n#endif\n\n    if (ret != KERN_SUCCESS) {\n        // See DEBUG_TASK_THREADS below to help debug this.\n        _objc_fatal(\"task_threads failed (result 0x%x)\\n\", ret);\n    }\n\n    // Check whether any thread is in the cache lookup code\n    result = FALSE;\n    for (count = 0; count < number; count++)\n    {\n        int region;\n        uintptr_t pc;\n\n        // Don't bother checking ourselves\n        if (threads[count] == mythread)\n            continue;\n\n        // Find out where thread is executing\n        pc = _get_pc_for_thread (threads[count]);\n\n        // Check for bad status, and if so, assume the worse (can't collect)\n        if (pc == PC_SENTINEL)\n        {\n            result = TRUE;\n            goto done;\n        }\n        \n        // Check whether it is in the cache lookup code\n        for (region = 0; objc_entryPoints[region] != 0; region++)\n        {\n            if ((pc >= objc_entryPoints[region]) &&\n                (pc <= objc_exitPoints[region])) \n            {\n                result = TRUE;\n                goto done;\n            }\n        }\n    }\n\n done:\n    // Deallocate the port rights for the threads\n    for (count = 0; count < number; count++) {\n        mach_port_deallocate(mach_task_self (), threads[count]);\n    }\n\n    // Deallocate the thread list\n    vm_deallocate (mach_task_self (), (vm_address_t) threads, sizeof(threads[0]) * number);\n\n    // Return our finding\n    return result;\n#endif\n}\n\n\n/***********************************************************************\n* _garbage_make_room.  Ensure that there is enough room for at least\n* one more ref in the garbage.\n**********************************************************************/\n\n// amount of memory represented by all refs in the garbage\nstatic size_t garbage_byte_size = 0;\n\n// do not empty the garbage until garbage_byte_size gets at least this big\nstatic size_t garbage_threshold = 32*1024;\n\n// table of refs to free\nstatic bucket_t **garbage_refs = 0;\n\n// current number of refs in garbage_refs\nstatic size_t garbage_count = 0;\n\n// capacity of current garbage_refs\nstatic size_t garbage_max = 0;\n\n// capacity of initial garbage_refs\nenum {\n    INIT_GARBAGE_COUNT = 128\n};\n\nstatic void _garbage_make_room(void)\n{\n    static int first = 1;\n\n    // Create the collection table the first time it is needed\n    if (first)\n    {\n        first = 0;\n        garbage_refs = (bucket_t**)\n            malloc(INIT_GARBAGE_COUNT * sizeof(void *));\n        garbage_max = INIT_GARBAGE_COUNT;\n    }\n\n    // Double the table if it is full\n    else if (garbage_count == garbage_max)\n    {\n        garbage_refs = (bucket_t**)\n            realloc(garbage_refs, garbage_max * 2 * sizeof(void *));\n        garbage_max *= 2;\n    }\n}\n\n\n/***********************************************************************\n* cache_collect_free.  Add the specified malloc'd memory to the list\n* of them to free at some later point.\n* size is used for the collection threshold. It does not have to be \n* precisely the block's size.\n* Cache locks: cacheUpdateLock must be held by the caller.\n**********************************************************************/\nstatic void cache_collect_free(bucket_t *data, mask_t capacity)\n{\n    cacheUpdateLock.assertLocked();\n\n    if (PrintCaches) recordDeadCache(capacity);\n\n    _garbage_make_room ();\n    garbage_byte_size += cache_t::bytesForCapacity(capacity);\n    garbage_refs[garbage_count++] = data;\n}\n\n\n/***********************************************************************\n* cache_collect.  Try to free accumulated dead caches.\n* collectALot tries harder to free memory.\n* Cache locks: cacheUpdateLock must be held by the caller.\n**********************************************************************/\nvoid cache_collect(bool collectALot)\n{\n    cacheUpdateLock.assertLocked();\n\n    // Done if the garbage is not full\n    if (garbage_byte_size < garbage_threshold  &&  !collectALot) {\n        return;\n    }\n\n    // Synchronize collection with objc_msgSend and other cache readers\n    if (!collectALot) {\n        if (_collecting_in_critical ()) {\n            // objc_msgSend (or other cache reader) is currently looking in\n            // the cache and might still be using some garbage.\n            if (PrintCaches) {\n                _objc_inform (\"CACHES: not collecting; \"\n                              \"objc_msgSend in progress\");\n            }\n            return;\n        }\n    } \n    else {\n        // No excuses.\n        while (_collecting_in_critical()) \n            ;\n    }\n\n    // No cache readers in progress - garbage is now deletable\n\n    // Log our progress\n    if (PrintCaches) {\n        cache_collections++;\n        _objc_inform (\"CACHES: COLLECTING %zu bytes (%zu allocations, %zu collections)\", garbage_byte_size, cache_allocations, cache_collections);\n    }\n    \n    // Dispose all refs now in the garbage\n    // Erase each entry so debugging tools don't see stale pointers.\n    while (garbage_count--) {\n        auto dead = garbage_refs[garbage_count];\n        garbage_refs[garbage_count] = nil;\n        free(dead);\n    }\n    \n    // Clear the garbage count and total size indicator\n    garbage_count = 0;\n    garbage_byte_size = 0;\n\n    if (PrintCaches) {\n        size_t i;\n        size_t total_count = 0;\n        size_t total_size = 0;\n\n        for (i = 0; i < countof(cache_counts); i++) {\n            int count = cache_counts[i];\n            int slots = 1 << i;\n            size_t size = count * slots * sizeof(bucket_t);\n\n            if (!count) continue;\n\n            _objc_inform(\"CACHES: %4d slots: %4d caches, %6zu bytes\", \n                         slots, count, size);\n\n            total_count += count;\n            total_size += size;\n        }\n\n        _objc_inform(\"CACHES:      total: %4zu caches, %6zu bytes\", \n                     total_count, total_size);\n    }\n}\n\n\n/***********************************************************************\n* objc_task_threads\n* Replacement for task_threads(). Define DEBUG_TASK_THREADS to debug \n* crashes when task_threads() is failing.\n*\n* A failure in task_threads() usually means somebody has botched their \n* Mach or MIG traffic. For example, somebody's error handling was wrong \n* and they left a message queued on the MIG reply port for task_threads() \n* to trip over.\n*\n* The code below is a modified version of task_threads(). It logs \n* the msgh_id of the reply message. The msgh_id can identify the sender \n* of the message, which can help pinpoint the faulty code.\n* DEBUG_TASK_THREADS also calls collecting_in_critical() during every \n* message dispatch, which can increase reproducibility of bugs.\n*\n* This code can be regenerated by running \n* `mig /usr/include/mach/task.defs`.\n**********************************************************************/\n#if DEBUG_TASK_THREADS\n\n#include <mach/mach.h>\n#include <mach/message.h>\n#include <mach/mig.h>\n\n#define __MIG_check__Reply__task_subsystem__ 1\n#define mig_internal static inline\n#define __DeclareSendRpc(a, b)\n#define __BeforeSendRpc(a, b)\n#define __AfterSendRpc(a, b)\n#define msgh_request_port       msgh_remote_port\n#define msgh_reply_port         msgh_local_port\n\n#ifndef __MachMsgErrorWithTimeout\n#define __MachMsgErrorWithTimeout(_R_) { \\\n        switch (_R_) { \\\n        case MACH_SEND_INVALID_DATA: \\\n        case MACH_SEND_INVALID_DEST: \\\n        case MACH_SEND_INVALID_HEADER: \\\n            mig_put_reply_port(InP->Head.msgh_reply_port); \\\n            break; \\\n        case MACH_SEND_TIMED_OUT: \\\n        case MACH_RCV_TIMED_OUT: \\\n        default: \\\n            mig_dealloc_reply_port(InP->Head.msgh_reply_port); \\\n        } \\\n    }\n#endif  /* __MachMsgErrorWithTimeout */\n\n#ifndef __MachMsgErrorWithoutTimeout\n#define __MachMsgErrorWithoutTimeout(_R_) { \\\n        switch (_R_) { \\\n        case MACH_SEND_INVALID_DATA: \\\n        case MACH_SEND_INVALID_DEST: \\\n        case MACH_SEND_INVALID_HEADER: \\\n            mig_put_reply_port(InP->Head.msgh_reply_port); \\\n            break; \\\n        default: \\\n            mig_dealloc_reply_port(InP->Head.msgh_reply_port); \\\n        } \\\n    }\n#endif  /* __MachMsgErrorWithoutTimeout */\n\n\n#if ( __MigTypeCheck )\n#if __MIG_check__Reply__task_subsystem__\n#if !defined(__MIG_check__Reply__task_threads_t__defined)\n#define __MIG_check__Reply__task_threads_t__defined\n\nmig_internal kern_return_t __MIG_check__Reply__task_threads_t(__Reply__task_threads_t *Out0P)\n{\n\n\ttypedef __Reply__task_threads_t __Reply;\n\tboolean_t msgh_simple;\n#if\t__MigTypeCheck\n\tunsigned int msgh_size;\n#endif\t/* __MigTypeCheck */\n\tif (Out0P->Head.msgh_id != 3502) {\n\t    if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)\n\t\t{ return MIG_SERVER_DIED; }\n\t    else\n\t\t{ return MIG_REPLY_MISMATCH; }\n\t}\n\n\tmsgh_simple = !(Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);\n#if\t__MigTypeCheck\n\tmsgh_size = Out0P->Head.msgh_size;\n\n\tif ((msgh_simple || Out0P->msgh_body.msgh_descriptor_count != 1 ||\n\t    msgh_size != (mach_msg_size_t)sizeof(__Reply)) &&\n\t    (!msgh_simple || msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||\n\t    ((mig_reply_error_t *)Out0P)->RetCode == KERN_SUCCESS))\n\t\t{ return MIG_TYPE_ERROR ; }\n#endif\t/* __MigTypeCheck */\n\n\tif (msgh_simple) {\n\t\treturn ((mig_reply_error_t *)Out0P)->RetCode;\n\t}\n\n#if\t__MigTypeCheck\n\tif (Out0P->act_list.type != MACH_MSG_OOL_PORTS_DESCRIPTOR ||\n\t    Out0P->act_list.disposition != 17) {\n\t\treturn MIG_TYPE_ERROR;\n\t}\n#endif\t/* __MigTypeCheck */\n\n\treturn MACH_MSG_SUCCESS;\n}\n#endif /* !defined(__MIG_check__Reply__task_threads_t__defined) */\n#endif /* __MIG_check__Reply__task_subsystem__ */\n#endif /* ( __MigTypeCheck ) */\n\n\n/* Routine task_threads */\nstatic kern_return_t objc_task_threads\n(\n\ttask_t target_task,\n\tthread_act_array_t *act_list,\n\tmach_msg_type_number_t *act_listCnt\n)\n{\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t} Request;\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\t/* start of the kernel processed data */\n\t\tmach_msg_body_t msgh_body;\n\t\tmach_msg_ool_ports_descriptor_t act_list;\n\t\t/* end of the kernel processed data */\n\t\tNDR_record_t NDR;\n\t\tmach_msg_type_number_t act_listCnt;\n\t\tmach_msg_trailer_t trailer;\n\t} Reply;\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\t/* start of the kernel processed data */\n\t\tmach_msg_body_t msgh_body;\n\t\tmach_msg_ool_ports_descriptor_t act_list;\n\t\t/* end of the kernel processed data */\n\t\tNDR_record_t NDR;\n\t\tmach_msg_type_number_t act_listCnt;\n\t} __Reply;\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n\t/*\n\t * typedef struct {\n\t * \tmach_msg_header_t Head;\n\t * \tNDR_record_t NDR;\n\t * \tkern_return_t RetCode;\n\t * } mig_reply_error_t;\n\t */\n\n\tunion {\n\t\tRequest In;\n\t\tReply Out;\n\t} Mess;\n\n\tRequest *InP = &Mess.In;\n\tReply *Out0P = &Mess.Out;\n\n\tmach_msg_return_t msg_result;\n\n#ifdef\t__MIG_check__Reply__task_threads_t__defined\n\tkern_return_t check_result;\n#endif\t/* __MIG_check__Reply__task_threads_t__defined */\n\n\t__DeclareSendRpc(3402, \"task_threads\")\n\n\tInP->Head.msgh_bits =\n\t\tMACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);\n\t/* msgh_size passed as argument */\n\tInP->Head.msgh_request_port = target_task;\n\tInP->Head.msgh_reply_port = mig_get_reply_port();\n\tInP->Head.msgh_id = 3402;\n\n\t__BeforeSendRpc(3402, \"task_threads\")\n\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n\t__AfterSendRpc(3402, \"task_threads\")\n\tif (msg_result != MACH_MSG_SUCCESS) {\n\t\t_objc_inform(\"task_threads received unexpected reply msgh_id 0x%zx\", \n                             (size_t)Out0P->Head.msgh_id);\n\t\t__MachMsgErrorWithoutTimeout(msg_result);\n\t\t{ return msg_result; }\n\t}\n\n\n#if\tdefined(__MIG_check__Reply__task_threads_t__defined)\n\tcheck_result = __MIG_check__Reply__task_threads_t((__Reply__task_threads_t *)Out0P);\n\tif (check_result != MACH_MSG_SUCCESS)\n\t\t{ return check_result; }\n#endif\t/* defined(__MIG_check__Reply__task_threads_t__defined) */\n\n\t*act_list = (thread_act_array_t)(Out0P->act_list.address);\n\t*act_listCnt = Out0P->act_listCnt;\n\n\treturn KERN_SUCCESS;\n}\n\n// DEBUG_TASK_THREADS\n#endif\n\n\n// __OBJC2__\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-class-old.mm",
    "content": "/*\n * Copyright (c) 1999-2009 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-class-old.m\n* Support for old-ABI classes, methods, and categories.\n**********************************************************************/\n\n#if !__OBJC2__\n\n#include \"objc-private.h\"\n#include \"objc-runtime-old.h\"\n#include \"objc-file-old.h\"\n#include \"objc-cache-old.h\"\n\nstatic Method _class_getMethod(Class cls, SEL sel);\nstatic Method _class_getMethodNoSuper(Class cls, SEL sel);\nstatic Method _class_getMethodNoSuper_nolock(Class cls, SEL sel);\nstatic void flush_caches(Class cls, bool flush_meta);\n\n\n// Freed objects have their isa set to point to this dummy class.\n// This avoids the need to check for Nil classes in the messenger.\nstatic const void* freedObjectClass[12] =\n{\n    Nil,\t\t\t\t// isa\n    Nil,\t\t\t\t// superclass\n    \"FREED(id)\",\t\t\t// name\n    0,\t\t\t\t// version\n    0,\t\t\t\t// info\n    0,\t\t\t\t// instance_size\n    nil,\t\t\t\t// ivars\n    nil,\t\t\t\t// methodLists\n    (Cache) &_objc_empty_cache,\t\t// cache\n    nil,\t\t\t\t// protocols\n    nil,\t\t\t// ivar_layout;\n    nil\t\t\t// ext\n};\n\n\n/***********************************************************************\n* _class_getFreedObjectClass.  Return a pointer to the dummy freed\n* object class.  Freed objects get their isa pointers replaced with\n* a pointer to the freedObjectClass, so that we can catch usages of\n* the freed object.\n**********************************************************************/\nstatic Class _class_getFreedObjectClass(void)\n{\n    return (Class)freedObjectClass;\n}\n\n\n/***********************************************************************\n* _objc_getFreedObjectClass.  Return a pointer to the dummy freed\n* object class.  Freed objects get their isa pointers replaced with\n* a pointer to the freedObjectClass, so that we can catch usages of\n* the freed object.\n**********************************************************************/\nClass _objc_getFreedObjectClass(void)\n{\n    return _class_getFreedObjectClass();\n}\n\n\nstatic void allocateExt(Class cls)\n{\n    if (! (cls->info & CLS_EXT)) {\n        _objc_inform(\"class '%s' needs to be recompiled\", cls->name);\n        return;\n    } \n    if (!cls->ext) {\n        uint32_t size = (uint32_t)sizeof(old_class_ext);\n        cls->ext = (old_class_ext *)calloc(size, 1);\n        cls->ext->size = size;\n    }\n}\n\n\nstatic inline old_method *_findNamedMethodInList(old_method_list * mlist, const char *meth_name) {\n    int i;\n    if (!mlist) return nil;\n    for (i = 0; i < mlist->method_count; i++) {\n        old_method *m = &mlist->method_list[i];\n        if (0 == strcmp((const char *)(m->method_name), meth_name)) {\n            return m;\n        }\n    }\n    return nil;\n}\n\n\n/***********************************************************************\n* Method list fixup markers.\n* mlist->obsolete == fixed_up_method_list marks method lists with real SELs \n*   versus method lists with un-uniqued char*.\n* PREOPTIMIZED VERSION:\n*   Fixed-up method lists get mlist->obsolete == OBJC_FIXED_UP \n*   dyld shared cache sets this for method lists it preoptimizes.\n* UN-PREOPTIMIZED VERSION\n*   Fixed-up method lists get mlist->obsolete == OBJC_FIXED_UP_outside_dyld\n*   dyld shared cache uses OBJC_FIXED_UP, but those aren't trusted.\n**********************************************************************/\n#define OBJC_FIXED_UP ((void *)1771)\n#define OBJC_FIXED_UP_outside_dyld ((void *)1773)\nstatic void *fixed_up_method_list = OBJC_FIXED_UP;\n\n// sel_init() decided that selectors in the dyld shared cache are untrustworthy\nvoid disableSharedCacheOptimizations(void)\n{\n    fixed_up_method_list = OBJC_FIXED_UP_outside_dyld;\n}\n\n/***********************************************************************\n* fixupSelectorsInMethodList\n* Uniques selectors in the given method list.\n* The given method list must be non-nil and not already fixed-up.\n* If the class was loaded from a bundle:\n*   fixes up the given list in place with heap-allocated selector strings\n* If the class was not from a bundle:\n*   allocates a copy of the method list, fixes up the copy, and returns \n*   the copy. The given list is unmodified.\n*\n* If cls is already in use, methodListLock must be held by the caller.\n**********************************************************************/\nstatic old_method_list *fixupSelectorsInMethodList(Class cls, old_method_list *mlist)\n{\n    int i;\n    size_t size;\n    old_method *method;\n    old_method_list *old_mlist; \n    \n    if ( ! mlist ) return nil;\n    if ( mlist->obsolete == fixed_up_method_list ) {\n        // method list OK\n    } else {\n        bool isBundle = cls->info & CLS_FROM_BUNDLE;\n        if (!isBundle) {\n            old_mlist = mlist;\n            size = sizeof(old_method_list) - sizeof(old_method) + old_mlist->method_count * sizeof(old_method);\n            mlist = (old_method_list *)malloc(size);\n            memmove(mlist, old_mlist, size);\n        } else {\n            // Mach-O bundles are fixed up in place. \n            // This prevents leaks when a bundle is unloaded.\n        }\n        mutex_locker_t lock(selLock);\n        for ( i = 0; i < mlist->method_count; i += 1 ) {\n            method = &mlist->method_list[i];\n            method->method_name =\n                sel_registerNameNoLock((const char *)method->method_name, isBundle);  // Always copy selector data from bundles.\n        }\n        mlist->obsolete = fixed_up_method_list;\n    }\n    return mlist;\n}\n\n\n/***********************************************************************\n* nextMethodList\n* Returns successive method lists from the given class.\n* Method lists are returned in method search order (i.e. highest-priority \n* implementations first).\n* All necessary method list fixups are performed, so the \n* returned method list is fully-constructed.\n*\n* If cls is already in use, methodListLock must be held by the caller.\n* For full thread-safety, methodListLock must be continuously held by the \n* caller across all calls to nextMethodList(). If the lock is released, \n* the bad results listed in class_nextMethodList() may occur.\n*\n* void *iterator = nil;\n* old_method_list *mlist;\n* mutex_locker_t lock(methodListLock);\n* while ((mlist = nextMethodList(cls, &iterator))) {\n*     // do something with mlist\n* }\n**********************************************************************/\nstatic old_method_list *nextMethodList(Class cls,\n                                               void **it)\n{\n    uintptr_t index = *(uintptr_t *)it;\n    old_method_list **resultp;\n\n    if (index == 0) {\n        // First call to nextMethodList.\n        if (!cls->methodLists) {\n            resultp = nil;\n        } else if (cls->info & CLS_NO_METHOD_ARRAY) {\n            resultp = (old_method_list **)&cls->methodLists;\n        } else {\n            resultp = &cls->methodLists[0];\n            if (!*resultp  ||  *resultp == END_OF_METHODS_LIST) {\n                resultp = nil;\n            }\n        }\n    } else {\n        // Subsequent call to nextMethodList.\n        if (!cls->methodLists) {\n            resultp = nil;\n        } else if (cls->info & CLS_NO_METHOD_ARRAY) {\n            resultp = nil;\n        } else {\n            resultp = &cls->methodLists[index];\n            if (!*resultp  ||  *resultp == END_OF_METHODS_LIST) {\n                resultp = nil;\n            }\n        }\n    }\n\n    // resultp now is nil, meaning there are no more method lists, \n    // OR the address of the method list pointer to fix up and return.\n    \n    if (resultp) {\n        if (*resultp) {\n            *resultp = fixupSelectorsInMethodList(cls, *resultp);\n        }\n        *it = (void *)(index + 1);\n        return *resultp;\n    } else {\n        *it = 0;\n        return nil;\n    }\n}\n\n\n/* These next three functions are the heart of ObjC method lookup. \n * If the class is currently in use, methodListLock must be held by the caller.\n */\nstatic inline old_method *_findMethodInList(old_method_list * mlist, SEL sel) {\n    int i;\n    if (!mlist) return nil;\n    for (i = 0; i < mlist->method_count; i++) {\n        old_method *m = &mlist->method_list[i];\n        if (m->method_name == sel) {\n            return m;\n        }\n    }\n    return nil;\n}\n\nstatic inline old_method * _findMethodInClass(Class cls, SEL sel) __attribute__((always_inline));\nstatic inline old_method * _findMethodInClass(Class cls, SEL sel) {\n    // Flattened version of nextMethodList(). The optimizer doesn't \n    // do a good job with hoisting the conditionals out of the loop.\n    // Conceptually, this looks like:\n    // while ((mlist = nextMethodList(cls, &iterator))) {\n    //     old_method *m = _findMethodInList(mlist, sel);\n    //     if (m) return m;\n    // }\n\n    if (!cls->methodLists) {\n        // No method lists.\n        return nil;\n    }\n    else if (cls->info & CLS_NO_METHOD_ARRAY) {\n        // One method list.\n        old_method_list **mlistp;\n        mlistp = (old_method_list **)&cls->methodLists;\n        *mlistp = fixupSelectorsInMethodList(cls, *mlistp);\n        return _findMethodInList(*mlistp, sel);\n    }\n    else {\n        // Multiple method lists.\n        old_method_list **mlistp;\n        for (mlistp = cls->methodLists; \n             *mlistp != nil  &&  *mlistp != END_OF_METHODS_LIST; \n             mlistp++) \n        {\n            old_method *m;\n            *mlistp = fixupSelectorsInMethodList(cls, *mlistp);\n            m = _findMethodInList(*mlistp, sel);\n            if (m) return m;\n        }\n        return nil;\n    }\n}\n\nstatic inline old_method * _getMethod(Class cls, SEL sel) {\n    for (; cls; cls = cls->superclass) {\n        old_method *m;\n        m = _findMethodInClass(cls, sel);\n        if (m) return m;\n    }\n    return nil;\n}\n\n\n// called by a debugging check in _objc_insertMethods\nIMP findIMPInClass(Class cls, SEL sel)\n{\n    old_method *m = _findMethodInClass(cls, sel);\n    if (m) return m->method_imp;\n    else return nil;\n}\n\n\n/***********************************************************************\n* _freedHandler.\n**********************************************************************/\nstatic void _freedHandler(id obj, SEL sel)\n{\n    __objc_error (obj, \"message %s sent to freed object=%p\", \n                  sel_getName(sel), (void*)obj);\n}\n\n\n/***********************************************************************\n* log_and_fill_cache\n* Log this method call. If the logger permits it, fill the method cache.\n* cls is the method whose cache should be filled. \n* implementer is the class that owns the implementation in question.\n**********************************************************************/\nstatic void\nlog_and_fill_cache(Class cls, Class implementer, Method meth, SEL sel)\n{\n#if SUPPORT_MESSAGE_LOGGING\n    if (objcMsgLogEnabled) {\n        bool cacheIt = logMessageSend(implementer->isMetaClass(), \n                                      cls->nameForLogging(),\n                                      implementer->nameForLogging(), \n                                      sel);\n        if (!cacheIt) return;\n    }\n#endif\n    _cache_fill (cls, meth, sel);\n}\n\n\n/***********************************************************************\n* _class_lookupMethodAndLoadCache.\n* Method lookup for dispatchers ONLY. OTHER CODE SHOULD USE lookUpImp().\n* This lookup avoids optimistic cache scan because the dispatcher \n* already tried that.\n**********************************************************************/\nIMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls)\n{        \n    return lookUpImpOrForward(cls, sel, obj, \n                              YES/*initialize*/, NO/*cache*/, YES/*resolver*/);\n}\n\n\n/***********************************************************************\n* lookUpImpOrForward.\n* The standard IMP lookup. \n* initialize==NO tries to avoid +initialize (but sometimes fails)\n* cache==NO skips optimistic unlocked lookup (but uses cache elsewhere)\n* Most callers should use initialize==YES and cache==YES.\n* inst is an instance of cls or a subclass thereof, or nil if none is known. \n*   If cls is an un-initialized metaclass then a non-nil inst is faster.\n* May return _objc_msgForward_impcache. IMPs destined for external use \n*   must be converted to _objc_msgForward or _objc_msgForward_stret.\n*   If you don't want forwarding at all, use lookUpImpOrNil() instead.\n**********************************************************************/\nIMP lookUpImpOrForward(Class cls, SEL sel, id inst, \n                       bool initialize, bool cache, bool resolver)\n{\n    Class curClass;\n    IMP methodPC = nil;\n    Method meth;\n    bool triedResolver = NO;\n\n    methodListLock.assertUnlocked();\n\n    // Optimistic cache lookup\n    if (cache) {\n        methodPC = _cache_getImp(cls, sel);\n        if (methodPC) return methodPC;    \n    }\n\n    // Check for freed class\n    if (cls == _class_getFreedObjectClass())\n        return (IMP) _freedHandler;\n\n    // Check for +initialize\n    if (initialize  &&  !cls->isInitialized()) {\n        _class_initialize (_class_getNonMetaClass(cls, inst));\n        // If sel == initialize, _class_initialize will send +initialize and \n        // then the messenger will send +initialize again after this \n        // procedure finishes. Of course, if this is not being called \n        // from the messenger then it won't happen. 2778172\n    }\n\n    // The lock is held to make method-lookup + cache-fill atomic \n    // with respect to method addition. Otherwise, a category could \n    // be added but ignored indefinitely because the cache was re-filled \n    // with the old value after the cache flush on behalf of the category.\n retry:\n    methodListLock.lock();\n\n    // Try this class's cache.\n\n    methodPC = _cache_getImp(cls, sel);\n    if (methodPC) goto done;\n\n    // Try this class's method lists.\n\n    meth = _class_getMethodNoSuper_nolock(cls, sel);\n    if (meth) {\n        log_and_fill_cache(cls, cls, meth, sel);\n        methodPC = method_getImplementation(meth);\n        goto done;\n    }\n\n    // Try superclass caches and method lists.\n\n    curClass = cls;\n    while ((curClass = curClass->superclass)) {\n        // Superclass cache.\n        meth = _cache_getMethod(curClass, sel, _objc_msgForward_impcache);\n        if (meth) {\n            if (meth != (Method)1) {\n                // Found the method in a superclass. Cache it in this class.\n                log_and_fill_cache(cls, curClass, meth, sel);\n                methodPC = method_getImplementation(meth);\n                goto done;\n            }\n            else {\n                // Found a forward:: entry in a superclass.\n                // Stop searching, but don't cache yet; call method \n                // resolver for this class first.\n                break;\n            }\n        }\n\n        // Superclass method list.\n        meth = _class_getMethodNoSuper_nolock(curClass, sel);\n        if (meth) {\n            log_and_fill_cache(cls, curClass, meth, sel);\n            methodPC = method_getImplementation(meth);\n            goto done;\n        }\n    }\n\n    // No implementation found. Try method resolver once.\n\n    if (resolver  &&  !triedResolver) {\n        methodListLock.unlock();\n        _class_resolveMethod(cls, sel, inst);\n        triedResolver = YES;\n        goto retry;\n    }\n\n    // No implementation found, and method resolver didn't help. \n    // Use forwarding.\n\n    _cache_addForwardEntry(cls, sel);\n    methodPC = _objc_msgForward_impcache;\n\n done:\n    methodListLock.unlock();\n\n    return methodPC;\n}\n\n\n/***********************************************************************\n* lookUpImpOrNil.\n* Like lookUpImpOrForward, but returns nil instead of _objc_msgForward_impcache\n**********************************************************************/\nIMP lookUpImpOrNil(Class cls, SEL sel, id inst, \n                   bool initialize, bool cache, bool resolver)\n{\n    IMP imp = lookUpImpOrForward(cls, sel, inst, initialize, cache, resolver);\n    if (imp == _objc_msgForward_impcache) return nil;\n    else return imp;\n}\n\n\n/***********************************************************************\n* lookupMethodInClassAndLoadCache.\n* Like _class_lookupMethodAndLoadCache, but does not search superclasses.\n* Caches and returns objc_msgForward if the method is not found in the class.\n**********************************************************************/\nIMP lookupMethodInClassAndLoadCache(Class cls, SEL sel)\n{\n    Method meth;\n    IMP imp;\n\n    // fixme this still has the method list vs method cache race \n    // because it doesn't hold a lock across lookup+cache_fill, \n    // but it's only used for .cxx_construct/destruct and we assume \n    // categories don't change them.\n\n    // Search cache first.\n    imp = _cache_getImp(cls, sel);\n    if (imp) return imp;\n\n    // Cache miss. Search method list.\n\n    meth = _class_getMethodNoSuper(cls, sel);\n\n    if (meth) {\n        // Hit in method list. Cache it.\n        _cache_fill(cls, meth, sel);\n        return method_getImplementation(meth);\n    } else {\n        // Miss in method list. Cache objc_msgForward.\n        _cache_addForwardEntry(cls, sel);\n        return _objc_msgForward_impcache;\n    }\n}\n\n\n/***********************************************************************\n* _class_getClassForIvar\n* Given a class and an ivar that is in it or one of its superclasses, \n* find the actual class that defined the ivar.\n**********************************************************************/\nClass _class_getClassForIvar(Class cls, Ivar ivar)\n{\n    for ( ; cls; cls = cls->superclass) {\n        if (auto ivars = cls->ivars) {\n            if (ivar >= &ivars->ivar_list[0]  &&  \n                ivar < &ivars->ivar_list[ivars->ivar_count]) \n            {\n                return cls;\n            }\n        }\n    }\n\n    return nil;\n}\n\n\n/***********************************************************************\n* class_getVariable.  Return the named instance variable.\n**********************************************************************/\n\nIvar _class_getVariable(Class cls, const char *name)\n{\n    for (; cls != Nil; cls = cls->superclass) {\n        int i;\n\n        // Skip class having no ivars\n        if (!cls->ivars) continue;\n\n        for (i = 0; i < cls->ivars->ivar_count; i++) {\n            // Check this ivar's name.  Be careful because the\n            // compiler generates ivar entries with nil ivar_name\n            // (e.g. for anonymous bit fields).\n            old_ivar *ivar = &cls->ivars->ivar_list[i];\n            if (ivar->ivar_name  &&  0 == strcmp(name, ivar->ivar_name)) {\n                return (Ivar)ivar;\n            }\n        }\n    }\n\n    // Not found\n    return nil;\n}\n\n\nold_property * \nproperty_list_nth(const old_property_list *plist, uint32_t i)\n{\n    return (old_property *)(i*plist->entsize + (char *)&plist->first);\n}\n\nold_property **\ncopyPropertyList(old_property_list *plist, unsigned int *outCount)\n{\n    old_property **result = nil;\n    unsigned int count = 0;\n\n    if (plist) {\n        count = plist->count;\n    }\n\n    if (count > 0) {\n        unsigned int i;\n        result = (old_property **)malloc((count+1) * sizeof(old_property *));\n        \n        for (i = 0; i < count; i++) {\n            result[i] = property_list_nth(plist, i);\n        }\n        result[i] = nil;\n    }\n\n    if (outCount) *outCount = count;\n    return result;\n}\n\n\nstatic old_property_list *\nnextPropertyList(Class cls, uintptr_t *indexp)\n{\n    old_property_list *result = nil;\n\n    classLock.assertLocked();\n    if (! ((cls->info & CLS_EXT)  &&  cls->ext)) {\n        // No class ext\n        result = nil;\n    } else if (!cls->ext->propertyLists) {\n        // No property lists\n        result = nil;\n    } else if (cls->info & CLS_NO_PROPERTY_ARRAY) {\n        // Only one property list\n        if (*indexp == 0) {\n            result = (old_property_list *)cls->ext->propertyLists;\n        } else {\n            result = nil;\n        }\n    } else {\n        // More than one property list\n        result = cls->ext->propertyLists[*indexp];\n    }\n\n    if (result) {\n        ++*indexp;\n        return result;\n    } else {\n        *indexp = 0;\n        return nil;\n    }\n}\n\n\n/***********************************************************************\n* class_getIvarLayout\n* nil means all-scanned. \"\" means non-scanned.\n**********************************************************************/\nconst uint8_t *\nclass_getIvarLayout(Class cls)\n{\n    if (cls  &&  (cls->info & CLS_EXT)) {\n        return cls->ivar_layout;\n    } else {\n        return nil;  // conservative scan\n    }\n}\n\n\n/***********************************************************************\n* class_getWeakIvarLayout\n* nil means no weak ivars.\n**********************************************************************/\nconst uint8_t *\nclass_getWeakIvarLayout(Class cls)\n{\n    if (cls  &&  (cls->info & CLS_EXT)  &&  cls->ext) {\n        return cls->ext->weak_ivar_layout;\n    } else {\n        return nil;  // no weak ivars\n    }\n}\n\n\n/***********************************************************************\n* class_setIvarLayout\n* nil means all-scanned. \"\" means non-scanned.\n**********************************************************************/\nvoid class_setIvarLayout(Class cls, const uint8_t *layout)\n{\n    if (!cls) return;\n\n    if (! (cls->info & CLS_EXT)) {\n        _objc_inform(\"class '%s' needs to be recompiled\", cls->name);\n        return;\n    } \n\n    // fixme leak\n    cls->ivar_layout = ustrdupMaybeNil(layout);\n}\n\n\n/***********************************************************************\n* class_setWeakIvarLayout\n* nil means no weak ivars.\n**********************************************************************/\nvoid class_setWeakIvarLayout(Class cls, const uint8_t *layout)\n{\n    if (!cls) return;\n\n    mutex_locker_t lock(classLock);\n\n    allocateExt(cls);\n    \n    // fixme leak\n    cls->ext->weak_ivar_layout = ustrdupMaybeNil(layout);\n}\n\n\n/***********************************************************************\n* class_setVersion.  Record the specified version with the class.\n**********************************************************************/\nvoid class_setVersion(Class cls, int version)\n{\n    if (!cls) return;\n    cls->version = version;\n}\n\n/***********************************************************************\n* class_getVersion.  Return the version recorded with the class.\n**********************************************************************/\nint class_getVersion(Class cls)\n{\n    if (!cls) return 0;\n    return (int)cls->version;\n}\n\n\n/***********************************************************************\n* class_getName.\n**********************************************************************/\nconst char *class_getName(Class cls)\n{\n    if (!cls) return \"nil\";\n    else return cls->demangledName();\n}\n\n\n/***********************************************************************\n* _class_getNonMetaClass. \n* Return the ordinary class for this class or metaclass. \n* Used by +initialize. \n**********************************************************************/\nClass _class_getNonMetaClass(Class cls, id obj)\n{\n    // fixme ick\n    if (cls->isMetaClass()) {\n        if (cls->info & CLS_CONSTRUCTING) {\n            // Class is under construction and isn't in the class_hash, \n            // so objc_getClass doesn't work.\n            cls = obj;  // fixme this may be nil in some paths\n        }\n        else if (strncmp(cls->name, \"_%\", 2) == 0) {\n            // Posee's meta's name is smashed and isn't in the class_hash, \n            // so objc_getClass doesn't work.\n            const char *baseName = strchr(cls->name, '%'); // get posee's real name\n            cls = objc_getClass(baseName);\n        }\n        else {\n            cls = objc_getClass(cls->name);\n        }\n        assert(cls);\n    }\n\n    return cls;\n}\n\n\nCache _class_getCache(Class cls)\n{\n    return cls->cache;\n}\n\nvoid _class_setCache(Class cls, Cache cache)\n{\n    cls->cache = cache;\n}\n\nconst char *_category_getName(Category cat)\n{\n    return oldcategory(cat)->category_name;\n}\n\nconst char *_category_getClassName(Category cat)\n{\n    return oldcategory(cat)->class_name;\n}\n\nClass _category_getClass(Category cat)\n{\n    return objc_getClass(oldcategory(cat)->class_name);\n}\n\nIMP _category_getLoadMethod(Category cat)\n{\n    old_method_list *mlist = oldcategory(cat)->class_methods;\n    if (mlist) {\n        return lookupNamedMethodInMethodList(mlist, \"load\");\n    } else {\n        return nil;\n    }\n}\n\n\n\n/***********************************************************************\n* class_nextMethodList.\n* External version of nextMethodList().\n*\n* This function is not fully thread-safe. A series of calls to \n* class_nextMethodList() may fail if methods are added to or removed \n* from the class between calls.\n* If methods are added between calls to class_nextMethodList(), it may \n* return previously-returned method lists again, and may fail to return \n* newly-added lists. \n* If methods are removed between calls to class_nextMethodList(), it may \n* omit surviving method lists or simply crash.\n**********************************************************************/\nstruct objc_method_list *class_nextMethodList(Class cls, void **it)\n{\n    OBJC_WARN_DEPRECATED;\n\n    mutex_locker_t lock(methodListLock);\n    return (struct objc_method_list *) nextMethodList(cls, it);\n}\n\n\n/***********************************************************************\n* class_addMethods.\n*\n* Formerly class_addInstanceMethods ()\n**********************************************************************/\nvoid class_addMethods(Class cls, struct objc_method_list *meths)\n{\n    OBJC_WARN_DEPRECATED;\n\n    // Add the methods.\n    {\n        mutex_locker_t lock(methodListLock);\n        _objc_insertMethods(cls, (old_method_list *)meths, nil);\n    }\n\n    // Must flush when dynamically adding methods.  No need to flush\n    // all the class method caches.  If cls is a meta class, though,\n    // this will still flush it and any of its sub-meta classes.\n    flush_caches (cls, NO);\n}\n\n\n/***********************************************************************\n* class_removeMethods.\n**********************************************************************/\nvoid class_removeMethods(Class cls, struct objc_method_list *meths)\n{\n    OBJC_WARN_DEPRECATED;\n\n    // Remove the methods\n    {\n        mutex_locker_t lock(methodListLock);\n        _objc_removeMethods(cls, (old_method_list *)meths);\n    }\n\n    // Must flush when dynamically removing methods.  No need to flush\n    // all the class method caches.  If cls is a meta class, though,\n    // this will still flush it and any of its sub-meta classes.\n    flush_caches (cls, NO);\n}\n\n/***********************************************************************\n* lookupNamedMethodInMethodList\n* Only called to find +load/-.cxx_construct/-.cxx_destruct methods, \n* without fixing up the entire method list.\n* The class is not yet in use, so methodListLock is not taken.\n**********************************************************************/\nIMP lookupNamedMethodInMethodList(old_method_list *mlist, const char *meth_name)\n{\n    old_method *m;\n    m = meth_name ? _findNamedMethodInList(mlist, meth_name) : nil;\n    return (m ? m->method_imp : nil);\n}\n\nstatic Method _class_getMethod(Class cls, SEL sel)\n{\n    mutex_locker_t lock(methodListLock);\n    return (Method)_getMethod(cls, sel);\n}\n\nstatic Method _class_getMethodNoSuper(Class cls, SEL sel)\n{\n    mutex_locker_t lock(methodListLock);\n    return (Method)_findMethodInClass(cls, sel);\n}\n\nstatic Method _class_getMethodNoSuper_nolock(Class cls, SEL sel)\n{\n    methodListLock.assertLocked();\n    return (Method)_findMethodInClass(cls, sel);\n}\n\n\n/***********************************************************************\n* class_getInstanceMethod.  Return the instance method for the\n* specified class and selector.\n**********************************************************************/\nMethod class_getInstanceMethod(Class cls, SEL sel)\n{\n    if (!cls  ||  !sel) return nil;\n\n    // This deliberately avoids +initialize because it historically did so.\n\n    // This implementation is a bit weird because it's the only place that \n    // wants a Method instead of an IMP.\n\n    Method meth;\n    meth = _cache_getMethod(cls, sel, _objc_msgForward_impcache);\n    if (meth == (Method)1) {\n        // Cache contains forward:: . Stop searching.\n        return nil;\n    } else if (meth) {\n        return meth;\n    }\n        \n    // Search method lists, try method resolver, etc.\n    lookUpImpOrNil(cls, sel, nil, \n                   NO/*initialize*/, NO/*cache*/, YES/*resolver*/);\n\n    meth = _cache_getMethod(cls, sel, _objc_msgForward_impcache);\n    if (meth == (Method)1) {\n        // Cache contains forward:: . Stop searching.\n        return nil;\n    } else if (meth) {\n        return meth;\n    }\n\n    return _class_getMethod(cls, sel);\n}\n\n\nBOOL class_conformsToProtocol(Class cls, Protocol *proto_gen)\n{\n    old_protocol *proto = oldprotocol(proto_gen);\n    \n    if (!cls) return NO;\n    if (!proto) return NO;\n\n    if (cls->ISA()->version >= 3) {\n        old_protocol_list *list;\n        for (list = cls->protocols; list != nil; list = list->next) {\n            int i;\n            for (i = 0; i < list->count; i++) {\n                if (list->list[i] == proto) return YES;\n                if (protocol_conformsToProtocol((Protocol *)list->list[i], proto_gen)) return YES;\n            }\n            if (cls->ISA()->version <= 4) break;\n        }\n    }\n    return NO;\n}\n\n\nstatic NXMapTable *\tposed_class_hash = nil;\n\n/***********************************************************************\n* objc_getOrigClass.\n**********************************************************************/\nextern \"C\" \nClass _objc_getOrigClass(const char *name)\n{\n    // Look for class among the posers\n    {\n        mutex_locker_t lock(classLock);\n        if (posed_class_hash) {\n            Class cls = (Class) NXMapGet (posed_class_hash, name);\n            if (cls) return cls;\n        }\n    }\n\n    // Not a poser.  Do a normal lookup.\n    Class cls = objc_getClass (name);\n    if (cls) return cls;\n\n    _objc_inform (\"class `%s' not linked into application\", name);\n    return nil;\n}\n\nClass objc_getOrigClass(const char *name)\n{\n    OBJC_WARN_DEPRECATED;\n    return _objc_getOrigClass(name);\n}\n\n/***********************************************************************\n* _objc_addOrigClass.  This function is only used from class_poseAs.\n* Registers the original class names, before they get obscured by\n* posing, so that [super ..] will work correctly from categories\n* in posing classes and in categories in classes being posed for.\n**********************************************************************/\nstatic void\t_objc_addOrigClass\t   (Class origClass)\n{\n    mutex_locker_t lock(classLock);\n\n    // Create the poser's hash table on first use\n    if (!posed_class_hash)\n    {\n        posed_class_hash = NXCreateMapTable(NXStrValueMapPrototype, 8);\n    }\n\n    // Add the named class iff it is not already there (or collides?)\n    if (NXMapGet (posed_class_hash, origClass->name) == 0)\n        NXMapInsert (posed_class_hash, origClass->name, origClass);\n}\n\n\n/***********************************************************************\n* change_class_references\n* Change classrefs and superclass pointers from original to imposter\n* But if copy!=nil, don't change copy->superclass.\n* If changeSuperRefs==YES, also change [super message] classrefs. \n* Used by class_poseAs and objc_setFutureClass\n* classLock must be locked.\n**********************************************************************/\nvoid change_class_references(Class imposter, \n                             Class original, \n                             Class copy, \n                             bool changeSuperRefs)\n{\n    header_info *hInfo;\n    Class clsObject;\n    NXHashState state;\n\n    // Change all subclasses of the original to point to the imposter.\n    state = NXInitHashState (class_hash);\n    while (NXNextHashState (class_hash, &state, (void **) &clsObject))\n    {\n        while  ((clsObject) && (clsObject != imposter) &&\n                (clsObject != copy))\n        {\n            if (clsObject->superclass == original)\n            {\n                clsObject->superclass = imposter;\n                clsObject->ISA()->superclass = imposter->ISA();\n                // We must flush caches here!\n                break;\n            }\n\n            clsObject = clsObject->superclass;\n        }\n    }\n\n    // Replace the original with the imposter in all class refs\n    // Major loop - process all headers\n    for (hInfo = FirstHeader; hInfo != nil; hInfo = hInfo->getNext())\n    {\n        Class *cls_refs;\n        size_t\trefCount;\n        unsigned int\tindex;\n\n        // Fix class refs associated with this header\n        cls_refs = _getObjcClassRefs(hInfo, &refCount);\n        if (cls_refs) {\n            for (index = 0; index < refCount; index += 1) {\n                if (cls_refs[index] == original) {\n                    cls_refs[index] = imposter;\n                }\n            }\n        }\n    }\n}\n\n\n/***********************************************************************\n* class_poseAs.\n*\n* !!! class_poseAs () does not currently flush any caches.\n**********************************************************************/\nClass class_poseAs(Class imposter, Class original)\n{\n    char *\t\t\timposterNamePtr;\n    Class \t\t\tcopy;\n\n    OBJC_WARN_DEPRECATED;\n\n    // Trivial case is easy\n    if (imposter == original)\n        return imposter;\n\n    // Imposter must be an immediate subclass of the original\n    if (imposter->superclass != original) {\n        __objc_error(imposter, \n                     \"[%s poseAs:%s]: target not immediate superclass\", \n                     imposter->name, original->name);\n    }\n\n    // Can't pose when you have instance variables (how could it work?)\n    if (imposter->ivars) {\n        __objc_error(imposter, \n                     \"[%s poseAs:%s]: %s defines new instance variables\", \n                     imposter->name, original->name, imposter->name);\n    }\n\n    // Build a string to use to replace the name of the original class.\n#if TARGET_OS_WIN32\n#   define imposterNamePrefix \"_%\"\n    imposterNamePtr = malloc(strlen(original->name) + strlen(imposterNamePrefix) + 1);\n    strcpy(imposterNamePtr, imposterNamePrefix);\n    strcat(imposterNamePtr, original->name);\n#   undef imposterNamePrefix\n#else\n    asprintf(&imposterNamePtr, \"_%%%s\", original->name);\n#endif\n\n    // We lock the class hashtable, so we are thread safe with respect to\n    // calls to objc_getClass ().  However, the class names are not\n    // changed atomically, nor are all of the subclasses updated\n    // atomically.  I have ordered the operations so that you will\n    // never crash, but you may get inconsistent results....\n\n    // Register the original class so that [super ..] knows\n    // exactly which classes are the \"original\" classes.\n    _objc_addOrigClass (original);\n    _objc_addOrigClass (imposter);\n\n    // Copy the imposter, so that the imposter can continue\n    // its normal life in addition to changing the behavior of\n    // the original.  As a hack we don't bother to copy the metaclass.\n    // For some reason we modify the original rather than the copy.\n    copy = (Class)malloc(sizeof(objc_class));\n    memmove(copy, imposter, sizeof(objc_class));\n\n    mutex_locker_t lock(classLock);\n\n    // Remove both the imposter and the original class.\n    NXHashRemove (class_hash, imposter);\n    NXHashRemove (class_hash, original);\n\n    NXHashInsert (class_hash, copy);\n\n    // Mark the imposter as such\n    imposter->setInfo(CLS_POSING);\n    imposter->ISA()->setInfo(CLS_POSING);\n\n    // Change the name of the imposter to that of the original class.\n    imposter->name      = original->name;\n    imposter->ISA()->name = original->ISA()->name;\n\n    // Also copy the version field to avoid archiving problems.\n    imposter->version = original->version;\n\n    // Change classrefs and superclass pointers\n    // Don't change copy->superclass\n    // Don't change [super ...] messages\n    change_class_references(imposter, original, copy, NO);\n\n    // Change the name of the original class.\n    original->name      = imposterNamePtr + 1;\n    original->ISA()->name = imposterNamePtr;\n\n    // Restore the imposter and the original class with their new names.\n    NXHashInsert (class_hash, imposter);\n    NXHashInsert (class_hash, original);\n\n    return imposter;\n}\n\n\n/***********************************************************************\n* _objc_flush_caches.  Flush the instance and class method caches\n* of cls and all its subclasses.\n*\n* Specifying Nil for the class \"all classes.\"\n**********************************************************************/\nstatic void flush_caches(Class target, bool flush_meta)\n{\n    bool collectALot = (target == nil);\n    NXHashState state;\n    Class clsObject;\n#ifdef OBJC_INSTRUMENTED\n    unsigned int classesVisited;\n    unsigned int subclassCount;\n#endif\n\n    mutex_locker_t lock(classLock);\n    mutex_locker_t lock2(cacheUpdateLock);\n\n    // Leaf classes are fastest because there are no subclass caches to flush.\n    // fixme instrument\n    if (target  &&  (target->info & CLS_LEAF)) {\n        _cache_flush (target);\n        \n        if (target->ISA()  &&  (target->ISA()->info & CLS_LEAF)) {\n            _cache_flush (target->ISA());\n            return;  // done\n        } else {\n            // Reset target and handle it by one of the methods below.\n            target = target->ISA();\n            flush_meta = NO;\n            // NOT done\n        }\n    }\n\n    state = NXInitHashState(class_hash);\n\n    // Handle nil and root instance class specially: flush all\n    // instance and class method caches.  Nice that this\n    // loop is linear vs the N-squared loop just below.\n    if (!target  ||  !target->superclass)\n    {\n#ifdef OBJC_INSTRUMENTED\n        LinearFlushCachesCount += 1;\n        classesVisited = 0;\n        subclassCount = 0;\n#endif\n        // Traverse all classes in the hash table\n        while (NXNextHashState(class_hash, &state, (void**)&clsObject))\n        {\n            Class metaClsObject;\n#ifdef OBJC_INSTRUMENTED\n            classesVisited += 1;\n#endif\n\n            // Skip class that is known not to be a subclass of this root\n            // (the isa pointer of any meta class points to the meta class\n            // of the root).\n            // NOTE: When is an isa pointer of a hash tabled class ever nil?\n            metaClsObject = clsObject->ISA();\n            if (target  &&  metaClsObject  &&  target->ISA() != metaClsObject->ISA()) {\n                continue;\n            }\n\n#ifdef OBJC_INSTRUMENTED\n            subclassCount += 1;\n#endif\n\n            _cache_flush (clsObject);\n            if (flush_meta  &&  metaClsObject != nil) {\n                _cache_flush (metaClsObject);\n            }\n        }\n#ifdef OBJC_INSTRUMENTED\n        LinearFlushCachesVisitedCount += classesVisited;\n        if (classesVisited > MaxLinearFlushCachesVisitedCount)\n            MaxLinearFlushCachesVisitedCount = classesVisited;\n        IdealFlushCachesCount += subclassCount;\n        if (subclassCount > MaxIdealFlushCachesCount)\n            MaxIdealFlushCachesCount = subclassCount;\n#endif\n\n        goto done;\n    }\n\n    // Outer loop - flush any cache that could now get a method from\n    // cls (i.e. the cache associated with cls and any of its subclasses).\n#ifdef OBJC_INSTRUMENTED\n    NonlinearFlushCachesCount += 1;\n    classesVisited = 0;\n    subclassCount = 0;\n#endif\n    while (NXNextHashState(class_hash, &state, (void**)&clsObject))\n    {\n        Class clsIter;\n\n#ifdef OBJC_INSTRUMENTED\n        NonlinearFlushCachesClassCount += 1;\n#endif\n\n        // Inner loop - Process a given class\n        clsIter = clsObject;\n        while (clsIter)\n        {\n\n#ifdef OBJC_INSTRUMENTED\n            classesVisited += 1;\n#endif\n            // Flush clsObject instance method cache if\n            // clsObject is a subclass of cls, or is cls itself\n            // Flush the class method cache if that was asked for\n            if (clsIter == target)\n            {\n#ifdef OBJC_INSTRUMENTED\n                subclassCount += 1;\n#endif\n                _cache_flush (clsObject);\n                if (flush_meta)\n                    _cache_flush (clsObject->ISA());\n\n                break;\n\n            }\n\n            // Flush clsObject class method cache if cls is\n            // the meta class of clsObject or of one\n            // of clsObject's superclasses\n            else if (clsIter->ISA() == target)\n            {\n#ifdef OBJC_INSTRUMENTED\n                subclassCount += 1;\n#endif\n                _cache_flush (clsObject->ISA());\n                break;\n            }\n\n            // Move up superclass chain\n            // else if (clsIter->isInitialized())\n            clsIter = clsIter->superclass;\n\n            // clsIter is not initialized, so its cache\n            // must be empty.  This happens only when\n            // clsIter == clsObject, because\n            // superclasses are initialized before\n            // subclasses, and this loop traverses\n            // from sub- to super- classes.\n            // else\n                // break;\n        }\n    }\n#ifdef OBJC_INSTRUMENTED\n    NonlinearFlushCachesVisitedCount += classesVisited;\n    if (classesVisited > MaxNonlinearFlushCachesVisitedCount)\n        MaxNonlinearFlushCachesVisitedCount = classesVisited;\n    IdealFlushCachesCount += subclassCount;\n    if (subclassCount > MaxIdealFlushCachesCount)\n        MaxIdealFlushCachesCount = subclassCount;\n#endif\n\n\n done:\n    if (collectALot) {\n        _cache_collect(true);\n    }\n}\n\n\nvoid _objc_flush_caches(Class target)\n{\n    flush_caches(target, YES);\n}\n\n\n\n/***********************************************************************\n* flush_marked_caches. Flush the method cache of any class marked \n* CLS_FLUSH_CACHE (and all subclasses thereof)\n* fixme instrument\n**********************************************************************/\nvoid flush_marked_caches(void)\n{\n    Class cls;\n    Class supercls;\n    NXHashState state;\n\n    mutex_locker_t lock(classLock);\n    mutex_locker_t lock2(cacheUpdateLock);\n\n    state = NXInitHashState(class_hash);\n    while (NXNextHashState(class_hash, &state, (void**)&cls)) {\n        for (supercls = cls; supercls; supercls = supercls->superclass) {\n            if (supercls->info & CLS_FLUSH_CACHE) {\n                _cache_flush(cls);\n                break;\n            }\n        }\n\n        for (supercls = cls->ISA(); supercls; supercls = supercls->superclass) {\n            if (supercls->info & CLS_FLUSH_CACHE) {\n                _cache_flush(cls->ISA());\n                break;\n            }\n        }\n    }\n\n    state = NXInitHashState(class_hash);\n    while (NXNextHashState(class_hash, &state, (void**)&cls)) {\n        if (cls->info & CLS_FLUSH_CACHE) {\n            cls->clearInfo(CLS_FLUSH_CACHE);            \n        }\n        if (cls->ISA()->info & CLS_FLUSH_CACHE) {\n            cls->ISA()->clearInfo(CLS_FLUSH_CACHE);\n        }\n    }\n}\n\n\n/***********************************************************************\n* get_base_method_list\n* Returns the method list containing the class's own methods, \n* ignoring any method lists added by categories or class_addMethods. \n* Called only by add_class_to_loadable_list. \n* Does not hold methodListLock because add_class_to_loadable_list \n* does not manipulate in-use classes.\n**********************************************************************/\nstatic old_method_list *get_base_method_list(Class cls) \n{\n    old_method_list **ptr;\n\n    if (!cls->methodLists) return nil;\n    if (cls->info & CLS_NO_METHOD_ARRAY) return (old_method_list *)cls->methodLists;\n    ptr = cls->methodLists;\n    if (!*ptr  ||  *ptr == END_OF_METHODS_LIST) return nil;\n    while ( *ptr != 0 && *ptr != END_OF_METHODS_LIST ) { ptr++; }\n    --ptr;\n    return *ptr;\n}\n\n\nstatic IMP _class_getLoadMethod_nocheck(Class cls)\n{\n    old_method_list *mlist;\n    mlist = get_base_method_list(cls->ISA());\n    if (mlist) {\n        return lookupNamedMethodInMethodList (mlist, \"load\");\n    }\n    return nil;\n}\n\n\nbool _class_hasLoadMethod(Class cls)\n{\n    if (cls->ISA()->info & CLS_HAS_LOAD_METHOD) return YES;\n    return _class_getLoadMethod_nocheck(cls);\n}\n\n\n/***********************************************************************\n* objc_class::getLoadMethod\n* Returns cls's +load implementation, or nil if it doesn't have one.\n**********************************************************************/\nIMP objc_class::getLoadMethod()\n{\n    if (ISA()->info & CLS_HAS_LOAD_METHOD) {\n        return _class_getLoadMethod_nocheck((Class)this);\n    }\n    return nil;\n}\n\nptrdiff_t ivar_getOffset(Ivar ivar)\n{\n    return oldivar(ivar)->ivar_offset;\n}\n\nconst char *ivar_getName(Ivar ivar)\n{\n    return oldivar(ivar)->ivar_name;\n}\n\nconst char *ivar_getTypeEncoding(Ivar ivar)\n{\n    return oldivar(ivar)->ivar_type;\n}\n\n\nIMP method_getImplementation(Method m)\n{\n    if (!m) return nil;\n    return oldmethod(m)->method_imp;\n}\n\nSEL method_getName(Method m)\n{\n    if (!m) return nil;\n    return oldmethod(m)->method_name;\n}\n\nconst char *method_getTypeEncoding(Method m)\n{\n    if (!m) return nil;\n    return oldmethod(m)->method_types;\n}\n\nunsigned int method_getSizeOfArguments(Method m)\n{\n    OBJC_WARN_DEPRECATED;\n    if (!m) return 0;\n    return encoding_getSizeOfArguments(method_getTypeEncoding(m));\n}\n\n// This function was accidentally un-exported beginning in macOS 10.9.\n// As of macOS 10.13 nobody had complained.\n/*\nunsigned int method_getArgumentInfo(Method m, int arg,\n                                    const char **type, int *offset)\n{\n    OBJC_WARN_DEPRECATED;\n    if (!m) return 0;\n    return encoding_getArgumentInfo(method_getTypeEncoding(m), \n                                    arg, type, offset);\n}\n*/\n\n\nspinlock_t impLock;\n\nIMP method_setImplementation(Method m_gen, IMP imp)\n{\n    IMP old;\n    old_method *m = oldmethod(m_gen);\n    if (!m) return nil;\n    if (!imp) return nil;\n\n    impLock.lock();\n    old = m->method_imp;\n    m->method_imp = imp;\n    impLock.unlock();\n    return old;\n}\n\n\nvoid method_exchangeImplementations(Method m1_gen, Method m2_gen)\n{\n    IMP m1_imp;\n    old_method *m1 = oldmethod(m1_gen);\n    old_method *m2 = oldmethod(m2_gen);\n    if (!m1  ||  !m2) return;\n\n    impLock.lock();\n    m1_imp = m1->method_imp;\n    m1->method_imp = m2->method_imp;\n    m2->method_imp = m1_imp;\n    impLock.unlock();\n}\n\n\nstruct objc_method_description * method_getDescription(Method m)\n{\n    if (!m) return nil;\n    return (struct objc_method_description *)oldmethod(m);\n}\n\n\nconst char *property_getName(objc_property_t prop)\n{\n    return oldproperty(prop)->name;\n}\n\nconst char *property_getAttributes(objc_property_t prop)\n{\n    return oldproperty(prop)->attributes;\n}\n\nobjc_property_attribute_t *property_copyAttributeList(objc_property_t prop, \n                                                      unsigned int *outCount)\n{\n    if (!prop) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    mutex_locker_t lock(classLock);\n    return copyPropertyAttributeList(oldproperty(prop)->attributes,outCount);\n}\n\nchar * property_copyAttributeValue(objc_property_t prop, const char *name)\n{\n    if (!prop  ||  !name  ||  *name == '\\0') return nil;\n    \n    mutex_locker_t lock(classLock);\n    return copyPropertyAttributeValue(oldproperty(prop)->attributes, name);\n}\n\n\n/***********************************************************************\n* class_addMethod\n**********************************************************************/\nstatic IMP _class_addMethod(Class cls, SEL name, IMP imp, \n                            const char *types, bool replace)\n{\n    old_method *m;\n    IMP result = nil;\n\n    if (!types) types = \"\";\n\n    mutex_locker_t lock(methodListLock);\n\n    if ((m = _findMethodInClass(cls, name))) {\n        // already exists\n        // fixme atomic\n        result = method_getImplementation((Method)m);\n        if (replace) {\n            method_setImplementation((Method)m, imp);\n        }\n    } else {\n        // fixme could be faster\n        old_method_list *mlist = \n            (old_method_list *)calloc(sizeof(old_method_list), 1);\n        mlist->obsolete = fixed_up_method_list;\n        mlist->method_count = 1;\n        mlist->method_list[0].method_name = name;\n        mlist->method_list[0].method_types = strdup(types);\n        mlist->method_list[0].method_imp = imp;\n        \n        _objc_insertMethods(cls, mlist, nil);\n        if (!(cls->info & CLS_CONSTRUCTING)) {\n            flush_caches(cls, NO);\n        } else {\n            // in-construction class has no subclasses\n            flush_cache(cls);\n        }\n        result = nil;\n    }\n\n    return result;\n}\n\n\n/***********************************************************************\n* class_addMethod\n**********************************************************************/\nBOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)\n{\n    IMP old;\n    if (!cls) return NO;\n\n    old = _class_addMethod(cls, name, imp, types, NO);\n    return !old;\n}\n\n\n/***********************************************************************\n* class_replaceMethod\n**********************************************************************/\nIMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)\n{\n    if (!cls) return nil;\n\n    return _class_addMethod(cls, name, imp, types, YES);\n}\n\n\n/***********************************************************************\n* class_addIvar\n**********************************************************************/\nBOOL class_addIvar(Class cls, const char *name, size_t size, \n                   uint8_t alignment, const char *type)\n{\n    bool result = YES;\n\n    if (!cls) return NO;\n    if (ISMETA(cls)) return NO;\n    if (!(cls->info & CLS_CONSTRUCTING)) return NO;\n\n    if (!type) type = \"\";\n    if (name  &&  0 == strcmp(name, \"\")) name = nil;\n    \n    mutex_locker_t lock(classLock);\n\n    // Check for existing ivar with this name\n    // fixme check superclasses?\n    if (cls->ivars) {\n        int i;\n        for (i = 0; i < cls->ivars->ivar_count; i++) {\n            if (0 == strcmp(cls->ivars->ivar_list[i].ivar_name, name)) {\n                result = NO;\n                break;\n            }\n        }\n    }\n\n    if (result) {\n        old_ivar_list *old = cls->ivars;\n        size_t oldSize;\n        int newCount;\n        old_ivar *ivar;\n        size_t alignBytes;\n        size_t misalign;\n        \n        if (old) {\n            oldSize = sizeof(old_ivar_list) + \n                (old->ivar_count - 1) * sizeof(old_ivar);\n            newCount = 1 + old->ivar_count;\n        } else {\n            oldSize = sizeof(old_ivar_list) - sizeof(old_ivar);\n            newCount = 1;\n        }\n\n        // allocate new ivar list\n        cls->ivars = (old_ivar_list *)\n            calloc(oldSize+sizeof(old_ivar), 1);\n        if (old) memcpy(cls->ivars, old, oldSize);\n        if (old  &&  malloc_size(old)) free(old);\n        cls->ivars->ivar_count = newCount;\n        ivar = &cls->ivars->ivar_list[newCount-1];\n\n        // set ivar name and type\n        ivar->ivar_name = strdup(name);\n        ivar->ivar_type = strdup(type);\n\n        // align if necessary\n        alignBytes = 1 << alignment;\n        misalign = cls->instance_size % alignBytes;\n        if (misalign) cls->instance_size += (long)(alignBytes - misalign);\n\n        // set ivar offset and increase instance size\n        ivar->ivar_offset = (int)cls->instance_size;\n        cls->instance_size += (long)size;\n    }\n\n    return result;\n}\n\n\n/***********************************************************************\n* class_addProtocol\n**********************************************************************/\nBOOL class_addProtocol(Class cls, Protocol *protocol_gen)\n{\n    old_protocol *protocol = oldprotocol(protocol_gen);\n    old_protocol_list *plist;\n\n    if (!cls) return NO;\n    if (class_conformsToProtocol(cls, protocol_gen)) return NO;\n\n    mutex_locker_t lock(classLock);\n\n    // fixme optimize - protocol list doesn't escape?\n    plist = (old_protocol_list*)calloc(sizeof(old_protocol_list), 1);\n    plist->count = 1;\n    plist->list[0] = protocol;\n    plist->next = cls->protocols;\n    cls->protocols = plist;\n\n    // fixme metaclass?\n\n    return YES;\n}\n\n\n/***********************************************************************\n* _class_addProperties\n* Internal helper to add properties to a class. \n* Used by category attachment and  class_addProperty() \n* Locking: acquires classLock\n**********************************************************************/\nbool \n_class_addProperties(Class cls,\n                     old_property_list *additions)\n{\n    old_property_list *newlist;\n\n    if (!(cls->info & CLS_EXT)) return NO;\n\n    newlist = (old_property_list *)\n        memdup(additions, sizeof(*newlist) - sizeof(newlist->first) \n                         + (additions->entsize * additions->count));\n\n    mutex_locker_t lock(classLock);\n\n    allocateExt(cls);\n    if (!cls->ext->propertyLists) {\n        // cls has no properties - simply use this list\n        cls->ext->propertyLists = (old_property_list **)newlist;\n        cls->setInfo(CLS_NO_PROPERTY_ARRAY);\n    } \n    else if (cls->info & CLS_NO_PROPERTY_ARRAY) {\n        // cls has one property list - make a new array\n        old_property_list **newarray = (old_property_list **)\n            malloc(3 * sizeof(*newarray));\n        newarray[0] = newlist;\n        newarray[1] = (old_property_list *)cls->ext->propertyLists;\n        newarray[2] = nil;\n        cls->ext->propertyLists = newarray;\n        cls->clearInfo(CLS_NO_PROPERTY_ARRAY);\n    }\n    else {\n        // cls has a property array - make a bigger one\n        old_property_list **newarray;\n        int count = 0;\n        while (cls->ext->propertyLists[count]) count++;\n        newarray = (old_property_list **)\n            malloc((count+2) * sizeof(*newarray));\n        newarray[0] = newlist;\n        memcpy(&newarray[1], &cls->ext->propertyLists[0], \n               count * sizeof(*newarray));\n        newarray[count+1] = nil;\n        free(cls->ext->propertyLists);\n        cls->ext->propertyLists = newarray;\n    }\n\n    return YES;\n}\n\n\n/***********************************************************************\n* class_addProperty\n* Adds a property to a class. Returns NO if the proeprty already exists.\n* Locking: acquires classLock\n**********************************************************************/\nstatic bool \n_class_addProperty(Class cls, const char *name, \n                   const objc_property_attribute_t *attrs, unsigned int count, \n                   bool replace)\n{\n    if (!cls) return NO;\n    if (!name) return NO;\n\n    old_property *prop = oldproperty(class_getProperty(cls, name));\n    if (prop  &&  !replace) {\n        // already exists, refuse to replace\n        return NO;\n    } \n    else if (prop) {\n        // replace existing\n        mutex_locker_t lock(classLock);\n        try_free(prop->attributes);\n        prop->attributes = copyPropertyAttributeString(attrs, count);\n        return YES;\n    } \n    else {\n        // add new\n        old_property_list proplist;\n        proplist.entsize = sizeof(old_property);\n        proplist.count = 1;\n        proplist.first.name = strdup(name);\n        proplist.first.attributes = copyPropertyAttributeString(attrs, count);\n        \n        return _class_addProperties(cls, &proplist);\n    }\n}\n\nBOOL \nclass_addProperty(Class cls, const char *name, \n                  const objc_property_attribute_t *attrs, unsigned int n)\n{\n    return _class_addProperty(cls, name, attrs, n, NO);\n}\n\nvoid \nclass_replaceProperty(Class cls, const char *name, \n                      const objc_property_attribute_t *attrs, unsigned int n)\n{\n    _class_addProperty(cls, name, attrs, n, YES);\n}\n\n\n/***********************************************************************\n* class_copyProtocolList.  Returns a heap block containing the \n* protocols implemented by the class, or nil if the class \n* implements no protocols. Caller must free the block.\n* Does not copy any superclass's protocols.\n**********************************************************************/\nProtocol * __unsafe_unretained *\nclass_copyProtocolList(Class cls, unsigned int *outCount)\n{\n    old_protocol_list *plist;\n    Protocol **result = nil;\n    unsigned int count = 0;\n    unsigned int p;\n\n    if (!cls) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    mutex_locker_t lock(classLock);\n\n    for (plist = cls->protocols; plist != nil; plist = plist->next) {\n        count += (int)plist->count;\n    }\n\n    if (count > 0) {\n        result = (Protocol **)malloc((count+1) * sizeof(Protocol *));\n        \n        for (p = 0, plist = cls->protocols; \n             plist != nil; \n             plist = plist->next) \n        {\n            int i;\n            for (i = 0; i < plist->count; i++) {\n                result[p++] = (Protocol *)plist->list[i];\n            }\n        }\n        result[p] = nil;\n    }\n\n    if (outCount) *outCount = count;\n    return result;\n}\n\n\n/***********************************************************************\n* class_getProperty.  Return the named property.\n**********************************************************************/\nobjc_property_t class_getProperty(Class cls, const char *name)\n{\n    if (!cls  ||  !name) return nil;\n\n    mutex_locker_t lock(classLock);\n\n    for (; cls; cls = cls->superclass) {\n        uintptr_t iterator = 0;\n        old_property_list *plist;\n        while ((plist = nextPropertyList(cls, &iterator))) {\n            uint32_t i;\n            for (i = 0; i < plist->count; i++) {\n                old_property *p = property_list_nth(plist, i);\n                if (0 == strcmp(name, p->name)) {\n                    return (objc_property_t)p;\n                }\n            }\n        }\n    }\n\n    return nil;\n}\n\n\n/***********************************************************************\n* class_copyPropertyList. Returns a heap block containing the \n* properties declared in the class, or nil if the class \n* declares no properties. Caller must free the block.\n* Does not copy any superclass's properties.\n**********************************************************************/\nobjc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)\n{\n    old_property_list *plist;\n    uintptr_t iterator = 0;\n    old_property **result = nil;\n    unsigned int count = 0;\n    unsigned int p, i;\n\n    if (!cls) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    mutex_locker_t lock(classLock);\n\n    iterator = 0;\n    while ((plist = nextPropertyList(cls, &iterator))) {\n        count += plist->count;\n    }\n\n    if (count > 0) {\n        result = (old_property **)malloc((count+1) * sizeof(old_property *));\n        \n        p = 0;\n        iterator = 0;\n        while ((plist = nextPropertyList(cls, &iterator))) {\n            for (i = 0; i < plist->count; i++) {\n                result[p++] = property_list_nth(plist, i);\n            }\n        }\n        result[p] = nil;\n    }\n\n    if (outCount) *outCount = count;\n    return (objc_property_t *)result;\n}\n\n\n/***********************************************************************\n* class_copyMethodList.  Returns a heap block containing the \n* methods implemented by the class, or nil if the class \n* implements no methods. Caller must free the block.\n* Does not copy any superclass's methods.\n**********************************************************************/\nMethod *class_copyMethodList(Class cls, unsigned int *outCount)\n{\n    old_method_list *mlist;\n    void *iterator = nil;\n    Method *result = nil;\n    unsigned int count = 0;\n    unsigned int m;\n\n    if (!cls) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    mutex_locker_t lock(methodListLock);\n\n    iterator = nil;\n    while ((mlist = nextMethodList(cls, &iterator))) {\n        count += mlist->method_count;\n    }\n\n    if (count > 0) {\n        result = (Method *)malloc((count+1) * sizeof(Method));\n        \n        m = 0;\n        iterator = nil;\n        while ((mlist = nextMethodList(cls, &iterator))) {\n            int i;\n            for (i = 0; i < mlist->method_count; i++) {\n                result[m++] = (Method)&mlist->method_list[i];\n            }\n        }\n        result[m] = nil;\n    }\n\n    if (outCount) *outCount = count;\n    return result;\n}\n\n\n/***********************************************************************\n* class_copyIvarList.  Returns a heap block containing the \n* ivars declared in the class, or nil if the class \n* declares no ivars. Caller must free the block.\n* Does not copy any superclass's ivars.\n**********************************************************************/\nIvar *class_copyIvarList(Class cls, unsigned int *outCount)\n{\n    Ivar *result = nil;\n    unsigned int count = 0;\n    int i;\n\n    if (!cls) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    if (cls->ivars) {\n        count = cls->ivars->ivar_count;\n    }\n\n    if (count > 0) {\n        result = (Ivar *)malloc((count+1) * sizeof(Ivar));\n\n        for (i = 0; i < cls->ivars->ivar_count; i++) {\n            result[i] = (Ivar)&cls->ivars->ivar_list[i];\n        }\n        result[i] = nil;\n    }\n\n    if (outCount) *outCount = count;\n    return result;\n}\n\n\n/***********************************************************************\n* objc_allocateClass.\n**********************************************************************/\n\nvoid set_superclass(Class cls, Class supercls, bool cls_is_new)\n{\n    Class meta = cls->ISA();\n\n    if (supercls) {\n        cls->superclass = supercls;\n        meta->superclass = supercls->ISA();\n        meta->initIsa(supercls->ISA()->ISA());\n\n        // Propagate C++ cdtors from superclass.\n        if (supercls->info & CLS_HAS_CXX_STRUCTORS) {\n            if (cls_is_new) cls->info |= CLS_HAS_CXX_STRUCTORS;\n            else cls->setInfo(CLS_HAS_CXX_STRUCTORS);\n        }\n\n        // Superclass is no longer a leaf for cache flushing\n        if (supercls->info & CLS_LEAF) {\n            supercls->clearInfo(CLS_LEAF);\n            supercls->ISA()->clearInfo(CLS_LEAF);\n        }\n    } else {\n        cls->superclass = Nil;  // superclass of root class is nil\n        meta->superclass = cls; // superclass of root metaclass is root class\n        meta->initIsa(meta);    // metaclass of root metaclass is root metaclass\n\n        // Root class is never a leaf for cache flushing, because the \n        // root metaclass is a subclass. (This could be optimized, but \n        // is too uncommon to bother.)\n        cls->clearInfo(CLS_LEAF);\n        meta->clearInfo(CLS_LEAF);\n    }    \n}\n\n// &UnsetLayout is the default ivar layout during class construction\nstatic const uint8_t UnsetLayout = 0;\n\nClass objc_initializeClassPair(Class supercls, const char *name, Class cls, Class meta)\n{\n    // Connect to superclasses and metaclasses\n    cls->initIsa(meta);\n    set_superclass(cls, supercls, YES);\n\n    // Set basic info\n    cls->name = strdup(name);\n    meta->name = strdup(name);\n    cls->version = 0;\n    meta->version = 7;\n    cls->info = CLS_CLASS | CLS_CONSTRUCTING | CLS_EXT | CLS_LEAF;\n    meta->info = CLS_META | CLS_CONSTRUCTING | CLS_EXT | CLS_LEAF;\n\n    // Set instance size based on superclass.\n    if (supercls) {\n        cls->instance_size = supercls->instance_size;\n        meta->instance_size = supercls->ISA()->instance_size;\n    } else {\n        cls->instance_size = sizeof(Class);  // just an isa\n        meta->instance_size = sizeof(objc_class);\n    }\n    \n    // No ivars. No methods. Empty cache. No protocols. No layout. Empty ext.\n    cls->ivars = nil;\n    cls->methodLists = nil;\n    cls->cache = (Cache)&_objc_empty_cache;\n    cls->protocols = nil;\n    cls->ivar_layout = &UnsetLayout;\n    cls->ext = nil;\n    allocateExt(cls);\n    cls->ext->weak_ivar_layout = &UnsetLayout;\n\n    meta->ivars = nil;\n    meta->methodLists = nil;\n    meta->cache = (Cache)&_objc_empty_cache;\n    meta->protocols = nil;\n    meta->ext = nil;\n    \n    return cls;\n}\n\nClass objc_allocateClassPair(Class supercls, const char *name, \n                             size_t extraBytes)\n{\n    Class cls, meta;\n\n    if (objc_getClass(name)) return nil;\n    // fixme reserve class name against simultaneous allocation\n\n    if (supercls  &&  (supercls->info & CLS_CONSTRUCTING)) {\n        // Can't make subclass of an in-construction class\n        return nil;\n    }\n\n    // Allocate new classes. \n    if (supercls) {\n        cls = _calloc_class(supercls->ISA()->alignedInstanceSize() + extraBytes);\n        meta = _calloc_class(supercls->ISA()->ISA()->alignedInstanceSize() + extraBytes);\n    } else {\n        cls = _calloc_class(sizeof(objc_class) + extraBytes);\n        meta = _calloc_class(sizeof(objc_class) + extraBytes);\n    }\n\n\n    objc_initializeClassPair(supercls, name, cls, meta);\n    \n    return cls;\n}\n\n\nvoid objc_registerClassPair(Class cls)\n{\n    if ((cls->info & CLS_CONSTRUCTED)  ||  \n        (cls->ISA()->info & CLS_CONSTRUCTED)) \n    {\n        _objc_inform(\"objc_registerClassPair: class '%s' was already \"\n                     \"registered!\", cls->name);\n        return;\n    }\n\n    if (!(cls->info & CLS_CONSTRUCTING)  ||  \n        !(cls->ISA()->info & CLS_CONSTRUCTING)) \n    {\n        _objc_inform(\"objc_registerClassPair: class '%s' was not \"\n                     \"allocated with objc_allocateClassPair!\", cls->name);\n        return;\n    }\n\n    if (ISMETA(cls)) {\n        _objc_inform(\"objc_registerClassPair: class '%s' is a metaclass, \"\n                     \"not a class!\", cls->name);\n        return;\n    }\n\n    mutex_locker_t lock(classLock);\n\n    // Clear \"under construction\" bit, set \"done constructing\" bit\n    cls->info &= ~CLS_CONSTRUCTING;\n    cls->ISA()->info &= ~CLS_CONSTRUCTING;\n    cls->info |= CLS_CONSTRUCTED;\n    cls->ISA()->info |= CLS_CONSTRUCTED;\n\n    NXHashInsertIfAbsent(class_hash, cls);\n}\n\n\nClass objc_duplicateClass(Class original, const char *name, size_t extraBytes)\n{\n    unsigned int count, i;\n    old_method **originalMethods;\n    old_method_list *duplicateMethods;\n    // Don't use sizeof(objc_class) here because \n    // instance_size has historically contained two extra words, \n    // and instance_size is what objc_getIndexedIvars() actually uses.\n    Class duplicate = \n        _calloc_class(original->ISA()->alignedInstanceSize() + extraBytes);\n\n    duplicate->initIsa(original->ISA());\n    duplicate->superclass = original->superclass;\n    duplicate->name = strdup(name);\n    duplicate->version = original->version;\n    duplicate->info = original->info & (CLS_CLASS|CLS_META|CLS_INITIALIZED|CLS_JAVA_HYBRID|CLS_JAVA_CLASS|CLS_HAS_CXX_STRUCTORS|CLS_HAS_LOAD_METHOD);\n    duplicate->instance_size = original->instance_size;\n    duplicate->ivars = original->ivars;\n    // methodLists handled below\n    duplicate->cache = (Cache)&_objc_empty_cache;\n    duplicate->protocols = original->protocols;\n    if (original->info & CLS_EXT) {\n        duplicate->info |= original->info & (CLS_EXT|CLS_NO_PROPERTY_ARRAY);\n        duplicate->ivar_layout = original->ivar_layout;\n        if (original->ext) {\n            duplicate->ext = (old_class_ext *)malloc(original->ext->size);\n            memcpy(duplicate->ext, original->ext, original->ext->size);\n        } else {\n            duplicate->ext = nil;\n        }\n    }\n\n    // Method lists are deep-copied so they can be stomped.\n    originalMethods = (old_method **)class_copyMethodList(original, &count);\n    if (originalMethods) {\n        duplicateMethods = (old_method_list *)\n            calloc(sizeof(old_method_list) + \n                   (count-1)*sizeof(old_method), 1);\n        duplicateMethods->obsolete = fixed_up_method_list;\n        duplicateMethods->method_count = count;\n        for (i = 0; i < count; i++) {\n            duplicateMethods->method_list[i] = *(originalMethods[i]);\n        }\n        duplicate->methodLists = (old_method_list **)duplicateMethods;\n        duplicate->info |= CLS_NO_METHOD_ARRAY;\n        free(originalMethods);\n    }\n\n    mutex_locker_t lock(classLock);\n    NXHashInsert(class_hash, duplicate);\n\n    return duplicate;\n}\n\n\nvoid objc_disposeClassPair(Class cls)\n{\n    if (!(cls->info & (CLS_CONSTRUCTED|CLS_CONSTRUCTING))  ||  \n        !(cls->ISA()->info & (CLS_CONSTRUCTED|CLS_CONSTRUCTING))) \n    {\n        // class not allocated with objc_allocateClassPair\n        // disposing still-unregistered class is OK!\n        _objc_inform(\"objc_disposeClassPair: class '%s' was not \"\n                     \"allocated with objc_allocateClassPair!\", cls->name);\n        return;\n    }\n\n    if (ISMETA(cls)) {\n        _objc_inform(\"objc_disposeClassPair: class '%s' is a metaclass, \"\n                     \"not a class!\", cls->name);\n        return;\n    }\n\n    mutex_locker_t lock(classLock);\n    NXHashRemove(class_hash, cls);\n    unload_class(cls->ISA());\n    unload_class(cls);\n}\n\n\n/***********************************************************************\n* objc_constructInstance\n* Creates an instance of `cls` at the location pointed to by `bytes`. \n* `bytes` must point to at least class_getInstanceSize(cls) bytes of \n*   well-aligned zero-filled memory.\n* The new object's isa is set. Any C++ constructors are called.\n* Returns `bytes` if successful. Returns nil if `cls` or `bytes` is \n*   nil, or if C++ constructors fail.\n**********************************************************************/\nid \nobjc_constructInstance(Class cls, void *bytes) \n{\n    if (!cls  ||  !bytes) return nil;\n\n    id obj = (id)bytes;\n\n    obj->initIsa(cls);\n\n    if (cls->hasCxxCtor()) {\n        return object_cxxConstructFromClass(obj, cls);\n    } else {\n        return obj;\n    }\n}\n\n\n/***********************************************************************\n* _class_createInstanceFromZone.  Allocate an instance of the\n* specified class with the specified number of bytes for indexed\n* variables, in the specified zone.  The isa field is set to the\n* class, C++ default constructors are called, and all other fields are zeroed.\n**********************************************************************/\nid \n_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)\n{\n    void *bytes;\n    size_t size;\n\n    // Can't create something for nothing\n    if (!cls) return nil;\n\n    // Allocate and initialize\n    size = cls->alignedInstanceSize() + extraBytes;\n\n    // CF requires all objects be at least 16 bytes.\n    if (size < 16) size = 16;\n\n    if (zone) {\n        bytes = malloc_zone_calloc((malloc_zone_t *)zone, 1, size);\n    } else {\n        bytes = calloc(1, size);\n    }\n\n    return objc_constructInstance(cls, bytes);\n}\n\n\n/***********************************************************************\n* _class_createInstance.  Allocate an instance of the specified\n* class with the specified number of bytes for indexed variables, in\n* the default zone, using _class_createInstanceFromZone.\n**********************************************************************/\nstatic id _class_createInstance(Class cls, size_t extraBytes)\n{\n    return _class_createInstanceFromZone (cls, extraBytes, nil);\n}\n\n\nstatic id _object_copyFromZone(id oldObj, size_t extraBytes, void *zone) \n{\n    id obj;\n    size_t size;\n\n    if (!oldObj) return nil;\n\n    obj = (*_zoneAlloc)(oldObj->ISA(), extraBytes, zone);\n    size = oldObj->ISA()->alignedInstanceSize() + extraBytes;\n    \n    // fixme need C++ copy constructor\n    memmove(obj, oldObj, size);\n    \n    fixupCopiedIvars(obj, oldObj);\n    \n    return obj;\n}\n\n\n/***********************************************************************\n* objc_destructInstance\n* Destroys an instance without freeing memory. \n* Calls C++ destructors.\n* Removes associative references.\n* Returns `obj`. Does nothing if `obj` is nil.\n* CoreFoundation and other clients do call this under GC.\n**********************************************************************/\nvoid *objc_destructInstance(id obj) \n{\n    if (obj) {\n        Class isa = obj->getIsa();\n\n        if (isa->hasCxxDtor()) {\n            object_cxxDestruct(obj);\n        }\n\n        if (isa->instancesHaveAssociatedObjects()) {\n            _object_remove_assocations(obj);\n        }\n\n        objc_clear_deallocating(obj);\n    }\n\n    return obj;\n}\n\nstatic id \n_object_dispose(id anObject) \n{\n    if (anObject==nil) return nil;\n\n    objc_destructInstance(anObject);\n    \n    anObject->initIsa(_objc_getFreedObjectClass ()); \n\n    free(anObject);\n    return nil;\n}\n\nstatic id _object_copy(id oldObj, size_t extraBytes) \n{\n    void *z = malloc_zone_from_ptr(oldObj);\n    return _object_copyFromZone(oldObj, extraBytes,\n\t\t\t\t\t z ? z : malloc_default_zone());\n}\n\nstatic id _object_reallocFromZone(id anObject, size_t nBytes, void *zone) \n{\n    id newObject; \n    Class tmp;\n\n    if (anObject == nil)\n        __objc_error(nil, \"reallocating nil object\");\n\n    if (anObject->ISA() == _objc_getFreedObjectClass ())\n        __objc_error(anObject, \"reallocating freed object\");\n\n    if (nBytes < anObject->ISA()->alignedInstanceSize())\n        __objc_error(anObject, \"(%s, %zu) requested size too small\", \n                     object_getClassName(anObject), nBytes);\n\n    // fixme need C++ copy constructor\n    // fixme GC copy\n    // Make sure not to modify space that has been declared free\n    tmp = anObject->ISA(); \n    anObject->initIsa(_objc_getFreedObjectClass ());\n    newObject = (id)malloc_zone_realloc((malloc_zone_t *)zone, anObject, nBytes);\n    if (newObject) {\n        newObject->initIsa(tmp);\n    } else {\n        // realloc failed, anObject is still alive\n        anObject->initIsa(tmp);\n    }\n    return newObject;\n}\n\n\nstatic id _object_realloc(id anObject, size_t nBytes) \n{\n    void *z = malloc_zone_from_ptr(anObject);\n    return _object_reallocFromZone(anObject,\n\t\t\t\t\t    nBytes,\n\t\t\t\t\t    z ? z : malloc_default_zone());\n}\n\nid (*_alloc)(Class, size_t) = _class_createInstance;\nid (*_copy)(id, size_t) = _object_copy;\nid (*_realloc)(id, size_t) = _object_realloc;\nid (*_dealloc)(id) = _object_dispose;\nid (*_zoneAlloc)(Class, size_t, void *) = _class_createInstanceFromZone;\nid (*_zoneCopy)(id, size_t, void *) = _object_copyFromZone;\nid (*_zoneRealloc)(id, size_t, void *) = _object_reallocFromZone;\nvoid (*_error)(id, const char *, va_list) = _objc_error;\n\n\nid class_createInstance(Class cls, size_t extraBytes)\n{\n    return (*_alloc)(cls, extraBytes);\n}\n\nid class_createInstanceFromZone(Class cls, size_t extraBytes, void *z)\n{\n    OBJC_WARN_DEPRECATED;\n    return (*_zoneAlloc)(cls, extraBytes, z);\n}\n\nunsigned class_createInstances(Class cls, size_t extraBytes, \n                               id *results, unsigned num_requested)\n{\n    if (_alloc == &_class_createInstance) {\n        return _class_createInstancesFromZone(cls, extraBytes, nil, \n                                              results, num_requested);\n    } else {\n        // _alloc in use, which isn't understood by the batch allocator\n        return 0;\n    }\n}\n\nid object_copy(id obj, size_t extraBytes) \n{\n    return (*_copy)(obj, extraBytes); \n}\n\nid object_copyFromZone(id obj, size_t extraBytes, void *z) \n{\n    OBJC_WARN_DEPRECATED;\n    return (*_zoneCopy)(obj, extraBytes, z); \n}\n\nid object_dispose(id obj) \n{\n    return (*_dealloc)(obj); \n}\n\nid object_realloc(id obj, size_t nBytes) \n{\n    OBJC_WARN_DEPRECATED;\n    return (*_realloc)(obj, nBytes); \n}\n\nid object_reallocFromZone(id obj, size_t nBytes, void *z) \n{\n    OBJC_WARN_DEPRECATED;\n    return (*_zoneRealloc)(obj, nBytes, z); \n}\n\n\n/***********************************************************************\n* object_getIndexedIvars.\n**********************************************************************/\nvoid *object_getIndexedIvars(id obj)\n{\n    // ivars are tacked onto the end of the object\n    if (!obj) return nil;\n    if (obj->isTaggedPointer()) return nil;\n    return ((char *) obj) + obj->ISA()->alignedInstanceSize();\n}\n\n\n// ProKit SPI\nClass class_setSuperclass(Class cls, Class newSuper)\n{\n    Class oldSuper = cls->superclass;\n    set_superclass(cls, newSuper, NO);\n    flush_caches(cls, YES);\n    return oldSuper;\n}\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-class.h",
    "content": "#include <objc/runtime.h>\n#include <objc/message.h>\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-class.mm",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/***********************************************************************\n*\tobjc-class.m\n*\tCopyright 1988-1997, Apple Computer, Inc.\n*\tAuthor:\ts. naroff\n**********************************************************************/\n\n\n/***********************************************************************\n * Lazy method list arrays and method list locking  (2004-10-19)\n * \n * cls->methodLists may be in one of three forms:\n * 1. nil: The class has no methods.\n * 2. non-nil, with CLS_NO_METHOD_ARRAY set: cls->methodLists points \n *    to a single method list, which is the class's only method list.\n * 3. non-nil, with CLS_NO_METHOD_ARRAY clear: cls->methodLists points to \n *    an array of method list pointers. The end of the array's block \n *    is set to -1. If the actual number of method lists is smaller \n *    than that, the rest of the array is nil.\n * \n * Attaching categories and adding and removing classes may change \n * the form of the class list. In addition, individual method lists \n * may be reallocated when fixed up.\n *\n * Classes are initially read as #1 or #2. If a category is attached \n * or other methods added, the class is changed to #3. Once in form #3, \n * the class is never downgraded to #1 or #2, even if methods are removed.\n * Classes added with objc_addClass are initially either #1 or #3.\n * \n * Accessing and manipulating a class's method lists are synchronized, \n * to prevent races when one thread restructures the list. However, \n * if the class is not yet in use (i.e. not in class_hash), then the \n * thread loading the class may access its method lists without locking.\n * \n * The following functions acquire methodListLock:\n * class_getInstanceMethod\n * class_getClassMethod\n * class_nextMethodList\n * class_addMethods\n * class_removeMethods\n * class_respondsToMethod\n * _class_lookupMethodAndLoadCache\n * lookupMethodInClassAndLoadCache\n * _objc_add_category_flush_caches\n *\n * The following functions don't acquire methodListLock because they \n * only access method lists during class load and unload:\n * _objc_register_category\n * _resolve_categories_for_class (calls _objc_add_category)\n * add_class_to_loadable_list\n * _objc_addClass\n * _objc_remove_classes_in_image\n *\n * The following functions use method lists without holding methodListLock.\n * The caller must either hold methodListLock, or be loading the class.\n * _getMethod (called by class_getInstanceMethod, class_getClassMethod, \n *   and class_respondsToMethod)\n * _findMethodInClass (called by _class_lookupMethodAndLoadCache, \n *   lookupMethodInClassAndLoadCache, _getMethod)\n * _findMethodInList (called by _findMethodInClass)\n * nextMethodList (called by _findMethodInClass and class_nextMethodList\n * fixupSelectorsInMethodList (called by nextMethodList)\n * _objc_add_category (called by _objc_add_category_flush_caches, \n *   resolve_categories_for_class and _objc_register_category)\n * _objc_insertMethods (called by class_addMethods and _objc_add_category)\n * _objc_removeMethods (called by class_removeMethods)\n * _objcTweakMethodListPointerForClass (called by _objc_insertMethods)\n * get_base_method_list (called by add_class_to_loadable_list)\n * lookupNamedMethodInMethodList (called by add_class_to_loadable_list)\n ***********************************************************************/\n\n/***********************************************************************\n * Thread-safety of class info bits  (2004-10-19)\n * \n * Some class info bits are used to store mutable runtime state. \n * Modifications of the info bits at particular times need to be \n * synchronized to prevent races.\n * \n * Three thread-safe modification functions are provided:\n * cls->setInfo()     // atomically sets some bits\n * cls->clearInfo()   // atomically clears some bits\n * cls->changeInfo()  // atomically sets some bits and clears others\n * These replace CLS_SETINFO() for the multithreaded cases.\n * \n * Three modification windows are defined:\n * - compile time\n * - class construction or image load (before +load) in one thread\n * - multi-threaded messaging and method caches\n * \n * Info bit modification at compile time and class construction do not \n *   need to be locked, because only one thread is manipulating the class.\n * Info bit modification during messaging needs to be locked, because \n *   there may be other threads simultaneously messaging or otherwise \n *   manipulating the class.\n *   \n * Modification windows for each flag:\n * \n * CLS_CLASS: compile-time and class load\n * CLS_META: compile-time and class load\n * CLS_INITIALIZED: +initialize\n * CLS_POSING: messaging\n * CLS_MAPPED: compile-time\n * CLS_FLUSH_CACHE: class load and messaging\n * CLS_GROW_CACHE: messaging\n * CLS_NEED_BIND: unused\n * CLS_METHOD_ARRAY: unused\n * CLS_JAVA_HYBRID: JavaBridge only\n * CLS_JAVA_CLASS: JavaBridge only\n * CLS_INITIALIZING: messaging\n * CLS_FROM_BUNDLE: class load\n * CLS_HAS_CXX_STRUCTORS: compile-time and class load\n * CLS_NO_METHOD_ARRAY: class load and messaging\n * CLS_HAS_LOAD_METHOD: class load\n * \n * CLS_INITIALIZED and CLS_INITIALIZING have additional thread-safety \n * constraints to support thread-safe +initialize. See \"Thread safety \n * during class initialization\" for details.\n * \n * CLS_JAVA_HYBRID and CLS_JAVA_CLASS are set immediately after JavaBridge \n * calls objc_addClass(). The JavaBridge does not use an atomic update, \n * but the modification counts as \"class construction\" unless some other \n * thread quickly finds the class via the class list. This race is \n * small and unlikely in well-behaved code.\n *\n * Most info bits that may be modified during messaging are also never \n * read without a lock. There is no general read lock for the info bits.\n * CLS_INITIALIZED: classInitLock\n * CLS_FLUSH_CACHE: cacheUpdateLock\n * CLS_GROW_CACHE: cacheUpdateLock\n * CLS_NO_METHOD_ARRAY: methodListLock\n * CLS_INITIALIZING: classInitLock\n ***********************************************************************/\n\n/***********************************************************************\n* Imports.\n**********************************************************************/\n\n#include \"objc-private.h\"\n#include \"objc-abi.h\"\n#include <objc/message.h>\n\n/***********************************************************************\n* Information about multi-thread support:\n*\n* Since we do not lock many operations which walk the superclass, method\n* and ivar chains, these chains must remain intact once a class is published\n* by inserting it into the class hashtable.  All modifications must be\n* atomic so that someone walking these chains will always geta valid\n* result.\n***********************************************************************/\n\n\n\n/***********************************************************************\n* object_getClass.\n* Locking: None. If you add locking, tell gdb (rdar://7516456).\n**********************************************************************/\nClass object_getClass(id obj)\n{\n    if (obj) return obj->getIsa();\n    else return Nil;\n}\n\n\n/***********************************************************************\n* object_setClass.\n**********************************************************************/\nClass object_setClass(id obj, Class cls)\n{\n    if (!obj) return nil;\n\n    // Prevent a deadlock between the weak reference machinery\n    // and the +initialize machinery by ensuring that no \n    // weakly-referenced object has an un-+initialized isa.\n    // Unresolved future classes are not so protected.\n    if (!cls->isFuture()  &&  !cls->isInitialized()) {\n        _class_initialize(_class_getNonMetaClass(cls, nil));\n    }\n\n    return obj->changeIsa(cls);\n}\n\n\n/***********************************************************************\n* object_isClass.\n**********************************************************************/\nBOOL object_isClass(id obj)\n{\n    if (!obj) return NO;\n    return obj->isClass();\n}\n\n\n/***********************************************************************\n* object_getClassName.\n**********************************************************************/\nconst char *object_getClassName(id obj)\n{\n    return class_getName(obj ? obj->getIsa() : nil);\n}\n\n\n/***********************************************************************\n * object_getMethodImplementation.\n **********************************************************************/\nIMP object_getMethodImplementation(id obj, SEL name)\n{\n    Class cls = (obj ? obj->getIsa() : nil);\n    return class_getMethodImplementation(cls, name);\n}\n\n\n/***********************************************************************\n * object_getMethodImplementation_stret.\n **********************************************************************/\n#if SUPPORT_STRET\nIMP object_getMethodImplementation_stret(id obj, SEL name)\n{\n    Class cls = (obj ? obj->getIsa() : nil);\n    return class_getMethodImplementation_stret(cls, name);\n}\n#endif\n\n\nstatic bool isScanned(ptrdiff_t ivar_offset, const uint8_t *layout) \n{\n    if (!layout) return NO;\n\n    ptrdiff_t index = 0, ivar_index = ivar_offset / sizeof(void*);\n    uint8_t byte;\n    while ((byte = *layout++)) {\n        unsigned skips = (byte >> 4);\n        unsigned scans = (byte & 0x0F);\n        index += skips;\n        if (index > ivar_index) return NO;\n        index += scans;\n        if (index > ivar_index) return YES;\n    }\n    return NO;\n}\n\n\n/***********************************************************************\n* _class_lookUpIvar\n* Given an object and an ivar in it, look up some data about that ivar:\n* - its offset\n* - its memory management behavior\n* The ivar is assumed to be word-aligned and of of object type.\n**********************************************************************/\nstatic void \n_class_lookUpIvar(Class cls, Ivar ivar, ptrdiff_t& ivarOffset, \n                  objc_ivar_memory_management_t& memoryManagement)\n{\n    ivarOffset = ivar_getOffset(ivar);\n    \n    // Look for ARC variables and ARC-style weak.\n\n    // Preflight the hasAutomaticIvars check\n    // because _class_getClassForIvar() may need to take locks.\n    bool hasAutomaticIvars = NO;\n    for (Class c = cls; c; c = c->superclass) {\n        if (c->hasAutomaticIvars()) {\n            hasAutomaticIvars = YES;\n            break;\n        }\n    }\n\n    if (hasAutomaticIvars) {\n        Class ivarCls = _class_getClassForIvar(cls, ivar);\n        if (ivarCls->hasAutomaticIvars()) {\n            // ARC layout bitmaps encode the class's own ivars only.\n            // Use alignedInstanceStart() because unaligned bytes at the start\n            // of this class's ivars are not represented in the layout bitmap.\n            ptrdiff_t localOffset = \n                ivarOffset - ivarCls->alignedInstanceStart();\n\n            if (isScanned(localOffset, class_getIvarLayout(ivarCls))) {\n                memoryManagement = objc_ivar_memoryStrong;\n                return;\n            }\n            \n            if (isScanned(localOffset, class_getWeakIvarLayout(ivarCls))) {\n                memoryManagement = objc_ivar_memoryWeak;\n                return;\n            }\n\n            // Unretained is only for true ARC classes.\n            if (ivarCls->isARC()) {\n                memoryManagement = objc_ivar_memoryUnretained;\n                return;\n            }\n        }\n    }\n    \n    memoryManagement = objc_ivar_memoryUnknown;\n}\n\n\n/***********************************************************************\n* _class_getIvarMemoryManagement\n* SPI for KVO and others to decide what memory management to use \n* when setting instance variables directly.\n**********************************************************************/\nobjc_ivar_memory_management_t \n_class_getIvarMemoryManagement(Class cls, Ivar ivar)\n{\n    ptrdiff_t offset;\n    objc_ivar_memory_management_t memoryManagement;\n    _class_lookUpIvar(cls, ivar, offset, memoryManagement);\n    return memoryManagement;\n}\n\n\nstatic ALWAYS_INLINE \nvoid _object_setIvar(id obj, Ivar ivar, id value, bool assumeStrong)\n{\n    if (!obj  ||  !ivar  ||  obj->isTaggedPointer()) return;\n\n    ptrdiff_t offset;\n    objc_ivar_memory_management_t memoryManagement;\n    _class_lookUpIvar(obj->ISA(), ivar, offset, memoryManagement);\n\n    if (memoryManagement == objc_ivar_memoryUnknown) {\n        if (assumeStrong) memoryManagement = objc_ivar_memoryStrong;\n        else memoryManagement = objc_ivar_memoryUnretained;\n    }\n\n    id *location = (id *)((char *)obj + offset);\n\n    switch (memoryManagement) {\n    case objc_ivar_memoryWeak:       objc_storeWeak(location, value); break;\n    case objc_ivar_memoryStrong:     objc_storeStrong(location, value); break;\n    case objc_ivar_memoryUnretained: *location = value; break;\n    case objc_ivar_memoryUnknown:    _objc_fatal(\"impossible\");\n    }\n}\n\nvoid object_setIvar(id obj, Ivar ivar, id value)\n{\n    return _object_setIvar(obj, ivar, value, false /*not strong default*/);\n}\n\nvoid object_setIvarWithStrongDefault(id obj, Ivar ivar, id value)\n{\n    return _object_setIvar(obj, ivar, value, true /*strong default*/);\n}\n\n\nid object_getIvar(id obj, Ivar ivar)\n{\n    if (!obj  ||  !ivar  ||  obj->isTaggedPointer()) return nil;\n\n    ptrdiff_t offset;\n    objc_ivar_memory_management_t memoryManagement;\n    _class_lookUpIvar(obj->ISA(), ivar, offset, memoryManagement);\n\n    id *location = (id *)((char *)obj + offset);\n\n    if (memoryManagement == objc_ivar_memoryWeak) {\n        return objc_loadWeak(location);\n    } else {\n        return *location;\n    }\n}\n\n\nstatic ALWAYS_INLINE \nIvar _object_setInstanceVariable(id obj, const char *name, void *value, \n                                 bool assumeStrong)\n{\n    Ivar ivar = nil;\n\n    if (obj  &&  name  &&  !obj->isTaggedPointer()) {\n        if ((ivar = _class_getVariable(obj->ISA(), name))) {\n            _object_setIvar(obj, ivar, (id)value, assumeStrong);\n        }\n    }\n    return ivar;\n}\n\nIvar object_setInstanceVariable(id obj, const char *name, void *value)\n{\n    return _object_setInstanceVariable(obj, name, value, false);\n}\n\nIvar object_setInstanceVariableWithStrongDefault(id obj, const char *name, \n                                                 void *value)\n{\n    return _object_setInstanceVariable(obj, name, value, true);\n}\n\n\nIvar object_getInstanceVariable(id obj, const char *name, void **value)\n{\n    if (obj  &&  name  &&  !obj->isTaggedPointer()) {\n        Ivar ivar;\n        if ((ivar = class_getInstanceVariable(obj->ISA(), name))) {\n            if (value) *value = (void *)object_getIvar(obj, ivar);\n            return ivar;\n        }\n    }\n    if (value) *value = nil;\n    return nil;\n}\n\n\n/***********************************************************************\n* object_cxxDestructFromClass.\n* Call C++ destructors on obj, starting with cls's \n*   dtor method (if any) followed by superclasses' dtors (if any), \n*   stopping at cls's dtor (if any).\n* Uses methodListLock and cacheUpdateLock. The caller must hold neither.\n**********************************************************************/\nstatic void object_cxxDestructFromClass(id obj, Class cls)\n{\n    void (*dtor)(id);\n\n    // Call cls's dtor first, then superclasses's dtors.\n\n    for ( ; cls; cls = cls->superclass) {\n        if (!cls->hasCxxDtor()) return; \n        dtor = (void(*)(id))\n            lookupMethodInClassAndLoadCache(cls, SEL_cxx_destruct);\n        if (dtor != (void(*)(id))_objc_msgForward_impcache) {\n            if (PrintCxxCtors) {\n                _objc_inform(\"CXX: calling C++ destructors for class %s\", \n                             cls->nameForLogging());\n            }\n            (*dtor)(obj);\n        }\n    }\n}\n\n\n/***********************************************************************\n* object_cxxDestruct.\n* Call C++ destructors on obj, if any.\n* Uses methodListLock and cacheUpdateLock. The caller must hold neither.\n**********************************************************************/\nvoid object_cxxDestruct(id obj)\n{\n    if (!obj) return;\n    if (obj->isTaggedPointer()) return;\n    object_cxxDestructFromClass(obj, obj->ISA());\n}\n\n\n/***********************************************************************\n* object_cxxConstructFromClass.\n* Recursively call C++ constructors on obj, starting with base class's \n*   ctor method (if any) followed by subclasses' ctors (if any), stopping \n*   at cls's ctor (if any).\n* Does not check cls->hasCxxCtor(). The caller should preflight that.\n* Returns self if construction succeeded.\n* Returns nil if some constructor threw an exception. The exception is \n*   caught and discarded. Any partial construction is destructed.\n* Uses methodListLock and cacheUpdateLock. The caller must hold neither.\n*\n* .cxx_construct returns id. This really means:\n* return self: construction succeeded\n* return nil:  construction failed because a C++ constructor threw an exception\n**********************************************************************/\nid \nobject_cxxConstructFromClass(id obj, Class cls)\n{\n    assert(cls->hasCxxCtor());  // required for performance, not correctness\n\n    id (*ctor)(id);\n    Class supercls;\n\n    supercls = cls->superclass;\n\n    // Call superclasses' ctors first, if any.\n    if (supercls  &&  supercls->hasCxxCtor()) {\n        bool ok = object_cxxConstructFromClass(obj, supercls);\n        if (!ok) return nil;  // some superclass's ctor failed - give up\n    }\n\n    // Find this class's ctor, if any.\n    ctor = (id(*)(id))lookupMethodInClassAndLoadCache(cls, SEL_cxx_construct);\n    if (ctor == (id(*)(id))_objc_msgForward_impcache) return obj;  // no ctor - ok\n    \n    // Call this class's ctor.\n    if (PrintCxxCtors) {\n        _objc_inform(\"CXX: calling C++ constructors for class %s\", \n                     cls->nameForLogging());\n    }\n    if ((*ctor)(obj)) return obj;  // ctor called and succeeded - ok\n\n    // This class's ctor was called and failed. \n    // Call superclasses's dtors to clean up.\n    if (supercls) object_cxxDestructFromClass(obj, supercls);\n    return nil;\n}\n\n\n/***********************************************************************\n* fixupCopiedIvars\n* Fix up ARC strong and ARC-style weak variables \n* after oldObject was memcpy'd to newObject.\n**********************************************************************/\nvoid fixupCopiedIvars(id newObject, id oldObject)\n{\n    for (Class cls = oldObject->ISA(); cls; cls = cls->superclass) {\n        if (cls->hasAutomaticIvars()) {\n            // Use alignedInstanceStart() because unaligned bytes at the start\n            // of this class's ivars are not represented in the layout bitmap.\n            size_t instanceStart = cls->alignedInstanceStart();\n\n            const uint8_t *strongLayout = class_getIvarLayout(cls);\n            if (strongLayout) {\n                id *newPtr = (id *)((char*)newObject + instanceStart);\n                unsigned char byte;\n                while ((byte = *strongLayout++)) {\n                    unsigned skips = (byte >> 4);\n                    unsigned scans = (byte & 0x0F);\n                    newPtr += skips;\n                    while (scans--) {\n                        // ensure strong references are properly retained.\n                        id value = *newPtr++;\n                        if (value) objc_retain(value);\n                    }\n                }\n            }\n\n            const uint8_t *weakLayout = class_getWeakIvarLayout(cls);\n            // fix up weak references if any.\n            if (weakLayout) {\n                id *newPtr = (id *)((char*)newObject + instanceStart), *oldPtr = (id *)((char*)oldObject + instanceStart);\n                unsigned char byte;\n                while ((byte = *weakLayout++)) {\n                    unsigned skips = (byte >> 4);\n                    unsigned weaks = (byte & 0x0F);\n                    newPtr += skips, oldPtr += skips;\n                    while (weaks--) {\n                        objc_copyWeak(newPtr, oldPtr);\n                        ++newPtr, ++oldPtr;\n                    }\n                }\n            }\n        }\n    }\n}\n\n\n/***********************************************************************\n* _class_resolveClassMethod\n* Call +resolveClassMethod, looking for a method to be added to class cls.\n* cls should be a metaclass.\n* Does not check if the method already exists.\n**********************************************************************/\nstatic void _class_resolveClassMethod(Class cls, SEL sel, id inst)\n{\n    assert(cls->isMetaClass());\n\n    if (! lookUpImpOrNil(cls, SEL_resolveClassMethod, inst, \n                         NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) \n    {\n        // Resolver not implemented.\n        return;\n    }\n\n    BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;\n    bool resolved = msg(_class_getNonMetaClass(cls, inst), \n                        SEL_resolveClassMethod, sel);\n\n    // Cache the result (good or bad) so the resolver doesn't fire next time.\n    // +resolveClassMethod adds to self->ISA() a.k.a. cls\n    IMP imp = lookUpImpOrNil(cls, sel, inst, \n                             NO/*initialize*/, YES/*cache*/, NO/*resolver*/);\n\n    if (resolved  &&  PrintResolving) {\n        if (imp) {\n            _objc_inform(\"RESOLVE: method %c[%s %s] \"\n                         \"dynamically resolved to %p\", \n                         cls->isMetaClass() ? '+' : '-', \n                         cls->nameForLogging(), sel_getName(sel), imp);\n        }\n        else {\n            // Method resolver didn't add anything?\n            _objc_inform(\"RESOLVE: +[%s resolveClassMethod:%s] returned YES\"\n                         \", but no new implementation of %c[%s %s] was found\",\n                         cls->nameForLogging(), sel_getName(sel), \n                         cls->isMetaClass() ? '+' : '-', \n                         cls->nameForLogging(), sel_getName(sel));\n        }\n    }\n}\n\n\n/***********************************************************************\n* _class_resolveInstanceMethod\n* Call +resolveInstanceMethod, looking for a method to be added to class cls.\n* cls may be a metaclass or a non-meta class.\n* Does not check if the method already exists.\n**********************************************************************/\nstatic void _class_resolveInstanceMethod(Class cls, SEL sel, id inst)\n{\n    if (! lookUpImpOrNil(cls->ISA(), SEL_resolveInstanceMethod, cls, \n                         NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) \n    {\n        // Resolver not implemented.\n        return;\n    }\n\n    BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;\n    bool resolved = msg(cls, SEL_resolveInstanceMethod, sel);\n\n    // Cache the result (good or bad) so the resolver doesn't fire next time.\n    // +resolveInstanceMethod adds to self a.k.a. cls\n    IMP imp = lookUpImpOrNil(cls, sel, inst, \n                             NO/*initialize*/, YES/*cache*/, NO/*resolver*/);\n\n    if (resolved  &&  PrintResolving) {\n        if (imp) {\n            _objc_inform(\"RESOLVE: method %c[%s %s] \"\n                         \"dynamically resolved to %p\", \n                         cls->isMetaClass() ? '+' : '-', \n                         cls->nameForLogging(), sel_getName(sel), imp);\n        }\n        else {\n            // Method resolver didn't add anything?\n            _objc_inform(\"RESOLVE: +[%s resolveInstanceMethod:%s] returned YES\"\n                         \", but no new implementation of %c[%s %s] was found\",\n                         cls->nameForLogging(), sel_getName(sel), \n                         cls->isMetaClass() ? '+' : '-', \n                         cls->nameForLogging(), sel_getName(sel));\n        }\n    }\n}\n\n\n/***********************************************************************\n* _class_resolveMethod\n* Call +resolveClassMethod or +resolveInstanceMethod.\n* Returns nothing; any result would be potentially out-of-date already.\n* Does not check if the method already exists.\n**********************************************************************/\nvoid _class_resolveMethod(Class cls, SEL sel, id inst)\n{\n    if (! cls->isMetaClass()) {\n        // try [cls resolveInstanceMethod:sel]\n        _class_resolveInstanceMethod(cls, sel, inst);\n    } \n    else {\n        // try [nonMetaClass resolveClassMethod:sel]\n        // and [cls resolveInstanceMethod:sel]\n        _class_resolveClassMethod(cls, sel, inst);\n        if (!lookUpImpOrNil(cls, sel, inst, \n                            NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) \n        {\n            _class_resolveInstanceMethod(cls, sel, inst);\n        }\n    }\n}\n\n\n/***********************************************************************\n* class_getClassMethod.  Return the class method for the specified\n* class and selector.\n**********************************************************************/\nMethod class_getClassMethod(Class cls, SEL sel)\n{\n    if (!cls  ||  !sel) return nil;\n\n    return class_getInstanceMethod(cls->getMeta(), sel);\n}\n\n\n/***********************************************************************\n* class_getInstanceVariable.  Return the named instance variable.\n**********************************************************************/\nIvar class_getInstanceVariable(Class cls, const char *name)\n{\n    if (!cls  ||  !name) return nil;\n\n    return _class_getVariable(cls, name);\n}\n\n\n/***********************************************************************\n* class_getClassVariable.  Return the named class variable.\n**********************************************************************/\nIvar class_getClassVariable(Class cls, const char *name)\n{\n    if (!cls) return nil;\n\n    return class_getInstanceVariable(cls->ISA(), name);\n}\n\n\n/***********************************************************************\n* gdb_objc_class_changed\n* Tell gdb that a class changed. Currently used for OBJC2 ivar layouts only\n* Does nothing; gdb sets a breakpoint on it.\n**********************************************************************/\nBREAKPOINT_FUNCTION( \n    void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname)\n);\n\n\n/***********************************************************************\n* class_respondsToSelector.\n**********************************************************************/\nBOOL class_respondsToMethod(Class cls, SEL sel)\n{\n    OBJC_WARN_DEPRECATED;\n\n    return class_respondsToSelector(cls, sel);\n}\n\n\nBOOL class_respondsToSelector(Class cls, SEL sel)\n{\n    return class_respondsToSelector_inst(cls, sel, nil);\n}\n\n\n// inst is an instance of cls or a subclass thereof, or nil if none is known.\n// Non-nil inst is faster in some cases. See lookUpImpOrForward() for details.\nbool class_respondsToSelector_inst(Class cls, SEL sel, id inst)\n{\n    IMP imp;\n\n    if (!sel  ||  !cls) return NO;\n\n    // Avoids +initialize because it historically did so.\n    // We're not returning a callable IMP anyway.\n    imp = lookUpImpOrNil(cls, sel, inst, \n                         NO/*initialize*/, YES/*cache*/, YES/*resolver*/);\n    return bool(imp);\n}\n\n\n/***********************************************************************\n* class_getMethodImplementation.\n* Returns the IMP that would be invoked if [obj sel] were sent, \n* where obj is an instance of class cls.\n**********************************************************************/\nIMP class_lookupMethod(Class cls, SEL sel)\n{\n    OBJC_WARN_DEPRECATED;\n\n    // No one responds to zero!\n    if (!sel) {\n        __objc_error(cls, \"invalid selector (null)\");\n    }\n\n    return class_getMethodImplementation(cls, sel);\n}\n\nIMP class_getMethodImplementation(Class cls, SEL sel)\n{\n    IMP imp;\n\n    if (!cls  ||  !sel) return nil;\n\n    imp = lookUpImpOrNil(cls, sel, nil, \n                         YES/*initialize*/, YES/*cache*/, YES/*resolver*/);\n\n    // Translate forwarding function to C-callable external version\n    if (!imp) {\n        return _objc_msgForward;\n    }\n\n    return imp;\n}\n\n#if SUPPORT_STRET\nIMP class_getMethodImplementation_stret(Class cls, SEL sel)\n{\n    IMP imp = class_getMethodImplementation(cls, sel);\n\n    // Translate forwarding function to struct-returning version\n    if (imp == (IMP)&_objc_msgForward /* not _internal! */) {\n        return (IMP)&_objc_msgForward_stret;\n    }\n    return imp;\n}\n#endif\n\n\n/***********************************************************************\n* instrumentObjcMessageSends\n**********************************************************************/\n// Define this everywhere even if it isn't used to simplify fork() safety code.\nspinlock_t objcMsgLogLock;\n\n#if !SUPPORT_MESSAGE_LOGGING\n\nvoid\tinstrumentObjcMessageSends(BOOL flag)\n{\n}\n\n#else\n\nbool objcMsgLogEnabled = false;\nstatic int objcMsgLogFD = -1;\n\nbool logMessageSend(bool isClassMethod,\n                    const char *objectsClass,\n                    const char *implementingClass,\n                    SEL selector)\n{\n    char\tbuf[ 1024 ];\n\n    // Create/open the log file\n    if (objcMsgLogFD == (-1))\n    {\n        snprintf (buf, sizeof(buf), \"/tmp/msgSends-%d\", (int) getpid ());\n        objcMsgLogFD = secure_open (buf, O_WRONLY | O_CREAT, geteuid());\n        if (objcMsgLogFD < 0) {\n            // no log file - disable logging\n            objcMsgLogEnabled = false;\n            objcMsgLogFD = -1;\n            return true;\n        }\n    }\n\n    // Make the log entry\n    snprintf(buf, sizeof(buf), \"%c %s %s %s\\n\",\n            isClassMethod ? '+' : '-',\n            objectsClass,\n            implementingClass,\n            sel_getName(selector));\n\n    objcMsgLogLock.lock();\n    write (objcMsgLogFD, buf, strlen(buf));\n    objcMsgLogLock.unlock();\n\n    // Tell caller to not cache the method\n    return false;\n}\n\nvoid instrumentObjcMessageSends(BOOL flag)\n{\n    bool enable = flag;\n\n    // Shortcut NOP\n    if (objcMsgLogEnabled == enable)\n        return;\n\n    // If enabling, flush all method caches so we get some traces\n    if (enable)\n        _objc_flush_caches(Nil);\n\n    // Sync our log file\n    if (objcMsgLogFD != -1)\n        fsync (objcMsgLogFD);\n\n    objcMsgLogEnabled = enable;\n}\n\n// SUPPORT_MESSAGE_LOGGING\n#endif\n\n\nClass _calloc_class(size_t size)\n{\n    return (Class) calloc(1, size);\n}\n\nClass class_getSuperclass(Class cls)\n{\n    if (!cls) return nil;\n    return cls->superclass;\n}\n\nBOOL class_isMetaClass(Class cls)\n{\n    if (!cls) return NO;\n    return cls->isMetaClass();\n}\n\n\nsize_t class_getInstanceSize(Class cls)\n{\n    if (!cls) return 0;\n    return cls->alignedInstanceSize();\n}\n\n\n/***********************************************************************\n* method_getNumberOfArguments.\n**********************************************************************/\nunsigned int method_getNumberOfArguments(Method m)\n{\n    if (!m) return 0;\n    return encoding_getNumberOfArguments(method_getTypeEncoding(m));\n}\n\n\nvoid method_getReturnType(Method m, char *dst, size_t dst_len)\n{\n    encoding_getReturnType(method_getTypeEncoding(m), dst, dst_len);\n}\n\n\nchar * method_copyReturnType(Method m)\n{\n    return encoding_copyReturnType(method_getTypeEncoding(m));\n}\n\n\nvoid method_getArgumentType(Method m, unsigned int index, \n                            char *dst, size_t dst_len)\n{\n    encoding_getArgumentType(method_getTypeEncoding(m),\n                             index, dst, dst_len);\n}\n\n\nchar * method_copyArgumentType(Method m, unsigned int index)\n{\n    return encoding_copyArgumentType(method_getTypeEncoding(m), index);\n}\n\n\n/***********************************************************************\n* _objc_constructOrFree\n* Call C++ constructors, and free() if they fail.\n* bytes->isa must already be set.\n* cls must have cxx constructors.\n* Returns the object, or nil.\n**********************************************************************/\nid\n_objc_constructOrFree(id bytes, Class cls)\n{\n    assert(cls->hasCxxCtor());  // for performance, not correctness\n\n    id obj = object_cxxConstructFromClass(bytes, cls);\n    if (!obj) free(bytes);\n\n    return obj;\n}\n\n\n/***********************************************************************\n* _class_createInstancesFromZone\n* Batch-allocating version of _class_createInstanceFromZone.\n* Attempts to allocate num_requested objects, each with extraBytes.\n* Returns the number of allocated objects (possibly zero), with \n* the allocated pointers in *results.\n**********************************************************************/\nunsigned\n_class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone, \n                               id *results, unsigned num_requested)\n{\n    unsigned num_allocated;\n    if (!cls) return 0;\n\n    size_t size = cls->instanceSize(extraBytes);\n\n    num_allocated = \n        malloc_zone_batch_malloc((malloc_zone_t *)(zone ? zone : malloc_default_zone()), \n                                 size, (void**)results, num_requested);\n    for (unsigned i = 0; i < num_allocated; i++) {\n        bzero(results[i], size);\n    }\n\n    // Construct each object, and delete any that fail construction.\n\n    unsigned shift = 0;\n    bool ctor = cls->hasCxxCtor();\n    for (unsigned i = 0; i < num_allocated; i++) {\n        id obj = results[i];\n        obj->initIsa(cls);    // fixme allow nonpointer\n        if (ctor) obj = _objc_constructOrFree(obj, cls);\n\n        if (obj) {\n            results[i-shift] = obj;\n        } else {\n            shift++;\n        }\n    }\n\n    return num_allocated - shift;    \n}\n\n\n/***********************************************************************\n* inform_duplicate. Complain about duplicate class implementations.\n**********************************************************************/\nvoid \ninform_duplicate(const char *name, Class oldCls, Class newCls)\n{\n#if TARGET_OS_WIN32\n    (DebugDuplicateClasses ? _objc_fatal : _objc_inform)\n        (\"Class %s is implemented in two different images.\", name);\n#else\n    const header_info *oldHeader = _headerForClass(oldCls);\n    const header_info *newHeader = _headerForClass(newCls);\n    const char *oldName = oldHeader ? oldHeader->fname() : \"??\";\n    const char *newName = newHeader ? newHeader->fname() : \"??\";\n\n    (DebugDuplicateClasses ? _objc_fatal : _objc_inform)\n        (\"Class %s is implemented in both %s (%p) and %s (%p). \"\n         \"One of the two will be used. Which one is undefined.\",\n         name, oldName, oldCls, newName, newCls);\n#endif\n}\n\n\nconst char *\ncopyPropertyAttributeString(const objc_property_attribute_t *attrs,\n                            unsigned int count)\n{\n    char *result;\n    unsigned int i;\n    if (count == 0) return strdup(\"\");\n    \n#if DEBUG\n    // debug build: sanitize input\n    for (i = 0; i < count; i++) {\n        assert(attrs[i].name);\n        assert(strlen(attrs[i].name) > 0);\n        assert(! strchr(attrs[i].name, ','));\n        assert(! strchr(attrs[i].name, '\"'));\n        if (attrs[i].value) assert(! strchr(attrs[i].value, ','));\n    }\n#endif\n\n    size_t len = 0;\n    for (i = 0; i < count; i++) {\n        if (attrs[i].value) {\n            size_t namelen = strlen(attrs[i].name);\n            if (namelen > 1) namelen += 2;  // long names get quoted\n            len += namelen + strlen(attrs[i].value) + 1;\n        }\n    }\n\n    result = (char *)malloc(len + 1);\n    char *s = result;\n    for (i = 0; i < count; i++) {\n        if (attrs[i].value) {\n            size_t namelen = strlen(attrs[i].name);\n            if (namelen > 1) {\n                s += sprintf(s, \"\\\"%s\\\"%s,\", attrs[i].name, attrs[i].value);\n            } else {\n                s += sprintf(s, \"%s%s,\", attrs[i].name, attrs[i].value);\n            }\n        }\n    }\n\n    // remove trailing ',' if any\n    if (s > result) s[-1] = '\\0';\n\n    return result;\n}\n\n/*\n  Property attribute string format:\n\n  - Comma-separated name-value pairs. \n  - Name and value may not contain ,\n  - Name may not contain \"\n  - Value may be empty\n  - Name is single char, value follows\n  - OR Name is double-quoted string of 2+ chars, value follows\n\n  Grammar:\n    attribute-string: \\0\n    attribute-string: name-value-pair (',' name-value-pair)*\n    name-value-pair:  unquoted-name optional-value\n    name-value-pair:  quoted-name optional-value\n    unquoted-name:    [^\",]\n    quoted-name:      '\"' [^\",]{2,} '\"'\n    optional-value:   [^,]*\n\n*/\nstatic unsigned int \niteratePropertyAttributes(const char *attrs, \n                          bool (*fn)(unsigned int index, \n                                     void *ctx1, void *ctx2, \n                                     const char *name, size_t nlen, \n                                     const char *value, size_t vlen), \n                          void *ctx1, void *ctx2)\n{\n    if (!attrs) return 0;\n\n#if DEBUG\n    const char *attrsend = attrs + strlen(attrs);\n#endif\n    unsigned int attrcount = 0;\n\n    while (*attrs) {\n        // Find the next comma-separated attribute\n        const char *start = attrs;\n        const char *end = start + strcspn(attrs, \",\");\n\n        // Move attrs past this attribute and the comma (if any)\n        attrs = *end ? end+1 : end;\n\n        assert(attrs <= attrsend);\n        assert(start <= attrsend);\n        assert(end <= attrsend);\n        \n        // Skip empty attribute\n        if (start == end) continue;\n\n        // Process one non-empty comma-free attribute [start,end)\n        const char *nameStart;\n        const char *nameEnd;\n\n        assert(start < end);\n        assert(*start);\n        if (*start != '\\\"') {\n            // single-char short name\n            nameStart = start;\n            nameEnd = start+1;\n            start++;\n        }\n        else {\n            // double-quoted long name\n            nameStart = start+1;\n            nameEnd = nameStart + strcspn(nameStart, \"\\\",\");\n            start++;                       // leading quote\n            start += nameEnd - nameStart;  // name\n            if (*start == '\\\"') start++;   // trailing quote, if any\n        }\n\n        // Process one possibly-empty comma-free attribute value [start,end)\n        const char *valueStart;\n        const char *valueEnd;\n\n        assert(start <= end);\n\n        valueStart = start;\n        valueEnd = end;\n\n        bool more = (*fn)(attrcount, ctx1, ctx2, \n                          nameStart, nameEnd-nameStart, \n                          valueStart, valueEnd-valueStart);\n        attrcount++;\n        if (!more) break;\n    }\n\n    return attrcount;\n}\n\n\nstatic bool \ncopyOneAttribute(unsigned int index, void *ctxa, void *ctxs, \n                 const char *name, size_t nlen, const char *value, size_t vlen)\n{\n    objc_property_attribute_t **ap = (objc_property_attribute_t**)ctxa;\n    char **sp = (char **)ctxs;\n\n    objc_property_attribute_t *a = *ap;\n    char *s = *sp;\n\n    a->name = s;\n    memcpy(s, name, nlen);\n    s += nlen;\n    *s++ = '\\0';\n    \n    a->value = s;\n    memcpy(s, value, vlen);\n    s += vlen;\n    *s++ = '\\0';\n\n    a++;\n    \n    *ap = a;\n    *sp = s;\n\n    return YES;\n}\n\n                 \nobjc_property_attribute_t *\ncopyPropertyAttributeList(const char *attrs, unsigned int *outCount)\n{\n    if (!attrs) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    // Result size:\n    //   number of commas plus 1 for the attributes (upper bound)\n    //   plus another attribute for the attribute array terminator\n    //   plus strlen(attrs) for name/value string data (upper bound)\n    //   plus count*2 for the name/value string terminators (upper bound)\n    unsigned int attrcount = 1;\n    const char *s;\n    for (s = attrs; s && *s; s++) {\n        if (*s == ',') attrcount++;\n    }\n\n    size_t size = \n        attrcount * sizeof(objc_property_attribute_t) + \n        sizeof(objc_property_attribute_t) + \n        strlen(attrs) + \n        attrcount * 2;\n    objc_property_attribute_t *result = (objc_property_attribute_t *) \n        calloc(size, 1);\n\n    objc_property_attribute_t *ra = result;\n    char *rs = (char *)(ra+attrcount+1);\n\n    attrcount = iteratePropertyAttributes(attrs, copyOneAttribute, &ra, &rs);\n\n    assert((uint8_t *)(ra+1) <= (uint8_t *)result+size);\n    assert((uint8_t *)rs <= (uint8_t *)result+size);\n\n    if (attrcount == 0) {\n        free(result);\n        result = nil;\n    }\n\n    if (outCount) *outCount = attrcount;\n    return result;\n}\n\n\nstatic bool \nfindOneAttribute(unsigned int index, void *ctxa, void *ctxs, \n                 const char *name, size_t nlen, const char *value, size_t vlen)\n{\n    const char *query = (char *)ctxa;\n    char **resultp = (char **)ctxs;\n\n    if (strlen(query) == nlen  &&  0 == strncmp(name, query, nlen)) {\n        char *result = (char *)calloc(vlen+1, 1);\n        memcpy(result, value, vlen);\n        result[vlen] = '\\0';\n        *resultp = result;\n        return NO;\n    }\n\n    return YES;\n}\n\nchar *copyPropertyAttributeValue(const char *attrs, const char *name)\n{\n    char *result = nil;\n\n    iteratePropertyAttributes(attrs, findOneAttribute, (void*)name, &result);\n\n    return result;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-config.h",
    "content": "/*\n * Copyright (c) 1999-2002, 2005-2008 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _OBJC_CONFIG_H_\n#define _OBJC_CONFIG_H_\n\n#include <TargetConditionals.h>\n\n// Define __OBJC2__ for the benefit of our asm files.\n#ifndef __OBJC2__\n#   if TARGET_OS_OSX  &&  !TARGET_OS_IOSMAC  &&  __i386__\n        // old ABI\n#   else\n#       define __OBJC2__ 1\n#   endif\n#endif\n\n// Avoid the !NDEBUG double negative.\n#if !NDEBUG\n#   define DEBUG 1\n#else\n#   define DEBUG 0\n#endif\n\n// Define SUPPORT_GC_COMPAT=1 to enable compatibility where GC once was.\n// OBJC_NO_GC and OBJC_NO_GC_API in objc-api.h mean something else.\n#if !TARGET_OS_OSX\n#   define SUPPORT_GC_COMPAT 0\n#else\n#   define SUPPORT_GC_COMPAT 1\n#endif\n\n// Define SUPPORT_ZONES=1 to enable malloc zone support in NXHashTable.\n#if !(TARGET_OS_OSX || TARGET_OS_IOSMAC)\n#   define SUPPORT_ZONES 0\n#else\n#   define SUPPORT_ZONES 1\n#endif\n\n// Define SUPPORT_MOD=1 to use the mod operator in NXHashTable and objc-sel-set\n#if defined(__arm__)\n#   define SUPPORT_MOD 0\n#else\n#   define SUPPORT_MOD 1\n#endif\n\n// Define SUPPORT_PREOPT=1 to enable dyld shared cache optimizations\n#if TARGET_OS_WIN32  ||  TARGET_OS_SIMULATOR\n#   define SUPPORT_PREOPT 0\n#else\n#   define SUPPORT_PREOPT 1\n#endif\n\n// Define SUPPORT_TAGGED_POINTERS=1 to enable tagged pointer objects\n// Be sure to edit tagged pointer SPI in objc-internal.h as well.\n#if !(__OBJC2__  &&  __LP64__)\n#   define SUPPORT_TAGGED_POINTERS 0\n#else\n#   define SUPPORT_TAGGED_POINTERS 1\n#endif\n\n// Define SUPPORT_MSB_TAGGED_POINTERS to use the MSB \n// as the tagged pointer marker instead of the LSB.\n// Be sure to edit tagged pointer SPI in objc-internal.h as well.\n#if !SUPPORT_TAGGED_POINTERS  ||  (TARGET_OS_OSX || TARGET_OS_IOSMAC)\n#   define SUPPORT_MSB_TAGGED_POINTERS 0\n#else\n#   define SUPPORT_MSB_TAGGED_POINTERS 1\n#endif\n\n// Define SUPPORT_INDEXED_ISA=1 on platforms that store the class in the isa \n// field as an index into a class table.\n// Note, keep this in sync with any .s files which also define it.\n// Be sure to edit objc-abi.h as well.\n#if __ARM_ARCH_7K__ >= 2  ||  (__arm64__ && !__LP64__)\n#   define SUPPORT_INDEXED_ISA 1\n#else\n#   define SUPPORT_INDEXED_ISA 0\n#endif\n\n// Define SUPPORT_PACKED_ISA=1 on platforms that store the class in the isa \n// field as a maskable pointer with other data around it.\n#if (!__LP64__  ||  TARGET_OS_WIN32  ||  \\\n     (TARGET_OS_SIMULATOR && !TARGET_OS_IOSMAC))\n#   define SUPPORT_PACKED_ISA 0\n#else\n#   define SUPPORT_PACKED_ISA 1\n#endif\n\n// Define SUPPORT_NONPOINTER_ISA=1 on any platform that may store something\n// in the isa field that is not a raw pointer.\n#if !SUPPORT_INDEXED_ISA  &&  !SUPPORT_PACKED_ISA\n#   define SUPPORT_NONPOINTER_ISA 0\n#else\n#   define SUPPORT_NONPOINTER_ISA 1\n#endif\n\n// Define SUPPORT_FIXUP=1 to repair calls sites for fixup dispatch.\n// Fixup messaging itself is no longer supported.\n// Be sure to edit objc-abi.h as well (objc_msgSend*_fixup)\n#if !(defined(__x86_64__) && (TARGET_OS_OSX || TARGET_OS_SIMULATOR))\n#   define SUPPORT_FIXUP 0\n#else\n#   define SUPPORT_FIXUP 1\n#endif\n\n// Define SUPPORT_ZEROCOST_EXCEPTIONS to use \"zero-cost\" exceptions for OBJC2.\n// Be sure to edit objc-exception.h as well (objc_add/removeExceptionHandler)\n#if !__OBJC2__  ||  (defined(__arm__)  &&  __USING_SJLJ_EXCEPTIONS__)\n#   define SUPPORT_ZEROCOST_EXCEPTIONS 0\n#else\n#   define SUPPORT_ZEROCOST_EXCEPTIONS 1\n#endif\n\n// Define SUPPORT_ALT_HANDLERS if you're using zero-cost exceptions \n// but also need to support AppKit's alt-handler scheme\n// Be sure to edit objc-exception.h as well (objc_add/removeExceptionHandler)\n#if !SUPPORT_ZEROCOST_EXCEPTIONS  ||  !TARGET_OS_OSX\n#   define SUPPORT_ALT_HANDLERS 0\n#else\n#   define SUPPORT_ALT_HANDLERS 1\n#endif\n\n// Define SUPPORT_RETURN_AUTORELEASE to optimize autoreleased return values\n#if TARGET_OS_WIN32\n#   define SUPPORT_RETURN_AUTORELEASE 0\n#else\n#   define SUPPORT_RETURN_AUTORELEASE 1\n#endif\n\n// Define SUPPORT_STRET on architectures that need separate struct-return ABI.\n#if defined(__arm64__)\n#   define SUPPORT_STRET 0\n#else\n#   define SUPPORT_STRET 1\n#endif\n\n// Define SUPPORT_MESSAGE_LOGGING to enable NSObjCMessageLoggingEnabled\n#if !TARGET_OS_OSX\n#   define SUPPORT_MESSAGE_LOGGING 0\n#else\n#   define SUPPORT_MESSAGE_LOGGING 1\n#endif\n\n// OBJC_INSTRUMENTED controls whether message dispatching is dynamically\n// monitored.  Monitoring introduces substantial overhead.\n// NOTE: To define this condition, do so in the build command, NOT by\n// uncommenting the line here.  This is because objc-class.h heeds this\n// condition, but objc-class.h can not #include this file (objc-config.h)\n// because objc-class.h is public and objc-config.h is not.\n//#define OBJC_INSTRUMENTED\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-env.h",
    "content": "// -*- truncate-lines: t; -*-\n\n// OPTION(var, env, help)\n\nOPTION( PrintImages,              OBJC_PRINT_IMAGES,               \"log image and library names as they are loaded\")\nOPTION( PrintImageTimes,          OBJC_PRINT_IMAGE_TIMES,          \"measure duration of image loading steps\")\nOPTION( PrintLoading,             OBJC_PRINT_LOAD_METHODS,         \"log calls to class and category +load methods\")\nOPTION( PrintInitializing,        OBJC_PRINT_INITIALIZE_METHODS,   \"log calls to class +initialize methods\")\nOPTION( PrintResolving,           OBJC_PRINT_RESOLVED_METHODS,     \"log methods created by +resolveClassMethod: and +resolveInstanceMethod:\")\nOPTION( PrintConnecting,          OBJC_PRINT_CLASS_SETUP,          \"log progress of class and category setup\")\nOPTION( PrintProtocols,           OBJC_PRINT_PROTOCOL_SETUP,       \"log progress of protocol setup\")\nOPTION( PrintIvars,               OBJC_PRINT_IVAR_SETUP,           \"log processing of non-fragile ivars\")\nOPTION( PrintVtables,             OBJC_PRINT_VTABLE_SETUP,         \"log processing of class vtables\")\nOPTION( PrintVtableImages,        OBJC_PRINT_VTABLE_IMAGES,        \"print vtable images showing overridden methods\")\nOPTION( PrintCaches,              OBJC_PRINT_CACHE_SETUP,          \"log processing of method caches\")\nOPTION( PrintFuture,              OBJC_PRINT_FUTURE_CLASSES,       \"log use of future classes for toll-free bridging\")\nOPTION( PrintPreopt,              OBJC_PRINT_PREOPTIMIZATION,      \"log preoptimization courtesy of dyld shared cache\")\nOPTION( PrintCxxCtors,            OBJC_PRINT_CXX_CTORS,            \"log calls to C++ ctors and dtors for instance variables\")\nOPTION( PrintExceptions,          OBJC_PRINT_EXCEPTIONS,           \"log exception handling\")\nOPTION( PrintExceptionThrow,      OBJC_PRINT_EXCEPTION_THROW,      \"log backtrace of every objc_exception_throw()\")\nOPTION( PrintAltHandlers,         OBJC_PRINT_ALT_HANDLERS,         \"log processing of exception alt handlers\")\nOPTION( PrintReplacedMethods,     OBJC_PRINT_REPLACED_METHODS,     \"log methods replaced by category implementations\")\nOPTION( PrintDeprecation,         OBJC_PRINT_DEPRECATION_WARNINGS, \"warn about calls to deprecated runtime functions\")\nOPTION( PrintPoolHiwat,           OBJC_PRINT_POOL_HIGHWATER,       \"log high-water marks for autorelease pools\")\nOPTION( PrintCustomRR,            OBJC_PRINT_CUSTOM_RR,            \"log classes with un-optimized custom retain/release methods\")\nOPTION( PrintCustomAWZ,           OBJC_PRINT_CUSTOM_AWZ,           \"log classes with un-optimized custom allocWithZone methods\")\nOPTION( PrintRawIsa,              OBJC_PRINT_RAW_ISA,              \"log classes that require raw pointer isa fields\")\n\nOPTION( DebugUnload,              OBJC_DEBUG_UNLOAD,               \"warn about poorly-behaving bundles when unloaded\")\nOPTION( DebugFragileSuperclasses, OBJC_DEBUG_FRAGILE_SUPERCLASSES, \"warn about subclasses that may have been broken by subsequent changes to superclasses\")\nOPTION( DebugNilSync,             OBJC_DEBUG_NIL_SYNC,             \"warn about @synchronized(nil), which does no synchronization\")\nOPTION( DebugNonFragileIvars,     OBJC_DEBUG_NONFRAGILE_IVARS,     \"capriciously rearrange non-fragile ivars\")\nOPTION( DebugAltHandlers,         OBJC_DEBUG_ALT_HANDLERS,         \"record more info about bad alt handler use\")\nOPTION( DebugMissingPools,        OBJC_DEBUG_MISSING_POOLS,        \"warn about autorelease with no pool in place, which may be a leak\")\nOPTION( DebugPoolAllocation,      OBJC_DEBUG_POOL_ALLOCATION,      \"halt when autorelease pools are popped out of order, and allow heap debuggers to track autorelease pools\")\nOPTION( DebugDuplicateClasses,    OBJC_DEBUG_DUPLICATE_CLASSES,    \"halt when multiple classes with the same name are present\")\nOPTION( DebugDontCrash,           OBJC_DEBUG_DONT_CRASH,           \"halt the process by exiting instead of crashing\")\n\nOPTION( DisableVtables,           OBJC_DISABLE_VTABLES,            \"disable vtable dispatch\")\nOPTION( DisablePreopt,            OBJC_DISABLE_PREOPTIMIZATION,    \"disable preoptimization courtesy of dyld shared cache\")\nOPTION( DisableTaggedPointers,    OBJC_DISABLE_TAGGED_POINTERS,    \"disable tagged pointer optimization of NSNumber et al.\") \nOPTION( DisableTaggedPointerObfuscation, OBJC_DISABLE_TAG_OBFUSCATION,    \"disable obfuscation of tagged pointers\")\nOPTION( DisableNonpointerIsa,     OBJC_DISABLE_NONPOINTER_ISA,     \"disable non-pointer isa fields\")\nOPTION( DisableInitializeForkSafety, OBJC_DISABLE_INITIALIZE_FORK_SAFETY, \"disable safety checks for +initialize after fork\")\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-errors.mm",
    "content": "/*\n * Copyright (c) 1999-2003, 2005-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\n *\tobjc-errors.m\n * \tCopyright 1988-2001, NeXT Software, Inc., Apple Computer, Inc.\n */\n\n#include \"objc-private.h\"\n\n#if TARGET_OS_WIN32\n\n#include <conio.h>\n\nvoid _objc_inform_on_crash(const char *fmt, ...)\n{\n}\n\nvoid _objc_inform(const char *fmt, ...)\n{\n    va_list args;\n    va_start(args, fmt);\n    _vcprintf(fmt, args);\n    va_end(args);\n    _cprintf(\"\\n\");\n}\n\nvoid _objc_fatal(const char *fmt, ...)\n{\n    va_list args;\n    va_start(args, fmt);\n    _vcprintf(fmt, args);\n    va_end(args);\n    _cprintf(\"\\n\");\n\n    abort();\n}\n\nvoid __objc_error(id rcv, const char *fmt, ...) \n{\n    va_list args;\n    va_start(args, fmt);\n    _vcprintf(fmt, args);\n    va_end(args);\n\n    abort();\n}\n\nvoid _objc_error(id rcv, const char *fmt, va_list args) \n{\n    _vcprintf(fmt, args);\n\n    abort();\n}\n\n#else\n\n#include <_simple.h>\n\n// Return true if c is a UTF8 continuation byte\nstatic bool isUTF8Continuation(char c)\n{\n    return (c & 0xc0) == 0x80;  // continuation byte is 0b10xxxxxx\n}\n\n// Add \"message\" to any forthcoming crash log.\nmutex_t crashlog_lock;\nstatic void _objc_crashlog(const char *message)\n{\n    char *newmsg;\n\n#if 0\n    {\n        // for debugging at BOOT time.\n        extern char **_NSGetProgname(void);\n        FILE *crashlog = fopen(\"/_objc_crash.log\", \"a\");\n        setbuf(crashlog, NULL);\n        fprintf(crashlog, \"[%s] %s\\n\", *_NSGetProgname(), message);\n        fclose(crashlog);\n        sync();\n    }\n#endif\n\n    mutex_locker_t lock(crashlog_lock);\n\n    char *oldmsg = (char *)CRGetCrashLogMessage();\n    size_t oldlen;\n    const size_t limit = 8000;\n\n    if (!oldmsg) {\n        newmsg = strdup(message);\n    } else if ((oldlen = strlen(oldmsg)) > limit) {\n        // limit total length by dropping old contents\n        char *truncmsg = oldmsg + oldlen - limit;\n        // advance past partial UTF-8 bytes\n        while (isUTF8Continuation(*truncmsg)) truncmsg++;\n        asprintf(&newmsg, \"... %s\\n%s\", truncmsg, message);\n    } else {\n        asprintf(&newmsg, \"%s\\n%s\", oldmsg, message);\n    }\n\n    if (newmsg) {\n        // Strip trailing newline\n        char *c = &newmsg[strlen(newmsg)-1];\n        if (*c == '\\n') *c = '\\0';\n        \n        if (oldmsg) free(oldmsg);\n        CRSetCrashLogMessage(newmsg);\n    }\n}\n\n// Returns true if logs should be sent to stderr as well as syslog.\n// Copied from CFUtilities.c\nstatic bool also_do_stderr(void) \n{\n    struct stat st;\n    int ret = fstat(STDERR_FILENO, &st);\n    if (ret < 0) return false;\n    mode_t m = st.st_mode & S_IFMT;\n    if (m == S_IFREG  ||  m == S_IFSOCK  ||  m == S_IFIFO  ||  m == S_IFCHR) {\n        return true;\n    }\n    return false;\n}\n\n// Print \"message\" to the console.\nstatic void _objc_syslog(const char *message)\n{\n    _simple_asl_log(ASL_LEVEL_ERR, nil, message);\n\n    if (also_do_stderr()) {\n        write(STDERR_FILENO, message, strlen(message));\n    }\n}\n\n/*\n * _objc_error is the default *_error handler.\n */\n#if !__OBJC2__\n// used by ExceptionHandling.framework\n#endif\n__attribute__((noreturn))\nvoid _objc_error(id self, const char *fmt, va_list ap) \n{ \n    char *buf;\n    vasprintf(&buf, fmt, ap);\n    _objc_fatal(\"%s: %s\", object_getClassName(self), buf);\n}\n\n/*\n * this routine handles errors that involve an object (or class).\n */\nvoid __objc_error(id rcv, const char *fmt, ...) \n{ \n    va_list vp; \n\n    va_start(vp,fmt); \n#if !__OBJC2__\n    (*_error)(rcv, fmt, vp); \n#endif\n    _objc_error (rcv, fmt, vp);  /* In case (*_error)() returns. */\n    va_end(vp);\n}\n\nstatic __attribute__((noreturn))\nvoid _objc_fatalv(uint64_t reason, uint64_t flags, const char *fmt, va_list ap)\n{\n    char *buf1;\n    vasprintf(&buf1, fmt, ap);\n\n    char *buf2;\n    asprintf(&buf2, \"objc[%d]: %s\\n\", getpid(), buf1);\n    _objc_syslog(buf2);\n\n    if (DebugDontCrash) {\n        char *buf3;\n        asprintf(&buf3, \"objc[%d]: HALTED\\n\", getpid());\n        _objc_syslog(buf3);\n        _Exit(1);\n    }\n    else {\n        abort_with_reason(OS_REASON_OBJC, reason, buf1, flags);\n    }\n}\n\nvoid _objc_fatal_with_reason(uint64_t reason, uint64_t flags, \n                             const char *fmt, ...)\n{\n    va_list ap;\n    va_start(ap, fmt);\n    _objc_fatalv(reason, flags, fmt, ap);\n}\n\nvoid _objc_fatal(const char *fmt, ...)\n{\n    va_list ap; \n    va_start(ap,fmt); \n    _objc_fatalv(OBJC_EXIT_REASON_UNSPECIFIED, \n                 OS_REASON_FLAG_ONE_TIME_FAILURE, \n                 fmt, ap);\n}\n\n/*\n * this routine handles soft runtime errors...like not being able\n * add a category to a class (because it wasn't linked in).\n */\nvoid _objc_inform(const char *fmt, ...)\n{\n    va_list ap; \n    char *buf1;\n    char *buf2;\n\n    va_start (ap,fmt); \n    vasprintf(&buf1, fmt, ap);\n    va_end (ap);\n\n    asprintf(&buf2, \"objc[%d]: %s\\n\", getpid(), buf1);\n    _objc_syslog(buf2);\n\n    free(buf2);\n    free(buf1);\n}\n\n\n/* \n * Like _objc_inform(), but prints the message only in any \n * forthcoming crash log, not to the console.\n */\nvoid _objc_inform_on_crash(const char *fmt, ...)\n{\n    va_list ap; \n    char *buf1;\n    char *buf2;\n\n    va_start (ap,fmt); \n    vasprintf(&buf1, fmt, ap);\n    va_end (ap);\n\n    asprintf(&buf2, \"objc[%d]: %s\\n\", getpid(), buf1);\n    _objc_crashlog(buf2);\n\n    free(buf2);\n    free(buf1);\n}\n\n\n/* \n * Like calling both _objc_inform and _objc_inform_on_crash.\n */\nvoid _objc_inform_now_and_on_crash(const char *fmt, ...)\n{\n    va_list ap; \n    char *buf1;\n    char *buf2;\n\n    va_start (ap,fmt); \n    vasprintf(&buf1, fmt, ap);\n    va_end (ap);\n\n    asprintf(&buf2, \"objc[%d]: %s\\n\", getpid(), buf1);\n    _objc_crashlog(buf2);\n    _objc_syslog(buf2);\n\n    free(buf2);\n    free(buf1);\n}\n\n#endif\n\n\nBREAKPOINT_FUNCTION( \n    void _objc_warn_deprecated(void)\n);\n\nvoid _objc_inform_deprecated(const char *oldf, const char *newf)\n{\n    if (PrintDeprecation) {\n        if (newf) {\n            _objc_inform(\"The function %s is obsolete. Use %s instead. Set a breakpoint on _objc_warn_deprecated to find the culprit.\", oldf, newf);\n        } else {\n            _objc_inform(\"The function %s is obsolete. Do not use it. Set a breakpoint on _objc_warn_deprecated to find the culprit.\", oldf);\n        }\n    }\n    _objc_warn_deprecated();\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-exception.h",
    "content": "/*\n * Copyright (c) 2002-2003, 2006-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __OBJC_EXCEPTION_H_\n#define __OBJC_EXCEPTION_H_\n\n#include <objc/objc.h>\n#include <stdint.h>\n\n#if !__OBJC2__\n\n// compiler reserves a setjmp buffer + 4 words as localExceptionData\n\nOBJC_EXPORT void\nobjc_exception_throw(id _Nonnull exception)\n    __OSX_AVAILABLE(10.3) \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\nOBJC_EXPORT void\nobjc_exception_try_enter(void * _Nonnull localExceptionData)\n    __OSX_AVAILABLE(10.3) \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\nOBJC_EXPORT void\nobjc_exception_try_exit(void * _Nonnull localExceptionData)\n    __OSX_AVAILABLE(10.3) \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\nOBJC_EXPORT id _Nonnull\nobjc_exception_extract(void * _Nonnull localExceptionData)\n    __OSX_AVAILABLE(10.3) \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\nOBJC_EXPORT int objc_exception_match(Class _Nonnull exceptionClass,\n                                     id _Nonnull exception)\n    __OSX_AVAILABLE(10.3) \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\n\ntypedef struct {\n    int version;\n    void (* _Nonnull throw_exc)(id _Nonnull);\t          // version 0\n    void (* _Nonnull try_enter)(void * _Nonnull);         // version 0\n    void (* _Nonnull try_exit)(void * _Nonnull);          // version 0\n    id _Nonnull (* _Nonnull extract)(void * _Nonnull);    // version 0\n    int\t(* _Nonnull match)(Class _Nonnull, id _Nonnull);  // version 0\n} objc_exception_functions_t;\n\n// get table; version tells how many\nOBJC_EXPORT void\nobjc_exception_get_functions(objc_exception_functions_t * _Nullable table)\n    __OSX_AVAILABLE(10.3) \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\n// set table\nOBJC_EXPORT void\nobjc_exception_set_functions(objc_exception_functions_t * _Nullable table)\n    __OSX_AVAILABLE(10.3) \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\n\n// !__OBJC2__\n#else\n// __OBJC2__\n\ntypedef id _Nonnull (*objc_exception_preprocessor)(id _Nonnull exception);\ntypedef int (*objc_exception_matcher)(Class _Nonnull catch_type,\n                                      id _Nonnull exception);\ntypedef void (*objc_uncaught_exception_handler)(id _Null_unspecified /* _Nonnull */ exception);\ntypedef void (*objc_exception_handler)(id _Nullable unused,\n                                       void * _Nullable context);\n\n/** \n * Throw a runtime exception. This function is inserted by the compiler\n * where \\c @throw would otherwise be.\n * \n * @param exception The exception to be thrown.\n */\nOBJC_EXPORT void\nobjc_exception_throw(id _Nonnull exception)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_exception_rethrow(void)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT id _Nonnull\nobjc_begin_catch(void * _Nonnull exc_buf)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_end_catch(void)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_terminate(void)\n    OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT objc_exception_preprocessor _Nonnull\nobjc_setExceptionPreprocessor(objc_exception_preprocessor _Nonnull fn)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT objc_exception_matcher _Nonnull\nobjc_setExceptionMatcher(objc_exception_matcher _Nonnull fn)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT objc_uncaught_exception_handler _Nonnull\nobjc_setUncaughtExceptionHandler(objc_uncaught_exception_handler _Nonnull fn)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n// Not for iOS.\nOBJC_EXPORT uintptr_t\nobjc_addExceptionHandler(objc_exception_handler _Nonnull fn,\n                         void * _Nullable context)\n    __OSX_AVAILABLE(10.5) \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\nOBJC_EXPORT void\nobjc_removeExceptionHandler(uintptr_t token)\n    __OSX_AVAILABLE(10.5) \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\n// __OBJC2__\n#endif\n\n#endif  // __OBJC_EXCEPTION_H_\n\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-exception.mm",
    "content": "/*\n * Copyright (c) 2002-2007 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#if !__OBJC2__\n\n/***********************************************************************\n* 32-bit implementation\n**********************************************************************/\n\n#include \"objc-private.h\"\n#include <stdlib.h>\n#include <setjmp.h>\n#include <execinfo.h>\n\n#include \"objc-exception.h\"\n\nstatic objc_exception_functions_t xtab;\n\n// forward declaration\nstatic void set_default_handlers();\n\n\n/*\n * Exported functions\n */\n\n// get table; version tells how many\nvoid objc_exception_get_functions(objc_exception_functions_t *table) {\n    // only version 0 supported at this point\n    if (table && table->version == 0)\n        *table = xtab;\n}\n\n// set table\nvoid objc_exception_set_functions(objc_exception_functions_t *table) {\n    // only version 0 supported at this point\n    if (table && table->version == 0)\n        xtab = *table;\n}\n\n/*\n * The following functions are\n * synthesized by the compiler upon encountering language constructs\n */\n \nvoid objc_exception_throw(id exception) {\n    if (!xtab.throw_exc) {\n        set_default_handlers();\n    }\n    \n    if (PrintExceptionThrow) {\n        _objc_inform(\"EXCEPTIONS: throwing %p (%s)\", \n                     (void*)exception, object_getClassName(exception));\n        void* callstack[500];\n        int frameCount = backtrace(callstack, 500);\n        backtrace_symbols_fd(callstack, frameCount, fileno(stderr));\n    }\n\n    OBJC_RUNTIME_OBJC_EXCEPTION_THROW(exception);  // dtrace probe to log throw activity.\n    xtab.throw_exc(exception);\n    _objc_fatal(\"objc_exception_throw failed\");\n}\n\nvoid objc_exception_try_enter(void *localExceptionData) {\n    if (!xtab.throw_exc) {\n        set_default_handlers();\n    }\n    xtab.try_enter(localExceptionData);\n}\n\n\nvoid objc_exception_try_exit(void *localExceptionData) {\n    if (!xtab.throw_exc) {\n        set_default_handlers();\n    }\n    xtab.try_exit(localExceptionData);\n}\n\n\nid objc_exception_extract(void *localExceptionData) {\n    if (!xtab.throw_exc) {\n        set_default_handlers();\n    }\n    return xtab.extract(localExceptionData);\n}\n\n\nint objc_exception_match(Class exceptionClass, id exception) {\n    if (!xtab.throw_exc) {\n        set_default_handlers();\n    }\n    return xtab.match(exceptionClass, exception);\n}\n\n\n// quick and dirty exception handling code\n// default implementation - mostly a toy for use outside/before Foundation\n// provides its implementation\n// Perhaps the default implementation should just complain loudly and quit\n\n\nextern void _objc_inform(const char *fmt, ...);\n\ntypedef struct { jmp_buf buf; void *pointers[4]; } LocalData_t;\n\ntypedef struct _threadChain {\n    LocalData_t *topHandler;\n    objc_thread_t perThreadID;\n    struct _threadChain *next;\n}\n    ThreadChainLink_t;\n\nstatic ThreadChainLink_t ThreadChainLink;\n\nstatic ThreadChainLink_t *getChainLink() {\n    // follow links until thread_self() found (someday) XXX\n    objc_thread_t self = thread_self();\n    ThreadChainLink_t *walker = &ThreadChainLink;\n    while (walker->perThreadID != self) {\n        if (walker->next != nil) {\n            walker = walker->next;\n            continue;\n        }\n        // create a new one\n        // XXX not thread safe (!)\n        // XXX Also, we don't register to deallocate on thread death\n        walker->next = (ThreadChainLink_t *)malloc(sizeof(ThreadChainLink_t));\n        walker = walker->next;\n        walker->next = nil;\n        walker->topHandler = nil;\n        walker->perThreadID = self;\n    }\n    return walker;\n}\n\nstatic void default_try_enter(void *localExceptionData) {\n    LocalData_t *data = (LocalData_t *)localExceptionData;\n    ThreadChainLink_t *chainLink = getChainLink();\n    data->pointers[1] = chainLink->topHandler;\n    chainLink->topHandler = data;\n    if (PrintExceptions) _objc_inform(\"EXCEPTIONS: entered try block %p\\n\", chainLink->topHandler);\n}\n\nstatic void default_throw(id value) {\n    ThreadChainLink_t *chainLink = getChainLink();\n    LocalData_t *led;\n    if (value == nil) {\n        if (PrintExceptions) _objc_inform(\"EXCEPTIONS: objc_exception_throw with nil value\\n\");\n        return;\n    }\n    if (chainLink == nil) {\n        if (PrintExceptions) _objc_inform(\"EXCEPTIONS: No handler in place!\\n\");\n        return;\n    }\n    if (PrintExceptions) _objc_inform(\"EXCEPTIONS: exception thrown, going to handler block %p\\n\", chainLink->topHandler);\n    led = chainLink->topHandler;\n    chainLink->topHandler = (LocalData_t *)\n        led->pointers[1];\t// pop top handler\n    led->pointers[0] = value;\t\t\t// store exception that is thrown\n#if TARGET_OS_WIN32\n    longjmp(led->buf, 1);\n#else\n    _longjmp(led->buf, 1);\n#endif\n}\n    \nstatic void default_try_exit(void *led) {\n    ThreadChainLink_t *chainLink = getChainLink();\n    if (!chainLink || led != chainLink->topHandler) {\n        if (PrintExceptions) _objc_inform(\"EXCEPTIONS: *** mismatched try block exit handlers\\n\");\n        return;\n    }\n    if (PrintExceptions) _objc_inform(\"EXCEPTIONS: removing try block handler %p\\n\", chainLink->topHandler);\n    chainLink->topHandler = (LocalData_t *)\n        chainLink->topHandler->pointers[1];\t// pop top handler\n}\n\nstatic id default_extract(void *localExceptionData) {\n    LocalData_t *led = (LocalData_t *)localExceptionData;\n    return (id)led->pointers[0];\n}\n\nstatic int default_match(Class exceptionClass, id exception) {\n    //return [exception isKindOfClass:exceptionClass];\n    Class cls;\n    for (cls = exception->getIsa(); nil != cls; cls = cls->superclass) \n        if (cls == exceptionClass) return 1;\n    return 0;\n}\n\nstatic void set_default_handlers() {\n    objc_exception_functions_t default_functions = {\n        0, default_throw, default_try_enter, default_try_exit, default_extract, default_match };\n\n    // should this always print?\n    if (PrintExceptions) _objc_inform(\"EXCEPTIONS: *** Setting default (non-Foundation) exception mechanism\\n\");\n    objc_exception_set_functions(&default_functions);\n}\n\n\nvoid exception_init(void)\n{\n    // nothing to do\n}\n\nvoid _destroyAltHandlerList(struct alt_handler_list *list)\n{\n    // nothing to do\n}\n\n\n// !__OBJC2__\n#else\n// __OBJC2__\n\n/***********************************************************************\n* 64-bit implementation.\n**********************************************************************/\n\n#include \"objc-private.h\"\n#include <objc/objc-abi.h>\n#include <objc/objc-exception.h>\n#include <objc/NSObject.h>\n#include <execinfo.h>\n\n// unwind library types and functions\n// Mostly adapted from Itanium C++ ABI: Exception Handling\n//   http://www.codesourcery.com/cxx-abi/abi-eh.html\n\nstruct _Unwind_Exception;\nstruct _Unwind_Context;\n\ntypedef int _Unwind_Action;\nenum : _Unwind_Action {\n    _UA_SEARCH_PHASE = 1, \n    _UA_CLEANUP_PHASE = 2, \n    _UA_HANDLER_FRAME = 4, \n    _UA_FORCE_UNWIND = 8\n};\n\ntypedef int _Unwind_Reason_Code;\nenum : _Unwind_Reason_Code {\n    _URC_NO_REASON = 0,\n    _URC_FOREIGN_EXCEPTION_CAUGHT = 1,\n    _URC_FATAL_PHASE2_ERROR = 2,\n    _URC_FATAL_PHASE1_ERROR = 3,\n    _URC_NORMAL_STOP = 4,\n    _URC_END_OF_STACK = 5,\n    _URC_HANDLER_FOUND = 6,\n    _URC_INSTALL_CONTEXT = 7,\n    _URC_CONTINUE_UNWIND = 8\n};\n\nstruct dwarf_eh_bases\n{\n    uintptr_t tbase;\n    uintptr_t dbase;\n    uintptr_t func;\n};\n\nOBJC_EXTERN uintptr_t _Unwind_GetIP (struct _Unwind_Context *);\nOBJC_EXTERN uintptr_t _Unwind_GetCFA (struct _Unwind_Context *);\nOBJC_EXTERN uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context *);\n\n\n// C++ runtime types and functions\n// copied from cxxabi.h\n\nOBJC_EXTERN void *__cxa_allocate_exception(size_t thrown_size);\nOBJC_EXTERN void __cxa_throw(void *exc, void *typeinfo, void (*destructor)(void *)) __attribute__((noreturn));\nOBJC_EXTERN void *__cxa_begin_catch(void *exc);\nOBJC_EXTERN void __cxa_end_catch(void);\nOBJC_EXTERN void __cxa_rethrow(void);\nOBJC_EXTERN void *__cxa_current_exception_type(void);\n\n#if SUPPORT_ZEROCOST_EXCEPTIONS\n#   define CXX_PERSONALITY __gxx_personality_v0\n#else\n#   define CXX_PERSONALITY __gxx_personality_sj0\n#endif\n\nOBJC_EXTERN _Unwind_Reason_Code \nCXX_PERSONALITY(int version,\n                _Unwind_Action actions,\n                uint64_t exceptionClass,\n                struct _Unwind_Exception *exceptionObject,\n                struct _Unwind_Context *context);\n\n\n// objc's internal exception types and data\n\nstruct objc_typeinfo {\n    // Position of vtable and name fields must match C++ typeinfo object\n    const void ** __ptrauth_cxx_vtable_pointer vtable;  // objc_ehtype_vtable+2\n    const char *name;     // c++ typeinfo string\n\n    Class cls_unremapped;\n};\n\nstruct objc_exception {\n    id obj;\n    struct objc_typeinfo tinfo;\n};\n\n\nextern \"C\" void _objc_exception_noop(void) { } \nextern \"C\" bool _objc_exception_false(void) { return 0; } \n// extern \"C\" bool _objc_exception_true(void) { return 1; } \nextern \"C\" void _objc_exception_abort1(void) { \n    _objc_fatal(\"unexpected call into objc exception typeinfo vtable %d\", 1); \n} \nextern \"C\" void _objc_exception_abort2(void) { \n    _objc_fatal(\"unexpected call into objc exception typeinfo vtable %d\", 2); \n} \nextern \"C\" void _objc_exception_abort3(void) { \n    _objc_fatal(\"unexpected call into objc exception typeinfo vtable %d\", 3); \n} \nextern \"C\" void _objc_exception_abort4(void) { \n    _objc_fatal(\"unexpected call into objc exception typeinfo vtable %d\", 4); \n} \n\nextern \"C\" bool _objc_exception_do_catch(struct objc_typeinfo *catch_tinfo, \n                                         struct objc_typeinfo *throw_tinfo, \n                                         void **throw_obj_p, \n                                         unsigned outer);\n\n// C++ pointers to vtables are signed with no extra data.\n// C++ vtable entries are signed with a number derived from the function name.\n// For this fake vtable, we hardcode number as deciphered from the\n// assembly output during libc++abi's build.\n#if __has_feature(ptrauth_calls)\n#   define VTABLE_PTR_AUTH      \"@AUTH(da, 0)\"\n#   define VTABLE_ENTRY_AUTH(x) \"@AUTH(ia,\" #x \",addr)\"\n#else\n#   define VTABLE_PTR_AUTH      \"\"\n#   define VTABLE_ENTRY_AUTH(x) \"\"\n#endif\n\n#if __LP64__\n#   define PTR \".quad \"\n#   define TWOPTRSIZE \"16\"\n#else\n#   define PTR \".long \"\n#   define TWOPTRSIZE \"8\"\n#endif\n\n// Hand-built vtable for objc exception typeinfo.\n// \"OLD\" is GNU libcpp, \"NEW\" is libc++abi.\n\nasm(\n    \"\\n .cstring\"\n    \"\\n l_.id_str: .asciz \\\"id\\\"\"\n\n    \"\\n .section __DATA,__const\"\n    \"\\n .globl _OBJC_EHTYPE_id\"\n    \"\\n .globl _objc_ehtype_vtable\"\n    \"\\n .p2align 4\"\n\n    \"\\n _OBJC_EHTYPE_id:\"\n    \"\\n  \" PTR \"(_objc_ehtype_vtable+\" TWOPTRSIZE \") \"      VTABLE_PTR_AUTH\n    \"\\n  \" PTR \"l_.id_str\"\n    \"\\n  \" PTR \"0\"\n\n    \"\\n _objc_ehtype_vtable:\"\n    \"\\n  \" PTR \"0\"\n    // typeinfo's typeinfo - fixme hack\n    \"\\n  \" PTR \"_OBJC_EHTYPE_id\"\n    // destructor and in-place destructor\n    \"\\n  \" PTR \"__objc_exception_noop\"      VTABLE_ENTRY_AUTH(52634)\n    \"\\n  \" PTR \"__objc_exception_noop\"      VTABLE_ENTRY_AUTH(10344)\n    // OLD __is_pointer_p\n    \"\\n  \" PTR \"__objc_exception_noop\"      VTABLE_ENTRY_AUTH(6889)\n    // OLD __is_function_p\n    \"\\n  \" PTR \"__objc_exception_noop\"      VTABLE_ENTRY_AUTH(23080)\n    // OLD __do_catch,  NEW can_catch\n    \"\\n  \" PTR \"__objc_exception_do_catch\"  VTABLE_ENTRY_AUTH(27434)\n    // OLD __do_upcast, NEW search_above_dst\n    \"\\n  \" PTR \"__objc_exception_false\"     VTABLE_ENTRY_AUTH(48481)\n    //                  NEW search_below_dst\n    \"\\n  \" PTR \"__objc_exception_false\"     VTABLE_ENTRY_AUTH(41165)\n    // NEW has_unambiguous_public_base (fixme need this?)\n    \"\\n  \" PTR \"__objc_exception_abort1\"    VTABLE_ENTRY_AUTH(14357)\n    // paranoia: die if libcxxabi adds anything else\n    \"\\n  \" PTR \"__objc_exception_abort2\"\n    \"\\n  \" PTR \"__objc_exception_abort3\"\n    \"\\n  \" PTR \"__objc_exception_abort4\"\n    );\n\n\n\n/***********************************************************************\n* Foundation customization\n**********************************************************************/\n\n/***********************************************************************\n* _objc_default_exception_preprocessor\n* Default exception preprocessor. Expected to be overridden by Foundation.\n**********************************************************************/\nstatic id _objc_default_exception_preprocessor(id exception)\n{\n    return exception;\n}\nstatic objc_exception_preprocessor exception_preprocessor = _objc_default_exception_preprocessor;\n\n\n/***********************************************************************\n* _objc_default_exception_matcher\n* Default exception matcher. Expected to be overridden by Foundation.\n**********************************************************************/\nstatic int _objc_default_exception_matcher(Class catch_cls, id exception)\n{\n    Class cls;\n    for (cls = exception->getIsa();\n         cls != nil; \n         cls = cls->superclass)\n    {\n        if (cls == catch_cls) return 1;\n    }\n\n    return 0;\n}\nstatic objc_exception_matcher exception_matcher = _objc_default_exception_matcher;\n\n\n/***********************************************************************\n* _objc_default_uncaught_exception_handler\n* Default uncaught exception handler. Expected to be overridden by Foundation.\n**********************************************************************/\nstatic void _objc_default_uncaught_exception_handler(id exception)\n{\n}\nstatic objc_uncaught_exception_handler uncaught_handler = _objc_default_uncaught_exception_handler;\n\n\n/***********************************************************************\n* objc_setExceptionPreprocessor\n* Set a handler for preprocessing Objective-C exceptions. \n* Returns the previous handler. \n**********************************************************************/\nobjc_exception_preprocessor\nobjc_setExceptionPreprocessor(objc_exception_preprocessor fn)\n{\n    objc_exception_preprocessor result = exception_preprocessor;\n    exception_preprocessor = fn;\n    return result;\n}\n\n\n/***********************************************************************\n* objc_setExceptionMatcher\n* Set a handler for matching Objective-C exceptions. \n* Returns the previous handler. \n**********************************************************************/\nobjc_exception_matcher\nobjc_setExceptionMatcher(objc_exception_matcher fn)\n{\n    objc_exception_matcher result = exception_matcher;\n    exception_matcher = fn;\n    return result;\n}\n\n\n/***********************************************************************\n* objc_setUncaughtExceptionHandler\n* Set a handler for uncaught Objective-C exceptions. \n* Returns the previous handler. \n**********************************************************************/\nobjc_uncaught_exception_handler \nobjc_setUncaughtExceptionHandler(objc_uncaught_exception_handler fn)\n{\n    objc_uncaught_exception_handler result = uncaught_handler;\n    uncaught_handler = fn;\n    return result;\n}\n\n\n/***********************************************************************\n* Exception personality\n**********************************************************************/\n\nstatic void call_alt_handlers(struct _Unwind_Context *ctx);\n\n_Unwind_Reason_Code \n__objc_personality_v0(int version,\n                      _Unwind_Action actions,\n                      uint64_t exceptionClass,\n                      struct _Unwind_Exception *exceptionObject,\n                      struct _Unwind_Context *context)\n{\n    bool unwinding = ((actions & _UA_CLEANUP_PHASE)  ||  \n                      (actions & _UA_FORCE_UNWIND));\n\n    if (PrintExceptions) {\n        _objc_inform(\"EXCEPTIONS: %s through frame [ip=%p sp=%p] \"\n                     \"for exception %p\", \n                     unwinding ? \"unwinding\" : \"searching\", \n                     (void*)(_Unwind_GetIP(context)-1),\n                     (void*)_Unwind_GetCFA(context), exceptionObject);\n    }\n\n    // If we're executing the unwind, call this frame's alt handlers, if any.\n    if (unwinding) {\n        call_alt_handlers(context);\n    }\n\n    // Let C++ handle the unwind itself.\n    return CXX_PERSONALITY(version, actions, exceptionClass, \n                           exceptionObject, context);\n}\n\n\n/***********************************************************************\n* Compiler ABI\n**********************************************************************/\n\nstatic void _objc_exception_destructor(void *exc_gen) \n{\n    // Release the retain from objc_exception_throw().\n\n    struct objc_exception *exc = (struct objc_exception *)exc_gen;\n    id obj = exc->obj;\n\n    if (PrintExceptions) {\n        _objc_inform(\"EXCEPTIONS: releasing completed exception %p (object %p, a %s)\", \n                     exc, obj, object_getClassName(obj));\n    }\n\n    [obj release];\n}\n\n\nvoid objc_exception_throw(id obj)\n{\n    struct objc_exception *exc = (struct objc_exception *)\n        __cxa_allocate_exception(sizeof(struct objc_exception));\n\n    obj = (*exception_preprocessor)(obj);\n\n    // Retain the exception object during unwinding\n    // because otherwise an autorelease pool pop can cause a crash\n    [obj retain];\n\n    exc->obj = obj;\n    exc->tinfo.vtable = objc_ehtype_vtable+2;\n    exc->tinfo.name = object_getClassName(obj);\n    exc->tinfo.cls_unremapped = obj ? obj->getIsa() : Nil;\n\n    if (PrintExceptions) {\n        _objc_inform(\"EXCEPTIONS: throwing %p (object %p, a %s)\", \n                     exc, (void*)obj, object_getClassName(obj));\n    }\n\n    if (PrintExceptionThrow) {\n        if (!PrintExceptions)\n            _objc_inform(\"EXCEPTIONS: throwing %p (object %p, a %s)\", \n                         exc, (void*)obj, object_getClassName(obj));\n        void* callstack[500];\n        int frameCount = backtrace(callstack, 500);\n        backtrace_symbols_fd(callstack, frameCount, fileno(stderr));\n    }\n    \n    OBJC_RUNTIME_OBJC_EXCEPTION_THROW(obj);  // dtrace probe to log throw activity\n    __cxa_throw(exc, &exc->tinfo, &_objc_exception_destructor);\n    __builtin_trap();\n}\n\n\nvoid objc_exception_rethrow(void)\n{\n    // exception_preprocessor doesn't get another bite of the apple\n    if (PrintExceptions) {\n        _objc_inform(\"EXCEPTIONS: rethrowing current exception\");\n    }\n    \n    OBJC_RUNTIME_OBJC_EXCEPTION_RETHROW(); // dtrace probe to log throw activity.\n    __cxa_rethrow();\n    __builtin_trap();\n}\n\n\nid objc_begin_catch(void *exc_gen)\n{\n    if (PrintExceptions) {\n        _objc_inform(\"EXCEPTIONS: handling exception %p at %p\", \n                     exc_gen, __builtin_return_address(0));\n    }\n    // NOT actually an id in the catch(...) case!\n    return (id)__cxa_begin_catch(exc_gen);\n}\n\n\nvoid objc_end_catch(void)\n{\n    if (PrintExceptions) {\n        _objc_inform(\"EXCEPTIONS: finishing handler\");\n    }\n    __cxa_end_catch();\n}\n\n\n// `outer` is not passed by the new libcxxabi\nbool _objc_exception_do_catch(struct objc_typeinfo *catch_tinfo, \n                              struct objc_typeinfo *throw_tinfo, \n                              void **throw_obj_p, \n                              unsigned outer UNAVAILABLE_ATTRIBUTE)\n{\n    id exception;\n\n    if (throw_tinfo->vtable != objc_ehtype_vtable+2) {\n        // Only objc types can be caught here.\n        if (PrintExceptions) _objc_inform(\"EXCEPTIONS: skipping catch(?)\");\n        return false;\n    }\n\n    // Adjust exception pointer.\n    // Old libcppabi: we lied about __is_pointer_p() so we have to do it here\n    // New libcxxabi: we have to do it here regardless\n    *throw_obj_p = **(void***)throw_obj_p;\n\n    // `catch (id)` always catches objc types.\n    if (catch_tinfo == &OBJC_EHTYPE_id) {\n        if (PrintExceptions) _objc_inform(\"EXCEPTIONS: catch(id)\");\n        return true;\n    }\n\n    exception = *(id *)throw_obj_p;\n\n    Class handler_cls = _class_remap(catch_tinfo->cls_unremapped);\n    if (!handler_cls) {\n        // catch handler's class is weak-linked and missing. Not a match.\n    }\n    else if ((*exception_matcher)(handler_cls, exception)) {\n        if (PrintExceptions) _objc_inform(\"EXCEPTIONS: catch(%s)\", \n                                          handler_cls->nameForLogging());\n        return true;\n    }\n\n    if (PrintExceptions) _objc_inform(\"EXCEPTIONS: skipping catch(%s)\", \n                                      handler_cls->nameForLogging());\n\n    return false;\n}\n\n\n/***********************************************************************\n* _objc_terminate\n* Custom std::terminate handler.\n*\n* The uncaught exception callback is implemented as a std::terminate handler. \n* 1. Check if there's an active exception\n* 2. If so, check if it's an Objective-C exception\n* 3. If so, call our registered callback with the object.\n* 4. Finally, call the previous terminate handler.\n**********************************************************************/\nstatic void (*old_terminate)(void) = nil;\nstatic void _objc_terminate(void)\n{\n    if (PrintExceptions) {\n        _objc_inform(\"EXCEPTIONS: terminating\");\n    }\n\n    if (! __cxa_current_exception_type()) {\n        // No current exception.\n        (*old_terminate)();\n    }\n    else {\n        // There is a current exception. Check if it's an objc exception.\n        @try {\n            __cxa_rethrow();\n        } @catch (id e) {\n            // It's an objc object. Call Foundation's handler, if any.\n            (*uncaught_handler)((id)e);\n            (*old_terminate)();\n        } @catch (...) {\n            // It's not an objc object. Continue to C++ terminate.\n            (*old_terminate)();\n        }\n    }\n}\n\n\n/***********************************************************************\n* objc_terminate\n* Calls std::terminate for clients who don't link to C++ themselves.\n* Called by the compiler if an exception is thrown \n* from a context where exceptions may not be thrown. \n**********************************************************************/\nvoid objc_terminate(void)\n{\n    std::terminate();\n}\n\n\n/***********************************************************************\n* alt handler support - zerocost implementation only\n**********************************************************************/\n\n#if !SUPPORT_ALT_HANDLERS\n\nvoid _destroyAltHandlerList(struct alt_handler_list *list)\n{\n}\n\nstatic void call_alt_handlers(struct _Unwind_Context *ctx)\n{\n    // unsupported in sjlj environments\n}\n\n#else\n\n#include <libunwind.h>\n#include <execinfo.h>\n#include <dispatch/dispatch.h>\n\n// Dwarf eh data encodings\n#define DW_EH_PE_omit      0xff  // no data follows\n\n#define DW_EH_PE_absptr    0x00\n#define DW_EH_PE_uleb128   0x01\n#define DW_EH_PE_udata2    0x02\n#define DW_EH_PE_udata4    0x03\n#define DW_EH_PE_udata8    0x04\n#define DW_EH_PE_sleb128   0x09\n#define DW_EH_PE_sdata2    0x0A\n#define DW_EH_PE_sdata4    0x0B\n#define DW_EH_PE_sdata8    0x0C\n\n#define DW_EH_PE_pcrel     0x10\n#define DW_EH_PE_textrel   0x20\n#define DW_EH_PE_datarel   0x30\n#define DW_EH_PE_funcrel   0x40\n#define DW_EH_PE_aligned   0x50  // fixme\n\n#define DW_EH_PE_indirect  0x80  // gcc extension\n\n\n/***********************************************************************\n* read_uleb\n* Read a LEB-encoded unsigned integer from the address stored in *pp.\n* Increments *pp past the bytes read.\n* Adapted from DWARF Debugging Information Format 1.1, appendix 4\n**********************************************************************/\nstatic uintptr_t read_uleb(uintptr_t *pp)\n{\n    uintptr_t result = 0;\n    uintptr_t shift = 0;\n    unsigned char byte;\n    do {\n        byte = *(const unsigned char *)(*pp)++;\n        result |= (byte & 0x7f) << shift;\n        shift += 7;\n    } while (byte & 0x80);\n    return result;\n}\n\n\n/***********************************************************************\n* read_sleb\n* Read a LEB-encoded signed integer from the address stored in *pp.\n* Increments *pp past the bytes read.\n* Adapted from DWARF Debugging Information Format 1.1, appendix 4\n**********************************************************************/\nstatic intptr_t read_sleb(uintptr_t *pp)\n{\n    uintptr_t result = 0;\n    uintptr_t shift = 0;\n    unsigned char byte;\n    do {\n        byte = *(const unsigned char *)(*pp)++;\n        result |= (byte & 0x7f) << shift;\n        shift += 7;\n    } while (byte & 0x80);\n    if ((shift < 8*sizeof(intptr_t))  &&  (byte & 0x40)) {\n        result |= ((intptr_t)-1) << shift;\n    }\n    return result;\n}\n\n\n/***********************************************************************\n* read_address\n* Reads an encoded address from the address stored in *pp.\n* Increments *pp past the bytes read.\n* The data is interpreted according to the given dwarf encoding \n* and base addresses.\n**********************************************************************/\nstatic uintptr_t read_address(uintptr_t *pp, \n                              const struct dwarf_eh_bases *bases, \n                              unsigned char encoding)\n{\n    uintptr_t result = 0;\n    uintptr_t oldp = *pp;\n\n    // fixme need DW_EH_PE_aligned?\n\n#define READ(type) \\\n    result = *(type *)(*pp); \\\n    *pp += sizeof(type);\n\n    if (encoding == DW_EH_PE_omit) return 0;\n\n    switch (encoding & 0x0f) {\n    case DW_EH_PE_absptr:\n        READ(uintptr_t);\n        break;\n    case DW_EH_PE_uleb128:\n        result = read_uleb(pp);\n        break;\n    case DW_EH_PE_udata2:\n        READ(uint16_t);\n        break;\n    case DW_EH_PE_udata4:\n        READ(uint32_t);\n        break;\n#if __LP64__\n    case DW_EH_PE_udata8:\n        READ(uint64_t);\n        break;\n#endif\n    case DW_EH_PE_sleb128:\n        result = read_sleb(pp);\n        break;\n    case DW_EH_PE_sdata2:\n        READ(int16_t);\n        break;\n    case DW_EH_PE_sdata4:\n        READ(int32_t);\n        break;\n#if __LP64__\n    case DW_EH_PE_sdata8:\n        READ(int64_t);\n        break;\n#endif\n    default:\n        _objc_inform(\"unknown DWARF EH encoding 0x%x at %p\", \n                     encoding, (void *)*pp);\n        break;\n    }\n\n#undef READ\n\n    if (result) {\n        switch (encoding & 0x70) {\n        case DW_EH_PE_pcrel:\n            // fixme correct?\n            result += (uintptr_t)oldp;\n            break;\n        case DW_EH_PE_textrel:\n            result += bases->tbase;\n            break;\n        case DW_EH_PE_datarel:\n            result += bases->dbase;\n            break;\n        case DW_EH_PE_funcrel:\n            result += bases->func;\n            break;\n        case DW_EH_PE_aligned:\n            _objc_inform(\"unknown DWARF EH encoding 0x%x at %p\", \n                         encoding, (void *)*pp);\n            break;\n        default:\n            // no adjustment\n            break;\n        }\n\n        if (encoding & DW_EH_PE_indirect) {\n            result = *(uintptr_t *)result;\n        }\n    }\n\n    return (uintptr_t)result;\n}\n\n\nstruct frame_ips {\n    uintptr_t start;\n    uintptr_t end;\n};\nstruct frame_range {\n    uintptr_t ip_start;\n    uintptr_t ip_end;\n    uintptr_t cfa;\n    // precise ranges within ip_start..ip_end; nil or {0,0} terminated\n    frame_ips *ips;\n};\n\n\nstatic bool isObjCExceptionCatcher(uintptr_t lsda, uintptr_t ip, \n                                   const struct dwarf_eh_bases* bases,\n                                   struct frame_range *frame)\n{\n    unsigned char LPStart_enc = *(const unsigned char *)lsda++;    \n\n    if (LPStart_enc != DW_EH_PE_omit) {\n        read_address(&lsda, bases, LPStart_enc); // LPStart\n    }\n\n    unsigned char TType_enc = *(const unsigned char *)lsda++;\n    if (TType_enc != DW_EH_PE_omit) {\n        read_uleb(&lsda);  // TType\n    }\n\n    unsigned char call_site_enc = *(const unsigned char *)lsda++;\n    uintptr_t length = read_uleb(&lsda);\n    uintptr_t call_site_table = lsda;\n    uintptr_t call_site_table_end = call_site_table + length;\n    uintptr_t action_record_table = call_site_table_end;\n\n    uintptr_t action_record = 0;\n    uintptr_t p = call_site_table;\n\n    uintptr_t try_start;\n    uintptr_t try_end;\n    uintptr_t try_landing_pad;\n\n    while (p < call_site_table_end) {\n        uintptr_t start   = read_address(&p, bases, call_site_enc)+bases->func;\n        uintptr_t len     = read_address(&p, bases, call_site_enc);\n        uintptr_t pad     = read_address(&p, bases, call_site_enc);\n        uintptr_t action  = read_uleb(&p);\n\n        if (ip < start) {\n            // no more source ranges\n            return false;\n        } \n        else if (ip < start + len) {\n            // found the range\n            if (!pad) return false;  // ...but it has no landing pad\n            // found the landing pad\n            action_record = action ? action_record_table + action - 1 : 0;\n            try_start = start;\n            try_end = start + len;\n            try_landing_pad = pad;\n            break;\n        }        \n    }\n    \n    if (!action_record) return false;  // no catch handlers\n\n    // has handlers, destructors, and/or throws specifications\n    // Use this frame if it has any handlers\n    bool has_handler = false;\n    p = action_record;\n    intptr_t offset;\n    do {\n        intptr_t filter = read_sleb(&p);\n        uintptr_t temp = p;\n        offset = read_sleb(&temp);\n        p += offset;\n        \n        if (filter < 0) {\n            // throws specification - ignore\n        } else if (filter == 0) {\n            // destructor - ignore\n        } else /* filter >= 0 */ {\n            // catch handler - use this frame\n            has_handler = true;\n            break;\n        }\n    } while (offset);\n\n    if (!has_handler) return false;\n    \n    // Count the number of source ranges with the same landing pad as our match\n    unsigned int range_count = 0;\n    p = call_site_table;\n    while (p < call_site_table_end) {\n                /*start*/  read_address(&p, bases, call_site_enc)/*+bases->func*/;\n                /*len*/    read_address(&p, bases, call_site_enc);\n        uintptr_t pad    = read_address(&p, bases, call_site_enc);\n                /*action*/ read_uleb(&p);\n        \n        if (pad == try_landing_pad) {\n            range_count++;\n        }\n    }\n\n    if (range_count == 1) {\n        // No other source ranges with the same landing pad. We're done here.\n        frame->ips = nil;\n    }\n    else {\n        // Record all ranges with the same landing pad as our match.\n        frame->ips = (frame_ips *)\n            malloc((range_count + 1) * sizeof(frame->ips[0]));\n        unsigned int r = 0;\n        p = call_site_table;\n        while (p < call_site_table_end) {\n            uintptr_t start  = read_address(&p, bases, call_site_enc)+bases->func;\n            uintptr_t len    = read_address(&p, bases, call_site_enc);\n            uintptr_t pad    = read_address(&p, bases, call_site_enc);\n                    /*action*/ read_uleb(&p);\n            \n            if (pad == try_landing_pad) {\n                if (start < try_start) try_start = start;\n                if (start+len > try_end) try_end = start+len;\n                frame->ips[r].start = start;\n                frame->ips[r].end = start+len;\n                r++;\n            }\n        }\n\n        frame->ips[r].start = 0;\n        frame->ips[r].end = 0;\n    }\n\n    frame->ip_start = try_start;\n    frame->ip_end = try_end;\n\n    return true;\n}\n\n\nstatic struct frame_range findHandler(void)\n{\n    // walk stack looking for frame with objc catch handler\n    unw_context_t    uc;\n    unw_cursor_t    cursor; \n    unw_proc_info_t    info;\n    unw_getcontext(&uc);\n    unw_init_local(&cursor, &uc);\n    while ( (unw_step(&cursor) > 0) && (unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS) ) {\n        // must use objc personality handler\n        if ( info.handler != (uintptr_t)__objc_personality_v0 )\n            continue;\n        // must have landing pad\n        if ( info.lsda == 0 )\n            continue;\n        // must have landing pad that catches objc exceptions\n        struct dwarf_eh_bases bases;\n        bases.tbase = 0;  // from unwind-dw2-fde-darwin.c:examine_objects()\n        bases.dbase = 0;  // from unwind-dw2-fde-darwin.c:examine_objects()\n        bases.func = info.start_ip;\n        unw_word_t ip;\n        unw_get_reg(&cursor, UNW_REG_IP, &ip);\n        ip -= 1;\n        struct frame_range try_range = {0, 0, 0, 0};\n        if ( isObjCExceptionCatcher(info.lsda, ip, &bases, &try_range) ) {\n            unw_word_t cfa;\n            unw_get_reg(&cursor, UNW_REG_SP, &cfa);\n            try_range.cfa = cfa;\n            return try_range;\n        }\n    }\n\n    return (struct frame_range){0, 0, 0, 0};\n}\n\n\n// This data structure assumes the number of \n// active alt handlers per frame is small.\n\n// for OBJC_DEBUG_ALT_HANDLERS, record the call to objc_addExceptionHandler.\n#define BACKTRACE_COUNT 46\n#define THREADNAME_COUNT 64\nstruct alt_handler_debug {\n    uintptr_t token;\n    int backtraceSize;\n    void *backtrace[BACKTRACE_COUNT];\n    char thread[THREADNAME_COUNT];\n    char queue[THREADNAME_COUNT];\n};\n\nstruct alt_handler_data {\n    struct frame_range frame;\n    objc_exception_handler fn;\n    void *context;\n    struct alt_handler_debug *debug;\n};\n\nstruct alt_handler_list {\n    unsigned int allocated;\n    unsigned int used;\n    struct alt_handler_data *handlers;\n    struct alt_handler_list *next_DEBUGONLY;\n};\n\nstatic struct alt_handler_list *DebugLists;\nstatic uintptr_t DebugCounter;\n\n__attribute__((noinline, noreturn))\nvoid alt_handler_error(uintptr_t token);\n\nstatic struct alt_handler_list *\nfetch_handler_list(bool create)\n{\n    _objc_pthread_data *data = _objc_fetch_pthread_data(create);\n    if (!data) return nil;\n\n    struct alt_handler_list *list = data->handlerList;\n    if (!list) {\n        if (!create) return nil;\n        list = (struct alt_handler_list *)calloc(1, sizeof(*list));\n        data->handlerList = list;\n\n        if (DebugAltHandlers) {\n            // Save this list so the debug code can find it from other threads\n            mutex_locker_t lock(AltHandlerDebugLock);\n            list->next_DEBUGONLY = DebugLists;\n            DebugLists = list;\n        }\n    }\n\n    return list;\n}\n\n\nvoid _destroyAltHandlerList(struct alt_handler_list *list)\n{\n    if (list) {\n        if (DebugAltHandlers) {\n            // Detach from the list-of-lists.\n            mutex_locker_t lock(AltHandlerDebugLock);\n            struct alt_handler_list **listp = &DebugLists;\n            while (*listp && *listp != list) listp = &(*listp)->next_DEBUGONLY;\n            if (*listp) *listp = (*listp)->next_DEBUGONLY;\n        }\n\n        if (list->handlers) {\n            for (unsigned int i = 0; i < list->allocated; i++) {\n                if (list->handlers[i].frame.ips) {\n                    free(list->handlers[i].frame.ips);\n                }\n            }\n            free(list->handlers);\n        }\n        free(list);\n    }\n}\n\n\nuintptr_t objc_addExceptionHandler(objc_exception_handler fn, void *context)\n{ \n    // Find the closest enclosing frame with objc catch handlers\n    struct frame_range target_frame = findHandler();\n    if (!target_frame.ip_start) {\n        // No suitable enclosing handler found.\n        return 0;\n    }\n\n    // Record this alt handler for the discovered frame.\n    struct alt_handler_list *list = fetch_handler_list(YES);\n    unsigned int i = 0;\n\n    if (list->used == list->allocated) {\n        list->allocated = list->allocated*2 ?: 4;\n        list->handlers = (struct alt_handler_data *)\n            realloc(list->handlers, \n                              list->allocated * sizeof(list->handlers[0]));\n        bzero(&list->handlers[list->used], (list->allocated - list->used) * sizeof(list->handlers[0]));\n        i = list->used;\n    }\n    else {\n        for (i = 0; i < list->allocated; i++) {\n            if (list->handlers[i].frame.ip_start == 0  &&  \n                list->handlers[i].frame.ip_end == 0  &&  \n                list->handlers[i].frame.cfa == 0) \n            {\n                break;\n            }\n        }\n        if (i == list->allocated) {\n            _objc_fatal(\"alt handlers in objc runtime are buggy!\");\n        }\n    }\n\n    struct alt_handler_data *data = &list->handlers[i];\n\n    data->frame = target_frame;\n    data->fn = fn;\n    data->context = context;\n    list->used++;\n\n    uintptr_t token = i+1;\n\n    if (DebugAltHandlers) {\n        // Record backtrace in case this handler is misused later.\n        mutex_locker_t lock(AltHandlerDebugLock);\n\n        token = DebugCounter++;\n        if (token == 0) token = DebugCounter++;\n\n        if (!data->debug) {\n            data->debug = (struct alt_handler_debug *)\n                calloc(sizeof(*data->debug), 1);\n        } else {\n            bzero(data->debug, sizeof(*data->debug));\n        }\n\n        pthread_getname_np(pthread_self(), data->debug->thread, THREADNAME_COUNT);\n        strlcpy(data->debug->queue, \n                dispatch_queue_get_label(dispatch_get_current_queue()), \n                THREADNAME_COUNT);\n        data->debug->backtraceSize = \n            backtrace(data->debug->backtrace, BACKTRACE_COUNT);\n        data->debug->token = token;\n    }\n\n    if (PrintAltHandlers) {\n        _objc_inform(\"ALT HANDLERS: installing alt handler #%lu %p(%p) on \"\n                     \"frame [ip=%p..%p sp=%p]\", (unsigned long)token, \n                     data->fn, data->context, (void *)data->frame.ip_start, \n                     (void *)data->frame.ip_end, (void *)data->frame.cfa);\n        if (data->frame.ips) {\n            unsigned int r = 0;\n            while (1) {\n                uintptr_t start = data->frame.ips[r].start;\n                uintptr_t end = data->frame.ips[r].end;\n                r++;\n                if (start == 0  &&  end == 0) break;\n                _objc_inform(\"ALT HANDLERS:     ip=%p..%p\", \n                             (void*)start, (void*)end);\n            }\n        }\n    }\n\n    if (list->used > 1000) {\n        static int warned = 0;\n        if (!warned) {\n            _objc_inform(\"ALT HANDLERS: *** over 1000 alt handlers installed; \"\n                         \"this is probably a bug\");\n            warned = 1;\n        }\n    }\n\n    return token;\n}\n\n\nvoid objc_removeExceptionHandler(uintptr_t token)\n{\n    if (!token) {\n        // objc_addExceptionHandler failed\n        return;\n    }\n    \n    struct alt_handler_list *list = fetch_handler_list(NO);\n    if (!list  ||  !list->handlers) {\n        // no alt handlers active\n        alt_handler_error(token);\n    }\n\n    uintptr_t i = token-1;\n    \n    if (DebugAltHandlers) {\n        // search for the token instead of using token-1\n        for (i = 0; i < list->allocated; i++) {\n            struct alt_handler_data *data = &list->handlers[i];\n            if (data->debug  &&  data->debug->token == token) break;\n        }\n    }\n    \n    if (i >= list->allocated) {\n        // token out of range\n        alt_handler_error(token);\n    }\n\n    struct alt_handler_data *data = &list->handlers[i];\n\n    if (data->frame.ip_start == 0  &&  data->frame.ip_end == 0  &&  data->frame.cfa == 0) {\n        // token in range, but invalid\n        alt_handler_error(token);\n    }\n\n    if (PrintAltHandlers) {\n        _objc_inform(\"ALT HANDLERS: removing   alt handler #%lu %p(%p) on \"\n                     \"frame [ip=%p..%p sp=%p]\", (unsigned long)token, \n                     data->fn, data->context, (void *)data->frame.ip_start, \n                     (void *)data->frame.ip_end, (void *)data->frame.cfa);\n    }\n\n    if (data->debug) free(data->debug);\n    if (data->frame.ips) free(data->frame.ips);\n    bzero(data, sizeof(*data));\n    list->used--;\n}\n\n\nBREAKPOINT_FUNCTION(\nvoid objc_alt_handler_error(void));\n\n__attribute__((noinline, noreturn))\nvoid alt_handler_error(uintptr_t token)\n{\n    _objc_inform\n        (\"objc_removeExceptionHandler() called with unknown alt handler; \"\n         \"this is probably a bug in multithreaded AppKit use. \"\n         \"Set environment variable OBJC_DEBUG_ALT_HANDLERS=YES \"\n         \"or break in objc_alt_handler_error() to debug.\");\n\n    if (DebugAltHandlers) {\n        AltHandlerDebugLock.lock();\n        \n        // Search other threads' alt handler lists for this handler.\n        struct alt_handler_list *list;\n        for (list = DebugLists; list; list = list->next_DEBUGONLY) {\n            unsigned h;\n            for (h = 0; h < list->allocated; h++) {\n                struct alt_handler_data *data = &list->handlers[h];\n                if (data->debug  &&  data->debug->token == token) {\n                    // found it\n                    int i;\n                    \n                    // Build a string from the recorded backtrace\n                    char *symbolString;\n                    char **symbols = \n                        backtrace_symbols(data->debug->backtrace, \n                                          data->debug->backtraceSize);\n                    size_t len = 1;\n                    for (i = 0; i < data->debug->backtraceSize; i++){\n                        len += 4 + strlen(symbols[i]) + 1;\n                    }\n                    symbolString = (char *)calloc(len, 1);\n                    for (i = 0; i < data->debug->backtraceSize; i++){\n                        strcat(symbolString, \"    \");\n                        strcat(symbolString, symbols[i]);\n                        strcat(symbolString, \"\\n\");\n                    }\n                    \n                    free(symbols);\n                    \n                    _objc_inform_now_and_on_crash\n                        (\"The matching objc_addExceptionHandler() was called \"\n                         \"by:\\nThread '%s': Dispatch queue: '%s': \\n%s\", \n                         data->debug->thread, data->debug->queue, symbolString);\n\n                    goto done;\n                }\n            }\n        }\n    done:   \n        AltHandlerDebugLock.unlock();\n    }\n\n\n    objc_alt_handler_error();\n    \n    _objc_fatal\n        (\"objc_removeExceptionHandler() called with unknown alt handler; \"\n         \"this is probably a bug in multithreaded AppKit use. \");\n}\n\n// called in order registered, to match 32-bit _NSAddAltHandler2\n// fixme reverse registration order matches c++ destructors better\nstatic void call_alt_handlers(struct _Unwind_Context *ctx)\n{\n    uintptr_t ip = _Unwind_GetIP(ctx) - 1;\n    uintptr_t cfa = _Unwind_GetCFA(ctx);\n    unsigned int i;\n    \n    struct alt_handler_list *list = fetch_handler_list(NO);\n    if (!list  ||  list->used == 0) return;\n\n    for (i = 0; i < list->allocated; i++) {\n        struct alt_handler_data *data = &list->handlers[i];\n        if (ip >= data->frame.ip_start  &&  ip < data->frame.ip_end  &&  data->frame.cfa == cfa) \n        {\n            if (data->frame.ips) {\n                unsigned int r = 0;\n                bool found;\n                while (1) {\n                    uintptr_t start = data->frame.ips[r].start;\n                    uintptr_t end = data->frame.ips[r].end;\n                    r++;\n                    if (start == 0  &&  end == 0) {\n                        found = false;\n                        break;\n                    }\n                    if (ip >= start  &&  ip < end) {\n                        found = true; \n                        break;\n                    }\n                }\n                if (!found) continue;\n            }\n\n            // Copy and clear before the callback, in case the \n            // callback manipulates the alt handler list.\n            struct alt_handler_data copy = *data;\n            bzero(data, sizeof(*data));\n            list->used--;\n            if (PrintExceptions || PrintAltHandlers) {\n                _objc_inform(\"EXCEPTIONS: calling alt handler %p(%p) from \"\n                             \"frame [ip=%p..%p sp=%p]\", copy.fn, copy.context, \n                             (void *)copy.frame.ip_start, \n                             (void *)copy.frame.ip_end, \n                             (void *)copy.frame.cfa);\n            }\n            if (copy.fn) (*copy.fn)(nil, copy.context);\n            if (copy.frame.ips) free(copy.frame.ips);\n        }\n    }\n}\n\n// SUPPORT_ALT_HANDLERS\n#endif\n\n\n/***********************************************************************\n* exception_init\n* Initialize libobjc's exception handling system.\n* Called by map_images().\n**********************************************************************/\nvoid exception_init(void)\n{\n    old_terminate = std::set_terminate(&_objc_terminate);\n}\n\n\n// __OBJC2__\n#endif\n\n// Define this everywhere even if it isn't used, to simplify fork() safety code\nmutex_t AltHandlerDebugLock;\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-file-old.h",
    "content": "/*\n * Copyright (c) 2009 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _OBJC_FILE_OLD_H\n#define _OBJC_FILE_OLD_H\n\n#if !__OBJC2__\n\n#include \"objc-os.h\"\n\nstruct objc_module;\nstruct old_protocol;\nstruct old_class;\n\n__BEGIN_DECLS\n\nextern struct objc_module *_getObjcModules(const header_info *hi, size_t *nmodules);\nextern SEL *_getObjcSelectorRefs(const header_info *hi, size_t *nmess);\nextern struct old_protocol **_getObjcProtocols(const header_info *hi, size_t *nprotos);\nextern Class *_getObjcClassRefs(const header_info *hi, size_t *nclasses);\nextern const char *_getObjcClassNames(const header_info *hi, size_t *size);\n\nusing UnsignedInitializer = void(*)(void);\nextern UnsignedInitializer* getLibobjcInitializers(const headerType *mhdr, size_t *count);\n\n__END_DECLS\n\n#endif\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-file-old.mm",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n// Copyright 1988-1996 NeXT Software, Inc.\n\n#if !__OBJC2__\n\n#include \"objc-private.h\"\n#include \"objc-runtime-old.h\"\n#include \"objc-file-old.h\"\n\n#if TARGET_OS_WIN32\n\n/*\nModule \n_getObjcModules(const header_info *hi, size_t *nmodules)\n{\n    if (nmodules) *nmodules = hi->moduleCount;\n    return hi->modules;\n}\n*/\nSEL *\n_getObjcSelectorRefs(const header_info *hi, size_t *nmess)\n{\n    if (nmess) *nmess = hi->selrefCount;\n    return hi->selrefs;\n}\n\nstruct old_protocol **\n_getObjcProtocols(const header_info *hi, size_t *nprotos)\n{\n    if (nprotos) *nprotos = hi->protocolCount;\n    return hi->protocols;\n}\n\nClass*\n_getObjcClassRefs(const header_info *hi, size_t *nclasses)\n{\n    if (nclasses) *nclasses = hi->clsrefCount;\n    return (Class*)hi->clsrefs;\n}\n\n// __OBJC,__class_names section only emitted by CodeWarrior  rdar://4951638\nconst char *\n_getObjcClassNames(const header_info *hi, size_t *size)\n{\n    if (size) *size = 0;\n    return NULL;\n}\n\n#else\n\n#define GETSECT(name, type, segname, sectname)                          \\\n    type *name(const headerType *mhdr, size_t *outCount)                \\\n    {                                                                   \\\n        unsigned long byteCount = 0;                                    \\\n        type *data = (type *)                                           \\\n            getsectiondata(mhdr, segname, sectname, &byteCount);        \\\n        *outCount = byteCount / sizeof(type);                           \\\n        return data;                                                    \\\n    }                                                                   \\\n    type *name(const header_info *hi, size_t *outCount)                 \\\n    {                                                                   \\\n        return name(hi->mhdr(), outCount);                                \\\n    }\n\nGETSECT(_getObjcModules,        objc_module, \"__OBJC\", \"__module_info\");\nGETSECT(_getObjcSelectorRefs,   SEL,         \"__OBJC\", \"__message_refs\");\nGETSECT(_getObjcClassRefs,      Class,       \"__OBJC\", \"__cls_refs\");\nGETSECT(_getObjcClassNames,     const char,  \"__OBJC\", \"__class_names\");\n// __OBJC,__class_names section only emitted by CodeWarrior  rdar://4951638\nGETSECT(getLibobjcInitializers, UnsignedInitializer, \"__DATA\", \"__objc_init_func\");\n\n\nobjc_image_info *\n_getObjcImageInfo(const headerType *mhdr, size_t *outBytes)\n{\n    unsigned long byteCount = 0;\n    objc_image_info *info = (objc_image_info *)\n        getsectiondata(mhdr, SEG_OBJC, \"__image_info\", &byteCount);\n    *outBytes = byteCount;\n    return info;\n}\n\n\nstruct old_protocol **\n_getObjcProtocols(const header_info *hi, size_t *nprotos)\n{\n    unsigned long size = 0;\n    struct old_protocol *protos = (struct old_protocol *)\n        getsectiondata(hi->mhdr(), SEG_OBJC, \"__protocol\", &size);\n    *nprotos = size / sizeof(struct old_protocol);\n    \n    if (!hi->proto_refs  &&  *nprotos) {\n        size_t i;\n        header_info *whi = (header_info *)hi;\n        whi->proto_refs = (struct old_protocol **)\n            malloc(*nprotos * sizeof(*hi->proto_refs));\n        for (i = 0; i < *nprotos; i++) {\n            hi->proto_refs[i] = protos+i;\n        }\n    }\n    \n    return hi->proto_refs;\n}\n\n\nstatic const segmentType *\ngetsegbynamefromheader(const headerType *head, const char *segname)\n{\n    const segmentType *sgp;\n    unsigned long i;\n    \n    sgp = (const segmentType *) (head + 1);\n    for (i = 0; i < head->ncmds; i++){\n        if (sgp->cmd == SEGMENT_CMD) {\n            if (strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0) {\n                return sgp;\n            }\n        }\n        sgp = (const segmentType *)((char *)sgp + sgp->cmdsize);\n    }\n    return NULL;\n}\n\nbool\n_hasObjcContents(const header_info *hi)\n{\n    // Look for an __OBJC,* section other than __OBJC,__image_info\n    const segmentType *seg = getsegbynamefromheader(hi->mhdr(), \"__OBJC\");\n    const sectionType *sect;\n    uint32_t i;\n    for (i = 0; i < seg->nsects; i++) {\n        sect = ((const sectionType *)(seg+1))+i;\n        if (0 != strncmp(sect->sectname, \"__image_info\", 12)) {\n            return YES;\n        }\n    }\n\n    return NO;\n}\n\n\n#endif\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-file.h",
    "content": "/*\n * Copyright (c) 2009 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _OBJC_FILE_NEW_H\n#define _OBJC_FILE_NEW_H\n\n#if __OBJC2__\n\n#include \"objc-runtime-new.h\"\n\n// classref_t is not fixed up at launch; use remapClass() to convert\n\nextern SEL *_getObjc2SelectorRefs(const header_info *hi, size_t *count);\nextern message_ref_t *_getObjc2MessageRefs(const header_info *hi, size_t *count);\nextern Class*_getObjc2ClassRefs(const header_info *hi, size_t *count);\nextern Class*_getObjc2SuperRefs(const header_info *hi, size_t *count);\nextern classref_t *_getObjc2ClassList(const header_info *hi, size_t *count);\nextern classref_t *_getObjc2NonlazyClassList(const header_info *hi, size_t *count);\nextern category_t **_getObjc2CategoryList(const header_info *hi, size_t *count);\nextern category_t **_getObjc2NonlazyCategoryList(const header_info *hi, size_t *count);\nextern protocol_t **_getObjc2ProtocolList(const header_info *hi, size_t *count);\nextern protocol_t **_getObjc2ProtocolRefs(const header_info *hi, size_t *count);\n\n// FIXME: rdar://29241917&33734254 clang doesn't sign static initializers.\nstruct UnsignedInitializer {\nprivate:\n    uintptr_t storage;\npublic:\n    void operator () () const {\n        using Initializer = void(*)();\n        Initializer init =\n            ptrauth_sign_unauthenticated((Initializer)storage,\n                                         ptrauth_key_function_pointer, 0);\n        init();\n    }\n};\n\nextern UnsignedInitializer *getLibobjcInitializers(const header_info *hi, size_t *count);\n\nextern classref_t *_getObjc2NonlazyClassList(const headerType *mhdr, size_t *count);\nextern category_t **_getObjc2NonlazyCategoryList(const headerType *mhdr, size_t *count);\nextern UnsignedInitializer *getLibobjcInitializers(const headerType *mhdr, size_t *count);\n\nstatic inline void\nforeach_data_segment(const headerType *mhdr,\n                     std::function<void(const segmentType *, intptr_t slide)> code)\n{\n    intptr_t slide = 0;\n\n    // compute VM slide\n    const segmentType *seg = (const segmentType *) (mhdr + 1);\n    for (unsigned long i = 0; i < mhdr->ncmds; i++) {\n        if (seg->cmd == SEGMENT_CMD  &&\n            segnameEquals(seg->segname, \"__TEXT\"))\n        {\n            slide = (char *)mhdr - (char *)seg->vmaddr;\n            break;\n        }\n        seg = (const segmentType *)((char *)seg + seg->cmdsize);\n    }\n\n    // enumerate __DATA* segments\n    seg = (const segmentType *) (mhdr + 1);\n    for (unsigned long i = 0; i < mhdr->ncmds; i++) {\n        if (seg->cmd == SEGMENT_CMD  &&\n            segnameStartsWith(seg->segname, \"__DATA\"))\n        {\n            code(seg, slide);\n        }\n        seg = (const segmentType *)((char *)seg + seg->cmdsize);\n    }\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-file.mm",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#if __OBJC2__\n\n#include \"objc-private.h\"\n#include \"objc-file.h\"\n\n\n// Look for a __DATA or __DATA_CONST or __DATA_DIRTY section \n// with the given name that stores an array of T.\ntemplate <typename T>\nT* getDataSection(const headerType *mhdr, const char *sectname, \n                  size_t *outBytes, size_t *outCount)\n{\n    unsigned long byteCount = 0;\n    T* data = (T*)getsectiondata(mhdr, \"__DATA\", sectname, &byteCount);\n    if (!data) {\n        data = (T*)getsectiondata(mhdr, \"__DATA_CONST\", sectname, &byteCount);\n    }\n    if (!data) {\n        data = (T*)getsectiondata(mhdr, \"__DATA_DIRTY\", sectname, &byteCount);\n    }\n    if (outBytes) *outBytes = byteCount;\n    if (outCount) *outCount = byteCount / sizeof(T);\n    return data;\n}\n\n#define GETSECT(name, type, sectname)                                   \\\n    type *name(const headerType *mhdr, size_t *outCount) {              \\\n        return getDataSection<type>(mhdr, sectname, nil, outCount);     \\\n    }                                                                   \\\n    type *name(const header_info *hi, size_t *outCount) {               \\\n        return getDataSection<type>(hi->mhdr(), sectname, nil, outCount); \\\n    }\n\n//      function name                 content type     section name\nGETSECT(_getObjc2SelectorRefs,        SEL,             \"__objc_selrefs\"); \nGETSECT(_getObjc2MessageRefs,         message_ref_t,   \"__objc_msgrefs\"); \nGETSECT(_getObjc2ClassRefs,           Class,           \"__objc_classrefs\");\nGETSECT(_getObjc2SuperRefs,           Class,           \"__objc_superrefs\");\nGETSECT(_getObjc2ClassList,           classref_t,      \"__objc_classlist\");\nGETSECT(_getObjc2NonlazyClassList,    classref_t,      \"__objc_nlclslist\");\nGETSECT(_getObjc2CategoryList,        category_t *,    \"__objc_catlist\");\nGETSECT(_getObjc2NonlazyCategoryList, category_t *,    \"__objc_nlcatlist\");\nGETSECT(_getObjc2ProtocolList,        protocol_t *,    \"__objc_protolist\");\nGETSECT(_getObjc2ProtocolRefs,        protocol_t *,    \"__objc_protorefs\");\nGETSECT(getLibobjcInitializers,       UnsignedInitializer, \"__objc_init_func\");\n\n\nobjc_image_info *\n_getObjcImageInfo(const headerType *mhdr, size_t *outBytes)\n{\n    return getDataSection<objc_image_info>(mhdr, \"__objc_imageinfo\", \n                                           outBytes, nil);\n}\n\n// Look for an __objc* section other than __objc_imageinfo\nstatic bool segmentHasObjcContents(const segmentType *seg)\n{\n    for (uint32_t i = 0; i < seg->nsects; i++) {\n        const sectionType *sect = ((const sectionType *)(seg+1))+i;\n        if (sectnameStartsWith(sect->sectname, \"__objc_\")  &&\n            !sectnameEquals(sect->sectname, \"__objc_imageinfo\"))\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\n// Look for an __objc* section other than __objc_imageinfo\nbool\n_hasObjcContents(const header_info *hi)\n{\n    bool foundObjC = false;\n\n    foreach_data_segment(hi->mhdr(), [&](const segmentType *seg, intptr_t slide)\n    {\n        if (segmentHasObjcContents(seg)) foundObjC = true;\n    });\n\n    return foundObjC;\n    \n}\n\n\n// OBJC2\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-gdb.h",
    "content": "/*\n * Copyright (c) 2008 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _OBJC_GDB_H\n#define _OBJC_GDB_H\n\n/* \n * WARNING  DANGER  HAZARD  BEWARE  EEK\n * \n * Everything in this file is for debugger and developer tool use only.\n * These will change in arbitrary OS updates and in unpredictable ways.\n * When your program breaks, you get to keep both pieces.\n */\n\n#ifdef __APPLE_API_PRIVATE\n\n#ifndef _OBJC_PRIVATE_H_\n#   define _OBJC_PRIVATE_H_\n#endif\n#include <stdint.h>\n#include <objc/hashtable.h>\n#include <objc/maptable.h>\n\n__BEGIN_DECLS\n\n\n/***********************************************************************\n* Class pointer preflighting\n**********************************************************************/\n\n// Return cls if it's a valid class, or crash.\nOBJC_EXPORT Class _Nonnull\ngdb_class_getClass(Class _Nonnull cls)\n#if __OBJC2__\n    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);\n#else\n    OBJC_AVAILABLE(10.7, 3.1, 9.0, 1.0, 2.0);\n#endif\n\n// Same as gdb_class_getClass(object_getClass(cls)).\nOBJC_EXPORT Class _Nonnull gdb_object_getClass(id _Nullable obj)\n    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);\n\n\n/***********************************************************************\n* Class lists for heap.\n**********************************************************************/\n\n#if __OBJC2__\n\n// Maps class name to Class, for in-use classes only. NXStrValueMapPrototype.\nOBJC_EXPORT NXMapTable * _Nullable gdb_objc_realized_classes\n    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);\n\n#else\n\n// Hashes Classes, for all known classes. Custom prototype.\nOBJC_EXPORT NXHashTable * _Nullable _objc_debug_class_hash\n    __OSX_AVAILABLE(10.2) \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\n#endif\n\n\n/***********************************************************************\n* Non-pointer isa\n**********************************************************************/\n\n#if __OBJC2__\n\n// Extract isa pointer from an isa field.\n// (Class)(isa & mask) == class pointer\nOBJC_EXPORT const uintptr_t objc_debug_isa_class_mask\n    OBJC_AVAILABLE(10.10, 7.0, 9.0, 1.0, 2.0);\n\n// Extract magic cookie from an isa field.\n// (isa & magic_mask) == magic_value\nOBJC_EXPORT const uintptr_t objc_debug_isa_magic_mask\n    OBJC_AVAILABLE(10.10, 7.0, 9.0, 1.0, 2.0);\nOBJC_EXPORT const uintptr_t objc_debug_isa_magic_value\n    OBJC_AVAILABLE(10.10, 7.0, 9.0, 1.0, 2.0);\n\n// Use indexed ISAs for targets which store index of the class in the ISA.\n// This index can be used to index the array of classes.\nOBJC_EXPORT const uintptr_t objc_debug_indexed_isa_magic_mask;\nOBJC_EXPORT const uintptr_t objc_debug_indexed_isa_magic_value;\n\n// Then these are used to extract the index from the ISA.\nOBJC_EXPORT const uintptr_t objc_debug_indexed_isa_index_mask;\nOBJC_EXPORT const uintptr_t objc_debug_indexed_isa_index_shift;\n\n// And then we can use that index to get the class from this array.  Note\n// the size is provided so that clients can ensure the index they get is in\n// bounds and not read off the end of the array.\nOBJC_EXPORT Class _Nullable objc_indexed_classes[];\n\n// When we don't have enough bits to store a class*, we can instead store an\n// index in to this array.  Classes are added here when they are realized.\n// Note, an index of 0 is illegal.\nOBJC_EXPORT uintptr_t objc_indexed_classes_count;\n\n// Absolute symbols for some of the above values are in objc-abi.h.\n\n#endif\n\n\n/***********************************************************************\n* Class structure decoding\n**********************************************************************/\n#if __OBJC2__\n\n// Mask for the pointer from class struct to class rw data.\n// Other bits may be used for flags.\n// Use 0x00007ffffffffff8UL or 0xfffffffcUL when this variable is unavailable.\nOBJC_EXPORT const uintptr_t objc_debug_class_rw_data_mask\n    OBJC_AVAILABLE(10.13, 11.0, 11.0, 4.0, 2.0);\n\n#endif\n\n\n/***********************************************************************\n* Tagged pointer decoding\n**********************************************************************/\n#if __OBJC2__\n\n// Basic tagged pointers (7 classes, 60-bit payload).\n\n// if (obj & mask) obj is a tagged pointer object\nOBJC_EXPORT uintptr_t objc_debug_taggedpointer_mask\n    OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);\n\n// tagged pointers are obfuscated by XORing with a random value\n// decoded_obj = (obj ^ obfuscator)\nOBJC_EXPORT uintptr_t objc_debug_taggedpointer_obfuscator\n    OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);\n\n\n// tag_slot = (obj >> slot_shift) & slot_mask\nOBJC_EXPORT unsigned int objc_debug_taggedpointer_slot_shift\n    OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);\nOBJC_EXPORT uintptr_t objc_debug_taggedpointer_slot_mask\n    OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);\n\n// class = classes[tag_slot]\nOBJC_EXPORT Class _Nullable objc_debug_taggedpointer_classes[]\n    OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);\n\n// payload = (decoded_obj << payload_lshift) >> payload_rshift\n// Payload signedness is determined by the signedness of the right-shift.\nOBJC_EXPORT unsigned int objc_debug_taggedpointer_payload_lshift\n    OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);\nOBJC_EXPORT unsigned int objc_debug_taggedpointer_payload_rshift\n    OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);\n\n\n// Extended tagged pointers (255 classes, 52-bit payload).\n\n// If you interrogate an extended tagged pointer using the basic \n// tagged pointer scheme alone, it will appear to have an isa \n// that is either nil or class __NSUnrecognizedTaggedPointer.\n\n// if (ext_mask != 0  &&  (decoded_obj & ext_mask) == ext_mask)\n//   obj is a ext tagged pointer object\nOBJC_EXPORT uintptr_t objc_debug_taggedpointer_ext_mask\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\n// ext_tag_slot = (obj >> ext_slot_shift) & ext_slot_mask\nOBJC_EXPORT unsigned int objc_debug_taggedpointer_ext_slot_shift\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\nOBJC_EXPORT uintptr_t objc_debug_taggedpointer_ext_slot_mask\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\n// class = ext_classes[ext_tag_slot]\nOBJC_EXPORT Class _Nullable objc_debug_taggedpointer_ext_classes[]\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\n// payload = (decoded_obj << ext_payload_lshift) >> ext_payload_rshift\n// Payload signedness is determined by the signedness of the right-shift.\nOBJC_EXPORT unsigned int objc_debug_taggedpointer_ext_payload_lshift\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\nOBJC_EXPORT unsigned int objc_debug_taggedpointer_ext_payload_rshift\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\n#endif\n\n__END_DECLS\n\n// APPLE_API_PRIVATE\n#endif\n\n// _OBJC_GDB_H\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-initialize.h",
    "content": "/*\n * Copyright (c) 2005-2006 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _OBJC_INITIALIZE_H\n#define _OBJC_INITIALIZE_H\n\n#include \"objc-private.h\"\n\n__BEGIN_DECLS\n\nstruct _objc_initializing_classes;\n\nextern void _class_initialize(Class cls);\n\nextern void _destroyInitializingClassList(struct _objc_initializing_classes *list);\n\nextern bool _thisThreadIsInitializingClass(Class cls);\n\n__END_DECLS\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-initialize.mm",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-initialize.m\n* +initialize support\n**********************************************************************/\n\n/***********************************************************************\n * Thread-safety during class initialization (GrP 2001-9-24)\n *\n * Initial state: CLS_INITIALIZING and CLS_INITIALIZED both clear. \n * During initialization: CLS_INITIALIZING is set\n * After initialization: CLS_INITIALIZING clear and CLS_INITIALIZED set.\n * CLS_INITIALIZING and CLS_INITIALIZED are never set at the same time.\n * CLS_INITIALIZED is never cleared once set.\n *\n * Only one thread is allowed to actually initialize a class and send \n * +initialize. Enforced by allowing only one thread to set CLS_INITIALIZING.\n *\n * Additionally, threads trying to send messages to a class must wait for \n * +initialize to finish. During initialization of a class, that class's \n * method cache is kept empty. objc_msgSend will revert to \n * class_lookupMethodAndLoadCache, which checks CLS_INITIALIZED before \n * messaging. If CLS_INITIALIZED is clear but CLS_INITIALIZING is set, \n * the thread must block, unless it is the thread that started \n * initializing the class in the first place. \n *\n * Each thread keeps a list of classes it's initializing. \n * The global classInitLock is used to synchronize changes to CLS_INITIALIZED \n * and CLS_INITIALIZING: the transition to CLS_INITIALIZING must be \n * an atomic test-and-set with respect to itself and the transition \n * to CLS_INITIALIZED.\n * The global classInitWaitCond is used to block threads waiting for an \n * initialization to complete. The classInitLock synchronizes\n * condition checking and the condition variable.\n **********************************************************************/\n\n/***********************************************************************\n *  +initialize deadlock case when a class is marked initializing while \n *  its superclass is initialized. Solved by completely initializing \n *  superclasses before beginning to initialize a class.\n *\n *  OmniWeb class hierarchy:\n *                 OBObject \n *                     |    ` OBPostLoader\n *                 OFObject\n *                 /     \\\n *      OWAddressEntry  OWController\n *                        | \n *                      OWConsoleController\n *\n *  Thread 1 (evil testing thread):\n *    initialize OWAddressEntry\n *    super init OFObject\n *    super init OBObject\t\t     \n *    [OBObject initialize] runs OBPostLoader, which inits lots of classes...\n *    initialize OWConsoleController\n *    super init OWController - wait for Thread 2 to finish OWController init\n *\n *  Thread 2 (normal OmniWeb thread):\n *    initialize OWController\n *    super init OFObject - wait for Thread 1 to finish OFObject init\n *\n *  deadlock!\n *\n *  Solution: fully initialize super classes before beginning to initialize \n *  a subclass. Then the initializing+initialized part of the class hierarchy\n *  will be a contiguous subtree starting at the root, so other threads \n *  can't jump into the middle between two initializing classes, and we won't \n *  get stuck while a superclass waits for its subclass which waits for the \n *  superclass.\n **********************************************************************/\n\n#include \"objc-private.h\"\n#include \"message.h\"\n#include \"objc-initialize.h\"\n\n/* classInitLock protects CLS_INITIALIZED and CLS_INITIALIZING, and \n * is signalled when any class is done initializing. \n * Threads that are waiting for a class to finish initializing wait on this. */\nmonitor_t classInitLock;\n\n\n/***********************************************************************\n* struct _objc_initializing_classes\n* Per-thread list of classes currently being initialized by that thread. \n* During initialization, that thread is allowed to send messages to that \n* class, but other threads have to wait.\n* The list is a simple array of metaclasses (the metaclass stores \n* the initialization state). \n**********************************************************************/\ntypedef struct _objc_initializing_classes {\n    int classesAllocated;\n    Class *metaclasses;\n} _objc_initializing_classes;\n\n\n/***********************************************************************\n* _fetchInitializingClassList\n* Return the list of classes being initialized by this thread.\n* If create == YES, create the list when no classes are being initialized by this thread.\n* If create == NO, return nil when no classes are being initialized by this thread.\n**********************************************************************/\nstatic _objc_initializing_classes *_fetchInitializingClassList(bool create)\n{\n    _objc_pthread_data *data;\n    _objc_initializing_classes *list;\n    Class *classes;\n\n    data = _objc_fetch_pthread_data(create);\n    if (data == nil) return nil;\n\n    list = data->initializingClasses;\n    if (list == nil) {\n        if (!create) {\n            return nil;\n        } else {\n            list = (_objc_initializing_classes *)\n                calloc(1, sizeof(_objc_initializing_classes));\n            data->initializingClasses = list;\n        }\n    }\n\n    classes = list->metaclasses;\n    if (classes == nil) {\n        // If _objc_initializing_classes exists, allocate metaclass array, \n        // even if create == NO.\n        // Allow 4 simultaneous class inits on this thread before realloc.\n        list->classesAllocated = 4;\n        classes = (Class *)\n            calloc(list->classesAllocated, sizeof(Class));\n        list->metaclasses = classes;\n    }\n    return list;\n}\n\n\n/***********************************************************************\n* _destroyInitializingClassList\n* Deallocate memory used by the given initialization list. \n* Any part of the list may be nil.\n* Called from _objc_pthread_destroyspecific().\n**********************************************************************/\n\nvoid _destroyInitializingClassList(struct _objc_initializing_classes *list)\n{\n    if (list != nil) {\n        if (list->metaclasses != nil) {\n            free(list->metaclasses);\n        }\n        free(list);\n    }\n}\n\n\n/***********************************************************************\n* _thisThreadIsInitializingClass\n* Return TRUE if this thread is currently initializing the given class.\n**********************************************************************/\nbool _thisThreadIsInitializingClass(Class cls)\n{\n    int i;\n\n    _objc_initializing_classes *list = _fetchInitializingClassList(NO);\n    if (list) {\n        cls = cls->getMeta();\n        for (i = 0; i < list->classesAllocated; i++) {\n            if (cls == list->metaclasses[i]) return YES;\n        }\n    }\n\n    // no list or not found in list\n    return NO;\n}\n\n\n/***********************************************************************\n* _setThisThreadIsInitializingClass\n* Record that this thread is currently initializing the given class. \n* This thread will be allowed to send messages to the class, but \n*   other threads will have to wait.\n**********************************************************************/\nstatic void _setThisThreadIsInitializingClass(Class cls)\n{\n    int i;\n    _objc_initializing_classes *list = _fetchInitializingClassList(YES);\n    cls = cls->getMeta();\n  \n    // paranoia: explicitly disallow duplicates\n    for (i = 0; i < list->classesAllocated; i++) {\n        if (cls == list->metaclasses[i]) {\n            _objc_fatal(\"thread is already initializing this class!\");\n            return; // already the initializer\n        }\n    }\n  \n    for (i = 0; i < list->classesAllocated; i++) {\n        if (! list->metaclasses[i]) {\n            list->metaclasses[i] = cls;\n            return;\n        }\n    }\n\n    // class list is full - reallocate\n    list->classesAllocated = list->classesAllocated * 2 + 1;\n    list->metaclasses = (Class *) \n        realloc(list->metaclasses,\n                          list->classesAllocated * sizeof(Class));\n    // zero out the new entries\n    list->metaclasses[i++] = cls;\n    for ( ; i < list->classesAllocated; i++) {\n        list->metaclasses[i] = nil;\n    }\n}\n\n\n/***********************************************************************\n* _setThisThreadIsNotInitializingClass\n* Record that this thread is no longer initializing the given class. \n**********************************************************************/\nstatic void _setThisThreadIsNotInitializingClass(Class cls)\n{\n    int i;\n\n    _objc_initializing_classes *list = _fetchInitializingClassList(NO);\n    if (list) {\n        cls = cls->getMeta();\n        for (i = 0; i < list->classesAllocated; i++) {\n            if (cls == list->metaclasses[i]) {\n                list->metaclasses[i] = nil;\n                return;\n            }\n        }\n    }\n\n    // no list or not found in list\n    _objc_fatal(\"thread is not initializing this class!\");  \n}\n\n\ntypedef struct PendingInitialize {\n    Class subclass;\n    struct PendingInitialize *next;\n} PendingInitialize;\n\nstatic NXMapTable *pendingInitializeMap;\n\n/***********************************************************************\n* _finishInitializing\n* cls has completed its +initialize method, and so has its superclass.\n* Mark cls as initialized as well, then mark any of cls's subclasses \n* that have already finished their own +initialize methods.\n**********************************************************************/\nstatic void _finishInitializing(Class cls, Class supercls)\n{\n    PendingInitialize *pending;\n\n    classInitLock.assertLocked();\n    assert(!supercls  ||  supercls->isInitialized());\n\n    if (PrintInitializing) {\n        _objc_inform(\"INITIALIZE: thread %p: %s is fully +initialized\",\n                     pthread_self(), cls->nameForLogging());\n    }\n\n    // mark this class as fully +initialized\n    cls->setInitialized();\n    classInitLock.notifyAll();\n    _setThisThreadIsNotInitializingClass(cls);\n    \n    // mark any subclasses that were merely waiting for this class\n    if (!pendingInitializeMap) return;\n    pending = (PendingInitialize *)NXMapGet(pendingInitializeMap, cls);\n    if (!pending) return;\n\n    NXMapRemove(pendingInitializeMap, cls);\n    \n    // Destroy the pending table if it's now empty, to save memory.\n    if (NXCountMapTable(pendingInitializeMap) == 0) {\n        NXFreeMapTable(pendingInitializeMap);\n        pendingInitializeMap = nil;\n    }\n\n    while (pending) {\n        PendingInitialize *next = pending->next;\n        if (pending->subclass) _finishInitializing(pending->subclass, cls);\n        free(pending);\n        pending = next;\n    }\n}\n\n\n/***********************************************************************\n* _finishInitializingAfter\n* cls has completed its +initialize method, but its superclass has not.\n* Wait until supercls finishes before marking cls as initialized.\n**********************************************************************/\nstatic void _finishInitializingAfter(Class cls, Class supercls)\n{\n    PendingInitialize *pending;\n\n    classInitLock.assertLocked();\n\n    if (PrintInitializing) {\n        _objc_inform(\"INITIALIZE: thread %p: class %s will be marked as fully \"\n                     \"+initialized after superclass +[%s initialize] completes\",\n                     pthread_self(), cls->nameForLogging(),\n                     supercls->nameForLogging());\n    }\n\n    if (!pendingInitializeMap) {\n        pendingInitializeMap = \n            NXCreateMapTable(NXPtrValueMapPrototype, 10);\n        // fixme pre-size this table for CF/NSObject +initialize\n    }\n\n    pending = (PendingInitialize *)malloc(sizeof(*pending));\n    pending->subclass = cls;\n    pending->next = (PendingInitialize *)\n        NXMapGet(pendingInitializeMap, supercls);\n    NXMapInsert(pendingInitializeMap, supercls, pending);\n}\n\n\n// Provide helpful messages in stack traces.\nOBJC_EXTERN __attribute__((noinline, used, visibility(\"hidden\")))\nvoid waitForInitializeToComplete(Class cls)\n    asm(\"_WAITING_FOR_ANOTHER_THREAD_TO_FINISH_CALLING_+initialize\");\nOBJC_EXTERN __attribute__((noinline, used, visibility(\"hidden\")))\nvoid callInitialize(Class cls)\n    asm(\"_CALLING_SOME_+initialize_METHOD\");\n\n\nvoid waitForInitializeToComplete(Class cls)\n{\n    if (PrintInitializing) {\n        _objc_inform(\"INITIALIZE: thread %p: blocking until +[%s initialize] \"\n                     \"completes\", pthread_self(), cls->nameForLogging());\n    }\n\n    monitor_locker_t lock(classInitLock);\n    while (!cls->isInitialized()) {\n        classInitLock.wait();\n    }\n    asm(\"\");\n}\n\n\nvoid callInitialize(Class cls)\n{\n    ((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize);\n    asm(\"\");\n}\n\n\n/***********************************************************************\n* classHasTrivialInitialize\n* Returns true if the class has no +initialize implementation or \n* has a +initialize implementation that looks empty.\n* Any root class +initialize implemetation is assumed to be trivial.\n**********************************************************************/\nstatic bool classHasTrivialInitialize(Class cls)\n{\n    if (cls->isRootClass() || cls->isRootMetaclass()) return true;\n\n    Class rootCls = cls->ISA()->ISA()->superclass;\n    \n    IMP rootImp = lookUpImpOrNil(rootCls->ISA(), SEL_initialize, rootCls, \n                             NO/*initialize*/, YES/*cache*/, NO/*resolver*/);\n    IMP imp = lookUpImpOrNil(cls->ISA(), SEL_initialize, cls,\n                             NO/*initialize*/, YES/*cache*/, NO/*resolver*/);\n    return (imp == nil  ||  imp == (IMP)&objc_noop_imp  ||  imp == rootImp);\n}\n\n\n/***********************************************************************\n* lockAndFinishInitializing\n* Mark a class as finished initializing and notify waiters, or queue for later.\n* If the superclass is also done initializing, then update \n*   the info bits and notify waiting threads.\n* If not, update them later. (This can happen if this +initialize \n*   was itself triggered from inside a superclass +initialize.)\n**********************************************************************/\nstatic void lockAndFinishInitializing(Class cls, Class supercls)\n{\n    monitor_locker_t lock(classInitLock);\n    if (!supercls  ||  supercls->isInitialized()) {\n        _finishInitializing(cls, supercls);\n    } else {\n        _finishInitializingAfter(cls, supercls);\n    }\n}\n\n\n/***********************************************************************\n* performForkChildInitialize\n* +initialize after fork() is problematic. It's possible for the \n* fork child process to call some +initialize that would deadlock waiting \n* for another +initialize in the parent process. \n* We wouldn't know how much progress it made therein, so we can't\n* act as if +initialize completed nor can we restart +initialize\n* from scratch.\n*\n* Instead we proceed introspectively. If the class has some\n* +initialize implementation, we halt. If the class has no\n* +initialize implementation of its own, we continue. Root\n* class +initialize is assumed to be empty if it exists.\n*\n* We apply this rule even if the child's +initialize does not appear \n* to be blocked by anything. This prevents races wherein the +initialize\n* deadlock only rarely hits. Instead we disallow it even when we \"won\" \n* the race. \n*\n* Exception: processes that are single-threaded when fork() is called \n* have no restrictions on +initialize in the child. Examples: sshd and httpd.\n*\n* Classes that wish to implement +initialize and be callable after \n* fork() must use an atfork() handler to provoke +initialize in fork prepare.\n**********************************************************************/\n\n// Called before halting when some +initialize \n// method can't be called after fork().\nBREAKPOINT_FUNCTION(\n    void objc_initializeAfterForkError(Class cls)\n);\n\nvoid performForkChildInitialize(Class cls, Class supercls)\n{\n    if (classHasTrivialInitialize(cls)) {\n        if (PrintInitializing) {\n            _objc_inform(\"INITIALIZE: thread %p: skipping trivial +[%s \"\n                         \"initialize] in fork() child process\",\n                         pthread_self(), cls->nameForLogging());\n        }\n        lockAndFinishInitializing(cls, supercls);\n    }\n    else {\n        if (PrintInitializing) {\n            _objc_inform(\"INITIALIZE: thread %p: refusing to call +[%s \"\n                         \"initialize] in fork() child process because \"\n                         \"it may have been in progress when fork() was called\",\n                         pthread_self(), cls->nameForLogging());\n        }\n        _objc_inform_now_and_on_crash\n            (\"+[%s initialize] may have been in progress in another thread \"\n             \"when fork() was called.\",\n             cls->nameForLogging());\n        objc_initializeAfterForkError(cls);\n        _objc_fatal\n            (\"+[%s initialize] may have been in progress in another thread \"\n             \"when fork() was called. We cannot safely call it or \"\n             \"ignore it in the fork() child process. Crashing instead. \"\n             \"Set a breakpoint on objc_initializeAfterForkError to debug.\",\n             cls->nameForLogging());\n    }\n}\n\n\n/***********************************************************************\n* class_initialize.  Send the '+initialize' message on demand to any\n* uninitialized class. Force initialization of superclasses first.\n**********************************************************************/\nvoid _class_initialize(Class cls)\n{\n    assert(!cls->isMetaClass());\n\n    Class supercls;\n    bool reallyInitialize = NO;\n\n    // Make sure super is done initializing BEFORE beginning to initialize cls.\n    // See note about deadlock above.\n    supercls = cls->superclass;\n    if (supercls  &&  !supercls->isInitialized()) {\n        _class_initialize(supercls);\n    }\n    \n    // Try to atomically set CLS_INITIALIZING.\n    {\n        monitor_locker_t lock(classInitLock);\n        if (!cls->isInitialized() && !cls->isInitializing()) {\n            cls->setInitializing();\n            reallyInitialize = YES;\n        }\n    }\n    \n    if (reallyInitialize) {\n        // We successfully set the CLS_INITIALIZING bit. Initialize the class.\n        \n        // Record that we're initializing this class so we can message it.\n        _setThisThreadIsInitializingClass(cls);\n\n        if (MultithreadedForkChild) {\n            // LOL JK we don't really call +initialize methods after fork().\n            performForkChildInitialize(cls, supercls);\n            return;\n        }\n        \n        // Send the +initialize message.\n        // Note that +initialize is sent to the superclass (again) if \n        // this class doesn't implement +initialize. 2157218\n        if (PrintInitializing) {\n            _objc_inform(\"INITIALIZE: thread %p: calling +[%s initialize]\",\n                         pthread_self(), cls->nameForLogging());\n        }\n\n        // Exceptions: A +initialize call that throws an exception \n        // is deemed to be a complete and successful +initialize.\n        //\n        // Only __OBJC2__ adds these handlers. !__OBJC2__ has a\n        // bootstrapping problem of this versus CF's call to\n        // objc_exception_set_functions().\n#if __OBJC2__\n        @try\n#endif\n        {\n            callInitialize(cls);\n\n            if (PrintInitializing) {\n                _objc_inform(\"INITIALIZE: thread %p: finished +[%s initialize]\",\n                             pthread_self(), cls->nameForLogging());\n            }\n        }\n#if __OBJC2__\n        @catch (...) {\n            if (PrintInitializing) {\n                _objc_inform(\"INITIALIZE: thread %p: +[%s initialize] \"\n                             \"threw an exception\",\n                             pthread_self(), cls->nameForLogging());\n            }\n            @throw;\n        }\n        @finally\n#endif\n        {\n            // Done initializing.\n            lockAndFinishInitializing(cls, supercls);\n        }\n        return;\n    }\n    \n    else if (cls->isInitializing()) {\n        // We couldn't set INITIALIZING because INITIALIZING was already set.\n        // If this thread set it earlier, continue normally.\n        // If some other thread set it, block until initialize is done.\n        // It's ok if INITIALIZING changes to INITIALIZED while we're here, \n        //   because we safely check for INITIALIZED inside the lock \n        //   before blocking.\n        if (_thisThreadIsInitializingClass(cls)) {\n            return;\n        } else if (!MultithreadedForkChild) {\n            waitForInitializeToComplete(cls);\n            return;\n        } else {\n            // We're on the child side of fork(), facing a class that\n            // was initializing by some other thread when fork() was called.\n            _setThisThreadIsInitializingClass(cls);\n            performForkChildInitialize(cls, supercls);\n        }\n    }\n    \n    else if (cls->isInitialized()) {\n        // Set CLS_INITIALIZING failed because someone else already \n        //   initialized the class. Continue normally.\n        // NOTE this check must come AFTER the ISINITIALIZING case.\n        // Otherwise: Another thread is initializing this class. ISINITIALIZED \n        //   is false. Skip this clause. Then the other thread finishes \n        //   initialization and sets INITIALIZING=no and INITIALIZED=yes. \n        //   Skip the ISINITIALIZING clause. Die horribly.\n        return;\n    }\n    \n    else {\n        // We shouldn't be here. \n        _objc_fatal(\"thread-safe class init in objc runtime is buggy!\");\n    }\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-internal.h",
    "content": "/*\n * Copyright (c) 2009 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n\n#ifndef _OBJC_INTERNAL_H\n#define _OBJC_INTERNAL_H\n\n/* \n * WARNING  DANGER  HAZARD  BEWARE  EEK\n * \n * Everything in this file is for Apple Internal use only.\n * These will change in arbitrary OS updates and in unpredictable ways.\n * When your program breaks, you get to keep both pieces.\n */\n\n/*\n * objc-internal.h: Private SPI for use by other system frameworks.\n */\n\n#include <objc/objc.h>\n#include <objc/runtime.h>\n#include <Availability.h>\n#include <malloc/malloc.h>\n#include <mach-o/loader.h>\n#include <dispatch/dispatch.h>\n\n\n// Termination reasons in the OS_REASON_OBJC namespace.\n#define OBJC_EXIT_REASON_UNSPECIFIED 1\n#define OBJC_EXIT_REASON_GC_NOT_SUPPORTED 2\n\n// This is the allocation size required for each of the class and the metaclass \n// with objc_initializeClassPair() and objc_readClassPair().\n// The runtime's class structure will never grow beyond this.\n#define OBJC_MAX_CLASS_SIZE (32*sizeof(void*))\n\n\n__BEGIN_DECLS\n\n// In-place construction of an Objective-C class.\n// cls and metacls must each be OBJC_MAX_CLASS_SIZE bytes.\n// Returns nil if a class with the same name already exists.\n// Returns nil if the superclass is under construction.\n// Call objc_registerClassPair() when you are done.\nOBJC_EXPORT Class _Nullable\nobjc_initializeClassPair(Class _Nullable superclass, const char * _Nonnull name,\n                         Class _Nonnull cls, Class _Nonnull metacls) \n    OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0, 2.0);\n\n// Class and metaclass construction from a compiler-generated memory image.\n// cls and cls->isa must each be OBJC_MAX_CLASS_SIZE bytes. \n// Extra bytes not used the the metadata must be zero.\n// info is the same objc_image_info that would be emitted by a static compiler.\n// Returns nil if a class with the same name already exists.\n// Returns nil if the superclass is nil and the class is not marked as a root.\n// Returns nil if the superclass is under construction.\n// Do not call objc_registerClassPair().\n#if __OBJC2__\nstruct objc_image_info;\nOBJC_EXPORT Class _Nullable\nobjc_readClassPair(Class _Nonnull cls,\n                   const struct objc_image_info * _Nonnull info)\n    OBJC_AVAILABLE(10.10, 8.0, 9.0, 1.0, 2.0);\n#endif\n\n// Batch object allocation using malloc_zone_batch_malloc().\nOBJC_EXPORT unsigned\nclass_createInstances(Class _Nullable cls, size_t extraBytes, \n                      id _Nonnull * _Nonnull results, unsigned num_requested)\n    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0)\n    OBJC_ARC_UNAVAILABLE;\n\n// Get the isa pointer written into objects just before being freed.\nOBJC_EXPORT Class _Nonnull\n_objc_getFreedObjectClass(void)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n// env NSObjCMessageLoggingEnabled\nOBJC_EXPORT void\ninstrumentObjcMessageSends(BOOL flag)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n// Initializer called by libSystem\nOBJC_EXPORT void\n_objc_init(void)\n#if __OBJC2__\n    OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);\n#else\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n#endif\n\n// fork() safety called by libSystem\nOBJC_EXPORT void\n_objc_atfork_prepare(void)\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\nOBJC_EXPORT void\n_objc_atfork_parent(void)\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\nOBJC_EXPORT void\n_objc_atfork_child(void)\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\n// Return YES if GC is on and `object` is a GC allocation.\nOBJC_EXPORT BOOL\nobjc_isAuto(id _Nullable object) \n    __OSX_DEPRECATED(10.4, 10.8, \"it always returns NO\") \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\n// GC debugging\nOBJC_EXPORT BOOL\nobjc_dumpHeap(char * _Nonnull filename, unsigned long length)\n    __OSX_DEPRECATED(10.4, 10.8, \"it always returns NO\") \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\n// GC startup callback from Foundation\nOBJC_EXPORT malloc_zone_t * _Nullable\nobjc_collect_init(int (* _Nonnull callback)(void))\n    __OSX_DEPRECATED(10.4, 10.8, \"it does nothing\") \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\n// Plainly-implemented GC barriers. Rosetta used to use these.\nOBJC_EXPORT id _Nullable\nobjc_assign_strongCast_generic(id _Nullable value, id _Nullable * _Nonnull dest)\n    UNAVAILABLE_ATTRIBUTE;\n\nOBJC_EXPORT id _Nullable\nobjc_assign_global_generic(id _Nullable value, id _Nullable * _Nonnull dest)\n    UNAVAILABLE_ATTRIBUTE;\n\nOBJC_EXPORT id _Nullable\nobjc_assign_threadlocal_generic(id _Nullable value,\n                                id _Nullable * _Nonnull dest)\n    UNAVAILABLE_ATTRIBUTE;\n\nOBJC_EXPORT id _Nullable\nobjc_assign_ivar_generic(id _Nullable value, id _Nonnull dest, ptrdiff_t offset)\n    UNAVAILABLE_ATTRIBUTE;\n\n// GC preflight for an app executable.\n// 1: some slice requires GC\n// 0: no slice requires GC\n// -1: I/O or file format error\nOBJC_EXPORT int\nobjc_appRequiresGC(int fd)\n    __OSX_AVAILABLE(10.11) \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\n// Install missing-class callback. Used by the late unlamented ZeroLink.\nOBJC_EXPORT void\n_objc_setClassLoader(BOOL (* _Nonnull newClassLoader)(const char * _Nonnull))\n    OBJC2_UNAVAILABLE;\n\n#if !(TARGET_OS_OSX && !TARGET_OS_IOSMAC && __i386__)\nOBJC_EXPORT void\n_objc_setClassCopyFixupHandler(void (* _Nonnull newFixupHandler)\n    (Class _Nonnull oldClass, Class _Nonnull newClass));\n// fixme work around bug in Swift\n//    OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0)\n#endif\n\n// Install handler for allocation failures. \n// Handler may abort, or throw, or provide an object to return.\nOBJC_EXPORT void\n_objc_setBadAllocHandler(id _Nullable (* _Nonnull newHandler)\n                           (Class _Nullable isa))\n    OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);\n\n// Used by ExceptionHandling.framework\n#if !__OBJC2__\nOBJC_EXPORT void\n_objc_error(id _Nullable rcv, const char * _Nonnull fmt, va_list args)\n    __attribute__((noreturn))\n    __OSX_DEPRECATED(10.0, 10.5, \"use other logging facilities instead\") \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;\n\n#endif\n\n\n/**\n * Returns the names of all the classes within a library.\n *\n * @param image The mach header for library or framework you are inquiring about.\n * @param outCount The number of class names returned.\n *\n * @return An array of C strings representing the class names.\n */\nOBJC_EXPORT const char * _Nonnull * _Nullable\nobjc_copyClassNamesForImageHeader(const struct mach_header * _Nonnull mh,\n                                  unsigned int * _Nullable outCount)\n    OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);\n\n// Tagged pointer objects.\n\n#if __LP64__\n#define OBJC_HAVE_TAGGED_POINTERS 1\n#endif\n\n#if OBJC_HAVE_TAGGED_POINTERS\n\n// Tagged pointer layout and usage is subject to change on different OS versions.\n\n// Tag indexes 0..<7 have a 60-bit payload.\n// Tag index 7 is reserved.\n// Tag indexes 8..<264 have a 52-bit payload.\n// Tag index 264 is reserved.\n\n#if __has_feature(objc_fixed_enum)  ||  __cplusplus >= 201103L\nenum objc_tag_index_t : uint16_t\n#else\ntypedef uint16_t objc_tag_index_t;\nenum\n#endif\n{\n    // 60-bit payloads\n    OBJC_TAG_NSAtom            = 0, \n    OBJC_TAG_1                 = 1, \n    OBJC_TAG_NSString          = 2, \n    OBJC_TAG_NSNumber          = 3, \n    OBJC_TAG_NSIndexPath       = 4, \n    OBJC_TAG_NSManagedObjectID = 5, \n    OBJC_TAG_NSDate            = 6,\n\n    // 60-bit reserved\n    OBJC_TAG_RESERVED_7        = 7, \n\n    // 52-bit payloads\n    OBJC_TAG_Photos_1          = 8,\n    OBJC_TAG_Photos_2          = 9,\n    OBJC_TAG_Photos_3          = 10,\n    OBJC_TAG_Photos_4          = 11,\n    OBJC_TAG_XPC_1             = 12,\n    OBJC_TAG_XPC_2             = 13,\n    OBJC_TAG_XPC_3             = 14,\n    OBJC_TAG_XPC_4             = 15,\n\n    OBJC_TAG_First60BitPayload = 0, \n    OBJC_TAG_Last60BitPayload  = 6, \n    OBJC_TAG_First52BitPayload = 8, \n    OBJC_TAG_Last52BitPayload  = 263, \n\n    OBJC_TAG_RESERVED_264      = 264\n};\n#if __has_feature(objc_fixed_enum)  &&  !defined(__cplusplus)\ntypedef enum objc_tag_index_t objc_tag_index_t;\n#endif\n\n\n// Returns true if tagged pointers are enabled.\n// The other functions below must not be called if tagged pointers are disabled.\nstatic inline bool \n_objc_taggedPointersEnabled(void);\n\n// Register a class for a tagged pointer tag.\n// Aborts if the tag is invalid or already in use.\nOBJC_EXPORT void\n_objc_registerTaggedPointerClass(objc_tag_index_t tag, Class _Nonnull cls)\n    OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);\n\n// Returns the registered class for the given tag.\n// Returns nil if the tag is valid but has no registered class.\n// Aborts if the tag is invalid.\nOBJC_EXPORT Class _Nullable\n_objc_getClassForTag(objc_tag_index_t tag)\n    OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);\n\n// Create a tagged pointer object with the given tag and payload.\n// Assumes the tag is valid.\n// Assumes tagged pointers are enabled.\n// The payload will be silently truncated to fit.\nstatic inline void * _Nonnull\n_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t payload);\n\n// Return true if ptr is a tagged pointer object.\n// Does not check the validity of ptr's class.\nstatic inline bool \n_objc_isTaggedPointer(const void * _Nullable ptr);\n\n// Extract the tag value from the given tagged pointer object.\n// Assumes ptr is a valid tagged pointer object.\n// Does not check the validity of ptr's tag.\nstatic inline objc_tag_index_t \n_objc_getTaggedPointerTag(const void * _Nullable ptr);\n\n// Extract the payload from the given tagged pointer object.\n// Assumes ptr is a valid tagged pointer object.\n// The payload value is zero-extended.\nstatic inline uintptr_t\n_objc_getTaggedPointerValue(const void * _Nullable ptr);\n\n// Extract the payload from the given tagged pointer object.\n// Assumes ptr is a valid tagged pointer object.\n// The payload value is sign-extended.\nstatic inline intptr_t\n_objc_getTaggedPointerSignedValue(const void * _Nullable ptr);\n\n// Don't use the values below. Use the declarations above.\n\n#if (TARGET_OS_OSX || TARGET_OS_IOSMAC) && __x86_64__\n    // 64-bit Mac - tag bit is LSB\n#   define OBJC_MSB_TAGGED_POINTERS 0\n#else\n    // Everything else - tag bit is MSB\n#   define OBJC_MSB_TAGGED_POINTERS 1\n#endif\n\n#define _OBJC_TAG_INDEX_MASK 0x7\n// array slot includes the tag bit itself\n#define _OBJC_TAG_SLOT_COUNT 16\n#define _OBJC_TAG_SLOT_MASK 0xf\n\n#define _OBJC_TAG_EXT_INDEX_MASK 0xff\n// array slot has no extra bits\n#define _OBJC_TAG_EXT_SLOT_COUNT 256\n#define _OBJC_TAG_EXT_SLOT_MASK 0xff\n\n#if OBJC_MSB_TAGGED_POINTERS\n#   define _OBJC_TAG_MASK (1UL<<63)\n#   define _OBJC_TAG_INDEX_SHIFT 60\n#   define _OBJC_TAG_SLOT_SHIFT 60\n#   define _OBJC_TAG_PAYLOAD_LSHIFT 4\n#   define _OBJC_TAG_PAYLOAD_RSHIFT 4\n#   define _OBJC_TAG_EXT_MASK (0xfUL<<60)\n#   define _OBJC_TAG_EXT_INDEX_SHIFT 52\n#   define _OBJC_TAG_EXT_SLOT_SHIFT 52\n#   define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 12\n#   define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12\n#else\n#   define _OBJC_TAG_MASK 1UL\n#   define _OBJC_TAG_INDEX_SHIFT 1\n#   define _OBJC_TAG_SLOT_SHIFT 0\n#   define _OBJC_TAG_PAYLOAD_LSHIFT 0\n#   define _OBJC_TAG_PAYLOAD_RSHIFT 4\n#   define _OBJC_TAG_EXT_MASK 0xfUL\n#   define _OBJC_TAG_EXT_INDEX_SHIFT 4\n#   define _OBJC_TAG_EXT_SLOT_SHIFT 4\n#   define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 0\n#   define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12\n#endif\n\nextern uintptr_t objc_debug_taggedpointer_obfuscator;\n\nstatic inline void * _Nonnull\n_objc_encodeTaggedPointer(uintptr_t ptr)\n{\n    return (void *)(objc_debug_taggedpointer_obfuscator ^ ptr);\n}\n\nstatic inline uintptr_t\n_objc_decodeTaggedPointer(const void * _Nullable ptr)\n{\n    return (uintptr_t)ptr ^ objc_debug_taggedpointer_obfuscator;\n}\n\nstatic inline bool \n_objc_taggedPointersEnabled(void)\n{\n    extern uintptr_t objc_debug_taggedpointer_mask;\n    return (objc_debug_taggedpointer_mask != 0);\n}\n\nstatic inline void * _Nonnull\n_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t value)\n{\n    // PAYLOAD_LSHIFT and PAYLOAD_RSHIFT are the payload extraction shifts.\n    // They are reversed here for payload insertion.\n\n    // assert(_objc_taggedPointersEnabled());\n    if (tag <= OBJC_TAG_Last60BitPayload) {\n        // assert(((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT) == value);\n        uintptr_t result =\n            (_OBJC_TAG_MASK | \n             ((uintptr_t)tag << _OBJC_TAG_INDEX_SHIFT) | \n             ((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT));\n        return _objc_encodeTaggedPointer(result);\n    } else {\n        // assert(tag >= OBJC_TAG_First52BitPayload);\n        // assert(tag <= OBJC_TAG_Last52BitPayload);\n        // assert(((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT) == value);\n        uintptr_t result =\n            (_OBJC_TAG_EXT_MASK |\n             ((uintptr_t)(tag - OBJC_TAG_First52BitPayload) << _OBJC_TAG_EXT_INDEX_SHIFT) |\n             ((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT));\n        return _objc_encodeTaggedPointer(result);\n    }\n}\n\nstatic inline bool \n_objc_isTaggedPointer(const void * _Nullable ptr)\n{\n    return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;\n}\n\nstatic inline objc_tag_index_t \n_objc_getTaggedPointerTag(const void * _Nullable ptr) \n{\n    // assert(_objc_isTaggedPointer(ptr));\n    uintptr_t value = _objc_decodeTaggedPointer(ptr);\n    uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;\n    uintptr_t extTag =   (value >> _OBJC_TAG_EXT_INDEX_SHIFT) & _OBJC_TAG_EXT_INDEX_MASK;\n    if (basicTag == _OBJC_TAG_INDEX_MASK) {\n        return (objc_tag_index_t)(extTag + OBJC_TAG_First52BitPayload);\n    } else {\n        return (objc_tag_index_t)basicTag;\n    }\n}\n\nstatic inline uintptr_t\n_objc_getTaggedPointerValue(const void * _Nullable ptr) \n{\n    // assert(_objc_isTaggedPointer(ptr));\n    uintptr_t value = _objc_decodeTaggedPointer(ptr);\n    uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;\n    if (basicTag == _OBJC_TAG_INDEX_MASK) {\n        return (value << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;\n    } else {\n        return (value << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT;\n    }\n}\n\nstatic inline intptr_t\n_objc_getTaggedPointerSignedValue(const void * _Nullable ptr) \n{\n    // assert(_objc_isTaggedPointer(ptr));\n    uintptr_t value = _objc_decodeTaggedPointer(ptr);\n    uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;\n    if (basicTag == _OBJC_TAG_INDEX_MASK) {\n        return ((intptr_t)value << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;\n    } else {\n        return ((intptr_t)value << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT;\n    }\n}\n\n// OBJC_HAVE_TAGGED_POINTERS\n#endif\n\n\n/**\n * Returns the method implementation of an object.\n *\n * @param obj An Objective-C object.\n * @param name An Objective-C selector.\n *\n * @return The IMP corresponding to the instance method implemented by\n * the class of \\e obj.\n * \n * @note Equivalent to:\n *\n * class_getMethodImplementation(object_getClass(obj), name);\n */\nOBJC_EXPORT IMP _Nonnull\nobject_getMethodImplementation(id _Nullable obj, SEL _Nonnull name)\n    OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT IMP _Nonnull\nobject_getMethodImplementation_stret(id _Nullable obj, SEL _Nonnull name)\n    OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n\n\n/**\n * Adds multiple methods to a class in bulk. This amortizes overhead that can be\n * expensive when adding methods one by one with class_addMethod.\n *\n * @param cls The class to which to add the methods.\n * @param names An array of selectors for the methods to add.\n * @param imps An array of functions which implement the new methods.\n * @param types An array of strings that describe the types of each method's\n *              arguments.\n * @param count The number of items in the names, imps, and types arrays.\n * @param outFiledCount Upon return, contains the number of failed selectors in\n *                      the returned array.\n *\n * @return A NULL-terminated C array of selectors which could not be added. A\n * method cannot be added when a method of that name already exists on that\n * class. When no failures occur, the return value is \\c NULL. When a non-NULL\n * value is returned, the caller must free the array with \\c free().\n *\n */\n#if __OBJC2__\nOBJC_EXPORT _Nullable SEL * _Nullable\nclass_addMethodsBulk(_Nullable Class cls, _Nonnull const SEL * _Nonnull names,\n                     _Nonnull const IMP * _Nonnull imps,\n                     const char * _Nonnull * _Nonnull types, uint32_t count,\n                     uint32_t * _Nullable outFailedCount)\n        OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);\n#endif\n\n/**\n * Replaces multiple methods in a class in bulk. This amortizes overhead that\n * can be expensive when adding methods one by one with class_replaceMethod.\n *\n * @param cls The class to modify.\n * @param names An array of selectors for the methods to replace.\n * @param imps An array of functions will be the new method implementantations.\n * @param types An array of strings that describe the types of each method's\n *              arguments.\n * @param count The number of items in the names, imps, and types arrays.\n */\n#if __OBJC2__\nOBJC_EXPORT void\nclass_replaceMethodsBulk(_Nullable Class cls,\n                         _Nonnull const SEL * _Nonnull names,\n                         _Nonnull const IMP * _Nonnull imps,\n                         const char * _Nonnull * _Nonnull types,\n                         uint32_t count)\n        OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);\n#endif\n\n\n// Instance-specific instance variable layout. This is no longer implemented.\n\nOBJC_EXPORT void\n_class_setIvarLayoutAccessor(Class _Nullable cls,\n                             const uint8_t* _Nullable (* _Nonnull accessor)\n                               (id _Nullable object))\n    UNAVAILABLE_ATTRIBUTE;\n\nOBJC_EXPORT const uint8_t * _Nullable\n_object_getIvarLayout(Class _Nullable cls, id _Nullable object)\n    UNAVAILABLE_ATTRIBUTE;\n\n\n/*\n  \"Unknown\" includes non-object ivars and non-ARC non-__weak ivars\n  \"Strong\" includes ARC __strong ivars\n  \"Weak\" includes ARC and new MRC __weak ivars\n  \"Unretained\" includes ARC __unsafe_unretained and old GC+MRC __weak ivars\n*/\ntypedef enum {\n    objc_ivar_memoryUnknown,     // unknown / unknown\n    objc_ivar_memoryStrong,      // direct access / objc_storeStrong\n    objc_ivar_memoryWeak,        // objc_loadWeak[Retained] / objc_storeWeak\n    objc_ivar_memoryUnretained   // direct access / direct access\n} objc_ivar_memory_management_t;\n\nOBJC_EXPORT objc_ivar_memory_management_t\n_class_getIvarMemoryManagement(Class _Nullable cls, Ivar _Nonnull ivar)\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\nOBJC_EXPORT BOOL _class_isFutureClass(Class _Nullable cls)\n    OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);\n\n\n// API to only be called by root classes like NSObject or NSProxy\n\nOBJC_EXPORT\nid _Nonnull\n_objc_rootRetain(id _Nonnull obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nvoid\n_objc_rootRelease(id _Nonnull obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nbool\n_objc_rootReleaseWasZero(id _Nonnull obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nbool\n_objc_rootTryRetain(id _Nonnull obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nbool\n_objc_rootIsDeallocating(id _Nonnull obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nid _Nonnull\n_objc_rootAutorelease(id _Nonnull obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nuintptr_t\n_objc_rootRetainCount(id _Nonnull obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nid _Nonnull\n_objc_rootInit(id _Nonnull obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nid _Nullable\n_objc_rootAllocWithZone(Class _Nonnull cls, malloc_zone_t * _Nullable zone)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nid _Nullable\n_objc_rootAlloc(Class _Nonnull cls)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nvoid\n_objc_rootDealloc(id _Nonnull obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nvoid\n_objc_rootFinalize(id _Nonnull obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nmalloc_zone_t * _Nonnull\n_objc_rootZone(id _Nonnull obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nuintptr_t\n_objc_rootHash(id _Nonnull obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nvoid * _Nonnull\nobjc_autoreleasePoolPush(void)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT\nvoid\nobjc_autoreleasePoolPop(void * _Nonnull context)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\n\nOBJC_EXPORT id _Nullable\nobjc_alloc(Class _Nullable cls)\n    OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT id _Nullable\nobjc_allocWithZone(Class _Nullable cls)\n    OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT id _Nullable\nobjc_retain(id _Nullable obj)\n    __asm__(\"_objc_retain\")\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_release(id _Nullable obj)\n    __asm__(\"_objc_release\")\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT id _Nullable\nobjc_autorelease(id _Nullable obj)\n    __asm__(\"_objc_autorelease\")\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\n// Prepare a value at +1 for return through a +0 autoreleasing convention.\nOBJC_EXPORT id _Nullable\nobjc_autoreleaseReturnValue(id _Nullable obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\n// Prepare a value at +0 for return through a +0 autoreleasing convention.\nOBJC_EXPORT id _Nullable\nobjc_retainAutoreleaseReturnValue(id _Nullable obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\n// Accept a value returned through a +0 autoreleasing convention for use at +1.\nOBJC_EXPORT id _Nullable\nobjc_retainAutoreleasedReturnValue(id _Nullable obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\n// Accept a value returned through a +0 autoreleasing convention for use at +0.\nOBJC_EXPORT id _Nullable\nobjc_unsafeClaimAutoreleasedReturnValue(id _Nullable obj)\n    OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_storeStrong(id _Nullable * _Nonnull location, id _Nullable obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT id _Nullable\nobjc_retainAutorelease(id _Nullable obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\n// obsolete.\nOBJC_EXPORT id _Nullable\nobjc_retain_autorelease(id _Nullable obj)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT id _Nullable\nobjc_loadWeakRetained(id _Nullable * _Nonnull location)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT id _Nullable \nobjc_initWeak(id _Nullable * _Nonnull location, id _Nullable val)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\n// Like objc_storeWeak, but stores nil if the new object is deallocating \n// or the new object's class does not support weak references.\n// Returns the value stored (either the new object or nil).\nOBJC_EXPORT id _Nullable\nobjc_storeWeakOrNil(id _Nullable * _Nonnull location, id _Nullable obj)\n    OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0, 2.0);\n\n// Like objc_initWeak, but stores nil if the new object is deallocating \n// or the new object's class does not support weak references.\n// Returns the value stored (either the new object or nil).\nOBJC_EXPORT id _Nullable\nobjc_initWeakOrNil(id _Nullable * _Nonnull location, id _Nullable val) \n    OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_destroyWeak(id _Nullable * _Nonnull location) \n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void \nobjc_copyWeak(id _Nullable * _Nonnull to, id _Nullable * _Nonnull from)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void \nobjc_moveWeak(id _Nullable * _Nonnull to, id _Nullable * _Nonnull from) \n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\n\nOBJC_EXPORT void\n_objc_autoreleasePoolPrint(void)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT BOOL\nobjc_should_deallocate(id _Nonnull object)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\nobjc_clear_deallocating(id _Nonnull object)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\n \n// to make CF link for now\n\nOBJC_EXPORT void * _Nonnull\n_objc_autoreleasePoolPush(void)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT void\n_objc_autoreleasePoolPop(void * _Nonnull context)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\n\n// Extra @encode data for XPC, or NULL\nOBJC_EXPORT const char * _Nullable\n_protocol_getMethodTypeEncoding(Protocol * _Nonnull proto, SEL _Nonnull sel,\n                                BOOL isRequiredMethod, BOOL isInstanceMethod)\n    OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);\n\n\n// API to only be called by classes that provide their own reference count storage\n\nOBJC_EXPORT void\n_objc_deallocOnMainThreadHelper(void * _Nullable context)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\n// On async versus sync deallocation and the _dealloc2main flag\n//\n// Theory:\n//\n// If order matters, then code must always: [self dealloc].\n// If order doesn't matter, then always async should be safe.\n//\n// Practice:\n//\n// The _dealloc2main bit is set for GUI objects that may be retained by other\n// threads. Once deallocation begins on the main thread, doing more async\n// deallocation will at best cause extra UI latency and at worst cause\n// use-after-free bugs in unretained delegate style patterns. Yes, this is\n// extremely fragile. Yes, in the long run, developers should switch to weak\n// references.\n//\n// Note is NOT safe to do any equality check against the result of\n// dispatch_get_current_queue(). The main thread can and does drain more than\n// one dispatch queue. That is why we call pthread_main_np().\n//\n\ntypedef enum {\n    _OBJC_RESURRECT_OBJECT = -1,        /* _logicBlock has called -retain, and scheduled a -release for later. */\n    _OBJC_DEALLOC_OBJECT_NOW = 1,       /* call [self dealloc] immediately. */\n    _OBJC_DEALLOC_OBJECT_LATER = 2      /* call [self dealloc] on the main queue. */\n} _objc_object_disposition_t;\n\n#define _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC_BLOCK(_rc_ivar, _logicBlock)        \\\n    -(id)retain {                                                               \\\n        /* this will fail to compile if _rc_ivar is an unsigned type */         \\\n        int _retain_count_ivar_must_not_be_unsigned[0L - (__typeof__(_rc_ivar))-1] __attribute__((unused)); \\\n        __typeof__(_rc_ivar) _prev = __sync_fetch_and_add(&_rc_ivar, 2);        \\\n        if (_prev < -2) { /* specifically allow resurrection from logical 0. */ \\\n            __builtin_trap(); /* BUG: retain of over-released ref */            \\\n        }                                                                       \\\n        return self;                                                            \\\n    }                                                                           \\\n    -(oneway void)release {                                                     \\\n        __typeof__(_rc_ivar) _prev = __sync_fetch_and_sub(&_rc_ivar, 2);        \\\n        if (_prev > 0) {                                                        \\\n            return;                                                             \\\n        } else if (_prev < 0) {                                                 \\\n            __builtin_trap(); /* BUG: over-release */                           \\\n        }                                                                       \\\n        _objc_object_disposition_t fate = _logicBlock(self);                    \\\n        if (fate == _OBJC_RESURRECT_OBJECT) {                                   \\\n            return;                                                             \\\n        }                                                                       \\\n        /* mark the object as deallocating. */                                  \\\n        if (!__sync_bool_compare_and_swap(&_rc_ivar, -2, 1)) {                  \\\n            __builtin_trap(); /* BUG: dangling ref did a retain */              \\\n        }                                                                       \\\n        if (fate == _OBJC_DEALLOC_OBJECT_NOW) {                                 \\\n            [self dealloc];                                                     \\\n        } else if (fate == _OBJC_DEALLOC_OBJECT_LATER) {                        \\\n            dispatch_barrier_async_f(dispatch_get_main_queue(), self,           \\\n                _objc_deallocOnMainThreadHelper);                               \\\n        } else {                                                                \\\n            __builtin_trap(); /* BUG: bogus fate value */                       \\\n        }                                                                       \\\n    }                                                                           \\\n    -(NSUInteger)retainCount {                                                  \\\n        return (_rc_ivar + 2) >> 1;                                             \\\n    }                                                                           \\\n    -(BOOL)_tryRetain {                                                         \\\n        __typeof__(_rc_ivar) _prev;                                             \\\n        do {                                                                    \\\n            _prev = _rc_ivar;                                                   \\\n            if (_prev & 1) {                                                    \\\n                return 0;                                                       \\\n            } else if (_prev == -2) {                                           \\\n                return 0;                                                       \\\n            } else if (_prev < -2) {                                            \\\n                __builtin_trap(); /* BUG: over-release elsewhere */             \\\n            }                                                                   \\\n        } while ( ! __sync_bool_compare_and_swap(&_rc_ivar, _prev, _prev + 2)); \\\n        return 1;                                                               \\\n    }                                                                           \\\n    -(BOOL)_isDeallocating {                                                    \\\n        if (_rc_ivar == -2) {                                                   \\\n            return 1;                                                           \\\n        } else if (_rc_ivar < -2) {                                             \\\n            __builtin_trap(); /* BUG: over-release elsewhere */                 \\\n        }                                                                       \\\n        return _rc_ivar & 1;                                                    \\\n    }\n\n#define _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, _dealloc2main)            \\\n    _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC_BLOCK(_rc_ivar, (^(id _self_ __attribute__((unused))) { \\\n        if (_dealloc2main && !pthread_main_np()) {                              \\\n            return _OBJC_DEALLOC_OBJECT_LATER;                                  \\\n        } else {                                                                \\\n            return _OBJC_DEALLOC_OBJECT_NOW;                                    \\\n        }                                                                       \\\n    }))\n\n#define _OBJC_SUPPORTED_INLINE_REFCNT(_rc_ivar) _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, 0)\n#define _OBJC_SUPPORTED_INLINE_REFCNT_WITH_DEALLOC2MAIN(_rc_ivar) _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, 1)\n\n__END_DECLS\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-layout.mm",
    "content": "/*\n * Copyright (c) 2004-2008 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include <stdlib.h>\n#include <assert.h>\n\n#include \"objc-private.h\"\n\n/**********************************************************************\n* Object Layouts.\n*\n* Layouts are used by the garbage collector to identify references from\n* the object to other objects.\n* \n* Layout information is in the form of a '\\0' terminated byte string. \n* Each byte contains a word skip count in the high nibble and a\n* consecutive references count in the low nibble. Counts that exceed 15 are\n* continued in the succeeding byte with a zero in the opposite nibble. \n* Objects that should be scanned conservatively will have a NULL layout.\n* Objects that have no references have a empty byte string.\n*\n* Example;\n* \n*   For a class with pointers at offsets 4,12, 16, 32-128\n*   the layout is { 0x11, 0x12, 0x3f, 0x0a, 0x00 } or\n*       skip 1 - 1 reference (4)\n*       skip 1 - 2 references (12, 16)\n*       skip 3 - 15 references (32-88)\n*       no skip - 10 references (92-128)\n*       end\n* \n**********************************************************************/\n\n\n/**********************************************************************\n* compress_layout\n* Allocates and returns a compressed string matching the given layout bitmap.\n**********************************************************************/\nstatic unsigned char *\ncompress_layout(const uint8_t *bits, size_t bitmap_bits, bool weak)\n{\n    bool all_set = YES;\n    bool none_set = YES;\n    unsigned char *result;\n\n    // overallocate a lot; reallocate at correct size later\n    unsigned char * const layout = (unsigned char *)\n        calloc(bitmap_bits + 1, 1);\n    unsigned char *l = layout;\n\n    size_t i = 0;\n    while (i < bitmap_bits) {\n        size_t skip = 0;\n        size_t scan = 0;\n\n        // Count one range each of skip and scan.\n        while (i < bitmap_bits) {\n            uint8_t bit = (uint8_t)((bits[i/8] >> (i % 8)) & 1);\n            if (bit) break;\n            i++;\n            skip++;\n        }\n        while (i < bitmap_bits) {\n            uint8_t bit = (uint8_t)((bits[i/8] >> (i % 8)) & 1);\n            if (!bit) break;\n            i++;\n            scan++;\n            none_set = NO;\n        }\n\n        // Record skip and scan\n        if (skip) all_set = NO;\n        if (scan) none_set = NO;\n        while (skip > 0xf) {\n            *l++ = 0xf0;\n            skip -= 0xf;\n        }\n        if (skip || scan) {\n            *l = (uint8_t)(skip << 4);    // NOT incremented - merges with scan\n            while (scan > 0xf) {\n                *l++ |= 0x0f;  // May merge with short skip; must calloc\n                scan -= 0xf;\n            }\n            *l++ |= scan;      // NOT checked for zero - always increments\n                               // May merge with short skip; must calloc\n        }\n    }\n    \n    // insert terminating byte\n    *l++ = '\\0';\n    \n    // return result\n    if (none_set  &&  weak) {\n        result = NULL;  // NULL weak layout means none-weak\n    } else if (all_set  &&  !weak) {\n        result = NULL;  // NULL ivar layout means all-scanned\n    } else {\n        result = (unsigned char *)strdup((char *)layout); \n    }\n    free(layout);\n    return result;\n}\n\n\nstatic void set_bits(layout_bitmap bits, size_t which, size_t count)\n{\n    // fixme optimize for byte/word at a time\n    size_t bit;\n    for (bit = which; bit < which + count  &&  bit < bits.bitCount; bit++) {\n        bits.bits[bit/8] |= 1 << (bit % 8);\n    }\n    if (bit == bits.bitCount  &&  bit < which + count) {\n        // couldn't fit full type in bitmap\n        _objc_fatal(\"layout bitmap too short\");\n    }\n}\n\nstatic void clear_bits(layout_bitmap bits, size_t which, size_t count)\n{\n    // fixme optimize for byte/word at a time\n    size_t bit;\n    for (bit = which; bit < which + count  &&  bit < bits.bitCount; bit++) {\n        bits.bits[bit/8] &= ~(1 << (bit % 8));\n    }\n    if (bit == bits.bitCount  &&  bit < which + count) {\n        // couldn't fit full type in bitmap\n        _objc_fatal(\"layout bitmap too short\");\n    }\n}\n\nstatic void move_bits(layout_bitmap bits, size_t src, size_t dst, \n                      size_t count)\n{\n    // fixme optimize for byte/word at a time\n\n    if (dst == src) {\n        return;\n    }\n    else if (dst > src) {\n        // Copy backwards in case of overlap\n        size_t pos = count;\n        while (pos--) {\n            size_t srcbit = src + pos;\n            size_t dstbit = dst + pos;\n            if (bits.bits[srcbit/8] & (1 << (srcbit % 8))) {\n                bits.bits[dstbit/8] |= 1 << (dstbit % 8);\n            } else {\n                bits.bits[dstbit/8] &= ~(1 << (dstbit % 8));\n            }\n        }\n    }\n    else {\n        // Copy forwards in case of overlap\n        size_t pos;\n        for (pos = 0; pos < count; pos++) {\n            size_t srcbit = src + pos;\n            size_t dstbit = dst + pos;\n            if (bits.bits[srcbit/8] & (1 << (srcbit % 8))) {\n                bits.bits[dstbit/8] |= 1 << (dstbit % 8);\n            } else {\n                bits.bits[dstbit/8] &= ~(1 << (dstbit % 8));\n            }\n        }\n    }\n}\n\n// emacs autoindent hack - it doesn't like the loop in set_bits/clear_bits\n#if 0\n} }\n#endif\n\n\nstatic void decompress_layout(const unsigned char *layout_string, layout_bitmap bits)\n{\n    unsigned char c;\n    size_t bit = 0;\n    while ((c = *layout_string++)) {\n        unsigned char skip = (c & 0xf0) >> 4;\n        unsigned char scan = (c & 0x0f);\n        bit += skip;\n        set_bits(bits, bit, scan);\n        bit += scan;\n    }\n}\n\n\n/***********************************************************************\n* layout_bitmap_create\n* Allocate a layout bitmap.\n* The new bitmap spans the given instance size bytes.\n* The start of the bitmap is filled from the given layout string (which \n*   spans an instance size of layoutStringSize); the rest is zero-filled.\n* The returned bitmap must be freed with layout_bitmap_free().\n**********************************************************************/\nlayout_bitmap \nlayout_bitmap_create(const unsigned char *layout_string,\n                     size_t layoutStringInstanceSize, \n                     size_t instanceSize, bool weak)\n{\n    layout_bitmap result;\n    size_t words = instanceSize / sizeof(id);\n    \n    result.weak = weak;\n    result.bitCount = words;\n    result.bitsAllocated = words;\n    result.bits = (uint8_t *)calloc((words+7)/8, 1);\n\n    if (!layout_string) {\n        if (!weak) {\n            // NULL ivar layout means all-scanned\n            // (but only up to layoutStringSize instance size)\n            set_bits(result, 0, layoutStringInstanceSize/sizeof(id));\n        } else {\n            // NULL weak layout means none-weak.\n        }\n    } else {\n        decompress_layout(layout_string, result);\n    }\n\n    return result;\n}\n\n\n/***********************************************************************\n * layout_bitmap_create_empty\n * Allocate a layout bitmap.\n * The new bitmap spans the given instance size bytes.\n * The bitmap is empty, to represent an object whose ivars are completely unscanned.\n * The returned bitmap must be freed with layout_bitmap_free().\n **********************************************************************/\nlayout_bitmap\nlayout_bitmap_create_empty(size_t instanceSize, bool weak)\n{\n    layout_bitmap result;\n    size_t words = instanceSize / sizeof(id);\n    \n    result.weak = weak;\n    result.bitCount = words;\n    result.bitsAllocated = words;\n    result.bits = (uint8_t *)calloc((words+7)/8, 1);\n\n    return result;\n}\n\nvoid \nlayout_bitmap_free(layout_bitmap bits)\n{\n    if (bits.bits) free(bits.bits);\n}\n\nconst unsigned char * \nlayout_string_create(layout_bitmap bits)\n{\n    const unsigned char *result =\n        compress_layout(bits.bits, bits.bitCount, bits.weak);\n\n#if DEBUG\n    // paranoia: cycle to bitmap and back to string again, and compare\n    layout_bitmap check = layout_bitmap_create(result, bits.bitCount*sizeof(id), \n                                               bits.bitCount*sizeof(id), bits.weak);\n    unsigned char *result2 = \n        compress_layout(check.bits, check.bitCount, check.weak);\n    if (result != result2  &&  0 != strcmp((char*)result, (char *)result2)) {\n        layout_bitmap_print(bits);\n        layout_bitmap_print(check);\n        _objc_fatal(\"libobjc bug: mishandled layout bitmap\");\n    }\n    free(result2);\n    layout_bitmap_free(check);\n#endif\n\n    return result;\n}\n\n\nvoid\nlayout_bitmap_set_ivar(layout_bitmap bits, const char *type, size_t offset)\n{\n    // fixme only handles some types\n    size_t bit = offset / sizeof(id);\n\n    if (!type) return;\n    if (type[0] == '@'  ||  0 == strcmp(type, \"^@\")) {\n        // id\n        // id *\n        // Block (\"@?\")\n        set_bits(bits, bit, 1);\n    } \n    else if (type[0] == '[') {\n        // id[]\n        char *t;\n        unsigned long count = strtoul(type+1, &t, 10);\n        if (t  &&  t[0] == '@') {\n            set_bits(bits, bit, count);\n        }\n    } \n    else if (strchr(type, '@')) {\n        _objc_inform(\"warning: failing to set GC layout for '%s'\\n\", type);\n    }\n}\n\n\n\n/***********************************************************************\n* layout_bitmap_grow\n* Expand a layout bitmap to span newCount bits. \n* The new bits are undefined.\n**********************************************************************/\nvoid \nlayout_bitmap_grow(layout_bitmap *bits, size_t newCount)\n{\n    if (bits->bitCount >= newCount) return;\n    bits->bitCount = newCount;\n    if (bits->bitsAllocated < newCount) {\n        size_t newAllocated = bits->bitsAllocated * 2;\n        if (newAllocated < newCount) newAllocated = newCount;\n        bits->bits = (uint8_t *)\n            realloc(bits->bits, (newAllocated+7) / 8);\n        bits->bitsAllocated = newAllocated;\n    }\n    assert(bits->bitsAllocated >= bits->bitCount);\n    assert(bits->bitsAllocated >= newCount);\n}\n\n\n/***********************************************************************\n* layout_bitmap_slide\n* Slide the end of a layout bitmap farther from the start.\n* Slides bits [oldPos, bits.bitCount) to [newPos, bits.bitCount+newPos-oldPos)\n* Bits [oldPos, newPos) are zero-filled.\n* The bitmap is expanded and bitCount updated if necessary.\n* newPos >= oldPos.\n**********************************************************************/\nvoid\nlayout_bitmap_slide(layout_bitmap *bits, size_t oldPos, size_t newPos)\n{\n    size_t shift;\n    size_t count;\n\n    if (oldPos == newPos) return;\n    if (oldPos > newPos) _objc_fatal(\"layout bitmap sliding backwards\");\n\n    shift = newPos - oldPos;\n    count = bits->bitCount - oldPos;\n    layout_bitmap_grow(bits, bits->bitCount + shift);\n    move_bits(*bits, oldPos, newPos, count);  // slide\n    clear_bits(*bits, oldPos, shift);         // zero-fill\n}\n\n\n/***********************************************************************\n* layout_bitmap_slide_anywhere\n* Slide the end of a layout bitmap relative to the start.\n* Like layout_bitmap_slide, but can slide backwards too.\n* The end of the bitmap is truncated.\n**********************************************************************/\nvoid\nlayout_bitmap_slide_anywhere(layout_bitmap *bits, size_t oldPos, size_t newPos)\n{\n    size_t shift;\n    size_t count;\n\n    if (oldPos == newPos) return;\n\n    if (oldPos < newPos) {\n        layout_bitmap_slide(bits, oldPos, newPos);\n        return;\n    } \n\n    shift = oldPos - newPos;\n    count = bits->bitCount - oldPos;\n    move_bits(*bits, oldPos, newPos, count);  // slide\n    bits->bitCount -= shift;\n}\n\n\n/***********************************************************************\n* layout_bitmap_splat\n* Pastes the contents of bitmap src to the start of bitmap dst.\n* dst bits between the end of src and oldSrcInstanceSize are zeroed.\n* dst must be at least as long as src.\n* Returns YES if any of dst's bits were changed.\n**********************************************************************/\nbool\nlayout_bitmap_splat(layout_bitmap dst, layout_bitmap src, \n                    size_t oldSrcInstanceSize)\n{\n    bool changed;\n    size_t oldSrcBitCount;\n    size_t bit;\n\n    if (dst.bitCount < src.bitCount) _objc_fatal(\"layout bitmap too short\");\n\n    changed = NO;\n    oldSrcBitCount = oldSrcInstanceSize / sizeof(id);\n    \n    // fixme optimize for byte/word at a time\n    for (bit = 0; bit < oldSrcBitCount; bit++) {\n        int dstset = dst.bits[bit/8] & (1 << (bit % 8));\n        int srcset = (bit < src.bitCount) \n            ? src.bits[bit/8] & (1 << (bit % 8))\n            : 0;\n        if (dstset != srcset) {\n            changed = YES;\n            if (srcset) {\n                dst.bits[bit/8] |= 1 << (bit % 8);\n            } else {\n                dst.bits[bit/8] &= ~(1 << (bit % 8));\n            }\n        }\n    }\n\n    return changed;\n}\n\n\n/***********************************************************************\n* layout_bitmap_or\n* Set dst=dst|src.\n* dst must be at least as long as src.\n* Returns YES if any of dst's bits were changed.\n**********************************************************************/\nbool\nlayout_bitmap_or(layout_bitmap dst, layout_bitmap src, const char *msg)\n{\n    bool changed = NO;\n    size_t bit;\n\n    if (dst.bitCount < src.bitCount) {\n        _objc_fatal(\"layout_bitmap_or: layout bitmap too short%s%s\", \n                    msg ? \": \" : \"\", msg ? msg : \"\");\n    }\n    \n    // fixme optimize for byte/word at a time\n    for (bit = 0; bit < src.bitCount; bit++) {\n        int dstset = dst.bits[bit/8] & (1 << (bit % 8));\n        int srcset = src.bits[bit/8] & (1 << (bit % 8));\n        if (srcset  &&  !dstset) {\n            changed = YES;\n            dst.bits[bit/8] |= 1 << (bit % 8);\n        }\n    }\n\n    return changed;\n}\n\n\n/***********************************************************************\n* layout_bitmap_clear\n* Set dst=dst&~src.\n* dst must be at least as long as src.\n* Returns YES if any of dst's bits were changed.\n**********************************************************************/\nbool\nlayout_bitmap_clear(layout_bitmap dst, layout_bitmap src, const char *msg)\n{\n    bool changed = NO;\n    size_t bit;\n\n    if (dst.bitCount < src.bitCount) {\n        _objc_fatal(\"layout_bitmap_clear: layout bitmap too short%s%s\", \n                    msg ? \": \" : \"\", msg ? msg : \"\");\n    }\n    \n    // fixme optimize for byte/word at a time\n    for (bit = 0; bit < src.bitCount; bit++) {\n        int dstset = dst.bits[bit/8] & (1 << (bit % 8));\n        int srcset = src.bits[bit/8] & (1 << (bit % 8));\n        if (srcset  &&  dstset) {\n            changed = YES;\n            dst.bits[bit/8] &= ~(1 << (bit % 8));\n        }\n    }\n\n    return changed;\n}\n\n\nvoid\nlayout_bitmap_print(layout_bitmap bits)\n{\n    size_t i;\n    printf(\"%zu: \", bits.bitCount);\n    for (i = 0; i < bits.bitCount; i++) {\n        int set = bits.bits[i/8] & (1 << (i % 8));\n        printf(\"%c\", set ? '#' : '.');\n    }\n    printf(\"\\n\");\n}\n\n#if 0\n// The code below may be useful when interpreting ivar types more precisely.\n\n/**********************************************************************\n* mark_offset_for_layout\n*\n* Marks the appropriate bit in the bits array cooresponding to a the\n* offset of a reference.  If we are scanning a nested pointer structure\n* then the bits array will be NULL then this function does nothing.  \n* \n**********************************************************************/\nstatic void mark_offset_for_layout(long offset, long bits_size, unsigned char *bits) {\n    // references are ignored if bits is NULL\n    if (bits) {\n        long slot = offset / sizeof(long);\n        \n        // determine byte index using (offset / 8 bits per byte)\n        long i_byte = slot >> 3;\n        \n        // if the byte index is valid \n        if (i_byte < bits_size) {\n            // set the (offset / 8 bits per byte)th bit\n            bits[i_byte] |= 1 << (slot & 7);\n        } else {\n            // offset not within instance size\n            _objc_inform (\"layout - offset exceeds instance size\");\n        }\n    }\n}\n\n/**********************************************************************\n* skip_ivar_type_name\n*\n* Skip over the name of a field/class in an ivar type string.  Names\n* are in the form of a double-quoted string.  Returns the remaining\n* string.\n*\n**********************************************************************/\nstatic char *skip_ivar_type_name(char *type) {\n    // current character\n    char ch;\n    \n    // if there is an open quote\n    if (*type == '\\\"') {\n        // skip quote\n        type++;\n        \n        // while no closing quote\n        while ((ch = *type) != '\\\"') {\n            // if end of string return end of string\n            if (!ch) return type;\n            \n            // skip character\n            type++;\n        }\n        \n        // skip closing quote\n        type++;\n    }\n    \n    // return remaining string\n    return type;\n}\n\n\n/**********************************************************************\n* skip_ivar_struct_name\n*\n* Skip over the name of a struct in an ivar type string.  Names\n* may be followed by an equals sign.  Returns the remaining string.\n*\n**********************************************************************/\nstatic char *skip_ivar_struct_name(char *type) {\n    // get first character\n    char ch = *type;\n    \n    if (ch == _C_UNDEF) {\n        // skip undefined name \n        type++;\n    } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_') {\n        // if alphabetic\n        \n        // scan alphanumerics\n        do {\n            // next character\n            ch = *++type;\n        } while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_' || (ch >= '0' && ch <= '9'));\n    } else {\n        // no struct name present\n        return type;\n    }\n    \n    // skip equals sign\n    if (*type == '=') type++;\n    \n    return type;\n}\n\n\n/**********************************************************************\n* scan_basic_ivar_type\n* \n* Determines the size and alignment of a basic ivar type.  If the basic\n* type is a possible reference to another garbage collected type the \n* is_reference is set to true (false otherwise.)  Returns the remaining\n* string.\n* \n**********************************************************************/\nstatic char *scan_ivar_type_for_layout(char *type, long offset, long bits_size, unsigned char *bits, long *next_offset);\nstatic char *scan_basic_ivar_type(char *type, long *size, long *alignment, bool *is_reference) {\n    // assume it is a non-reference type\n    *is_reference = NO;\n    \n    // get the first character (advancing string)\n    const char *full_type = type;\n    char ch = *type++;\n    \n    // GCC 4 uses for const type*.\n    if (ch == _C_CONST) ch = *type++;\n    \n    // act on first character\n    switch (ch) {\n        case _C_ID: {\n            // ID type\n            \n            // skip over optional class name\n            type = skip_ivar_type_name(type);\n            \n            // size and alignment of an id type\n            *size = sizeof(id);\n            *alignment = __alignof(id);\n            \n            // is a reference type\n            *is_reference = YES;\n            break;\n        }        \n        case _C_PTR: {\n            // C pointer type\n            \n            // skip underlying type\n            long ignored_offset;\n            type = scan_ivar_type_for_layout(type, 0, 0, NULL, &ignored_offset);\n            \n            // size and alignment of a generic pointer type\n            *size = sizeof(void *);\n            *alignment = __alignof(void *);\n            \n            // is a reference type\n            *is_reference = YES;\n            break;\n        }\n        case _C_CHARPTR: {\n            // C string \n            \n           // size and alignment of a char pointer type\n            *size = sizeof(char *);\n            *alignment = __alignof(char *);\n            \n            // is a reference type\n            *is_reference = YES;\n            break;\n        }\n        case _C_CLASS:\n        case _C_SEL: {\n            // classes and selectors are ignored for now\n            *size = sizeof(void *);\n            *alignment = __alignof(void *);\n            break;\n        }\n        case _C_CHR:\n        case _C_UCHR: {\n            // char and unsigned char\n            *size = sizeof(char);\n            *alignment = __alignof(char);\n            break;\n        }\n        case _C_SHT:\n        case _C_USHT: {\n            // short and unsigned short\n            *size = sizeof(short);\n            *alignment = __alignof(short);\n            break;\n        }\n        case _C_ATOM:\n        case _C_INT:\n        case _C_UINT: {\n            // int and unsigned int\n            *size = sizeof(int);\n            *alignment = __alignof(int);\n            break;\n        }\n        case _C_LNG:\n        case _C_ULNG: {\n            // long and unsigned long\n            *size = sizeof(long);\n            *alignment = __alignof(long);\n            break;\n        }\n        case _C_LNG_LNG:\n        case _C_ULNG_LNG: {\n            // long long and unsigned long long\n            *size = sizeof(long long);\n            *alignment = __alignof(long long);\n            break;\n        }\n        case _C_VECTOR: {\n            // vector\n            *size = 16;\n            *alignment = 16;\n            break;\n        }\n        case _C_FLT: {\n            // float\n            *size = sizeof(float);\n            *alignment = __alignof(float);\n            break;\n        }\n        case _C_DBL: {\n            // double\n            *size = sizeof(double);\n            *alignment = __alignof(double);\n            break;\n        }\n        case _C_BFLD: {\n            // bit field\n            \n            // get number of bits in bit field (advance type string)\n            long lng = strtol(type, &type, 10);\n            \n            // while next type is a bit field\n            while (*type == _C_BFLD) {\n                // skip over _C_BFLD\n                type++;\n                \n                // get next bit field length\n                long next_lng = strtol(type, &type, 10);\n                \n                // if spans next word then align to next word\n                if ((lng & ~31) != ((lng + next_lng) & ~31)) lng = (lng + 31) & ~31;\n                \n                // increment running length\n                lng += next_lng;\n                \n                // skip over potential field name\n                type = skip_ivar_type_name(type);\n            }\n            \n            // determine number of bytes bits represent\n            *size = (lng + 7) / 8;\n            \n            // byte alignment\n            *alignment = __alignof(char);\n            break;\n        }\n        case _C_BOOL: {\n            // double\n            *size = sizeof(BOOL);\n            *alignment = __alignof(BOOL);\n            break;\n        }\n        case _C_VOID: {\n            // skip void types\n            *size = 0;\n            *alignment = __alignof(char);\n            break;\n        }\n        case _C_UNDEF: {\n            *size = 0;\n            *alignment = __alignof(char);\n            break;\n        }\n        default: {\n            // unhandled type\n            _objc_fatal(\"unrecognized character \\'%c\\' in ivar type: \\\"%s\\\"\", ch, full_type);\n        }\n    }\n    \n    return type;\n}\n\n\n/**********************************************************************\n* scan_ivar_type_for_layout\n*\n* Scan an ivar type string looking for references.  The offset indicates\n* where the ivar begins.  bits is a byte array of size bits_size used to\n* contain the references bit map.  next_offset is the offset beyond the\n* ivar.  Returns the remaining string.\n*\n**********************************************************************/\nstatic char *scan_ivar_type_for_layout(char *type, long offset, long bits_size, unsigned char *bits, long *next_offset) {\n    long size;                                   // size of a basic type\n    long alignment;                              // alignment of the basic type\n    bool is_reference;                      // true if the type indicates a reference to a garbage collected object\n    \n    // get the first character\n    char ch = *type;\n\n    // GCC 4 uses for const type*.\n    if (ch == _C_CONST) ch = *++type;\n    \n    // act on first character\n    switch (ch) {\n        case _C_ARY_B: {\n            // array type\n            \n            // get the array length\n            long lng = strtol(type + 1, &type, 10);\n            \n            // next type will be where to advance the type string once the array is processed\n            char *next_type = type;\n           \n            // repeat the next type x lng\n            if (!lng) {\n                next_type = scan_ivar_type_for_layout(type, 0, 0, NULL, &offset);\n            } else {\n                while (lng--) {\n                    // repeatedly scan the same type\n                    next_type = scan_ivar_type_for_layout(type, offset, bits_size, bits, &offset);\n                }\n            }\n            \n            // advance the type now\n            type = next_type;\n            \n            // after the end of the array\n            *next_offset = offset;\n            \n            // advance over closing bracket\n            if (*type == _C_ARY_E) type++;\n            else                   _objc_inform(\"missing \\'%c\\' in ivar type.\", _C_ARY_E);\n            \n            break;\n        }\n        case _C_UNION_B: {\n            // union type\n            \n            // skip over possible union name\n            type = skip_ivar_struct_name(type + 1); \n            \n            // need to accumulate the maximum element offset\n            long max_offset = 0;\n        \n            // while not closing paren\n            while ((ch = *type) && ch != _C_UNION_E) {\n                // skip over potential field name\n                type = skip_ivar_type_name(type);\n                \n                // scan type\n                long union_offset;\n                type = scan_ivar_type_for_layout(type, offset, bits_size, bits, &union_offset);\n                \n                // adjust the maximum element offset\n                if (max_offset < union_offset) max_offset = union_offset;\n            }\n        \n            // after the largest element \n            *next_offset = max_offset;\n            \n            // advance over closing paren\n            if (ch == _C_UNION_E) {\n              type++;\n            } else {\n              _objc_inform(\"missing \\'%c\\' in ivar type\", _C_UNION_E);\n            }\n            \n            break;\n        }\n        case _C_STRUCT_B: {\n            // struct type\n            \n            // skip over possible struct name\n            type = skip_ivar_struct_name(type + 1); \n            \n            // while not closing brace\n            while ((ch = *type) && ch != _C_STRUCT_E) {\n                // skip over potential field name\n                type = skip_ivar_type_name(type);\n                \n                // scan type\n                type = scan_ivar_type_for_layout(type, offset, bits_size, bits, &offset);\n            }\n            \n            // after the end of the struct\n            *next_offset = offset;\n            \n            // advance over closing brace\n            if (ch == _C_STRUCT_E) type++;\n            else                   _objc_inform(\"missing \\'%c\\' in ivar type\", _C_STRUCT_E);\n            \n            break;\n        }\n        default: {\n            // basic type\n            \n            // scan type\n            type = scan_basic_ivar_type(type, &size, &alignment, &is_reference);\n            \n            // create alignment mask\n            alignment--; \n            \n            // align offset\n            offset = (offset + alignment) & ~alignment;\n            \n            // if is a reference then mark in the bit map\n            if (is_reference) mark_offset_for_layout(offset, bits_size, bits);\n            \n            // after the basic type\n            *next_offset = offset + size;\n            break;\n        }\n    }\n    \n    // return remainder of type string\n    return type;\n}\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-load.h",
    "content": "/*\n * Copyright (c) 1999-2001, 2005-2006 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\n *\tobjc-load.h\n *\tCopyright 1988-1996, NeXT Software, Inc.\n */\n\n#ifndef _OBJC_LOAD_H_\n#define _OBJC_LOAD_H_\n\n#include <objc/objc-class.h>\n\n#include <mach-o/loader.h>\n\n/* dynamically loading Mach-O object files that contain Objective-C code */\n\nOBJC_EXPORT long objc_loadModules (\n\tchar * _Nullable modlist[_Nullable], \n\tvoid * _Nullable errStream,\n\tvoid (* _Nullable class_callback) (Class _Nullable, Category _Nullable),\n\t/*headerType*/ struct mach_header * _Nullable * _Nullable hdr_addr,\n\tchar * _Nullable debug_file\n) OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT int objc_loadModule (\n\tchar * _Nullable moduleName, \n\tvoid\t(* _Nullable class_callback) (Class _Nullable, Category _Nullable),\n\tint * _Nullable errorCode\n) OBJC2_UNAVAILABLE;\nOBJC_EXPORT long objc_unloadModules(\n\tvoid * _Nullable errorStream,\t\t\t\t/* input (optional) */\n\tvoid (* _Nullable unloadCallback)(Class _Nullable, Category _Nullable)\t\t/* input (optional) */\n) OBJC2_UNAVAILABLE;\n\n#endif /* _OBJC_LOAD_H_ */\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-load.mm",
    "content": "/*\n * Copyright (c) 1999-2001, 2004-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/*\n *\tobjc-load.m\n *\tCopyright 1988-1996, NeXT Software, Inc.\n *\tAuthor:\ts. naroff\n *\n */\n\n#include \"objc-private.h\"\n#include \"objc-load.h\"\n\n#if !__OBJC2__  &&  !TARGET_OS_WIN32\n\nextern void (*callbackFunction)( Class, Category );\n\n\n/**********************************************************************************\n* objc_loadModule.\n*\n* NOTE: Loading isn't really thread safe.  If a load message recursively calls\n* objc_loadModules() both sets will be loaded correctly, but if the original\n* caller calls objc_unloadModules() it will probably unload the wrong modules.\n* If a load message calls objc_unloadModules(), then it will unload\n* the modules currently being loaded, which will probably cause a crash.\n*\n* Error handling is still somewhat crude.  If we encounter errors while\n* linking up classes or categories, we will not recover correctly.\n*\n* I removed attempts to lock the class hashtable, since this introduced\n* deadlock which was hard to remove.  The only way you can get into trouble\n* is if one thread loads a module while another thread tries to access the\n* loaded classes (using objc_lookUpClass) before the load is complete.\n**********************************************************************************/\nint objc_loadModule(char *moduleName, void (*class_callback) (Class, Category), int *errorCode)\n{\n    int\t\t\t\t\t\t\t\tsuccessFlag = 1;\n    int\t\t\t\t\t\t\t\tlocErrorCode;\n    NSObjectFileImage\t\t\t\tobjectFileImage;\n    NSObjectFileImageReturnCode\t\tcode;\n\n    // So we don't have to check this everywhere\n    if (errorCode == NULL)\n        errorCode = &locErrorCode;\n\n    if (moduleName == NULL)\n    {\n        *errorCode = NSObjectFileImageInappropriateFile;\n        return 0;\n    }\n\n    if (_dyld_present () == 0)\n    {\n        *errorCode = NSObjectFileImageFailure;\n        return 0;\n    }\n\n    callbackFunction = class_callback;\n    code = NSCreateObjectFileImageFromFile (moduleName, &objectFileImage);\n    if (code != NSObjectFileImageSuccess)\n    {\n        *errorCode = code;\n        return 0;\n    }\n\n    if (NSLinkModule(objectFileImage, moduleName, NSLINKMODULE_OPTION_RETURN_ON_ERROR) == NULL) {\n        NSLinkEditErrors error;\n        int errorNum;\n        const char *fileName, *errorString;\n        NSLinkEditError(&error, &errorNum, &fileName, &errorString);\n        // These errors may overlap with other errors that objc_loadModule returns in other failure cases.\n        *errorCode = error;\n        return 0;\n    }\n    callbackFunction = NULL;\n\n\n    return successFlag;\n}\n\n/**********************************************************************************\n* objc_loadModules.\n**********************************************************************************/\n/* Lock for dynamic loading and unloading. */\n//\tstatic OBJC_DECLARE_LOCK (loadLock);\n\n\nlong\tobjc_loadModules   (char *\t\t\tmodlist[],\n                         void *\t\t\terrStream,\n                         void\t\t\t(*class_callback) (Class, Category),\n                         headerType **\thdr_addr,\n                         char *\t\t\tdebug_file)\n{\n    char **\t\t\t\tmodules;\n    int\t\t\t\t\tcode;\n    int\t\t\t\t\titWorked;\n\n    if (modlist == 0)\n        return 0;\n\n    for (modules = &modlist[0]; *modules != 0; modules++)\n    {\n        itWorked = objc_loadModule (*modules, class_callback, &code);\n        if (itWorked == 0)\n        {\n            //if (errStream)\n            //\tNXPrintf ((NXStream *) errStream, \"objc_loadModules(%s) code = %d\\n\", *modules, code);\n            return 1;\n        }\n\n        if (hdr_addr)\n            *(hdr_addr++) = 0;\n    }\n\n    return 0;\n}\n\n/**********************************************************************************\n* objc_unloadModules.\n*\n* NOTE:  Unloading isn't really thread safe.  If an unload message calls\n* objc_loadModules() or objc_unloadModules(), then the current call\n* to objc_unloadModules() will probably unload the wrong stuff.\n**********************************************************************************/\n\nlong\tobjc_unloadModules (void *\t\t\terrStream,\n                         void\t\t\t(*unload_callback) (Class, Category))\n{\n    headerType *\theader_addr = 0;\n    int errflag = 0;\n\n    // TODO: to make unloading work, should get the current header\n\n    if (header_addr)\n    {\n        ; // TODO: unload the current header\n    }\n    else\n    {\n        errflag = 1;\n    }\n\n    return errflag;\n}\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-loadmethod.h",
    "content": "/*\n * Copyright (c) 2004-2006 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-loadmethod.h\n* Support for +load methods.\n**********************************************************************/\n\n#ifndef _OBJC_LOADMETHOD_H\n#define _OBJC_LOADMETHOD_H\n\n#include \"objc-private.h\"\n\n__BEGIN_DECLS\n\nextern void add_class_to_loadable_list(Class cls);\nextern void add_category_to_loadable_list(Category cat);\nextern void remove_class_from_loadable_list(Class cls);\nextern void remove_category_from_loadable_list(Category cat);\n\nextern void call_load_methods(void);\n\n__END_DECLS\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-loadmethod.mm",
    "content": "/*\n * Copyright (c) 2004-2006 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-loadmethod.m\n* Support for +load methods.\n**********************************************************************/\n\n#include \"objc-loadmethod.h\"\n#include \"objc-private.h\"\n\ntypedef void(*load_method_t)(id, SEL);\n\nstruct loadable_class {\n    Class cls;  // may be nil\n    IMP method;\n};\n\nstruct loadable_category {\n    Category cat;  // may be nil\n    IMP method;\n};\n\n\n// List of classes that need +load called (pending superclass +load)\n// This list always has superclasses first because of the way it is constructed\nstatic struct loadable_class *loadable_classes = nil;\nstatic int loadable_classes_used = 0;\nstatic int loadable_classes_allocated = 0;\n\n// List of categories that need +load called (pending parent class +load)\nstatic struct loadable_category *loadable_categories = nil;\nstatic int loadable_categories_used = 0;\nstatic int loadable_categories_allocated = 0;\n\n\n/***********************************************************************\n* add_class_to_loadable_list\n* Class cls has just become connected. Schedule it for +load if\n* it implements a +load method.\n**********************************************************************/\nvoid add_class_to_loadable_list(Class cls)\n{\n    IMP method;\n\n    loadMethodLock.assertLocked();\n\n    method = cls->getLoadMethod();\n    if (!method) return;  // Don't bother if cls has no +load method\n    \n    if (PrintLoading) {\n        _objc_inform(\"LOAD: class '%s' scheduled for +load\", \n                     cls->nameForLogging());\n    }\n    \n    if (loadable_classes_used == loadable_classes_allocated) {\n        loadable_classes_allocated = loadable_classes_allocated*2 + 16;\n        loadable_classes = (struct loadable_class *)\n            realloc(loadable_classes,\n                              loadable_classes_allocated *\n                              sizeof(struct loadable_class));\n    }\n    \n    loadable_classes[loadable_classes_used].cls = cls;\n    loadable_classes[loadable_classes_used].method = method;\n    loadable_classes_used++;\n}\n\n\n/***********************************************************************\n* add_category_to_loadable_list\n* Category cat's parent class exists and the category has been attached\n* to its class. Schedule this category for +load after its parent class\n* becomes connected and has its own +load method called.\n**********************************************************************/\nvoid add_category_to_loadable_list(Category cat)\n{\n    IMP method;\n\n    loadMethodLock.assertLocked();\n\n    method = _category_getLoadMethod(cat);\n\n    // Don't bother if cat has no +load method\n    if (!method) return;\n\n    if (PrintLoading) {\n        _objc_inform(\"LOAD: category '%s(%s)' scheduled for +load\", \n                     _category_getClassName(cat), _category_getName(cat));\n    }\n    \n    if (loadable_categories_used == loadable_categories_allocated) {\n        loadable_categories_allocated = loadable_categories_allocated*2 + 16;\n        loadable_categories = (struct loadable_category *)\n            realloc(loadable_categories,\n                              loadable_categories_allocated *\n                              sizeof(struct loadable_category));\n    }\n\n    loadable_categories[loadable_categories_used].cat = cat;\n    loadable_categories[loadable_categories_used].method = method;\n    loadable_categories_used++;\n}\n\n\n/***********************************************************************\n* remove_class_from_loadable_list\n* Class cls may have been loadable before, but it is now no longer \n* loadable (because its image is being unmapped). \n**********************************************************************/\nvoid remove_class_from_loadable_list(Class cls)\n{\n    loadMethodLock.assertLocked();\n\n    if (loadable_classes) {\n        int i;\n        for (i = 0; i < loadable_classes_used; i++) {\n            if (loadable_classes[i].cls == cls) {\n                loadable_classes[i].cls = nil;\n                if (PrintLoading) {\n                    _objc_inform(\"LOAD: class '%s' unscheduled for +load\", \n                                 cls->nameForLogging());\n                }\n                return;\n            }\n        }\n    }\n}\n\n\n/***********************************************************************\n* remove_category_from_loadable_list\n* Category cat may have been loadable before, but it is now no longer \n* loadable (because its image is being unmapped). \n**********************************************************************/\nvoid remove_category_from_loadable_list(Category cat)\n{\n    loadMethodLock.assertLocked();\n\n    if (loadable_categories) {\n        int i;\n        for (i = 0; i < loadable_categories_used; i++) {\n            if (loadable_categories[i].cat == cat) {\n                loadable_categories[i].cat = nil;\n                if (PrintLoading) {\n                    _objc_inform(\"LOAD: category '%s(%s)' unscheduled for +load\",\n                                 _category_getClassName(cat), \n                                 _category_getName(cat));\n                }\n                return;\n            }\n        }\n    }\n}\n\n\n/***********************************************************************\n* call_class_loads\n* Call all pending class +load methods.\n* If new classes become loadable, +load is NOT called for them.\n*\n* Called only by call_load_methods().\n**********************************************************************/\nstatic void call_class_loads(void)\n{\n    int i;\n    \n    // Detach current loadable list.\n    struct loadable_class *classes = loadable_classes;\n    int used = loadable_classes_used;\n    loadable_classes = nil;\n    loadable_classes_allocated = 0;\n    loadable_classes_used = 0;\n    \n    // Call all +loads for the detached list.\n    for (i = 0; i < used; i++) {\n        Class cls = classes[i].cls;\n        load_method_t load_method = (load_method_t)classes[i].method;\n        if (!cls) continue; \n\n        if (PrintLoading) {\n            _objc_inform(\"LOAD: +[%s load]\\n\", cls->nameForLogging());\n        }\n        (*load_method)(cls, SEL_load);\n    }\n    \n    // Destroy the detached list.\n    if (classes) free(classes);\n}\n\n\n/***********************************************************************\n* call_category_loads\n* Call some pending category +load methods.\n* The parent class of the +load-implementing categories has all of \n*   its categories attached, in case some are lazily waiting for +initalize.\n* Don't call +load unless the parent class is connected.\n* If new categories become loadable, +load is NOT called, and they \n*   are added to the end of the loadable list, and we return TRUE.\n* Return FALSE if no new categories became loadable.\n*\n* Called only by call_load_methods().\n**********************************************************************/\nstatic bool call_category_loads(void)\n{\n    int i, shift;\n    bool new_categories_added = NO;\n    \n    // Detach current loadable list.\n    struct loadable_category *cats = loadable_categories;\n    int used = loadable_categories_used;\n    int allocated = loadable_categories_allocated;\n    loadable_categories = nil;\n    loadable_categories_allocated = 0;\n    loadable_categories_used = 0;\n\n    // Call all +loads for the detached list.\n    for (i = 0; i < used; i++) {\n        Category cat = cats[i].cat;\n        load_method_t load_method = (load_method_t)cats[i].method;\n        Class cls;\n        if (!cat) continue;\n\n        cls = _category_getClass(cat);\n        if (cls  &&  cls->isLoadable()) {\n            if (PrintLoading) {\n                _objc_inform(\"LOAD: +[%s(%s) load]\\n\", \n                             cls->nameForLogging(), \n                             _category_getName(cat));\n            }\n            (*load_method)(cls, SEL_load);\n            cats[i].cat = nil;\n        }\n    }\n\n    // Compact detached list (order-preserving)\n    shift = 0;\n    for (i = 0; i < used; i++) {\n        if (cats[i].cat) {\n            cats[i-shift] = cats[i];\n        } else {\n            shift++;\n        }\n    }\n    used -= shift;\n\n    // Copy any new +load candidates from the new list to the detached list.\n    new_categories_added = (loadable_categories_used > 0);\n    for (i = 0; i < loadable_categories_used; i++) {\n        if (used == allocated) {\n            allocated = allocated*2 + 16;\n            cats = (struct loadable_category *)\n                realloc(cats, allocated *\n                                  sizeof(struct loadable_category));\n        }\n        cats[used++] = loadable_categories[i];\n    }\n\n    // Destroy the new list.\n    if (loadable_categories) free(loadable_categories);\n\n    // Reattach the (now augmented) detached list. \n    // But if there's nothing left to load, destroy the list.\n    if (used) {\n        loadable_categories = cats;\n        loadable_categories_used = used;\n        loadable_categories_allocated = allocated;\n    } else {\n        if (cats) free(cats);\n        loadable_categories = nil;\n        loadable_categories_used = 0;\n        loadable_categories_allocated = 0;\n    }\n\n    if (PrintLoading) {\n        if (loadable_categories_used != 0) {\n            _objc_inform(\"LOAD: %d categories still waiting for +load\\n\",\n                         loadable_categories_used);\n        }\n    }\n\n    return new_categories_added;\n}\n\n\n/***********************************************************************\n* call_load_methods\n* Call all pending class and category +load methods.\n* Class +load methods are called superclass-first. \n* Category +load methods are not called until after the parent class's +load.\n* \n* This method must be RE-ENTRANT, because a +load could trigger \n* more image mapping. In addition, the superclass-first ordering \n* must be preserved in the face of re-entrant calls. Therefore, \n* only the OUTERMOST call of this function will do anything, and \n* that call will handle all loadable classes, even those generated \n* while it was running.\n*\n* The sequence below preserves +load ordering in the face of \n* image loading during a +load, and make sure that no \n* +load method is forgotten because it was added during \n* a +load call.\n* Sequence:\n* 1. Repeatedly call class +loads until there aren't any more\n* 2. Call category +loads ONCE.\n* 3. Run more +loads if:\n*    (a) there are more classes to load, OR\n*    (b) there are some potential category +loads that have \n*        still never been attempted.\n* Category +loads are only run once to ensure \"parent class first\" \n* ordering, even if a category +load triggers a new loadable class \n* and a new loadable category attached to that class. \n*\n* Locking: loadMethodLock must be held by the caller \n*   All other locks must not be held.\n**********************************************************************/\nvoid call_load_methods(void)\n{\n    static bool loading = NO;\n    bool more_categories;\n\n    loadMethodLock.assertLocked();\n\n    // Re-entrant calls do nothing; the outermost call will finish the job.\n    if (loading) return;\n    loading = YES;\n\n    void *pool = objc_autoreleasePoolPush();\n\n    do {\n        // 1. Repeatedly call class +loads until there aren't any more\n        while (loadable_classes_used > 0) {\n            call_class_loads();\n        }\n\n        // 2. Call category +loads ONCE\n        more_categories = call_category_loads();\n\n        // 3. Run more +loads if there are classes OR more untried categories\n    } while (loadable_classes_used > 0  ||  more_categories);\n\n    objc_autoreleasePoolPop(pool);\n\n    loading = NO;\n}\n\n\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-lockdebug.h",
    "content": "/*\n * Copyright (c) 2015 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#if LOCKDEBUG\nextern void lockdebug_assert_all_locks_locked();\nextern void lockdebug_assert_no_locks_locked();\nextern void lockdebug_setInForkPrepare(bool);\nextern void lockdebug_lock_precedes_lock(const void *oldlock, const void *newlock);\n#else\nstatic constexpr inline void lockdebug_assert_all_locks_locked() { }\nstatic constexpr inline void lockdebug_assert_no_locks_locked() { }\nstatic constexpr inline void lockdebug_setInForkPrepare(bool) { }\nstatic constexpr inline void lockdebug_lock_precedes_lock(const void *, const void *) { }\n#endif\n\nextern void lockdebug_remember_mutex(mutex_tt<true> *lock);\nextern void lockdebug_mutex_lock(mutex_tt<true> *lock);\nextern void lockdebug_mutex_try_lock(mutex_tt<true> *lock);\nextern void lockdebug_mutex_unlock(mutex_tt<true> *lock);\nextern void lockdebug_mutex_assert_locked(mutex_tt<true> *lock);\nextern void lockdebug_mutex_assert_unlocked(mutex_tt<true> *lock);\n\nstatic constexpr inline void lockdebug_remember_mutex(mutex_tt<false> *lock) { }\nstatic constexpr inline void lockdebug_mutex_lock(mutex_tt<false> *lock) { }\nstatic constexpr inline void lockdebug_mutex_try_lock(mutex_tt<false> *lock) { }\nstatic constexpr inline void lockdebug_mutex_unlock(mutex_tt<false> *lock) { }\nstatic constexpr inline void lockdebug_mutex_assert_locked(mutex_tt<false> *lock) { }\nstatic constexpr inline void lockdebug_mutex_assert_unlocked(mutex_tt<false> *lock) { }\n\n\nextern void lockdebug_remember_monitor(monitor_tt<true> *lock);\nextern void lockdebug_monitor_enter(monitor_tt<true> *lock);\nextern void lockdebug_monitor_leave(monitor_tt<true> *lock);\nextern void lockdebug_monitor_wait(monitor_tt<true> *lock);\nextern void lockdebug_monitor_assert_locked(monitor_tt<true> *lock);\nextern void lockdebug_monitor_assert_unlocked(monitor_tt<true> *lock);\n\nstatic constexpr inline void lockdebug_remember_monitor(monitor_tt<false> *lock) { }\nstatic constexpr inline void lockdebug_monitor_enter(monitor_tt<false> *lock) { }\nstatic constexpr inline void lockdebug_monitor_leave(monitor_tt<false> *lock) { }\nstatic constexpr inline void lockdebug_monitor_wait(monitor_tt<false> *lock) { }\nstatic constexpr inline void lockdebug_monitor_assert_locked(monitor_tt<false> *lock) { }\nstatic constexpr inline void lockdebug_monitor_assert_unlocked(monitor_tt<false> *lock) {}\n\n\nextern void \nlockdebug_remember_recursive_mutex(recursive_mutex_tt<true> *lock);\nextern void \nlockdebug_recursive_mutex_lock(recursive_mutex_tt<true> *lock);\nextern void \nlockdebug_recursive_mutex_unlock(recursive_mutex_tt<true> *lock);\nextern void \nlockdebug_recursive_mutex_assert_locked(recursive_mutex_tt<true> *lock);\nextern void \nlockdebug_recursive_mutex_assert_unlocked(recursive_mutex_tt<true> *lock);\n\nstatic constexpr inline void\nlockdebug_remember_recursive_mutex(recursive_mutex_tt<false> *lock) { }\nstatic constexpr inline void\nlockdebug_recursive_mutex_lock(recursive_mutex_tt<false> *lock) { }\nstatic constexpr inline void\nlockdebug_recursive_mutex_unlock(recursive_mutex_tt<false> *lock) { }\nstatic constexpr inline void\nlockdebug_recursive_mutex_assert_locked(recursive_mutex_tt<false> *lock) { }\nstatic constexpr inline void\nlockdebug_recursive_mutex_assert_unlocked(recursive_mutex_tt<false> *lock) { }\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-lockdebug.mm",
    "content": "/*\n * Copyright (c) 2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-lock.m\n* Error-checking locks for debugging.\n**********************************************************************/\n\n#include \"objc-private.h\"\n\n#if LOCKDEBUG  &&  !TARGET_OS_WIN32\n\n#include <unordered_map>\n\n\n/***********************************************************************\n* Thread-local bool set during _objc_atfork_prepare().\n* That function is allowed to break some lock ordering rules.\n**********************************************************************/\n\nstatic tls_key_t fork_prepare_tls;\n\nvoid\nlockdebug_setInForkPrepare(bool inForkPrepare)\n{\n    INIT_ONCE_PTR(fork_prepare_tls, tls_create(nil), (void)0);\n    tls_set(fork_prepare_tls, (void*)inForkPrepare);\n}\n\nstatic bool\ninForkPrepare()\n{\n    INIT_ONCE_PTR(fork_prepare_tls, tls_create(nil), (void)0);\n    return (bool)tls_get(fork_prepare_tls);\n}\n\n\n\n/***********************************************************************\n* Lock order graph.\n* \"lock X precedes lock Y\" means that X must be acquired first.\n* This property is transitive.\n**********************************************************************/\n\nstruct lockorder {\n    const void *l;\n    std::vector<const lockorder *> predecessors;\n\n    mutable std::unordered_map<const lockorder *, bool> memo;\n\n    lockorder(const void *newl) : l(newl) { }\n};\n\nstatic std::unordered_map<const void*, lockorder *> lockOrderList;\n// not mutex_t because we don't want lock debugging on this lock\nstatic mutex_tt<false> lockOrderLock;\n\nstatic bool \nlockPrecedesLock(const lockorder *oldlock, const lockorder *newlock)\n{\n    auto memoed = newlock->memo.find(oldlock);\n    if (memoed != newlock->memo.end()) {\n        return memoed->second;\n    }\n\n    bool result = false;\n    for (const auto *pre : newlock->predecessors) {\n        if (oldlock == pre  ||  lockPrecedesLock(oldlock, pre)) {\n            result = true;\n            break;\n        }\n    }\n\n    newlock->memo[oldlock] = result;\n    return result;\n}\n\nstatic bool \nlockPrecedesLock(const void *oldlock, const void *newlock)\n{\n    mutex_tt<false>::locker lock(lockOrderLock);\n\n    auto oldorder = lockOrderList.find(oldlock);\n    auto neworder = lockOrderList.find(newlock);\n    if (neworder == lockOrderList.end() || oldorder == lockOrderList.end()) {\n        return false;\n    }\n    return lockPrecedesLock(oldorder->second, neworder->second);\n}\n\nstatic bool\nlockUnorderedWithLock(const void *oldlock, const void *newlock)\n{\n    mutex_tt<false>::locker lock(lockOrderLock);\n    \n    auto oldorder = lockOrderList.find(oldlock);\n    auto neworder = lockOrderList.find(newlock);\n    if (neworder == lockOrderList.end() || oldorder == lockOrderList.end()) {\n        return true;\n    }\n    \n    if (lockPrecedesLock(oldorder->second, neworder->second) ||\n        lockPrecedesLock(neworder->second, oldorder->second))\n    {\n        return false;\n    }\n\n    return true;\n}\n\nvoid lockdebug_lock_precedes_lock(const void *oldlock, const void *newlock)\n{\n    if (lockPrecedesLock(newlock, oldlock)) {\n        _objc_fatal(\"contradiction in lock order declaration\");\n    }\n\n    mutex_tt<false>::locker lock(lockOrderLock);\n\n    auto oldorder = lockOrderList.find(oldlock);\n    auto neworder = lockOrderList.find(newlock);\n    if (oldorder == lockOrderList.end()) {\n        lockOrderList[oldlock] = new lockorder(oldlock);\n        oldorder = lockOrderList.find(oldlock);\n    }\n    if (neworder == lockOrderList.end()) {\n        lockOrderList[newlock] = new lockorder(newlock);\n        neworder = lockOrderList.find(newlock);\n    }\n\n    neworder->second->predecessors.push_back(oldorder->second);\n}\n\n\n/***********************************************************************\n* Recording - per-thread list of mutexes and monitors held\n**********************************************************************/\n\nenum class lockkind {\n    MUTEX = 1, MONITOR = 2, RDLOCK = 3, WRLOCK = 4, RECURSIVE = 5\n};\n\n#define MUTEX     lockkind::MUTEX\n#define MONITOR   lockkind::MONITOR\n#define RDLOCK    lockkind::RDLOCK\n#define WRLOCK    lockkind::WRLOCK\n#define RECURSIVE lockkind::RECURSIVE\n\nstruct lockcount {\n    lockkind k;  // the kind of lock it is (MUTEX, MONITOR, etc)\n    int i;       // the lock's nest count\n};\n\nusing objc_lock_list = std::unordered_map<const void *, lockcount>;\n\n\n// Thread-local list of locks owned by a thread.\n// Used by lock ownership checks.\nstatic tls_key_t lock_tls;\n\n// Global list of all locks.\n// Used by fork() safety check.\n// This can't be a static struct because of C++ initialization order problems.\nstatic objc_lock_list& AllLocks() {\n    static objc_lock_list *locks;\n    INIT_ONCE_PTR(locks, new objc_lock_list, (void)0);\n    return *locks;\n}\n\n\nstatic void\ndestroyLocks(void *value)\n{\n    auto locks = (objc_lock_list *)value;\n    // fixme complain about any still-held locks?\n    if (locks) delete locks;\n}\n\nstatic objc_lock_list&\nownedLocks()\n{\n    // Use a dedicated tls key to prevent differences vs non-debug in \n    // usage of objc's other tls keys (required for some unit tests).\n    INIT_ONCE_PTR(lock_tls, tls_create(&destroyLocks), (void)0);\n\n    auto locks = (objc_lock_list *)tls_get(lock_tls);\n    if (!locks) {\n        locks = new objc_lock_list;\n        tls_set(lock_tls, locks);\n    }\n\n    return *locks;\n}\n\nstatic bool \nhasLock(objc_lock_list& locks, const void *lock, lockkind kind)\n{\n    auto iter = locks.find(lock);\n    if (iter != locks.end() && iter->second.k == kind) return true;\n    return false;\n}\n\n\nstatic const char *sym(const void *lock)\n{\n    Dl_info info;\n    int ok = dladdr(lock, &info);\n    if (ok && info.dli_sname && info.dli_sname[0]) return info.dli_sname;\n    else return \"??\";\n}\n\nstatic void \nsetLock(objc_lock_list& locks, const void *lock, lockkind kind)\n{\n    // Check if we already own this lock.\n    auto iter = locks.find(lock);\n    if (iter != locks.end() && iter->second.k == kind) {\n        iter->second.i++;\n        return;\n    }\n\n    // Newly-acquired lock. Verify lock ordering.\n    // Locks not in AllLocks are exempt (i.e. @synchronize locks)\n    if (&locks != &AllLocks() && AllLocks().find(lock) != AllLocks().end()) {\n        for (auto& oldlock : locks) {\n            if (AllLocks().find(oldlock.first) == AllLocks().end()) {\n                // oldlock is exempt\n                continue;\n            }\n\n            if (lockPrecedesLock(lock, oldlock.first)) {\n                _objc_fatal(\"lock %p (%s) incorrectly acquired before %p (%s)\",\n                            oldlock.first, sym(oldlock.first), lock, sym(lock));\n            }\n            if (!inForkPrepare() &&\n                lockUnorderedWithLock(lock, oldlock.first))\n            {\n                // _objc_atfork_prepare is allowed to acquire\n                // otherwise-unordered locks, but nothing else may.\n                _objc_fatal(\"lock %p (%s) acquired before %p (%s) \"\n                            \"with no defined lock order\",\n                            oldlock.first, sym(oldlock.first), lock, sym(lock));\n            }\n        }\n    }\n\n    locks[lock] = lockcount{kind, 1};\n}\n\nstatic void \nclearLock(objc_lock_list& locks, const void *lock, lockkind kind)\n{\n    auto iter = locks.find(lock);\n    if (iter != locks.end()) {\n        auto& l = iter->second;\n        if (l.k == kind) {\n            if (--l.i == 0) {\n                locks.erase(iter);\n            }\n            return;\n        }\n    }\n\n    _objc_fatal(\"lock not found!\");\n}\n\n\n/***********************************************************************\n* fork() safety checking\n**********************************************************************/\n\nvoid\nlockdebug_remember_mutex(mutex_t *lock)\n{\n    setLock(AllLocks(), lock, MUTEX);\n}\n\nvoid\nlockdebug_remember_recursive_mutex(recursive_mutex_t *lock)\n{\n    setLock(AllLocks(), lock, RECURSIVE);\n}\n\nvoid\nlockdebug_remember_monitor(monitor_t *lock)\n{\n    setLock(AllLocks(), lock, MONITOR);\n}\n\nvoid\nlockdebug_assert_all_locks_locked()\n{\n    auto& owned = ownedLocks();\n\n    for (const auto& l : AllLocks()) {\n        if (!hasLock(owned, l.first, l.second.k)) {\n            _objc_fatal(\"lock %p:%d is incorrectly not owned\",\n                        l.first, l.second.k);\n        }\n    }\n}\n\nvoid\nlockdebug_assert_no_locks_locked()\n{\n    auto& owned = ownedLocks();\n\n    for (const auto& l : AllLocks()) {\n        if (hasLock(owned, l.first, l.second.k)) {\n            _objc_fatal(\"lock %p:%d is incorrectly owned\", l.first, l.second.k);\n        }\n    }\n}\n\n\n/***********************************************************************\n* Mutex checking\n**********************************************************************/\n\nvoid \nlockdebug_mutex_lock(mutex_t *lock)\n{\n    auto& locks = ownedLocks();\n    \n    if (hasLock(locks, lock, MUTEX)) {\n        _objc_fatal(\"deadlock: relocking mutex\");\n    }\n    setLock(locks, lock, MUTEX);\n}\n\n// try-lock success is the only case with lockdebug effects.\n// try-lock when already locked is OK (will fail)\n// try-lock failure does nothing.\nvoid \nlockdebug_mutex_try_lock_success(mutex_t *lock)\n{\n    auto& locks = ownedLocks();\n    setLock(locks, lock, MUTEX);\n}\n\nvoid \nlockdebug_mutex_unlock(mutex_t *lock)\n{\n    auto& locks = ownedLocks();\n\n    if (!hasLock(locks, lock, MUTEX)) {\n        _objc_fatal(\"unlocking unowned mutex\");\n    }\n    clearLock(locks, lock, MUTEX);\n}\n\n\nvoid \nlockdebug_mutex_assert_locked(mutex_t *lock)\n{\n    auto& locks = ownedLocks();\n\n    if (!hasLock(locks, lock, MUTEX)) {\n        _objc_fatal(\"mutex incorrectly not locked\");\n    }\n}\n\nvoid \nlockdebug_mutex_assert_unlocked(mutex_t *lock)\n{\n    auto& locks = ownedLocks();\n\n    if (hasLock(locks, lock, MUTEX)) {\n        _objc_fatal(\"mutex incorrectly locked\");\n    }\n}\n\n\n/***********************************************************************\n* Recursive mutex checking\n**********************************************************************/\n\nvoid \nlockdebug_recursive_mutex_lock(recursive_mutex_t *lock)\n{\n    auto& locks = ownedLocks();\n    setLock(locks, lock, RECURSIVE);\n}\n\nvoid \nlockdebug_recursive_mutex_unlock(recursive_mutex_t *lock)\n{\n    auto& locks = ownedLocks();\n\n    if (!hasLock(locks, lock, RECURSIVE)) {\n        _objc_fatal(\"unlocking unowned recursive mutex\");\n    }\n    clearLock(locks, lock, RECURSIVE);\n}\n\n\nvoid \nlockdebug_recursive_mutex_assert_locked(recursive_mutex_t *lock)\n{\n    auto& locks = ownedLocks();\n\n    if (!hasLock(locks, lock, RECURSIVE)) {\n        _objc_fatal(\"recursive mutex incorrectly not locked\");\n    }\n}\n\nvoid \nlockdebug_recursive_mutex_assert_unlocked(recursive_mutex_t *lock)\n{\n    auto& locks = ownedLocks();\n\n    if (hasLock(locks, lock, RECURSIVE)) {\n        _objc_fatal(\"recursive mutex incorrectly locked\");\n    }\n}\n\n\n/***********************************************************************\n* Monitor checking\n**********************************************************************/\n\nvoid \nlockdebug_monitor_enter(monitor_t *lock)\n{\n    auto& locks = ownedLocks();\n\n    if (hasLock(locks, lock, MONITOR)) {\n        _objc_fatal(\"deadlock: relocking monitor\");\n    }\n    setLock(locks, lock, MONITOR);\n}\n\nvoid \nlockdebug_monitor_leave(monitor_t *lock)\n{\n    auto& locks = ownedLocks();\n\n    if (!hasLock(locks, lock, MONITOR)) {\n        _objc_fatal(\"unlocking unowned monitor\");\n    }\n    clearLock(locks, lock, MONITOR);\n}\n\nvoid \nlockdebug_monitor_wait(monitor_t *lock)\n{\n    auto& locks = ownedLocks();\n\n    if (!hasLock(locks, lock, MONITOR)) {\n        _objc_fatal(\"waiting in unowned monitor\");\n    }\n}\n\n\nvoid \nlockdebug_monitor_assert_locked(monitor_t *lock)\n{\n    auto& locks = ownedLocks();\n\n    if (!hasLock(locks, lock, MONITOR)) {\n        _objc_fatal(\"monitor incorrectly not locked\");\n    }\n}\n\nvoid \nlockdebug_monitor_assert_unlocked(monitor_t *lock)\n{\n    auto& locks = ownedLocks();\n\n    if (hasLock(locks, lock, MONITOR)) {\n        _objc_fatal(\"monitor incorrectly held\");\n    }\n}\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-locks-new.h",
    "content": "/*\n * Copyright (c) 2017 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-locks-new.h\n* Declarations of all locks used in the runtime.\n**********************************************************************/\n\n#ifndef _OBJC_LOCKS_NEW_H\n#define _OBJC_LOCKS_NEW_H\n\n// fork() safety requires careful tracking of all locks used in the runtime.\n// Thou shalt not declare any locks outside this file.\n\nextern mutex_t runtimeLock;\nextern mutex_t DemangleCacheLock;\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-locks-old.h",
    "content": "/*\n * Copyright (c) 2017 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-locks-old.h\n* Declarations of all locks used in the runtime.\n**********************************************************************/\n\n#ifndef _OBJC_LOCKS_OLD_H\n#define _OBJC_LOCKS_OLD_H\n\n// fork() safety requires careful tracking of all locks used in the runtime.\n// Thou shalt not declare any locks outside this file.\n\nextern mutex_t classLock;\nextern mutex_t methodListLock;\nextern mutex_t NXUniqueStringLock;\nextern spinlock_t impLock;\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-locks.h",
    "content": "/*\n * Copyright (c) 2017 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-locks.h\n* Declarations of all locks used in the runtime.\n**********************************************************************/\n\n#ifndef _OBJC_LOCKS_H\n#define _OBJC_LOCKS_H\n\n// fork() safety requires careful tracking of all locks used in the runtime.\n// Thou shalt not declare any locks outside this file.\n\n// Lock ordering is declared in _objc_fork_prepare()\n// and is enforced by lockdebug.\n\nextern monitor_t classInitLock;\nextern mutex_t selLock;\nextern mutex_t cacheUpdateLock;\nextern recursive_mutex_t loadMethodLock;\nextern mutex_t crashlog_lock;\nextern spinlock_t objcMsgLogLock;\nextern mutex_t AltHandlerDebugLock;\nextern mutex_t AssociationsManagerLock;\nextern StripedMap<spinlock_t> PropertyLocks;\nextern StripedMap<spinlock_t> StructLocks;\nextern StripedMap<spinlock_t> CppObjectLocks;\n\n// SideTable lock is buried awkwardly. Call a function to manipulate it.\nextern void SideTableLockAll();\nextern void SideTableUnlockAll();\nextern void SideTableForceResetAll();\nextern void SideTableDefineLockOrder();\nextern void SideTableLocksPrecedeLock(const void *newlock);\nextern void SideTableLocksSucceedLock(const void *oldlock);\nextern void SideTableLocksPrecedeLocks(StripedMap<spinlock_t>& newlocks);\nextern void SideTableLocksSucceedLocks(StripedMap<spinlock_t>& oldlocks);\n\n#if __OBJC2__\n#include \"objc-locks-new.h\"\n#else\n#include \"objc-locks-old.h\"\n#endif\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-object.h",
    "content": "/*\n * Copyright (c) 2010-2012 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n *\n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n *\n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n *\n * @APPLE_LICENSE_HEADER_END@\n */\n\n\n/***********************************************************************\n* Inlineable parts of NSObject / objc_object implementation\n**********************************************************************/\n\n#ifndef _OBJC_OBJCOBJECT_H_\n#define _OBJC_OBJCOBJECT_H_\n\n#include \"objc-private.h\"\n\n\nenum ReturnDisposition : bool {\n    ReturnAtPlus0 = false, ReturnAtPlus1 = true\n};\n\nstatic ALWAYS_INLINE \nbool prepareOptimizedReturn(ReturnDisposition disposition);\n\n\n#if SUPPORT_TAGGED_POINTERS\n\nextern \"C\" { \n    extern Class objc_debug_taggedpointer_classes[_OBJC_TAG_SLOT_COUNT*2];\n    extern Class objc_debug_taggedpointer_ext_classes[_OBJC_TAG_EXT_SLOT_COUNT];\n}\n#define objc_tag_classes objc_debug_taggedpointer_classes\n#define objc_tag_ext_classes objc_debug_taggedpointer_ext_classes\n\n#endif\n\n#if SUPPORT_INDEXED_ISA\n\nALWAYS_INLINE Class &\nclassForIndex(uintptr_t index) {\n    assert(index > 0);\n    assert(index < (uintptr_t)objc_indexed_classes_count);\n    return objc_indexed_classes[index];\n}\n\n#endif\n\n\ninline bool\nobjc_object::isClass()\n{\n    if (isTaggedPointer()) return false;\n    return ISA()->isMetaClass();\n}\n\n\n#if SUPPORT_TAGGED_POINTERS\n\ninline Class \nobjc_object::getIsa() \n{\n    if (!isTaggedPointer()) return ISA();\n\n    uintptr_t ptr = (uintptr_t)this;\n    if (isExtTaggedPointer()) {\n        uintptr_t slot = \n            (ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;\n        return objc_tag_ext_classes[slot];\n    } else {\n        uintptr_t slot = \n            (ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;\n        return objc_tag_classes[slot];\n    }\n}\n\n\ninline bool \nobjc_object::isTaggedPointer() \n{\n    return _objc_isTaggedPointer(this);\n}\n\ninline bool \nobjc_object::isBasicTaggedPointer() \n{\n    return isTaggedPointer()  &&  !isExtTaggedPointer();\n}\n\ninline bool \nobjc_object::isExtTaggedPointer() \n{\n    uintptr_t ptr = _objc_decodeTaggedPointer(this);\n    return (ptr & _OBJC_TAG_EXT_MASK) == _OBJC_TAG_EXT_MASK;\n}\n\n\n// SUPPORT_TAGGED_POINTERS\n#else\n// not SUPPORT_TAGGED_POINTERS\n\n\ninline Class \nobjc_object::getIsa() \n{\n    return ISA();\n}\n\n\ninline bool \nobjc_object::isTaggedPointer() \n{\n    return false;\n}\n\ninline bool \nobjc_object::isBasicTaggedPointer() \n{\n    return false;\n}\n\ninline bool \nobjc_object::isExtTaggedPointer() \n{\n    return false;\n}\n\n\n// not SUPPORT_TAGGED_POINTERS\n#endif\n\n\n#if SUPPORT_NONPOINTER_ISA\n\ninline Class \nobjc_object::ISA() \n{\n    assert(!isTaggedPointer()); \n#if SUPPORT_INDEXED_ISA\n    if (isa.nonpointer) {\n        uintptr_t slot = isa.indexcls;\n        return classForIndex((unsigned)slot);\n    }\n    return (Class)isa.bits;\n#else\n    return (Class)(isa.bits & ISA_MASK);\n#endif\n}\n\n\ninline bool \nobjc_object::hasNonpointerIsa()\n{\n    return isa.nonpointer;\n}\n\n\ninline void \nobjc_object::initIsa(Class cls)\n{\n    initIsa(cls, false, false);\n}\n\ninline void \nobjc_object::initClassIsa(Class cls)\n{\n    if (DisableNonpointerIsa  ||  cls->instancesRequireRawIsa()) {\n        initIsa(cls, false/*not nonpointer*/, false);\n    } else {\n        initIsa(cls, true/*nonpointer*/, false);\n    }\n}\n\ninline void\nobjc_object::initProtocolIsa(Class cls)\n{\n    return initClassIsa(cls);\n}\n\ninline void \nobjc_object::initInstanceIsa(Class cls, bool hasCxxDtor)\n{\n    assert(!cls->instancesRequireRawIsa());\n    assert(hasCxxDtor == cls->hasCxxDtor());\n\n    initIsa(cls, true, hasCxxDtor);\n}\n\ninline void \nobjc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) \n{ \n    assert(!isTaggedPointer()); \n    \n    if (!nonpointer) {\n        isa.cls = cls;\n    } else {\n        assert(!DisableNonpointerIsa);\n        assert(!cls->instancesRequireRawIsa());\n\n        isa_t newisa(0);\n\n#if SUPPORT_INDEXED_ISA\n        assert(cls->classArrayIndex() > 0);\n        newisa.bits = ISA_INDEX_MAGIC_VALUE;\n        // isa.magic is part of ISA_MAGIC_VALUE\n        // isa.nonpointer is part of ISA_MAGIC_VALUE\n        newisa.has_cxx_dtor = hasCxxDtor;\n        newisa.indexcls = (uintptr_t)cls->classArrayIndex();\n#else\n        newisa.bits = ISA_MAGIC_VALUE;\n        // isa.magic is part of ISA_MAGIC_VALUE\n        // isa.nonpointer is part of ISA_MAGIC_VALUE\n        newisa.has_cxx_dtor = hasCxxDtor;\n        newisa.shiftcls = (uintptr_t)cls >> 3;\n#endif\n\n        // This write must be performed in a single store in some cases\n        // (for example when realizing a class because other threads\n        // may simultaneously try to use the class).\n        // fixme use atomics here to guarantee single-store and to\n        // guarantee memory order w.r.t. the class index table\n        // ...but not too atomic because we don't want to hurt instantiation\n        isa = newisa;\n    }\n}\n\n\ninline Class \nobjc_object::changeIsa(Class newCls)\n{\n    // This is almost always true but there are \n    // enough edge cases that we can't assert it.\n    // assert(newCls->isFuture()  || \n    //        newCls->isInitializing()  ||  newCls->isInitialized());\n\n    assert(!isTaggedPointer()); \n\n    isa_t oldisa;\n    isa_t newisa;\n\n    bool sideTableLocked = false;\n    bool transcribeToSideTable = false;\n\n    do {\n        transcribeToSideTable = false;\n        oldisa = LoadExclusive(&isa.bits);\n        if ((oldisa.bits == 0  ||  oldisa.nonpointer)  &&\n            !newCls->isFuture()  &&  newCls->canAllocNonpointer())\n        {\n            // 0 -> nonpointer\n            // nonpointer -> nonpointer\n#if SUPPORT_INDEXED_ISA\n            if (oldisa.bits == 0) newisa.bits = ISA_INDEX_MAGIC_VALUE;\n            else newisa = oldisa;\n            // isa.magic is part of ISA_MAGIC_VALUE\n            // isa.nonpointer is part of ISA_MAGIC_VALUE\n            newisa.has_cxx_dtor = newCls->hasCxxDtor();\n            assert(newCls->classArrayIndex() > 0);\n            newisa.indexcls = (uintptr_t)newCls->classArrayIndex();\n#else\n            if (oldisa.bits == 0) newisa.bits = ISA_MAGIC_VALUE;\n            else newisa = oldisa;\n            // isa.magic is part of ISA_MAGIC_VALUE\n            // isa.nonpointer is part of ISA_MAGIC_VALUE\n            newisa.has_cxx_dtor = newCls->hasCxxDtor();\n            newisa.shiftcls = (uintptr_t)newCls >> 3;\n#endif\n        }\n        else if (oldisa.nonpointer) {\n            // nonpointer -> raw pointer\n            // Need to copy retain count et al to side table.\n            // Acquire side table lock before setting isa to \n            // prevent races such as concurrent -release.\n            if (!sideTableLocked) sidetable_lock();\n            sideTableLocked = true;\n            transcribeToSideTable = true;\n            newisa.cls = newCls;\n        }\n        else {\n            // raw pointer -> raw pointer\n            newisa.cls = newCls;\n        }\n    } while (!StoreExclusive(&isa.bits, oldisa.bits, newisa.bits));\n\n    if (transcribeToSideTable) {\n        // Copy oldisa's retain count et al to side table.\n        // oldisa.has_assoc: nothing to do\n        // oldisa.has_cxx_dtor: nothing to do\n        sidetable_moveExtraRC_nolock(oldisa.extra_rc, \n                                     oldisa.deallocating, \n                                     oldisa.weakly_referenced);\n    }\n\n    if (sideTableLocked) sidetable_unlock();\n\n    if (oldisa.nonpointer) {\n#if SUPPORT_INDEXED_ISA\n        return classForIndex(oldisa.indexcls);\n#else\n        return (Class)((uintptr_t)oldisa.shiftcls << 3);\n#endif\n    }\n    else {\n        return oldisa.cls;\n    }\n}\n\n\ninline bool\nobjc_object::hasAssociatedObjects()\n{\n    if (isTaggedPointer()) return true;\n    if (isa.nonpointer) return isa.has_assoc;\n    return true;\n}\n\n\ninline void\nobjc_object::setHasAssociatedObjects()\n{\n    if (isTaggedPointer()) return;\n\n retry:\n    isa_t oldisa = LoadExclusive(&isa.bits);\n    isa_t newisa = oldisa;\n    if (!newisa.nonpointer  ||  newisa.has_assoc) {\n        ClearExclusive(&isa.bits);\n        return;\n    }\n    newisa.has_assoc = true;\n    if (!StoreExclusive(&isa.bits, oldisa.bits, newisa.bits)) goto retry;\n}\n\n\ninline bool\nobjc_object::isWeaklyReferenced()\n{\n    assert(!isTaggedPointer());\n    if (isa.nonpointer) return isa.weakly_referenced;\n    else return sidetable_isWeaklyReferenced();\n}\n\n\ninline void\nobjc_object::setWeaklyReferenced_nolock()\n{\n retry:\n    isa_t oldisa = LoadExclusive(&isa.bits);\n    isa_t newisa = oldisa;\n    if (slowpath(!newisa.nonpointer)) {\n        ClearExclusive(&isa.bits);\n        sidetable_setWeaklyReferenced_nolock();\n        return;\n    }\n    if (newisa.weakly_referenced) {\n        ClearExclusive(&isa.bits);\n        return;\n    }\n    newisa.weakly_referenced = true;\n    if (!StoreExclusive(&isa.bits, oldisa.bits, newisa.bits)) goto retry;\n}\n\n\ninline bool\nobjc_object::hasCxxDtor()\n{\n    assert(!isTaggedPointer());\n    if (isa.nonpointer) return isa.has_cxx_dtor;\n    else return isa.cls->hasCxxDtor();\n}\n\n\n\ninline bool \nobjc_object::rootIsDeallocating()\n{\n    if (isTaggedPointer()) return false;\n    if (isa.nonpointer) return isa.deallocating;\n    return sidetable_isDeallocating();\n}\n\n\ninline void \nobjc_object::clearDeallocating()\n{\n    if (slowpath(!isa.nonpointer)) {\n        // Slow path for raw pointer isa.\n        sidetable_clearDeallocating();\n    }\n    else if (slowpath(isa.weakly_referenced  ||  isa.has_sidetable_rc)) {\n        // Slow path for non-pointer isa with weak refs and/or side table data.\n        clearDeallocating_slow();\n    }\n\n    assert(!sidetable_present());\n}\n\n\ninline void\nobjc_object::rootDealloc()\n{\n    if (isTaggedPointer()) return;  // fixme necessary?\n\n    if (fastpath(isa.nonpointer  &&  \n                 !isa.weakly_referenced  &&  \n                 !isa.has_assoc  &&  \n                 !isa.has_cxx_dtor  &&  \n                 !isa.has_sidetable_rc))\n    {\n        assert(!sidetable_present());\n        free(this);\n    } \n    else {\n        object_dispose((id)this);\n    }\n}\n\n\n// Equivalent to calling [this retain], with shortcuts if there is no override\ninline id \nobjc_object::retain()\n{\n    assert(!isTaggedPointer());\n\n    if (fastpath(!ISA()->hasCustomRR())) {\n        return rootRetain();\n    }\n\n    return ((id(*)(objc_object *, SEL))objc_msgSend)(this, SEL_retain);\n}\n\n\n// Base retain implementation, ignoring overrides.\n// This does not check isa.fast_rr; if there is an RR override then \n// it was already called and it chose to call [super retain].\n//\n// tryRetain=true is the -_tryRetain path.\n// handleOverflow=false is the frameless fast path.\n// handleOverflow=true is the framed slow path including overflow to side table\n// The code is structured this way to prevent duplication.\n\nALWAYS_INLINE id \nobjc_object::rootRetain()\n{\n    return rootRetain(false, false);\n}\n\nALWAYS_INLINE bool \nobjc_object::rootTryRetain()\n{\n    return rootRetain(true, false) ? true : false;\n}\n\nALWAYS_INLINE id \nobjc_object::rootRetain(bool tryRetain, bool handleOverflow)\n{\n    if (isTaggedPointer()) return (id)this;\n\n    bool sideTableLocked = false;\n    bool transcribeToSideTable = false;\n\n    isa_t oldisa;\n    isa_t newisa;\n\n    do {\n        transcribeToSideTable = false;\n        oldisa = LoadExclusive(&isa.bits);\n        newisa = oldisa;\n        if (slowpath(!newisa.nonpointer)) {\n            ClearExclusive(&isa.bits);\n            if (!tryRetain && sideTableLocked) sidetable_unlock();\n            if (tryRetain) return sidetable_tryRetain() ? (id)this : nil;\n            else return sidetable_retain();\n        }\n        // don't check newisa.fast_rr; we already called any RR overrides\n        if (slowpath(tryRetain && newisa.deallocating)) {\n            ClearExclusive(&isa.bits);\n            if (!tryRetain && sideTableLocked) sidetable_unlock();\n            return nil;\n        }\n        uintptr_t carry;\n        newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc++\n\n        if (slowpath(carry)) {\n            // newisa.extra_rc++ overflowed\n            if (!handleOverflow) {\n                ClearExclusive(&isa.bits);\n                return rootRetain_overflow(tryRetain);\n            }\n            // Leave half of the retain counts inline and \n            // prepare to copy the other half to the side table.\n            if (!tryRetain && !sideTableLocked) sidetable_lock();\n            sideTableLocked = true;\n            transcribeToSideTable = true;\n            newisa.extra_rc = RC_HALF;\n            newisa.has_sidetable_rc = true;\n        }\n    } while (slowpath(!StoreExclusive(&isa.bits, oldisa.bits, newisa.bits)));\n\n    if (slowpath(transcribeToSideTable)) {\n        // Copy the other half of the retain counts to the side table.\n        sidetable_addExtraRC_nolock(RC_HALF);\n    }\n\n    if (slowpath(!tryRetain && sideTableLocked)) sidetable_unlock();\n    return (id)this;\n}\n\n\n// Equivalent to calling [this release], with shortcuts if there is no override\ninline void\nobjc_object::release()\n{\n    assert(!isTaggedPointer());\n\n    if (fastpath(!ISA()->hasCustomRR())) {\n        rootRelease();\n        return;\n    }\n\n    ((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_release);\n}\n\n\n// Base release implementation, ignoring overrides.\n// Does not call -dealloc.\n// Returns true if the object should now be deallocated.\n// This does not check isa.fast_rr; if there is an RR override then \n// it was already called and it chose to call [super release].\n// \n// handleUnderflow=false is the frameless fast path.\n// handleUnderflow=true is the framed slow path including side table borrow\n// The code is structured this way to prevent duplication.\n\nALWAYS_INLINE bool \nobjc_object::rootRelease()\n{\n    return rootRelease(true, false);\n}\n\nALWAYS_INLINE bool \nobjc_object::rootReleaseShouldDealloc()\n{\n    return rootRelease(false, false);\n}\n\nALWAYS_INLINE bool \nobjc_object::rootRelease(bool performDealloc, bool handleUnderflow)\n{\n    if (isTaggedPointer()) return false;\n\n    bool sideTableLocked = false;\n\n    isa_t oldisa;\n    isa_t newisa;\n\n retry:\n    do {\n        oldisa = LoadExclusive(&isa.bits);\n        newisa = oldisa;\n        if (slowpath(!newisa.nonpointer)) {\n            ClearExclusive(&isa.bits);\n            if (sideTableLocked) sidetable_unlock();\n            return sidetable_release(performDealloc);\n        }\n        // don't check newisa.fast_rr; we already called any RR overrides\n        uintptr_t carry;\n        newisa.bits = subc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc--\n        if (slowpath(carry)) {\n            // don't ClearExclusive()\n            goto underflow;\n        }\n    } while (slowpath(!StoreReleaseExclusive(&isa.bits, \n                                             oldisa.bits, newisa.bits)));\n\n    if (slowpath(sideTableLocked)) sidetable_unlock();\n    return false;\n\n underflow:\n    // newisa.extra_rc-- underflowed: borrow from side table or deallocate\n\n    // abandon newisa to undo the decrement\n    newisa = oldisa;\n\n    if (slowpath(newisa.has_sidetable_rc)) {\n        if (!handleUnderflow) {\n            ClearExclusive(&isa.bits);\n            return rootRelease_underflow(performDealloc);\n        }\n\n        // Transfer retain count from side table to inline storage.\n\n        if (!sideTableLocked) {\n            ClearExclusive(&isa.bits);\n            sidetable_lock();\n            sideTableLocked = true;\n            // Need to start over to avoid a race against \n            // the nonpointer -> raw pointer transition.\n            goto retry;\n        }\n\n        // Try to remove some retain counts from the side table.        \n        size_t borrowed = sidetable_subExtraRC_nolock(RC_HALF);\n\n        // To avoid races, has_sidetable_rc must remain set \n        // even if the side table count is now zero.\n\n        if (borrowed > 0) {\n            // Side table retain count decreased.\n            // Try to add them to the inline count.\n            newisa.extra_rc = borrowed - 1;  // redo the original decrement too\n            bool stored = StoreReleaseExclusive(&isa.bits, \n                                                oldisa.bits, newisa.bits);\n            if (!stored) {\n                // Inline update failed. \n                // Try it again right now. This prevents livelock on LL/SC \n                // architectures where the side table access itself may have \n                // dropped the reservation.\n                isa_t oldisa2 = LoadExclusive(&isa.bits);\n                isa_t newisa2 = oldisa2;\n                if (newisa2.nonpointer) {\n                    uintptr_t overflow;\n                    newisa2.bits = \n                        addc(newisa2.bits, RC_ONE * (borrowed-1), 0, &overflow);\n                    if (!overflow) {\n                        stored = StoreReleaseExclusive(&isa.bits, oldisa2.bits, \n                                                       newisa2.bits);\n                    }\n                }\n            }\n\n            if (!stored) {\n                // Inline update failed.\n                // Put the retains back in the side table.\n                sidetable_addExtraRC_nolock(borrowed);\n                goto retry;\n            }\n\n            // Decrement successful after borrowing from side table.\n            // This decrement cannot be the deallocating decrement - the side \n            // table lock and has_sidetable_rc bit ensure that if everyone \n            // else tried to -release while we worked, the last one would block.\n            sidetable_unlock();\n            return false;\n        }\n        else {\n            // Side table is empty after all. Fall-through to the dealloc path.\n        }\n    }\n\n    // Really deallocate.\n\n    if (slowpath(newisa.deallocating)) {\n        ClearExclusive(&isa.bits);\n        if (sideTableLocked) sidetable_unlock();\n        return overrelease_error();\n        // does not actually return\n    }\n    newisa.deallocating = true;\n    if (!StoreExclusive(&isa.bits, oldisa.bits, newisa.bits)) goto retry;\n\n    if (slowpath(sideTableLocked)) sidetable_unlock();\n\n    __sync_synchronize();\n    if (performDealloc) {\n        ((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);\n    }\n    return true;\n}\n\n\n// Equivalent to [this autorelease], with shortcuts if there is no override\ninline id \nobjc_object::autorelease()\n{\n    if (isTaggedPointer()) return (id)this;\n    if (fastpath(!ISA()->hasCustomRR())) return rootAutorelease();\n\n    return ((id(*)(objc_object *, SEL))objc_msgSend)(this, SEL_autorelease);\n}\n\n\n// Base autorelease implementation, ignoring overrides.\ninline id \nobjc_object::rootAutorelease()\n{\n    if (isTaggedPointer()) return (id)this;\n    if (prepareOptimizedReturn(ReturnAtPlus1)) return (id)this;\n\n    return rootAutorelease2();\n}\n\n\ninline uintptr_t \nobjc_object::rootRetainCount()\n{\n    if (isTaggedPointer()) return (uintptr_t)this;\n\n    sidetable_lock();\n    isa_t bits = LoadExclusive(&isa.bits);\n    ClearExclusive(&isa.bits);\n    if (bits.nonpointer) {\n        uintptr_t rc = 1 + bits.extra_rc;\n        if (bits.has_sidetable_rc) {\n            rc += sidetable_getExtraRC_nolock();\n        }\n        sidetable_unlock();\n        return rc;\n    }\n\n    sidetable_unlock();\n    return sidetable_retainCount();\n}\n\n\n// SUPPORT_NONPOINTER_ISA\n#else\n// not SUPPORT_NONPOINTER_ISA\n\n\ninline Class \nobjc_object::ISA() \n{\n    assert(!isTaggedPointer()); \n    return isa.cls;\n}\n\n\ninline bool \nobjc_object::hasNonpointerIsa()\n{\n    return false;\n}\n\n\ninline void \nobjc_object::initIsa(Class cls)\n{\n    assert(!isTaggedPointer()); \n    isa = (uintptr_t)cls; \n}\n\n\ninline void \nobjc_object::initClassIsa(Class cls)\n{\n    initIsa(cls);\n}\n\n\ninline void \nobjc_object::initProtocolIsa(Class cls)\n{\n    initIsa(cls);\n}\n\n\ninline void \nobjc_object::initInstanceIsa(Class cls, bool)\n{\n    initIsa(cls);\n}\n\n\ninline void \nobjc_object::initIsa(Class cls, bool, bool)\n{ \n    initIsa(cls);\n}\n\n\ninline Class \nobjc_object::changeIsa(Class cls)\n{\n    // This is almost always rue but there are \n    // enough edge cases that we can't assert it.\n    // assert(cls->isFuture()  ||  \n    //        cls->isInitializing()  ||  cls->isInitialized());\n\n    assert(!isTaggedPointer()); \n    \n    isa_t oldisa, newisa;\n    newisa.cls = cls;\n    do {\n        oldisa = LoadExclusive(&isa.bits);\n    } while (!StoreExclusive(&isa.bits, oldisa.bits, newisa.bits));\n    \n    if (oldisa.cls  &&  oldisa.cls->instancesHaveAssociatedObjects()) {\n        cls->setInstancesHaveAssociatedObjects();\n    }\n    \n    return oldisa.cls;\n}\n\n\ninline bool\nobjc_object::hasAssociatedObjects()\n{\n    return getIsa()->instancesHaveAssociatedObjects();\n}\n\n\ninline void\nobjc_object::setHasAssociatedObjects()\n{\n    getIsa()->setInstancesHaveAssociatedObjects();\n}\n\n\ninline bool\nobjc_object::isWeaklyReferenced()\n{\n    assert(!isTaggedPointer());\n\n    return sidetable_isWeaklyReferenced();\n}\n\n\ninline void \nobjc_object::setWeaklyReferenced_nolock()\n{\n    assert(!isTaggedPointer());\n\n    sidetable_setWeaklyReferenced_nolock();\n}\n\n\ninline bool\nobjc_object::hasCxxDtor()\n{\n    assert(!isTaggedPointer());\n    return isa.cls->hasCxxDtor();\n}\n\n\ninline bool \nobjc_object::rootIsDeallocating()\n{\n    if (isTaggedPointer()) return false;\n    return sidetable_isDeallocating();\n}\n\n\ninline void \nobjc_object::clearDeallocating()\n{\n    sidetable_clearDeallocating();\n}\n\n\ninline void\nobjc_object::rootDealloc()\n{\n    if (isTaggedPointer()) return;\n    object_dispose((id)this);\n}\n\n\n// Equivalent to calling [this retain], with shortcuts if there is no override\ninline id \nobjc_object::retain()\n{\n    assert(!isTaggedPointer());\n\n    if (fastpath(!ISA()->hasCustomRR())) {\n        return sidetable_retain();\n    }\n\n    return ((id(*)(objc_object *, SEL))objc_msgSend)(this, SEL_retain);\n}\n\n\n// Base retain implementation, ignoring overrides.\n// This does not check isa.fast_rr; if there is an RR override then \n// it was already called and it chose to call [super retain].\ninline id \nobjc_object::rootRetain()\n{\n    if (isTaggedPointer()) return (id)this;\n    return sidetable_retain();\n}\n\n\n// Equivalent to calling [this release], with shortcuts if there is no override\ninline void\nobjc_object::release()\n{\n    assert(!isTaggedPointer());\n\n    if (fastpath(!ISA()->hasCustomRR())) {\n        sidetable_release();\n        return;\n    }\n\n    ((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_release);\n}\n\n\n// Base release implementation, ignoring overrides.\n// Does not call -dealloc.\n// Returns true if the object should now be deallocated.\n// This does not check isa.fast_rr; if there is an RR override then \n// it was already called and it chose to call [super release].\ninline bool \nobjc_object::rootRelease()\n{\n    if (isTaggedPointer()) return false;\n    return sidetable_release(true);\n}\n\ninline bool \nobjc_object::rootReleaseShouldDealloc()\n{\n    if (isTaggedPointer()) return false;\n    return sidetable_release(false);\n}\n\n\n// Equivalent to [this autorelease], with shortcuts if there is no override\ninline id \nobjc_object::autorelease()\n{\n    if (isTaggedPointer()) return (id)this;\n    if (fastpath(!ISA()->hasCustomRR())) return rootAutorelease();\n\n    return ((id(*)(objc_object *, SEL))objc_msgSend)(this, SEL_autorelease);\n}\n\n\n// Base autorelease implementation, ignoring overrides.\ninline id \nobjc_object::rootAutorelease()\n{\n    if (isTaggedPointer()) return (id)this;\n    if (prepareOptimizedReturn(ReturnAtPlus1)) return (id)this;\n\n    return rootAutorelease2();\n}\n\n\n// Base tryRetain implementation, ignoring overrides.\n// This does not check isa.fast_rr; if there is an RR override then \n// it was already called and it chose to call [super _tryRetain].\ninline bool \nobjc_object::rootTryRetain()\n{\n    if (isTaggedPointer()) return true;\n    return sidetable_tryRetain();\n}\n\n\ninline uintptr_t \nobjc_object::rootRetainCount()\n{\n    if (isTaggedPointer()) return (uintptr_t)this;\n    return sidetable_retainCount();\n}\n\n\n// not SUPPORT_NONPOINTER_ISA\n#endif\n\n\n#if SUPPORT_RETURN_AUTORELEASE\n\n/***********************************************************************\n  Fast handling of return through Cocoa's +0 autoreleasing convention.\n  The caller and callee cooperate to keep the returned object \n  out of the autorelease pool and eliminate redundant retain/release pairs.\n\n  An optimized callee looks at the caller's instructions following the \n  return. If the caller's instructions are also optimized then the callee \n  skips all retain count operations: no autorelease, no retain/autorelease.\n  Instead it saves the result's current retain count (+0 or +1) in \n  thread-local storage. If the caller does not look optimized then \n  the callee performs autorelease or retain/autorelease as usual.\n\n  An optimized caller looks at the thread-local storage. If the result \n  is set then it performs any retain or release needed to change the \n  result from the retain count left by the callee to the retain count \n  desired by the caller. Otherwise the caller assumes the result is \n  currently at +0 from an unoptimized callee and performs any retain \n  needed for that case.\n\n  There are two optimized callees:\n    objc_autoreleaseReturnValue\n      result is currently +1. The unoptimized path autoreleases it.\n    objc_retainAutoreleaseReturnValue\n      result is currently +0. The unoptimized path retains and autoreleases it.\n\n  There are two optimized callers:\n    objc_retainAutoreleasedReturnValue\n      caller wants the value at +1. The unoptimized path retains it.\n    objc_unsafeClaimAutoreleasedReturnValue\n      caller wants the value at +0 unsafely. The unoptimized path does nothing.\n\n  Example:\n\n    Callee:\n      // compute ret at +1\n      return objc_autoreleaseReturnValue(ret);\n    \n    Caller:\n      ret = callee();\n      ret = objc_retainAutoreleasedReturnValue(ret);\n      // use ret at +1 here\n\n    Callee sees the optimized caller, sets TLS, and leaves the result at +1.\n    Caller sees the TLS, clears it, and accepts the result at +1 as-is.\n\n  The callee's recognition of the optimized caller is architecture-dependent.\n  x86_64: Callee looks for `mov rax, rdi` followed by a call or \n    jump instruction to objc_retainAutoreleasedReturnValue or \n    objc_unsafeClaimAutoreleasedReturnValue. \n  i386:  Callee looks for a magic nop `movl %ebp, %ebp` (frame pointer register)\n  armv7: Callee looks for a magic nop `mov r7, r7` (frame pointer register). \n  arm64: Callee looks for a magic nop `mov x29, x29` (frame pointer register). \n\n  Tagged pointer objects do participate in the optimized return scheme, \n  because it saves message sends. They are not entered in the autorelease \n  pool in the unoptimized case.\n**********************************************************************/\n\n# if __x86_64__\n\nstatic ALWAYS_INLINE bool \ncallerAcceptsOptimizedReturn(const void * const ra0)\n{\n    const uint8_t *ra1 = (const uint8_t *)ra0;\n    const unaligned_uint16_t *ra2;\n    const unaligned_uint32_t *ra4 = (const unaligned_uint32_t *)ra1;\n    const void **sym;\n\n#define PREFER_GOTPCREL 0\n#if PREFER_GOTPCREL\n    // 48 89 c7    movq  %rax,%rdi\n    // ff 15       callq *symbol@GOTPCREL(%rip)\n    if (*ra4 != 0xffc78948) {\n        return false;\n    }\n    if (ra1[4] != 0x15) {\n        return false;\n    }\n    ra1 += 3;\n#else\n    // 48 89 c7    movq  %rax,%rdi\n    // e8          callq symbol\n    if (*ra4 != 0xe8c78948) {\n        return false;\n    }\n    ra1 += (long)*(const unaligned_int32_t *)(ra1 + 4) + 8l;\n    ra2 = (const unaligned_uint16_t *)ra1;\n    // ff 25       jmpq *symbol@DYLDMAGIC(%rip)\n    if (*ra2 != 0x25ff) {\n        return false;\n    }\n#endif\n    ra1 += 6l + (long)*(const unaligned_int32_t *)(ra1 + 2);\n    sym = (const void **)ra1;\n    if (*sym != objc_retainAutoreleasedReturnValue  &&  \n        *sym != objc_unsafeClaimAutoreleasedReturnValue) \n    {\n        return false;\n    }\n\n    return true;\n}\n\n// __x86_64__\n# elif __arm__\n\nstatic ALWAYS_INLINE bool \ncallerAcceptsOptimizedReturn(const void *ra)\n{\n    // if the low bit is set, we're returning to thumb mode\n    if ((uintptr_t)ra & 1) {\n        // 3f 46          mov r7, r7\n        // we mask off the low bit via subtraction\n        // 16-bit instructions are well-aligned\n        if (*(uint16_t *)((uint8_t *)ra - 1) == 0x463f) {\n            return true;\n        }\n    } else {\n        // 07 70 a0 e1    mov r7, r7\n        // 32-bit instructions may be only 16-bit aligned\n        if (*(unaligned_uint32_t *)ra == 0xe1a07007) {\n            return true;\n        }\n    }\n    return false;\n}\n\n// __arm__\n# elif __arm64__\n\nstatic ALWAYS_INLINE bool \ncallerAcceptsOptimizedReturn(const void *ra)\n{\n    // fd 03 1d aa    mov fp, fp\n    // arm64 instructions are well-aligned\n    if (*(uint32_t *)ra == 0xaa1d03fd) {\n        return true;\n    }\n    return false;\n}\n\n// __arm64__\n# elif __i386__\n\nstatic ALWAYS_INLINE bool \ncallerAcceptsOptimizedReturn(const void *ra)\n{\n    // 89 ed    movl %ebp, %ebp\n    if (*(unaligned_uint16_t *)ra == 0xed89) {\n        return true;\n    }\n    return false;\n}\n\n// __i386__\n# else\n\n#warning unknown architecture\n\nstatic ALWAYS_INLINE bool \ncallerAcceptsOptimizedReturn(const void *ra)\n{\n    return false;\n}\n\n// unknown architecture\n# endif\n\n\nstatic ALWAYS_INLINE ReturnDisposition \ngetReturnDisposition()\n{\n    return (ReturnDisposition)(uintptr_t)tls_get_direct(RETURN_DISPOSITION_KEY);\n}\n\n\nstatic ALWAYS_INLINE void \nsetReturnDisposition(ReturnDisposition disposition)\n{\n    tls_set_direct(RETURN_DISPOSITION_KEY, (void*)(uintptr_t)disposition);\n}\n\n\n// Try to prepare for optimized return with the given disposition (+0 or +1).\n// Returns true if the optimized path is successful.\n// Otherwise the return value must be retained and/or autoreleased as usual.\nstatic ALWAYS_INLINE bool \nprepareOptimizedReturn(ReturnDisposition disposition)\n{\n    assert(getReturnDisposition() == ReturnAtPlus0);\n\n    if (callerAcceptsOptimizedReturn(__builtin_return_address(0))) {\n        if (disposition) setReturnDisposition(disposition);\n        return true;\n    }\n\n    return false;\n}\n\n\n// Try to accept an optimized return.\n// Returns the disposition of the returned object (+0 or +1).\n// An un-optimized return is +0.\nstatic ALWAYS_INLINE ReturnDisposition \nacceptOptimizedReturn()\n{\n    ReturnDisposition disposition = getReturnDisposition();\n    setReturnDisposition(ReturnAtPlus0);  // reset to the unoptimized state\n    return disposition;\n}\n\n\n// SUPPORT_RETURN_AUTORELEASE\n#else\n// not SUPPORT_RETURN_AUTORELEASE\n\n\nstatic ALWAYS_INLINE bool\nprepareOptimizedReturn(ReturnDisposition disposition __unused)\n{\n    return false;\n}\n\n\nstatic ALWAYS_INLINE ReturnDisposition \nacceptOptimizedReturn()\n{\n    return ReturnAtPlus0;\n}\n\n\n// not SUPPORT_RETURN_AUTORELEASE\n#endif\n\n\n// _OBJC_OBJECT_H_\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-opt.mm",
    "content": "/*\n * Copyright (c) 2012 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/*\n  objc-opt.mm\n  Management of optimizations in the dyld shared cache \n*/\n\n#include \"objc-private.h\"\n\n\n#if !SUPPORT_PREOPT\n// Preoptimization not supported on this platform.\n\nstruct objc_selopt_t;\n\nbool isPreoptimized(void) \n{\n    return false;\n}\n\nbool noMissingWeakSuperclasses(void) \n{\n    return false;\n}\n\nbool header_info::isPreoptimized() const\n{\n    return false;\n}\n\nobjc_selopt_t *preoptimizedSelectors(void) \n{\n    return nil;\n}\n\nProtocol *getPreoptimizedProtocol(const char *name)\n{\n    return nil;\n}\n\nunsigned int getPreoptimizedClassUnreasonableCount()\n{\n    return 0;\n}\n\nClass getPreoptimizedClass(const char *name)\n{\n    return nil;\n}\n\nClass* copyPreoptimizedClasses(const char *name, int *outCount)\n{\n    *outCount = 0;\n    return nil;\n}\n\nbool sharedRegionContains(const void *ptr)\n{\n    return false;\n}\n\nheader_info *preoptimizedHinfoForHeader(const headerType *mhdr)\n{\n    return nil;\n}\n\nheader_info_rw *getPreoptimizedHeaderRW(const struct header_info *const hdr)\n{\n    return nil;\n}\n\nvoid preopt_init(void)\n{\n    disableSharedCacheOptimizations();\n    \n    if (PrintPreopt) {\n        _objc_inform(\"PREOPTIMIZATION: is DISABLED \"\n                     \"(not supported on ths platform)\");\n    }\n}\n\n\n// !SUPPORT_PREOPT\n#else\n// SUPPORT_PREOPT\n\n#include <objc-shared-cache.h>\n\nusing objc_opt::objc_stringhash_offset_t;\nusing objc_opt::objc_protocolopt_t;\nusing objc_opt::objc_clsopt_t;\nusing objc_opt::objc_headeropt_ro_t;\nusing objc_opt::objc_headeropt_rw_t;\nusing objc_opt::objc_opt_t;\n\n__BEGIN_DECLS\n\n// preopt: the actual opt used at runtime (nil or &_objc_opt_data)\n// _objc_opt_data: opt data possibly written by dyld\n// opt is initialized to ~0 to detect incorrect use before preopt_init()\n\nstatic const objc_opt_t *opt = (objc_opt_t *)~0;\nstatic uintptr_t shared_cache_start;\nstatic uintptr_t shared_cache_end;\nstatic bool preoptimized;\n\nextern const objc_opt_t _objc_opt_data;  // in __TEXT, __objc_opt_ro\n\n/***********************************************************************\n* Return YES if we have a valid optimized shared cache.\n**********************************************************************/\nbool isPreoptimized(void) \n{\n    return preoptimized;\n}\n\n\n/***********************************************************************\n* Return YES if the shared cache does not have any classes with \n* missing weak superclasses.\n**********************************************************************/\nbool noMissingWeakSuperclasses(void) \n{\n    if (!preoptimized) return NO;  // might have missing weak superclasses\n    return opt->flags & objc_opt::NoMissingWeakSuperclasses;\n}\n\n\n/***********************************************************************\n* Return YES if this image's dyld shared cache optimizations are valid.\n**********************************************************************/\nbool header_info::isPreoptimized() const\n{\n    // preoptimization disabled for some reason\n    if (!preoptimized) return NO;\n\n    // image not from shared cache, or not fixed inside shared cache\n    if (!info()->optimizedByDyld()) return NO;\n\n    return YES;\n}\n\n\nobjc_selopt_t *preoptimizedSelectors(void) \n{\n    return opt ? opt->selopt() : nil;\n}\n\n\nProtocol *getPreoptimizedProtocol(const char *name)\n{\n    objc_protocolopt_t *protocols = opt ? opt->protocolopt() : nil;\n    if (!protocols) return nil;\n\n    return (Protocol *)protocols->getProtocol(name);\n}\n\n\nunsigned int getPreoptimizedClassUnreasonableCount()\n{\n    objc_clsopt_t *classes = opt ? opt->clsopt() : nil;\n    if (!classes) return 0;\n    \n    // This is an overestimate: each set of duplicates \n    // gets double-counted in `capacity` as well.\n    return classes->capacity + classes->duplicateCount();\n}\n\n\nClass getPreoptimizedClass(const char *name)\n{\n    objc_clsopt_t *classes = opt ? opt->clsopt() : nil;\n    if (!classes) return nil;\n\n    void *cls;\n    void *hi;\n    uint32_t count = classes->getClassAndHeader(name, cls, hi);\n    if (count == 1  &&  ((header_info *)hi)->isLoaded()) {\n        // exactly one matching class, and its image is loaded\n        return (Class)cls;\n    } \n    else if (count > 1) {\n        // more than one matching class - find one that is loaded\n        void *clslist[count];\n        void *hilist[count];\n        classes->getClassesAndHeaders(name, clslist, hilist);\n        for (uint32_t i = 0; i < count; i++) {\n            if (((header_info *)hilist[i])->isLoaded()) {\n                return (Class)clslist[i];\n            }\n        }\n    }\n\n    // no match that is loaded\n    return nil;\n}\n\n\nClass* copyPreoptimizedClasses(const char *name, int *outCount)\n{\n    *outCount = 0;\n\n    objc_clsopt_t *classes = opt ? opt->clsopt() : nil;\n    if (!classes) return nil;\n\n    void *cls;\n    void *hi;\n    uint32_t count = classes->getClassAndHeader(name, cls, hi);\n    if (count == 0) return nil;\n\n    Class *result = (Class *)calloc(count, sizeof(Class));\n    if (count == 1  &&  ((header_info *)hi)->isLoaded()) {\n        // exactly one matching class, and its image is loaded\n        result[(*outCount)++] = (Class)cls;\n        return result;\n    } \n    else if (count > 1) {\n        // more than one matching class - find those that are loaded\n        void *clslist[count];\n        void *hilist[count];\n        classes->getClassesAndHeaders(name, clslist, hilist);\n        for (uint32_t i = 0; i < count; i++) {\n            if (((header_info *)hilist[i])->isLoaded()) {\n                result[(*outCount)++] = (Class)clslist[i];\n            }\n        }\n\n        if (*outCount == 0) {\n            // found multiple classes with that name, but none are loaded\n            free(result);\n            result = nil;\n        }\n        return result;\n    }\n\n    // no match that is loaded\n    return nil;\n}\n\n/***********************************************************************\n* Return YES if the given pointer lies within the shared cache.\n* If the shared cache is not set up or is not valid,\n**********************************************************************/\nbool sharedRegionContains(const void *ptr)\n{\n    uintptr_t address = (uintptr_t)ptr;\n    return shared_cache_start <= address && address < shared_cache_end;\n}\n\nnamespace objc_opt {\nstruct objc_headeropt_ro_t {\n    uint32_t count;\n    uint32_t entsize;\n    header_info headers[0];  // sorted by mhdr address\n\n    header_info *get(const headerType *mhdr) \n    {\n        assert(entsize == sizeof(header_info));\n\n        int32_t start = 0;\n        int32_t end = count;\n        while (start <= end) {\n            int32_t i = (start+end)/2;\n            header_info *hi = headers+i;\n            if (mhdr == hi->mhdr()) return hi;\n            else if (mhdr < hi->mhdr()) end = i-1;\n            else start = i+1;\n        }\n\n#if DEBUG\n        for (uint32_t i = 0; i < count; i++) {\n            header_info *hi = headers+i;\n            if (mhdr == hi->mhdr()) {\n                _objc_fatal(\"failed to find header %p (%d/%d)\", \n                            mhdr, i, count);\n            }\n        }\n#endif\n\n        return nil;\n    }\n};\n\nstruct objc_headeropt_rw_t {\n    uint32_t count;\n    uint32_t entsize;\n    header_info_rw headers[0];  // sorted by mhdr address\n};\n};\n\n\nheader_info *preoptimizedHinfoForHeader(const headerType *mhdr)\n{\n#if !__OBJC2__\n    // fixme old ABI shared cache doesn't prepare these properly\n    return nil;\n#endif\n\n    objc_headeropt_ro_t *hinfos = opt ? opt->headeropt_ro() : nil;\n    if (hinfos) return hinfos->get(mhdr);\n    else return nil;\n}\n\n\nheader_info_rw *getPreoptimizedHeaderRW(const struct header_info *const hdr)\n{\n#if !__OBJC2__\n    // fixme old ABI shared cache doesn't prepare these properly\n    return nil;\n#endif\n    \n    objc_headeropt_ro_t *hinfoRO = opt ? opt->headeropt_ro() : nil;\n    objc_headeropt_rw_t *hinfoRW = opt ? opt->headeropt_rw() : nil;\n    if (!hinfoRO || !hinfoRW) {\n        _objc_fatal(\"preoptimized header_info missing for %s (%p %p %p)\",\n                    hdr->fname(), hdr, hinfoRO, hinfoRW);\n    }\n    int32_t index = (int32_t)(hdr - hinfoRO->headers);\n    assert(hinfoRW->entsize == sizeof(header_info_rw));\n    return &hinfoRW->headers[index];\n}\n\n\nvoid preopt_init(void)\n{\n    // Get the memory region occupied by the shared cache.\n    size_t length;\n    const void *start = _dyld_get_shared_cache_range(&length);\n    if (start) {\n        shared_cache_start = (uintptr_t)start;\n        shared_cache_end = shared_cache_start + length;\n    } else {\n        shared_cache_start = shared_cache_end = 0;\n    }\n    \n    // `opt` not set at compile time in order to detect too-early usage\n    const char *failure = nil;\n    opt = &_objc_opt_data;\n\n    if (DisablePreopt) {\n        // OBJC_DISABLE_PREOPTIMIZATION is set\n        // If opt->version != VERSION then you continue at your own risk.\n        failure = \"(by OBJC_DISABLE_PREOPTIMIZATION)\";\n    } \n    else if (opt->version != objc_opt::VERSION) {\n        // This shouldn't happen. You probably forgot to edit objc-sel-table.s.\n        // If dyld really did write the wrong optimization version, \n        // then we must halt because we don't know what bits dyld twiddled.\n        _objc_fatal(\"bad objc preopt version (want %d, got %d)\", \n                    objc_opt::VERSION, opt->version);\n    }\n    else if (!opt->selopt()  ||  !opt->headeropt_ro()) {\n        // One of the tables is missing. \n        failure = \"(dyld shared cache is absent or out of date)\";\n    }\n    \n    if (failure) {\n        // All preoptimized selector references are invalid.\n        preoptimized = NO;\n        opt = nil;\n        disableSharedCacheOptimizations();\n\n        if (PrintPreopt) {\n            _objc_inform(\"PREOPTIMIZATION: is DISABLED %s\", failure);\n        }\n    }\n    else {\n        // Valid optimization data written by dyld shared cache\n        preoptimized = YES;\n\n        if (PrintPreopt) {\n            _objc_inform(\"PREOPTIMIZATION: is ENABLED \"\n                         \"(version %d)\", opt->version);\n        }\n    }\n}\n\n\n__END_DECLS\n\n// SUPPORT_PREOPT\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-os.h",
    "content": "/*\n * Copyright (c) 2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-os.h\n* OS portability layer.\n**********************************************************************/\n\n#ifndef _OBJC_OS_H\n#define _OBJC_OS_H\n\n#include <TargetConditionals.h>\n#include \"objc-config.h\"\n\n#ifdef __LP64__\n#   define WORD_SHIFT 3UL\n#   define WORD_MASK 7UL\n#   define WORD_BITS 64\n#else\n#   define WORD_SHIFT 2UL\n#   define WORD_MASK 3UL\n#   define WORD_BITS 32\n#endif\n\nstatic inline uint32_t word_align(uint32_t x) {\n    return (x + WORD_MASK) & ~WORD_MASK;\n}\nstatic inline size_t word_align(size_t x) {\n    return (x + WORD_MASK) & ~WORD_MASK;\n}\n\n\n// Mix-in for classes that must not be copied.\nclass nocopy_t {\n  private:\n    nocopy_t(const nocopy_t&) = delete;\n    const nocopy_t& operator=(const nocopy_t&) = delete;\n  protected:\n    constexpr nocopy_t() = default;\n    ~nocopy_t() = default;\n};\n\n\n#if TARGET_OS_MAC\n\n#   define OS_UNFAIR_LOCK_INLINE 1\n\n#   ifndef __STDC_LIMIT_MACROS\n#       define __STDC_LIMIT_MACROS\n#   endif\n\n#   include <stdio.h>\n#   include <stdlib.h>\n#   include <stdint.h>\n#   include <stdarg.h>\n#   include <string.h>\n#   include <ctype.h>\n#   include <errno.h>\n#   include <dlfcn.h>\n#   include <fcntl.h>\n#   include <assert.h>\n#   include <limits.h>\n#   include <syslog.h>\n#   include <unistd.h>\n#   include <pthread.h>\n#   include <crt_externs.h>\n#   undef check\n#   include <Availability.h>\n#   include <TargetConditionals.h>\n#   include <sys/mman.h>\n#   include <sys/time.h>\n#   include <sys/stat.h>\n#   include <sys/param.h>\n#   include <sys/reason.h>\n#   include <mach/mach.h>\n#   include <mach/vm_param.h>\n#   include <mach/mach_time.h>\n#   include <mach-o/dyld.h>\n#   include <mach-o/ldsyms.h>\n#   include <mach-o/loader.h>\n#   include <mach-o/getsect.h>\n#   include <mach-o/dyld_priv.h>\n#   include <malloc/malloc.h>\n#   include <os/lock_private.h>\n#   include <libkern/OSAtomic.h>\n#   include <libkern/OSCacheControl.h>\n#   include <System/pthread_machdep.h>\n#   include \"objc-probes.h\"  // generated dtrace probe definitions.\n\n// Some libc functions call objc_msgSend() \n// so we can't use them without deadlocks.\nvoid syslog(int, const char *, ...) UNAVAILABLE_ATTRIBUTE;\nvoid vsyslog(int, const char *, va_list) UNAVAILABLE_ATTRIBUTE;\n\n\n#define ALWAYS_INLINE inline __attribute__((always_inline))\n#define NEVER_INLINE inline __attribute__((noinline))\n\n#define fastpath(x) (__builtin_expect(bool(x), 1))\n#define slowpath(x) (__builtin_expect(bool(x), 0))\n\n\nstatic ALWAYS_INLINE uintptr_t \naddc(uintptr_t lhs, uintptr_t rhs, uintptr_t carryin, uintptr_t *carryout)\n{\n    return __builtin_addcl(lhs, rhs, carryin, carryout);\n}\n\nstatic ALWAYS_INLINE uintptr_t \nsubc(uintptr_t lhs, uintptr_t rhs, uintptr_t carryin, uintptr_t *carryout)\n{\n    return __builtin_subcl(lhs, rhs, carryin, carryout);\n}\n\n\n#if __arm64__\n\n// Pointer-size register prefix for inline asm\n# if __LP64__\n#   define p \"x\"  // true arm64\n# else\n#   define p \"w\"  // arm64_32\n# endif\n\nstatic ALWAYS_INLINE\nuintptr_t \nLoadExclusive(uintptr_t *src)\n{\n    uintptr_t result;\n    asm(\"ldxr %\" p \"0, [%x1]\" \n        : \"=r\" (result) \n        : \"r\" (src), \"m\" (*src));\n    return result;\n}\n\nstatic ALWAYS_INLINE\nbool \nStoreExclusive(uintptr_t *dst, uintptr_t oldvalue __unused, uintptr_t value)\n{\n    uint32_t result;\n    asm(\"stxr %w0, %\" p \"2, [%x3]\" \n        : \"=&r\" (result), \"=m\" (*dst)\n        : \"r\" (value), \"r\" (dst));\n    return !result;\n}\n\n\nstatic ALWAYS_INLINE\nbool \nStoreReleaseExclusive(uintptr_t *dst, uintptr_t oldvalue __unused, uintptr_t value)\n{\n    uint32_t result;\n    asm(\"stlxr %w0, %\" p \"2, [%x3]\" \n        : \"=&r\" (result), \"=m\" (*dst)\n        : \"r\" (value), \"r\" (dst));\n    return !result;\n}\n\nstatic ALWAYS_INLINE\nvoid \nClearExclusive(uintptr_t *dst)\n{\n    // pretend it writes to *dst for instruction ordering purposes\n    asm(\"clrex\" : \"=m\" (*dst));\n}\n\n#undef p\n\n#elif __arm__  \n\nstatic ALWAYS_INLINE\nuintptr_t \nLoadExclusive(uintptr_t *src)\n{\n    return *src;\n}\n\nstatic ALWAYS_INLINE\nbool \nStoreExclusive(uintptr_t *dst, uintptr_t oldvalue, uintptr_t value)\n{\n    return OSAtomicCompareAndSwapPtr((void *)oldvalue, (void *)value, \n                                     (void **)dst);\n}\n\nstatic ALWAYS_INLINE\nbool \nStoreReleaseExclusive(uintptr_t *dst, uintptr_t oldvalue, uintptr_t value)\n{\n    return OSAtomicCompareAndSwapPtrBarrier((void *)oldvalue, (void *)value, \n                                            (void **)dst);\n}\n\nstatic ALWAYS_INLINE\nvoid \nClearExclusive(uintptr_t *dst __unused)\n{\n}\n\n\n#elif __x86_64__  ||  __i386__\n\nstatic ALWAYS_INLINE\nuintptr_t \nLoadExclusive(uintptr_t *src)\n{\n    return *src;\n}\n\nstatic ALWAYS_INLINE\nbool \nStoreExclusive(uintptr_t *dst, uintptr_t oldvalue, uintptr_t value)\n{\n    \n    return __sync_bool_compare_and_swap((void **)dst, (void *)oldvalue, (void *)value);\n}\n\nstatic ALWAYS_INLINE\nbool \nStoreReleaseExclusive(uintptr_t *dst, uintptr_t oldvalue, uintptr_t value)\n{\n    return StoreExclusive(dst, oldvalue, value);\n}\n\nstatic ALWAYS_INLINE\nvoid \nClearExclusive(uintptr_t *dst __unused)\n{\n}\n\n\n#else \n#   error unknown architecture\n#endif\n\n\n#if !TARGET_OS_IPHONE\n#   include <CrashReporterClient.h>\n#else\n    // CrashReporterClient not yet available on iOS\n    __BEGIN_DECLS\n    extern const char *CRSetCrashLogMessage(const char *msg);\n    extern const char *CRGetCrashLogMessage(void);\n    __END_DECLS\n#endif\n\n#   if __cplusplus\n#       include <vector>\n#       include <algorithm>\n#       include <functional>\n        using namespace std;\n#   endif\n\n#   define PRIVATE_EXTERN __attribute__((visibility(\"hidden\")))\n#   undef __private_extern__\n#   define __private_extern__ use_PRIVATE_EXTERN_instead\n#   undef private_extern\n#   define private_extern use_PRIVATE_EXTERN_instead\n\n/* Use this for functions that are intended to be breakpoint hooks.\n   If you do not, the compiler may optimize them away.\n   BREAKPOINT_FUNCTION( void stop_on_error(void) ); */\n#   define BREAKPOINT_FUNCTION(prototype)                             \\\n    OBJC_EXTERN __attribute__((noinline, used, visibility(\"hidden\"))) \\\n    prototype { asm(\"\"); }\n\n#elif TARGET_OS_WIN32\n\n#   define WINVER 0x0501\t\t// target Windows XP and later\n#   define _WIN32_WINNT 0x0501\t// target Windows XP and later\n#   define WIN32_LEAN_AND_MEAN\n    // hack: windef.h typedefs BOOL as int\n#   define BOOL WINBOOL\n#   include <windows.h>\n#   undef BOOL\n\n#   include <stdio.h>\n#   include <stdlib.h>\n#   include <stdint.h>\n#   include <stdarg.h>\n#   include <string.h>\n#   include <assert.h>\n#   include <malloc.h>\n#   include <Availability.h>\n\n#   if __cplusplus\n#       include <vector>\n#       include <algorithm>\n#       include <functional>\n        using namespace std;\n#       define __BEGIN_DECLS extern \"C\" {\n#       define __END_DECLS   }\n#   else\n#       define __BEGIN_DECLS /*empty*/\n#       define __END_DECLS   /*empty*/\n#   endif\n\n#   define PRIVATE_EXTERN\n#   define __attribute__(x)\n#   define inline __inline\n\n/* Use this for functions that are intended to be breakpoint hooks.\n   If you do not, the compiler may optimize them away.\n   BREAKPOINT_FUNCTION( void MyBreakpointFunction(void) ); */\n#   define BREAKPOINT_FUNCTION(prototype) \\\n    __declspec(noinline) prototype { __asm { } }\n\n/* stub out dtrace probes */\n#   define OBJC_RUNTIME_OBJC_EXCEPTION_RETHROW() do {} while(0)  \n#   define OBJC_RUNTIME_OBJC_EXCEPTION_THROW(arg0) do {} while(0)\n\n#else\n#   error unknown OS\n#endif\n\n\n#include <objc/objc.h>\n#include <objc/objc-api.h>\n\nextern void _objc_fatal(const char *fmt, ...) \n    __attribute__((noreturn, format (printf, 1, 2)));\nextern void _objc_fatal_with_reason(uint64_t reason, uint64_t flags, \n                                    const char *fmt, ...) \n    __attribute__((noreturn, format (printf, 3, 4)));\n\n#define INIT_ONCE_PTR(var, create, delete)                              \\\n    do {                                                                \\\n        if (var) break;                                                 \\\n        typeof(var) v = create;                                         \\\n        while (!var) {                                                  \\\n            if (OSAtomicCompareAndSwapPtrBarrier(0, (void*)v, (void**)&var)){ \\\n                goto done;                                              \\\n            }                                                           \\\n        }                                                               \\\n        delete;                                                         \\\n    done:;                                                              \\\n    } while (0)\n\n#define INIT_ONCE_32(var, create, delete)                               \\\n    do {                                                                \\\n        if (var) break;                                                 \\\n        typeof(var) v = create;                                         \\\n        while (!var) {                                                  \\\n            if (OSAtomicCompareAndSwap32Barrier(0, v, (volatile int32_t *)&var)) { \\\n                goto done;                                              \\\n            }                                                           \\\n        }                                                               \\\n        delete;                                                         \\\n    done:;                                                              \\\n    } while (0)\n\n\n// Thread keys reserved by libc for our use.\n#if defined(__PTK_FRAMEWORK_OBJC_KEY0)\n#   define SUPPORT_DIRECT_THREAD_KEYS 1\n#   define TLS_DIRECT_KEY        ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY0)\n#   define SYNC_DATA_DIRECT_KEY  ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY1)\n#   define SYNC_COUNT_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY2)\n#   define AUTORELEASE_POOL_KEY  ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY3)\n# if SUPPORT_RETURN_AUTORELEASE\n#   define RETURN_DISPOSITION_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY4)\n# endif\n#else\n#   define SUPPORT_DIRECT_THREAD_KEYS 0\n#endif\n\n\n#if TARGET_OS_WIN32\n\n// Compiler compatibility\n\n// OS compatibility\n\n#define strdup _strdup\n\n#define issetugid() 0\n\n#define MIN(x, y) ((x) < (y) ? (x) : (y))\n\nstatic __inline void bcopy(const void *src, void *dst, size_t size) { memcpy(dst, src, size); }\nstatic __inline void bzero(void *dst, size_t size) { memset(dst, 0, size); }\n\nint asprintf(char **dstp, const char *format, ...);\n\ntypedef void * malloc_zone_t;\n\nstatic __inline malloc_zone_t malloc_default_zone(void) { return (malloc_zone_t)-1; }\nstatic __inline void *malloc_zone_malloc(malloc_zone_t z, size_t size) { return malloc(size); }\nstatic __inline void *malloc_zone_calloc(malloc_zone_t z, size_t size, size_t count) { return calloc(size, count); }\nstatic __inline void *malloc_zone_realloc(malloc_zone_t z, void *p, size_t size) { return realloc(p, size); }\nstatic __inline void malloc_zone_free(malloc_zone_t z, void *p) { free(p); }\nstatic __inline malloc_zone_t malloc_zone_from_ptr(const void *p) { return (malloc_zone_t)-1; }\nstatic __inline size_t malloc_size(const void *p) { return _msize((void*)p); /* fixme invalid pointer check? */ }\n\n\n// OSAtomic\n\nstatic __inline BOOL OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) \n{ \n    // fixme barrier is overkill\n    long original = InterlockedCompareExchange(dst, newl, oldl);\n    return (original == oldl);\n}\n\nstatic __inline BOOL OSAtomicCompareAndSwapPtrBarrier(void *oldp, void *newp, void * volatile *dst) \n{ \n    void *original = InterlockedCompareExchangePointer(dst, newp, oldp);\n    return (original == oldp);\n}\n\nstatic __inline BOOL OSAtomicCompareAndSwap32Barrier(int32_t oldl, int32_t newl, int32_t volatile *dst) \n{ \n    long original = InterlockedCompareExchange((volatile long *)dst, newl, oldl);\n    return (original == oldl);\n}\n\nstatic __inline int32_t OSAtomicDecrement32Barrier(volatile int32_t *dst)\n{\n    return InterlockedDecrement((volatile long *)dst);\n}\n\nstatic __inline int32_t OSAtomicIncrement32Barrier(volatile int32_t *dst)\n{\n    return InterlockedIncrement((volatile long *)dst);\n}\n\n\n// Internal data types\n\ntypedef DWORD objc_thread_t;  // thread ID\nstatic __inline int thread_equal(objc_thread_t t1, objc_thread_t t2) { \n    return t1 == t2; \n}\nstatic __inline objc_thread_t thread_self(void) { \n    return GetCurrentThreadId(); \n}\n\ntypedef struct {\n    DWORD key;\n    void (*dtor)(void *);\n} tls_key_t;\nstatic __inline tls_key_t tls_create(void (*dtor)(void*)) { \n    // fixme need dtor registry for DllMain to call on thread detach\n    tls_key_t k;\n    k.key = TlsAlloc();\n    k.dtor = dtor;\n    return k;\n}\nstatic __inline void *tls_get(tls_key_t k) { \n    return TlsGetValue(k.key); \n}\nstatic __inline void tls_set(tls_key_t k, void *value) { \n    TlsSetValue(k.key, value); \n}\n\ntypedef struct {\n    CRITICAL_SECTION *lock;\n} mutex_t;\n#define MUTEX_INITIALIZER {0};\nextern void mutex_init(mutex_t *m);\nstatic __inline int _mutex_lock_nodebug(mutex_t *m) { \n    // fixme error check\n    if (!m->lock) {\n        mutex_init(m);\n    }\n    EnterCriticalSection(m->lock); \n    return 0;\n}\nstatic __inline bool _mutex_try_lock_nodebug(mutex_t *m) { \n    // fixme error check\n    if (!m->lock) {\n        mutex_init(m);\n    }\n    return TryEnterCriticalSection(m->lock); \n}\nstatic __inline int _mutex_unlock_nodebug(mutex_t *m) { \n    // fixme error check\n    LeaveCriticalSection(m->lock); \n    return 0;\n}\n\n\ntypedef mutex_t spinlock_t;\n#define spinlock_lock(l) mutex_lock(l)\n#define spinlock_unlock(l) mutex_unlock(l)\n#define SPINLOCK_INITIALIZER MUTEX_INITIALIZER\n\n\ntypedef struct {\n    HANDLE mutex;\n} recursive_mutex_t;\n#define RECURSIVE_MUTEX_INITIALIZER {0};\n#define RECURSIVE_MUTEX_NOT_LOCKED 1\nextern void recursive_mutex_init(recursive_mutex_t *m);\nstatic __inline int _recursive_mutex_lock_nodebug(recursive_mutex_t *m) { \n    assert(m->mutex);\n    return WaitForSingleObject(m->mutex, INFINITE);\n}\nstatic __inline bool _recursive_mutex_try_lock_nodebug(recursive_mutex_t *m) { \n    assert(m->mutex);\n    return (WAIT_OBJECT_0 == WaitForSingleObject(m->mutex, 0));\n}\nstatic __inline int _recursive_mutex_unlock_nodebug(recursive_mutex_t *m) { \n    assert(m->mutex);\n    return ReleaseMutex(m->mutex) ? 0 : RECURSIVE_MUTEX_NOT_LOCKED;\n}\n\n\n/*\ntypedef HANDLE mutex_t;\nstatic inline void mutex_init(HANDLE *m) { *m = CreateMutex(NULL, FALSE, NULL); }\nstatic inline void _mutex_lock(mutex_t *m) { WaitForSingleObject(*m, INFINITE); }\nstatic inline bool mutex_try_lock(mutex_t *m) { return WaitForSingleObject(*m, 0) == WAIT_OBJECT_0; }\nstatic inline void _mutex_unlock(mutex_t *m) { ReleaseMutex(*m); }\n*/\n\n// based on http://www.cs.wustl.edu/~schmidt/win32-cv-1.html\n// Vista-only CONDITION_VARIABLE would be better\ntypedef struct {\n    HANDLE mutex;\n    HANDLE waiters;      // semaphore for those in cond_wait()\n    HANDLE waitersDone;  // auto-reset event after everyone gets a broadcast\n    CRITICAL_SECTION waitCountLock;  // guards waitCount and didBroadcast\n    unsigned int waitCount;\n    int didBroadcast; \n} monitor_t;\n#define MONITOR_INITIALIZER { 0 }\n#define MONITOR_NOT_ENTERED 1\nextern int monitor_init(monitor_t *c);\n\nstatic inline int _monitor_enter_nodebug(monitor_t *c) {\n    if (!c->mutex) {\n        int err = monitor_init(c);\n        if (err) return err;\n    }\n    return WaitForSingleObject(c->mutex, INFINITE);\n}\nstatic inline int _monitor_leave_nodebug(monitor_t *c) {\n    if (!ReleaseMutex(c->mutex)) return MONITOR_NOT_ENTERED;\n    else return 0;\n}\nstatic inline int _monitor_wait_nodebug(monitor_t *c) { \n    int last;\n    EnterCriticalSection(&c->waitCountLock);\n    c->waitCount++;\n    LeaveCriticalSection(&c->waitCountLock);\n\n    SignalObjectAndWait(c->mutex, c->waiters, INFINITE, FALSE);\n\n    EnterCriticalSection(&c->waitCountLock);\n    c->waitCount--;\n    last = c->didBroadcast  &&  c->waitCount == 0;\n    LeaveCriticalSection(&c->waitCountLock);\n\n    if (last) {\n        // tell broadcaster that all waiters have awoken\n        SignalObjectAndWait(c->waitersDone, c->mutex, INFINITE, FALSE);\n    } else {\n        WaitForSingleObject(c->mutex, INFINITE);\n    }\n\n    // fixme error checking\n    return 0;\n}\nstatic inline int monitor_notify(monitor_t *c) { \n    int haveWaiters;\n\n    EnterCriticalSection(&c->waitCountLock);\n    haveWaiters = c->waitCount > 0;\n    LeaveCriticalSection(&c->waitCountLock);\n\n    if (haveWaiters) {\n        ReleaseSemaphore(c->waiters, 1, 0);\n    }\n\n    // fixme error checking\n    return 0;\n}\nstatic inline int monitor_notifyAll(monitor_t *c) { \n    EnterCriticalSection(&c->waitCountLock);\n    if (c->waitCount == 0) {\n        LeaveCriticalSection(&c->waitCountLock);\n        return 0;\n    }\n    c->didBroadcast = 1;\n    ReleaseSemaphore(c->waiters, c->waitCount, 0);\n    LeaveCriticalSection(&c->waitCountLock);\n\n    // fairness: wait for everyone to move from waiters to mutex\n    WaitForSingleObject(c->waitersDone, INFINITE);\n    // not under waitCountLock, but still under mutex\n    c->didBroadcast = 0;\n\n    // fixme error checking\n    return 0;\n}\n\n\ntypedef IMAGE_DOS_HEADER headerType;\n// fixme YES bundle? NO bundle? sometimes?\n#define headerIsBundle(hi) YES\nOBJC_EXTERN IMAGE_DOS_HEADER __ImageBase;\n#define libobjc_header ((headerType *)&__ImageBase)\n\n// Prototypes\n\n\n#elif TARGET_OS_MAC\n\n\n// OS headers\n#include <mach-o/loader.h>\n#ifndef __LP64__\n#   define SEGMENT_CMD LC_SEGMENT\n#else\n#   define SEGMENT_CMD LC_SEGMENT_64\n#endif\n\n#ifndef VM_MEMORY_OBJC_DISPATCHERS\n#   define VM_MEMORY_OBJC_DISPATCHERS 0\n#endif\n\n\n// Compiler compatibility\n\n// OS compatibility\n\nstatic inline uint64_t nanoseconds() {\n    return mach_absolute_time();\n}\n\n// Internal data types\n\ntypedef pthread_t objc_thread_t;\n\nstatic __inline int thread_equal(objc_thread_t t1, objc_thread_t t2) { \n    return pthread_equal(t1, t2); \n}\nstatic __inline objc_thread_t thread_self(void) { \n    return pthread_self(); \n}\n\n\ntypedef pthread_key_t tls_key_t;\n\nstatic inline tls_key_t tls_create(void (*dtor)(void*)) { \n    tls_key_t k;\n    pthread_key_create(&k, dtor); \n    return k;\n}\nstatic inline void *tls_get(tls_key_t k) { \n    return pthread_getspecific(k); \n}\nstatic inline void tls_set(tls_key_t k, void *value) { \n    pthread_setspecific(k, value); \n}\n\n#if SUPPORT_DIRECT_THREAD_KEYS\n\n#if DEBUG\nstatic bool is_valid_direct_key(tls_key_t k) {\n    return (   k == SYNC_DATA_DIRECT_KEY\n            || k == SYNC_COUNT_DIRECT_KEY\n            || k == AUTORELEASE_POOL_KEY\n#   if SUPPORT_RETURN_AUTORELEASE\n            || k == RETURN_DISPOSITION_KEY\n#   endif\n               );\n}\n#endif\n\nstatic inline void *tls_get_direct(tls_key_t k) \n{ \n    assert(is_valid_direct_key(k));\n\n    if (_pthread_has_direct_tsd()) {\n        return _pthread_getspecific_direct(k);\n    } else {\n        return pthread_getspecific(k);\n    }\n}\nstatic inline void tls_set_direct(tls_key_t k, void *value) \n{ \n    assert(is_valid_direct_key(k));\n\n    if (_pthread_has_direct_tsd()) {\n        _pthread_setspecific_direct(k, value);\n    } else {\n        pthread_setspecific(k, value);\n    }\n}\n\n// SUPPORT_DIRECT_THREAD_KEYS\n#endif\n\n\nstatic inline pthread_t pthread_self_direct()\n{\n    return (pthread_t)\n        _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF);\n}\n\nstatic inline mach_port_t mach_thread_self_direct() \n{\n    return (mach_port_t)(uintptr_t)\n        _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_MACH_THREAD_SELF);\n}\n\n\ntemplate <bool Debug> class mutex_tt;\ntemplate <bool Debug> class monitor_tt;\ntemplate <bool Debug> class recursive_mutex_tt;\n\n#if DEBUG\n#   define LOCKDEBUG 1\n#else\n#   define LOCKDEBUG 0\n#endif\n\nusing spinlock_t = mutex_tt<LOCKDEBUG>;\nusing mutex_t = mutex_tt<LOCKDEBUG>;\nusing monitor_t = monitor_tt<LOCKDEBUG>;\nusing recursive_mutex_t = recursive_mutex_tt<LOCKDEBUG>;\n\n// Use fork_unsafe_lock to get a lock that isn't \n// acquired and released around fork().\n// All fork-safe locks are checked in debug builds.\nstruct fork_unsafe_lock_t {\n    constexpr fork_unsafe_lock_t() = default;\n};\nextern const fork_unsafe_lock_t fork_unsafe_lock;\n\n#include \"objc-lockdebug.h\"\n\ntemplate <bool Debug>\nclass mutex_tt : nocopy_t {\n    os_unfair_lock mLock;\n public:\n    constexpr mutex_tt() : mLock(OS_UNFAIR_LOCK_INIT) {\n        lockdebug_remember_mutex(this);\n    }\n\n    constexpr mutex_tt(const fork_unsafe_lock_t unsafe) : mLock(OS_UNFAIR_LOCK_INIT) { }\n\n    void lock() {\n        lockdebug_mutex_lock(this);\n\n        os_unfair_lock_lock_with_options_inline\n            (&mLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION);\n    }\n\n    void unlock() {\n        lockdebug_mutex_unlock(this);\n\n        os_unfair_lock_unlock_inline(&mLock);\n    }\n\n    void forceReset() {\n        lockdebug_mutex_unlock(this);\n\n        bzero(&mLock, sizeof(mLock));\n        mLock = os_unfair_lock OS_UNFAIR_LOCK_INIT;\n    }\n\n    void assertLocked() {\n        lockdebug_mutex_assert_locked(this);\n    }\n\n    void assertUnlocked() {\n        lockdebug_mutex_assert_unlocked(this);\n    }\n\n\n    // Address-ordered lock discipline for a pair of locks.\n\n    static void lockTwo(mutex_tt *lock1, mutex_tt *lock2) {\n        if (lock1 < lock2) {\n            lock1->lock();\n            lock2->lock();\n        } else {\n            lock2->lock();\n            if (lock2 != lock1) lock1->lock(); \n        }\n    }\n\n    static void unlockTwo(mutex_tt *lock1, mutex_tt *lock2) {\n        lock1->unlock();\n        if (lock2 != lock1) lock2->unlock();\n    }\n\n    // Scoped lock and unlock\n    class locker : nocopy_t {\n        mutex_tt& lock;\n    public:\n        locker(mutex_tt& newLock) \n            : lock(newLock) { lock.lock(); }\n        ~locker() { lock.unlock(); }\n    };\n\n    // Either scoped lock and unlock, or NOP.\n    class conditional_locker : nocopy_t {\n        mutex_tt& lock;\n        bool didLock;\n    public:\n        conditional_locker(mutex_tt& newLock, bool shouldLock)\n            : lock(newLock), didLock(shouldLock)\n        {\n            if (shouldLock) lock.lock();\n        }\n        ~conditional_locker() { if (didLock) lock.unlock(); }\n    };\n};\n\nusing mutex_locker_t = mutex_tt<LOCKDEBUG>::locker;\nusing conditional_mutex_locker_t = mutex_tt<LOCKDEBUG>::conditional_locker;\n\n\ntemplate <bool Debug>\nclass recursive_mutex_tt : nocopy_t {\n    os_unfair_recursive_lock mLock;\n\n  public:\n    constexpr recursive_mutex_tt() : mLock(OS_UNFAIR_RECURSIVE_LOCK_INIT) {\n        lockdebug_remember_recursive_mutex(this);\n    }\n\n    constexpr recursive_mutex_tt(const fork_unsafe_lock_t unsafe)\n        : mLock(OS_UNFAIR_RECURSIVE_LOCK_INIT)\n    { }\n\n    void lock()\n    {\n        lockdebug_recursive_mutex_lock(this);\n        os_unfair_recursive_lock_lock(&mLock);\n    }\n\n    void unlock()\n    {\n        lockdebug_recursive_mutex_unlock(this);\n\n        os_unfair_recursive_lock_unlock(&mLock);\n    }\n\n    void forceReset()\n    {\n        lockdebug_recursive_mutex_unlock(this);\n\n        bzero(&mLock, sizeof(mLock));\n        mLock = os_unfair_recursive_lock OS_UNFAIR_RECURSIVE_LOCK_INIT;\n    }\n\n    bool tryUnlock()\n    {\n        if (os_unfair_recursive_lock_tryunlock4objc(&mLock)) {\n            lockdebug_recursive_mutex_unlock(this);\n            return true;\n        }\n        return false;\n    }\n\n    void assertLocked() {\n        lockdebug_recursive_mutex_assert_locked(this);\n    }\n\n    void assertUnlocked() {\n        lockdebug_recursive_mutex_assert_unlocked(this);\n    }\n};\n\n\ntemplate <bool Debug>\nclass monitor_tt {\n    pthread_mutex_t mutex;\n    pthread_cond_t cond;\n\n  public:\n    constexpr monitor_tt()\n        : mutex(PTHREAD_MUTEX_INITIALIZER), cond(PTHREAD_COND_INITIALIZER)\n    {\n        lockdebug_remember_monitor(this);\n    }\n\n    monitor_tt(const fork_unsafe_lock_t unsafe) \n        : mutex(PTHREAD_MUTEX_INITIALIZER), cond(PTHREAD_COND_INITIALIZER)\n    { }\n\n    void enter() \n    {\n        lockdebug_monitor_enter(this);\n\n        int err = pthread_mutex_lock(&mutex);\n        if (err) _objc_fatal(\"pthread_mutex_lock failed (%d)\", err);\n    }\n\n    void leave() \n    {\n        lockdebug_monitor_leave(this);\n\n        int err = pthread_mutex_unlock(&mutex);\n        if (err) _objc_fatal(\"pthread_mutex_unlock failed (%d)\", err);\n    }\n\n    void wait() \n    {\n        lockdebug_monitor_wait(this);\n\n        int err = pthread_cond_wait(&cond, &mutex);\n        if (err) _objc_fatal(\"pthread_cond_wait failed (%d)\", err);\n    }\n\n    void notify() \n    {\n        int err = pthread_cond_signal(&cond);\n        if (err) _objc_fatal(\"pthread_cond_signal failed (%d)\", err);        \n    }\n\n    void notifyAll() \n    {\n        int err = pthread_cond_broadcast(&cond);\n        if (err) _objc_fatal(\"pthread_cond_broadcast failed (%d)\", err);        \n    }\n\n    void forceReset()\n    {\n        lockdebug_monitor_leave(this);\n        \n        bzero(&mutex, sizeof(mutex));\n        bzero(&cond, sizeof(cond));\n        mutex = pthread_mutex_t PTHREAD_MUTEX_INITIALIZER;\n        cond = pthread_cond_t PTHREAD_COND_INITIALIZER;\n    }\n\n    void assertLocked()\n    {\n        lockdebug_monitor_assert_locked(this);\n    }\n\n    void assertUnlocked()\n    {\n        lockdebug_monitor_assert_unlocked(this);\n    }\n};\n\n\n// semaphore_create formatted for INIT_ONCE use\nstatic inline semaphore_t create_semaphore(void)\n{\n    semaphore_t sem;\n    kern_return_t k;\n    k = semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, 0);\n    if (k) _objc_fatal(\"semaphore_create failed (0x%x)\", k);\n    return sem;\n}\n\n\n#ifndef __LP64__\ntypedef struct mach_header headerType;\ntypedef struct segment_command segmentType;\ntypedef struct section sectionType;\n#else\ntypedef struct mach_header_64 headerType;\ntypedef struct segment_command_64 segmentType;\ntypedef struct section_64 sectionType;\n#endif\n#define headerIsBundle(hi) (hi->mhdr()->filetype == MH_BUNDLE)\n#define libobjc_header ((headerType *)&_mh_dylib_header)\n\n// Prototypes\n\n/* Secure /tmp usage */\nextern int secure_open(const char *filename, int flags, uid_t euid);\n\n\n#else\n\n\n#error unknown OS\n\n\n#endif\n\n\nstatic inline void *\nmemdup(const void *mem, size_t len)\n{\n    void *dup = malloc(len);\n    memcpy(dup, mem, len);\n    return dup;\n}\n\n// strdup that doesn't copy read-only memory\nstatic inline char *\nstrdupIfMutable(const char *str)\n{\n    size_t size = strlen(str) + 1;\n    if (_dyld_is_memory_immutable(str, size)) {\n        return (char *)str;\n    } else {\n        return (char *)memdup(str, size);\n    }\n}\n\n// free strdupIfMutable() result\nstatic inline void\nfreeIfMutable(char *str)\n{\n    size_t size = strlen(str) + 1;\n    if (_dyld_is_memory_immutable(str, size)) {\n        // nothing\n    } else {\n        free(str);\n    }\n}\n\n// nil-checking unsigned strdup\nstatic inline uint8_t *\nustrdupMaybeNil(const uint8_t *str)\n{\n    if (!str) return nil;\n    return (uint8_t *)strdupIfMutable((char *)str);\n}\n\n// OS version checking:\n//\n// sdkVersion()\n// DYLD_OS_VERSION(mac, ios, tv, watch, bridge)\n// sdkIsOlderThan(mac, ios, tv, watch, bridge)\n// sdkIsAtLeast(mac, ios, tv, watch, bridge)\n// \n// This version order matches OBJC_AVAILABLE.\n\n#if TARGET_OS_OSX\n#   define DYLD_OS_VERSION(x, i, t, w, b) DYLD_MACOSX_VERSION_##x\n#   define sdkVersion() dyld_get_program_sdk_version()\n\n#elif TARGET_OS_IOS\n#   define DYLD_OS_VERSION(x, i, t, w, b) DYLD_IOS_VERSION_##i\n#   define sdkVersion() dyld_get_program_sdk_version()\n\n#elif TARGET_OS_TV\n    // dyld does not currently have distinct constants for tvOS\n#   define DYLD_OS_VERSION(x, i, t, w, b) DYLD_IOS_VERSION_##t\n#   define sdkVersion() dyld_get_program_sdk_version()\n\n#elif TARGET_OS_BRIDGE\n#   if TARGET_OS_WATCH\n#       error bridgeOS 1.0 not supported\n#   endif\n    // fixme don't need bridgeOS versioning yet\n#   define DYLD_OS_VERSION(x, i, t, w, b) DYLD_IOS_VERSION_##t\n#   define sdkVersion() dyld_get_program_sdk_bridge_os_version()\n\n#elif TARGET_OS_WATCH\n#   define DYLD_OS_VERSION(x, i, t, w, b) DYLD_WATCHOS_VERSION_##w\n    // watchOS has its own API for compatibility reasons\n#   define sdkVersion() dyld_get_program_sdk_watch_os_version()\n\n#else\n#   error unknown OS\n#endif\n\n\n#define sdkIsOlderThan(x, i, t, w, b)                           \\\n            (sdkVersion() < DYLD_OS_VERSION(x, i, t, w, b))\n#define sdkIsAtLeast(x, i, t, w, b)                             \\\n            (sdkVersion() >= DYLD_OS_VERSION(x, i, t, w, b))\n\n// Allow bare 0 to be used in DYLD_OS_VERSION() and sdkIsOlderThan()\n#define DYLD_MACOSX_VERSION_0 0\n#define DYLD_IOS_VERSION_0 0\n#define DYLD_TVOS_VERSION_0 0\n#define DYLD_WATCHOS_VERSION_0 0\n#define DYLD_BRIDGEOS_VERSION_0 0\n\n// Pretty-print a DYLD_*_VERSION_* constant.\n#define SDK_FORMAT \"%hu.%hhu.%hhu\"\n#define FORMAT_SDK(v) \\\n    (unsigned short)(((uint32_t)(v))>>16),  \\\n    (unsigned  char)(((uint32_t)(v))>>8),   \\\n    (unsigned  char)(((uint32_t)(v))>>0)\n\n// fork() safety requires careful tracking of all locks.\n// Our custom lock types check this in debug builds.\n// Disallow direct use of all other lock types.\ntypedef __darwin_pthread_mutex_t pthread_mutex_t UNAVAILABLE_ATTRIBUTE;\ntypedef __darwin_pthread_rwlock_t pthread_rwlock_t UNAVAILABLE_ATTRIBUTE;\ntypedef int32_t OSSpinLock UNAVAILABLE_ATTRIBUTE;\ntypedef struct os_unfair_lock_s os_unfair_lock UNAVAILABLE_ATTRIBUTE;\n\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-os.mm",
    "content": "/*\n * Copyright (c) 2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-os.m\n* OS portability layer.\n**********************************************************************/\n\n#include \"objc-private.h\"\n#include \"objc-loadmethod.h\"\n\n#if TARGET_OS_WIN32\n\n#include \"objc-runtime-old.h\"\n#include \"objcrt.h\"\n\nconst fork_unsafe_lock_t fork_unsafe_lock;\n\nint monitor_init(monitor_t *c) \n{\n    // fixme error checking\n    HANDLE mutex = CreateMutex(NULL, TRUE, NULL);\n    while (!c->mutex) {\n        // fixme memory barrier here?\n        if (0 == InterlockedCompareExchangePointer(&c->mutex, mutex, 0)) {\n            // we win - finish construction\n            c->waiters = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);\n            c->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);\n            InitializeCriticalSection(&c->waitCountLock);\n            c->waitCount = 0;\n            c->didBroadcast = 0;\n            ReleaseMutex(c->mutex);    \n            return 0;\n        }\n    }\n\n    // someone else allocated the mutex and constructed the monitor\n    ReleaseMutex(mutex);\n    CloseHandle(mutex);\n    return 0;\n}\n\nvoid mutex_init(mutex_t *m)\n{\n    while (!m->lock) {\n        CRITICAL_SECTION *newlock = malloc(sizeof(CRITICAL_SECTION));\n        InitializeCriticalSection(newlock);\n        // fixme memory barrier here?\n        if (0 == InterlockedCompareExchangePointer(&m->lock, newlock, 0)) {\n            return;\n        }\n        // someone else installed their lock first\n        DeleteCriticalSection(newlock);\n        free(newlock);\n    }\n}\n\n\nvoid recursive_mutex_init(recursive_mutex_t *m)\n{\n    // fixme error checking\n    HANDLE newmutex = CreateMutex(NULL, FALSE, NULL);\n    while (!m->mutex) {\n        // fixme memory barrier here?\n        if (0 == InterlockedCompareExchangePointer(&m->mutex, newmutex, 0)) {\n            // we win\n            return;\n        }\n    }\n    \n    // someone else installed their lock first\n    CloseHandle(newmutex);\n}\n\n\nWINBOOL APIENTRY DllMain( HMODULE hModule,\n                       DWORD  ul_reason_for_call,\n                       LPVOID lpReserved\n\t\t\t\t\t )\n{\n    switch (ul_reason_for_call) {\n    case DLL_PROCESS_ATTACH:\n        environ_init();\n        tls_init();\n        lock_init();\n        sel_init(3500);  // old selector heuristic\n        exception_init();\n        break;\n\n    case DLL_THREAD_ATTACH:\n        break;\n\n    case DLL_THREAD_DETACH:\n    case DLL_PROCESS_DETACH:\n        break;\n    }\n    return TRUE;\n}\n\nOBJC_EXPORT void *_objc_init_image(HMODULE image, const objc_sections *sects)\n{\n    header_info *hi = malloc(sizeof(header_info));\n    size_t count, i;\n\n    hi->mhdr = (const headerType *)image;\n    hi->info = sects->iiStart;\n    hi->allClassesRealized = NO;\n    hi->modules = sects->modStart ? (Module *)((void **)sects->modStart+1) : 0;\n    hi->moduleCount = (Module *)sects->modEnd - hi->modules;\n    hi->protocols = sects->protoStart ? (struct old_protocol **)((void **)sects->protoStart+1) : 0;\n    hi->protocolCount = (struct old_protocol **)sects->protoEnd - hi->protocols;\n    hi->imageinfo = NULL;\n    hi->imageinfoBytes = 0;\n    // hi->imageinfo = sects->iiStart ? (uint8_t *)((void **)sects->iiStart+1) : 0;;\n//     hi->imageinfoBytes = (uint8_t *)sects->iiEnd - hi->imageinfo;\n    hi->selrefs = sects->selrefsStart ? (SEL *)((void **)sects->selrefsStart+1) : 0;\n    hi->selrefCount = (SEL *)sects->selrefsEnd - hi->selrefs;\n    hi->clsrefs = sects->clsrefsStart ? (Class *)((void **)sects->clsrefsStart+1) : 0;\n    hi->clsrefCount = (Class *)sects->clsrefsEnd - hi->clsrefs;\n\n    count = 0;\n    for (i = 0; i < hi->moduleCount; i++) {\n        if (hi->modules[i]) count++;\n    }\n    hi->mod_count = 0;\n    hi->mod_ptr = 0;\n    if (count > 0) {\n        hi->mod_ptr = malloc(count * sizeof(struct objc_module));\n        for (i = 0; i < hi->moduleCount; i++) {\n            if (hi->modules[i]) memcpy(&hi->mod_ptr[hi->mod_count++], hi->modules[i], sizeof(struct objc_module));\n        }\n    }\n    \n    hi->moduleName = malloc(MAX_PATH * sizeof(TCHAR));\n    GetModuleFileName((HMODULE)(hi->mhdr), hi->moduleName, MAX_PATH * sizeof(TCHAR));\n\n    appendHeader(hi);\n\n    if (PrintImages) {\n        _objc_inform(\"IMAGES: loading image for %s%s%s%s\\n\", \n                     hi->fname, \n                     headerIsBundle(hi) ? \" (bundle)\" : \"\", \n                     hi->info->isReplacement() ? \" (replacement)\":\"\", \n                     hi->info->hasCategoryClassProperties() ? \" (has class properties)\":\"\");\n    }\n\n    // Count classes. Size various table based on the total.\n    int total = 0;\n    int unoptimizedTotal = 0;\n    {\n      if (_getObjc2ClassList(hi, &count)) {\n        total += (int)count;\n        if (!hi->getInSharedCache()) unoptimizedTotal += count;\n      }\n    }\n\n    _read_images(&hi, 1, total, unoptimizedTotal);\n\n    return hi;\n}\n\nOBJC_EXPORT void _objc_load_image(HMODULE image, header_info *hinfo)\n{\n    prepare_load_methods(hinfo);\n    call_load_methods();\n}\n\nOBJC_EXPORT void _objc_unload_image(HMODULE image, header_info *hinfo)\n{\n    _objc_fatal(\"image unload not supported\");\n}\n\n\n// TARGET_OS_WIN32\n#elif TARGET_OS_MAC\n\n#include \"objc-file-old.h\"\n#include \"objc-file.h\"\n\n\n/***********************************************************************\n* libobjc must never run static destructors. \n* Cover libc's __cxa_atexit with our own definition that runs nothing.\n* rdar://21734598  ER: Compiler option to suppress C++ static destructors\n**********************************************************************/\nextern \"C\" int __cxa_atexit();\nextern \"C\" int __cxa_atexit() { return 0; }\n\n\n/***********************************************************************\n* bad_magic.\n* Return YES if the header has invalid Mach-o magic.\n**********************************************************************/\nbool bad_magic(const headerType *mhdr)\n{\n    return (mhdr->magic != MH_MAGIC  &&  mhdr->magic != MH_MAGIC_64  &&  \n            mhdr->magic != MH_CIGAM  &&  mhdr->magic != MH_CIGAM_64);\n}\n\n\nstatic header_info * addHeader(const headerType *mhdr, const char *path, int &totalClasses, int &unoptimizedTotalClasses)\n{\n    header_info *hi;\n\n    if (bad_magic(mhdr)) return NULL;\n\n    bool inSharedCache = false;\n\n    // Look for hinfo from the dyld shared cache.\n    hi = preoptimizedHinfoForHeader(mhdr);\n    if (hi) {\n        // Found an hinfo in the dyld shared cache.\n\n        // Weed out duplicates.\n        if (hi->isLoaded()) {\n            return NULL;\n        }\n\n        inSharedCache = true;\n\n        // Initialize fields not set by the shared cache\n        // hi->next is set by appendHeader\n        hi->setLoaded(true);\n\n        if (PrintPreopt) {\n            _objc_inform(\"PREOPTIMIZATION: honoring preoptimized header info at %p for %s\", hi, hi->fname());\n        }\n\n#if !__OBJC2__\n        _objc_fatal(\"shouldn't be here\");\n#endif\n#if DEBUG\n        // Verify image_info\n        size_t info_size = 0;\n        const objc_image_info *image_info = _getObjcImageInfo(mhdr,&info_size);\n        assert(image_info == hi->info());\n#endif\n    }\n    else \n    {\n        // Didn't find an hinfo in the dyld shared cache.\n\n        // Weed out duplicates\n        for (hi = FirstHeader; hi; hi = hi->getNext()) {\n            if (mhdr == hi->mhdr()) return NULL;\n        }\n\n        // Locate the __OBJC segment\n        size_t info_size = 0;\n        unsigned long seg_size;\n        const objc_image_info *image_info = _getObjcImageInfo(mhdr,&info_size);\n        const uint8_t *objc_segment = getsegmentdata(mhdr,SEG_OBJC,&seg_size);\n        if (!objc_segment  &&  !image_info) return NULL;\n\n        // Allocate a header_info entry.\n        // Note we also allocate space for a single header_info_rw in the\n        // rw_data[] inside header_info.\n        hi = (header_info *)calloc(sizeof(header_info) + sizeof(header_info_rw), 1);\n\n        // Set up the new header_info entry.\n        hi->setmhdr(mhdr);\n#if !__OBJC2__\n        // mhdr must already be set\n        hi->mod_count = 0;\n        hi->mod_ptr = _getObjcModules(hi, &hi->mod_count);\n#endif\n        // Install a placeholder image_info if absent to simplify code elsewhere\n        static const objc_image_info emptyInfo = {0, 0};\n        hi->setinfo(image_info ?: &emptyInfo);\n\n        hi->setLoaded(true);\n        hi->setAllClassesRealized(NO);\n    }\n\n#if __OBJC2__\n    {\n        size_t count = 0;\n        if (_getObjc2ClassList(hi, &count)) {\n            totalClasses += (int)count;\n            if (!inSharedCache) unoptimizedTotalClasses += count;\n        }\n    }\n#endif\n\n    appendHeader(hi);\n    \n    return hi;\n}\n\n\n/***********************************************************************\n* linksToLibrary\n* Returns true if the image links directly to a dylib whose install name \n* is exactly the given name.\n**********************************************************************/\nbool\nlinksToLibrary(const header_info *hi, const char *name)\n{\n    const struct dylib_command *cmd;\n    unsigned long i;\n    \n    cmd = (const struct dylib_command *) (hi->mhdr() + 1);\n    for (i = 0; i < hi->mhdr()->ncmds; i++) {\n        if (cmd->cmd == LC_LOAD_DYLIB  ||  cmd->cmd == LC_LOAD_UPWARD_DYLIB  ||\n            cmd->cmd == LC_LOAD_WEAK_DYLIB  ||  cmd->cmd == LC_REEXPORT_DYLIB)\n        {\n            const char *dylib = cmd->dylib.name.offset + (const char *)cmd;\n            if (0 == strcmp(dylib, name)) return true;\n        }\n        cmd = (const struct dylib_command *)((char *)cmd + cmd->cmdsize);\n    }\n\n    return false;\n}\n\n\n#if SUPPORT_GC_COMPAT\n\n/***********************************************************************\n* shouldRejectGCApp\n* Return YES if the executable requires GC.\n**********************************************************************/\nstatic bool shouldRejectGCApp(const header_info *hi)\n{\n    assert(hi->mhdr()->filetype == MH_EXECUTE);\n\n    if (!hi->info()->supportsGC()) {\n        // App does not use GC. Don't reject it.\n        return NO;\n    }\n        \n    // Exception: Trivial AppleScriptObjC apps can run without GC.\n    // 1. executable defines no classes\n    // 2. executable references NSBundle only\n    // 3. executable links to AppleScriptObjC.framework\n    // Note that objc_appRequiresGC() also knows about this.\n    size_t classcount = 0;\n    size_t refcount = 0;\n#if __OBJC2__\n    _getObjc2ClassList(hi, &classcount);\n    _getObjc2ClassRefs(hi, &refcount);\n#else\n    if (hi->mod_count == 0  ||  (hi->mod_count == 1 && !hi->mod_ptr[0].symtab)) classcount = 0;\n    else classcount = 1;\n    _getObjcClassRefs(hi, &refcount);\n#endif\n    if (classcount == 0  &&  refcount == 1  &&  \n        linksToLibrary(hi, \"/System/Library/Frameworks\"\n                       \"/AppleScriptObjC.framework/Versions/A\"\n                       \"/AppleScriptObjC\"))\n    {\n        // It's AppleScriptObjC. Don't reject it.\n        return NO;\n    } \n    else {\n        // GC and not trivial AppleScriptObjC. Reject it.\n        return YES;\n    }\n}\n\n\n/***********************************************************************\n* rejectGCImage\n* Halt if an image requires GC.\n* Testing of the main executable should use rejectGCApp() instead.\n**********************************************************************/\nstatic bool shouldRejectGCImage(const headerType *mhdr)\n{\n    assert(mhdr->filetype != MH_EXECUTE);\n\n    objc_image_info *image_info;\n    size_t size;\n    \n#if !__OBJC2__\n    unsigned long seg_size;\n    // 32-bit: __OBJC seg but no image_info means no GC support\n    if (!getsegmentdata(mhdr, \"__OBJC\", &seg_size)) {\n        // Not objc, therefore not GC. Don't reject it.\n        return NO;\n    }\n    image_info = _getObjcImageInfo(mhdr, &size);\n    if (!image_info) {\n        // No image_info, therefore not GC. Don't reject it.\n        return NO;\n    }\n#else\n    // 64-bit: no image_info means no objc at all\n    image_info = _getObjcImageInfo(mhdr, &size);\n    if (!image_info) {\n        // Not objc, therefore not GC. Don't reject it.\n        return NO;\n    }\n#endif\n\n    return image_info->requiresGC();\n}\n\n// SUPPORT_GC_COMPAT\n#endif\n\n\n/***********************************************************************\n* map_images_nolock\n* Process the given images which are being mapped in by dyld.\n* All class registration and fixups are performed (or deferred pending\n* discovery of missing superclasses etc), and +load methods are called.\n*\n* info[] is in bottom-up order i.e. libobjc will be earlier in the \n* array than any library that links to libobjc.\n*\n* Locking: loadMethodLock(old) or runtimeLock(new) acquired by map_images.\n**********************************************************************/\n#if __OBJC2__\n#include \"objc-file.h\"\n#else\n#include \"objc-file-old.h\"\n#endif\n\nvoid \nmap_images_nolock(unsigned mhCount, const char * const mhPaths[],\n                  const struct mach_header * const mhdrs[])\n{\n    static bool firstTime = YES;\n    header_info *hList[mhCount];\n    uint32_t hCount;\n    size_t selrefCount = 0;\n\n    // Perform first-time initialization if necessary.\n    // This function is called before ordinary library initializers. \n    // fixme defer initialization until an objc-using image is found?\n    if (firstTime) {\n        preopt_init();\n    }\n\n    if (PrintImages) {\n        _objc_inform(\"IMAGES: processing %u newly-mapped images...\\n\", mhCount);\n    }\n\n\n    // Find all images with Objective-C metadata.\n    hCount = 0;\n\n    // Count classes. Size various table based on the total.\n    int totalClasses = 0;\n    int unoptimizedTotalClasses = 0;\n    {\n        uint32_t i = mhCount;\n        while (i--) {\n            const headerType *mhdr = (const headerType *)mhdrs[i];\n\n            auto hi = addHeader(mhdr, mhPaths[i], totalClasses, unoptimizedTotalClasses);\n            if (!hi) {\n                // no objc data in this entry\n                continue;\n            }\n            \n            if (mhdr->filetype == MH_EXECUTE) {\n                // Size some data structures based on main executable's size\n#if __OBJC2__\n                size_t count;\n                _getObjc2SelectorRefs(hi, &count);\n                selrefCount += count;\n                _getObjc2MessageRefs(hi, &count);\n                selrefCount += count;\n#else\n                _getObjcSelectorRefs(hi, &selrefCount);\n#endif\n                \n#if SUPPORT_GC_COMPAT\n                // Halt if this is a GC app.\n                if (shouldRejectGCApp(hi)) {\n                    _objc_fatal_with_reason\n                        (OBJC_EXIT_REASON_GC_NOT_SUPPORTED, \n                         OS_REASON_FLAG_CONSISTENT_FAILURE, \n                         \"Objective-C garbage collection \" \n                         \"is no longer supported.\");\n                }\n#endif\n            }\n            \n            hList[hCount++] = hi;\n            \n            if (PrintImages) {\n                _objc_inform(\"IMAGES: loading image for %s%s%s%s%s\\n\", \n                             hi->fname(),\n                             mhdr->filetype == MH_BUNDLE ? \" (bundle)\" : \"\",\n                             hi->info()->isReplacement() ? \" (replacement)\" : \"\",\n                             hi->info()->hasCategoryClassProperties() ? \" (has class properties)\" : \"\",\n                             hi->info()->optimizedByDyld()?\" (preoptimized)\":\"\");\n            }\n        }\n    }\n\n    // Perform one-time runtime initialization that must be deferred until \n    // the executable itself is found. This needs to be done before \n    // further initialization.\n    // (The executable may not be present in this infoList if the \n    // executable does not contain Objective-C code but Objective-C \n    // is dynamically loaded later.\n    if (firstTime) {\n        sel_init(selrefCount);\n        arr_init();\n\n#if SUPPORT_GC_COMPAT\n        // Reject any GC images linked to the main executable.\n        // We already rejected the app itself above.\n        // Images loaded after launch will be rejected by dyld.\n\n        for (uint32_t i = 0; i < hCount; i++) {\n            auto hi = hList[i];\n            auto mh = hi->mhdr();\n            if (mh->filetype != MH_EXECUTE  &&  shouldRejectGCImage(mh)) {\n                _objc_fatal_with_reason\n                    (OBJC_EXIT_REASON_GC_NOT_SUPPORTED, \n                     OS_REASON_FLAG_CONSISTENT_FAILURE, \n                     \"%s requires Objective-C garbage collection \"\n                     \"which is no longer supported.\", hi->fname());\n            }\n        }\n#endif\n\n#if TARGET_OS_OSX\n        // Disable +initialize fork safety if the app is too old (< 10.13).\n        // Disable +initialize fork safety if the app has a\n        //   __DATA,__objc_fork_ok section.\n\n        if (dyld_get_program_sdk_version() < DYLD_MACOSX_VERSION_10_13) {\n            DisableInitializeForkSafety = true;\n            if (PrintInitializing) {\n                _objc_inform(\"INITIALIZE: disabling +initialize fork \"\n                             \"safety enforcement because the app is \"\n                             \"too old (SDK version \" SDK_FORMAT \")\",\n                             FORMAT_SDK(dyld_get_program_sdk_version()));\n            }\n        }\n\n        for (uint32_t i = 0; i < hCount; i++) {\n            auto hi = hList[i];\n            auto mh = hi->mhdr();\n            if (mh->filetype != MH_EXECUTE) continue;\n            unsigned long size;\n            if (getsectiondata(hi->mhdr(), \"__DATA\", \"__objc_fork_ok\", &size)) {\n                DisableInitializeForkSafety = true;\n                if (PrintInitializing) {\n                    _objc_inform(\"INITIALIZE: disabling +initialize fork \"\n                                 \"safety enforcement because the app has \"\n                                 \"a __DATA,__objc_fork_ok section\");\n                }\n            }\n            break;  // assume only one MH_EXECUTE image\n        }\n#endif\n\n    }\n\n    if (hCount > 0) {\n        _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);\n    }\n\n    firstTime = NO;\n}\n\n\n/***********************************************************************\n* unmap_image_nolock\n* Process the given image which is about to be unmapped by dyld.\n* mh is mach_header instead of headerType because that's what \n*   dyld_priv.h says even for 64-bit.\n* \n* Locking: loadMethodLock(both) and runtimeLock(new) acquired by unmap_image.\n**********************************************************************/\nvoid \nunmap_image_nolock(const struct mach_header *mh)\n{\n    if (PrintImages) {\n        _objc_inform(\"IMAGES: processing 1 newly-unmapped image...\\n\");\n    }\n\n    header_info *hi;\n    \n    // Find the runtime's header_info struct for the image\n    for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) {\n        if (hi->mhdr() == (const headerType *)mh) {\n            break;\n        }\n    }\n\n    if (!hi) return;\n\n    if (PrintImages) {\n        _objc_inform(\"IMAGES: unloading image for %s%s%s\\n\", \n                     hi->fname(),\n                     hi->mhdr()->filetype == MH_BUNDLE ? \" (bundle)\" : \"\",\n                     hi->info()->isReplacement() ? \" (replacement)\" : \"\");\n    }\n\n    _unload_image(hi);\n\n    // Remove header_info from header list\n    removeHeader(hi);\n    free(hi);\n}\n\n\n/***********************************************************************\n* static_init\n* Run C++ static constructor functions.\n* libc calls _objc_init() before dyld would call our static constructors, \n* so we have to do it ourselves.\n**********************************************************************/\nstatic void static_init()\n{\n    size_t count;\n    auto inits = getLibobjcInitializers(&_mh_dylib_header, &count);\n    for (size_t i = 0; i < count; i++) {\n        inits[i]();\n    }\n}\n\n\n/***********************************************************************\n* _objc_atfork_prepare\n* _objc_atfork_parent\n* _objc_atfork_child\n* Allow ObjC to be used between fork() and exec().\n* libc requires this because it has fork-safe functions that use os_objects.\n*\n* _objc_atfork_prepare() acquires all locks.\n* _objc_atfork_parent() releases the locks again.\n* _objc_atfork_child() forcibly resets the locks.\n**********************************************************************/\n\n// Declare lock ordering.\n#if LOCKDEBUG\n__attribute__((constructor))\nstatic void defineLockOrder()\n{\n    // Every lock precedes crashlog_lock\n    // on the assumption that fatal errors could be anywhere.\n    lockdebug_lock_precedes_lock(&loadMethodLock, &crashlog_lock);\n    lockdebug_lock_precedes_lock(&classInitLock, &crashlog_lock);\n#if __OBJC2__\n    lockdebug_lock_precedes_lock(&runtimeLock, &crashlog_lock);\n    lockdebug_lock_precedes_lock(&DemangleCacheLock, &crashlog_lock);\n#else\n    lockdebug_lock_precedes_lock(&classLock, &crashlog_lock);\n    lockdebug_lock_precedes_lock(&methodListLock, &crashlog_lock);\n    lockdebug_lock_precedes_lock(&NXUniqueStringLock, &crashlog_lock);\n    lockdebug_lock_precedes_lock(&impLock, &crashlog_lock);\n#endif\n    lockdebug_lock_precedes_lock(&selLock, &crashlog_lock);\n    lockdebug_lock_precedes_lock(&cacheUpdateLock, &crashlog_lock);\n    lockdebug_lock_precedes_lock(&objcMsgLogLock, &crashlog_lock);\n    lockdebug_lock_precedes_lock(&AltHandlerDebugLock, &crashlog_lock);\n    lockdebug_lock_precedes_lock(&AssociationsManagerLock, &crashlog_lock);\n    SideTableLocksPrecedeLock(&crashlog_lock);\n    PropertyLocks.precedeLock(&crashlog_lock);\n    StructLocks.precedeLock(&crashlog_lock);\n    CppObjectLocks.precedeLock(&crashlog_lock);\n\n    // loadMethodLock precedes everything\n    // because it is held while +load methods run\n    lockdebug_lock_precedes_lock(&loadMethodLock, &classInitLock);\n#if __OBJC2__\n    lockdebug_lock_precedes_lock(&loadMethodLock, &runtimeLock);\n    lockdebug_lock_precedes_lock(&loadMethodLock, &DemangleCacheLock);\n#else\n    lockdebug_lock_precedes_lock(&loadMethodLock, &methodListLock);\n    lockdebug_lock_precedes_lock(&loadMethodLock, &classLock);\n    lockdebug_lock_precedes_lock(&loadMethodLock, &NXUniqueStringLock);\n    lockdebug_lock_precedes_lock(&loadMethodLock, &impLock);\n#endif\n    lockdebug_lock_precedes_lock(&loadMethodLock, &selLock);\n    lockdebug_lock_precedes_lock(&loadMethodLock, &cacheUpdateLock);\n    lockdebug_lock_precedes_lock(&loadMethodLock, &objcMsgLogLock);\n    lockdebug_lock_precedes_lock(&loadMethodLock, &AltHandlerDebugLock);\n    lockdebug_lock_precedes_lock(&loadMethodLock, &AssociationsManagerLock);\n    SideTableLocksSucceedLock(&loadMethodLock);\n    PropertyLocks.succeedLock(&loadMethodLock);\n    StructLocks.succeedLock(&loadMethodLock);\n    CppObjectLocks.succeedLock(&loadMethodLock);\n\n    // PropertyLocks and CppObjectLocks and AssociationManagerLock \n    // precede everything because they are held while objc_retain() \n    // or C++ copy are called.\n    // (StructLocks do not precede everything because it calls memmove only.)\n    auto PropertyAndCppObjectAndAssocLocksPrecedeLock = [&](const void *lock) {\n        PropertyLocks.precedeLock(lock);\n        CppObjectLocks.precedeLock(lock);\n        lockdebug_lock_precedes_lock(&AssociationsManagerLock, lock);\n    };\n#if __OBJC2__\n    PropertyAndCppObjectAndAssocLocksPrecedeLock(&runtimeLock);\n    PropertyAndCppObjectAndAssocLocksPrecedeLock(&DemangleCacheLock);\n#else\n    PropertyAndCppObjectAndAssocLocksPrecedeLock(&methodListLock);\n    PropertyAndCppObjectAndAssocLocksPrecedeLock(&classLock);\n    PropertyAndCppObjectAndAssocLocksPrecedeLock(&NXUniqueStringLock);\n    PropertyAndCppObjectAndAssocLocksPrecedeLock(&impLock);\n#endif\n    PropertyAndCppObjectAndAssocLocksPrecedeLock(&classInitLock);\n    PropertyAndCppObjectAndAssocLocksPrecedeLock(&selLock);\n    PropertyAndCppObjectAndAssocLocksPrecedeLock(&cacheUpdateLock);\n    PropertyAndCppObjectAndAssocLocksPrecedeLock(&objcMsgLogLock);\n    PropertyAndCppObjectAndAssocLocksPrecedeLock(&AltHandlerDebugLock);\n\n    SideTableLocksSucceedLocks(PropertyLocks);\n    SideTableLocksSucceedLocks(CppObjectLocks);\n    SideTableLocksSucceedLock(&AssociationsManagerLock);\n\n    PropertyLocks.precedeLock(&AssociationsManagerLock);\n    CppObjectLocks.precedeLock(&AssociationsManagerLock);\n    \n#if __OBJC2__\n    lockdebug_lock_precedes_lock(&classInitLock, &runtimeLock);\n#endif\n\n#if __OBJC2__\n    // Runtime operations may occur inside SideTable locks\n    // (such as storeWeak calling getMethodImplementation)\n    SideTableLocksPrecedeLock(&runtimeLock);\n    SideTableLocksPrecedeLock(&classInitLock);\n    // Some operations may occur inside runtimeLock.\n    lockdebug_lock_precedes_lock(&runtimeLock, &selLock);\n    lockdebug_lock_precedes_lock(&runtimeLock, &cacheUpdateLock);\n    lockdebug_lock_precedes_lock(&runtimeLock, &DemangleCacheLock);\n#else\n    // Runtime operations may occur inside SideTable locks\n    // (such as storeWeak calling getMethodImplementation)\n    SideTableLocksPrecedeLock(&methodListLock);\n    SideTableLocksPrecedeLock(&classInitLock);\n    // Method lookup and fixup.\n    lockdebug_lock_precedes_lock(&methodListLock, &classLock);\n    lockdebug_lock_precedes_lock(&methodListLock, &selLock);\n    lockdebug_lock_precedes_lock(&methodListLock, &cacheUpdateLock);\n    lockdebug_lock_precedes_lock(&methodListLock, &impLock);\n    lockdebug_lock_precedes_lock(&classLock, &selLock);\n    lockdebug_lock_precedes_lock(&classLock, &cacheUpdateLock);\n#endif\n\n    // Striped locks use address order internally.\n    SideTableDefineLockOrder();\n    PropertyLocks.defineLockOrder();\n    StructLocks.defineLockOrder();\n    CppObjectLocks.defineLockOrder();\n}\n// LOCKDEBUG\n#endif\n\nstatic bool ForkIsMultithreaded;\nvoid _objc_atfork_prepare()\n{\n    // Save threaded-ness for the child's use.\n    ForkIsMultithreaded = pthread_is_threaded_np();\n\n    lockdebug_assert_no_locks_locked();\n    lockdebug_setInForkPrepare(true);\n\n    loadMethodLock.lock();\n    PropertyLocks.lockAll();\n    CppObjectLocks.lockAll();\n    AssociationsManagerLock.lock();\n    SideTableLockAll();\n    classInitLock.enter();\n#if __OBJC2__\n    runtimeLock.lock();\n    DemangleCacheLock.lock();\n#else\n    methodListLock.lock();\n    classLock.lock();\n    NXUniqueStringLock.lock();\n    impLock.lock();\n#endif\n    selLock.lock();\n    cacheUpdateLock.lock();\n    objcMsgLogLock.lock();\n    AltHandlerDebugLock.lock();\n    StructLocks.lockAll();\n    crashlog_lock.lock();\n\n    lockdebug_assert_all_locks_locked();\n    lockdebug_setInForkPrepare(false);\n}\n\nvoid _objc_atfork_parent()\n{\n    lockdebug_assert_all_locks_locked();\n\n    CppObjectLocks.unlockAll();\n    StructLocks.unlockAll();\n    PropertyLocks.unlockAll();\n    AssociationsManagerLock.unlock();\n    AltHandlerDebugLock.unlock();\n    objcMsgLogLock.unlock();\n    crashlog_lock.unlock();\n    loadMethodLock.unlock();\n    cacheUpdateLock.unlock();\n    selLock.unlock();\n    SideTableUnlockAll();\n#if __OBJC2__\n    DemangleCacheLock.unlock();\n    runtimeLock.unlock();\n#else\n    impLock.unlock();\n    NXUniqueStringLock.unlock();\n    methodListLock.unlock();\n    classLock.unlock();\n#endif\n    classInitLock.leave();\n\n    lockdebug_assert_no_locks_locked();\n}\n\nvoid _objc_atfork_child()\n{\n    // Turn on +initialize fork safety enforcement if applicable.\n    if (ForkIsMultithreaded  &&  !DisableInitializeForkSafety) {\n        MultithreadedForkChild = true;\n    }\n\n    lockdebug_assert_all_locks_locked();\n\n    CppObjectLocks.forceResetAll();\n    StructLocks.forceResetAll();\n    PropertyLocks.forceResetAll();\n    AssociationsManagerLock.forceReset();\n    AltHandlerDebugLock.forceReset();\n    objcMsgLogLock.forceReset();\n    crashlog_lock.forceReset();\n    loadMethodLock.forceReset();\n    cacheUpdateLock.forceReset();\n    selLock.forceReset();\n    SideTableForceResetAll();\n#if __OBJC2__\n    DemangleCacheLock.forceReset();\n    runtimeLock.forceReset();\n#else\n    impLock.forceReset();\n    NXUniqueStringLock.forceReset();\n    methodListLock.forceReset();\n    classLock.forceReset();\n#endif\n    classInitLock.forceReset();\n\n    lockdebug_assert_no_locks_locked();\n}\n\n\n/***********************************************************************\n* _objc_init\n* Bootstrap initialization. Registers our image notifier with dyld.\n* Called by libSystem BEFORE library initialization time\n**********************************************************************/\n\nvoid _objc_init(void)\n{\n    static bool initialized = false;\n    if (initialized) return;\n    initialized = true;\n    \n    // fixme defer initialization until an objc-using image is found?\n    environ_init();\n    tls_init();\n    static_init();\n    lock_init();\n    exception_init();\n\n    _dyld_objc_notify_register(&map_images, load_images, unmap_image);\n}\n\n\n/***********************************************************************\n* _headerForAddress.\n* addr can be a class or a category\n**********************************************************************/\nstatic const header_info *_headerForAddress(void *addr)\n{\n#if __OBJC2__\n    const char *segnames[] = { \"__DATA\", \"__DATA_CONST\", \"__DATA_DIRTY\" };\n#else\n    const char *segnames[] = { \"__OBJC\" };\n#endif\n    header_info *hi;\n\n    for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) {\n        for (size_t i = 0; i < sizeof(segnames)/sizeof(segnames[0]); i++) {\n            unsigned long seg_size;            \n            uint8_t *seg = getsegmentdata(hi->mhdr(), segnames[i], &seg_size);\n            if (!seg) continue;\n            \n            // Is the class in this header?\n            if ((uint8_t *)addr >= seg  &&  (uint8_t *)addr < seg + seg_size) {\n                return hi;\n            }\n        }\n    }\n\n    // Not found\n    return 0;\n}\n\n\n/***********************************************************************\n* _headerForClass\n* Return the image header containing this class, or NULL.\n* Returns NULL on runtime-constructed classes, and the NSCF classes.\n**********************************************************************/\nconst header_info *_headerForClass(Class cls)\n{\n    return _headerForAddress(cls);\n}\n\n\n/**********************************************************************\n* secure_open\n* Securely open a file from a world-writable directory (like /tmp)\n* If the file does not exist, it will be atomically created with mode 0600\n* If the file exists, it must be, and remain after opening: \n*   1. a regular file (in particular, not a symlink)\n*   2. owned by euid\n*   3. permissions 0600\n*   4. link count == 1\n* Returns a file descriptor or -1. Errno may or may not be set on error.\n**********************************************************************/\nint secure_open(const char *filename, int flags, uid_t euid)\n{\n    struct stat fs, ls;\n    int fd = -1;\n    bool truncate = NO;\n    bool create = NO;\n\n    if (flags & O_TRUNC) {\n        // Don't truncate the file until after it is open and verified.\n        truncate = YES;\n        flags &= ~O_TRUNC;\n    }\n    if (flags & O_CREAT) {\n        // Don't create except when we're ready for it\n        create = YES;\n        flags &= ~O_CREAT;\n        flags &= ~O_EXCL;\n    }\n\n    if (lstat(filename, &ls) < 0) {\n        if (errno == ENOENT  &&  create) {\n            // No such file - create it\n            fd = open(filename, flags | O_CREAT | O_EXCL, 0600);\n            if (fd >= 0) {\n                // File was created successfully.\n                // New file does not need to be truncated.\n                return fd;\n            } else {\n                // File creation failed.\n                return -1;\n            }\n        } else {\n            // lstat failed, or user doesn't want to create the file\n            return -1;\n        }\n    } else {\n        // lstat succeeded - verify attributes and open\n        if (S_ISREG(ls.st_mode)  &&  // regular file?\n            ls.st_nlink == 1  &&     // link count == 1?\n            ls.st_uid == euid  &&    // owned by euid?\n            (ls.st_mode & ALLPERMS) == (S_IRUSR | S_IWUSR))  // mode 0600?\n        {\n            // Attributes look ok - open it and check attributes again\n            fd = open(filename, flags, 0000);\n            if (fd >= 0) {\n                // File is open - double-check attributes\n                if (0 == fstat(fd, &fs)  &&  \n                    fs.st_nlink == ls.st_nlink  &&  // link count == 1?\n                    fs.st_uid == ls.st_uid  &&      // owned by euid?\n                    fs.st_mode == ls.st_mode  &&    // regular file, 0600?\n                    fs.st_ino == ls.st_ino  &&      // same inode as before?\n                    fs.st_dev == ls.st_dev)         // same device as before?\n                {\n                    // File is open and OK\n                    if (truncate) ftruncate(fd, 0);\n                    return fd;\n                } else {\n                    // Opened file looks funny - close it\n                    close(fd);\n                    return -1;\n                }\n            } else {\n                // File didn't open\n                return -1;\n            }\n        } else {\n            // Unopened file looks funny - don't open it\n            return -1;\n        }\n    }\n}\n\n\n#if TARGET_OS_IPHONE\n\nconst char *__crashreporter_info__ = NULL;\n\nconst char *CRSetCrashLogMessage(const char *msg)\n{\n    __crashreporter_info__ = msg;\n    return msg;\n}\nconst char *CRGetCrashLogMessage(void)\n{\n    return __crashreporter_info__;\n}\n\n#endif\n\n// TARGET_OS_MAC\n#else\n\n\n#error unknown OS\n\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-private.h",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\n *    objc-private.h\n *    Copyright 1988-1996, NeXT Software, Inc.\n */\n\n#ifndef _OBJC_PRIVATE_H_\n#define _OBJC_PRIVATE_H_\n\n#include \"objc-config.h\"\n\n/* Isolate ourselves from the definitions of id and Class in the compiler \n * and public headers.\n */\n\n#ifdef _OBJC_OBJC_H_\n#error include objc-private.h before other headers\n#endif\n\n#define OBJC_TYPES_DEFINED 1\n#undef OBJC_OLD_DISPATCH_PROTOTYPES\n#define OBJC_OLD_DISPATCH_PROTOTYPES 0\n\n#include <cstddef>  // for nullptr_t\n#include <stdint.h>\n#include <assert.h>\n\nstruct objc_class;\nstruct objc_object;\n\ntypedef struct objc_class *Class;\ntypedef struct objc_object *id;\n\nnamespace {\n    struct SideTable;\n};\n\n#include \"isa.h\"\n\nunion isa_t {\n    isa_t() { }\n    isa_t(uintptr_t value) : bits(value) { }\n\n    Class cls;\n    uintptr_t bits;\n#if defined(ISA_BITFIELD)\n    struct {\n        ISA_BITFIELD;  // defined in isa.h\n    };\n#endif\n};\n\n\nstruct objc_object {\nprivate:\n    isa_t isa;\n\npublic:\n\n    // ISA() assumes this is NOT a tagged pointer object\n    Class ISA();\n\n    // getIsa() allows this to be a tagged pointer object\n    Class getIsa();\n\n    // initIsa() should be used to init the isa of new objects only.\n    // If this object already has an isa, use changeIsa() for correctness.\n    // initInstanceIsa(): objects with no custom RR/AWZ\n    // initClassIsa(): class objects\n    // initProtocolIsa(): protocol objects\n    // initIsa(): other objects\n    void initIsa(Class cls /*nonpointer=false*/);\n    void initClassIsa(Class cls /*nonpointer=maybe*/);\n    void initProtocolIsa(Class cls /*nonpointer=maybe*/);\n    void initInstanceIsa(Class cls, bool hasCxxDtor);\n\n    // changeIsa() should be used to change the isa of existing objects.\n    // If this is a new object, use initIsa() for performance.\n    Class changeIsa(Class newCls);\n\n    bool hasNonpointerIsa();\n    bool isTaggedPointer();\n    bool isBasicTaggedPointer();\n    bool isExtTaggedPointer();\n    bool isClass();\n\n    // object may have associated objects?\n    bool hasAssociatedObjects();\n    void setHasAssociatedObjects();\n\n    // object may be weakly referenced?\n    bool isWeaklyReferenced();\n    void setWeaklyReferenced_nolock();\n\n    // object may have -.cxx_destruct implementation?\n    bool hasCxxDtor();\n\n    // Optimized calls to retain/release methods\n    id retain();\n    void release();\n    id autorelease();\n\n    // Implementations of retain/release methods\n    id rootRetain();\n    bool rootRelease();\n    id rootAutorelease();\n    bool rootTryRetain();\n    bool rootReleaseShouldDealloc();\n    uintptr_t rootRetainCount();\n\n    // Implementation of dealloc methods\n    bool rootIsDeallocating();\n    void clearDeallocating();\n    void rootDealloc();\n\nprivate:\n    void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);\n\n    // Slow paths for inline control\n    id rootAutorelease2();\n    bool overrelease_error();\n\n#if SUPPORT_NONPOINTER_ISA\n    // Unified retain count manipulation for nonpointer isa\n    id rootRetain(bool tryRetain, bool handleOverflow);\n    bool rootRelease(bool performDealloc, bool handleUnderflow);\n    id rootRetain_overflow(bool tryRetain);\n    bool rootRelease_underflow(bool performDealloc);\n\n    void clearDeallocating_slow();\n\n    // Side table retain count overflow for nonpointer isa\n    void sidetable_lock();\n    void sidetable_unlock();\n\n    void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);\n    bool sidetable_addExtraRC_nolock(size_t delta_rc);\n    size_t sidetable_subExtraRC_nolock(size_t delta_rc);\n    size_t sidetable_getExtraRC_nolock();\n#endif\n\n    // Side-table-only retain count\n    bool sidetable_isDeallocating();\n    void sidetable_clearDeallocating();\n\n    bool sidetable_isWeaklyReferenced();\n    void sidetable_setWeaklyReferenced_nolock();\n\n    id sidetable_retain();\n    id sidetable_retain_slow(SideTable& table);\n\n    uintptr_t sidetable_release(bool performDealloc = true);\n    uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);\n\n    bool sidetable_tryRetain();\n\n    uintptr_t sidetable_retainCount();\n#if DEBUG\n    bool sidetable_present();\n#endif\n};\n\n\n#if __OBJC2__\ntypedef struct method_t *Method;\ntypedef struct ivar_t *Ivar;\ntypedef struct category_t *Category;\ntypedef struct property_t *objc_property_t;\n#else\ntypedef struct old_method *Method;\ntypedef struct old_ivar *Ivar;\ntypedef struct old_category *Category;\ntypedef struct old_property *objc_property_t;\n#endif\n\n// Public headers\n\n#include \"objc.h\"\n#include \"runtime.h\"\n#include \"objc-os.h\"\n#include \"objc-abi.h\"\n#include \"objc-api.h\"\n#include \"objc-config.h\"\n#include \"objc-internal.h\"\n#include \"maptable.h\"\n#include \"hashtable2.h\"\n\n/* Do not include message.h here. */\n/* #include \"message.h\" */\n\n#define __APPLE_API_PRIVATE\n#include \"objc-gdb.h\"\n#undef __APPLE_API_PRIVATE\n\n\n// Private headers\n\n#include \"objc-ptrauth.h\"\n\n#if __OBJC2__\n#include \"objc-runtime-new.h\"\n#else\n#include \"objc-runtime-old.h\"\n#endif\n\n#include \"objc-references.h\"\n#include \"objc-initialize.h\"\n#include \"objc-loadmethod.h\"\n\n\n#if SUPPORT_PREOPT  &&  __cplusplus\n#include <objc-shared-cache.h>\nusing objc_selopt_t = const objc_opt::objc_selopt_t;\n#else\nstruct objc_selopt_t;\n#endif\n\n\n#define STRINGIFY(x) #x\n#define STRINGIFY2(x) STRINGIFY(x)\n\n__BEGIN_DECLS\n\nstruct header_info;\n\n// Split out the rw data from header info.  For now put it in a huge array\n// that more than exceeds the space needed.  In future we'll just allocate\n// this in the shared cache builder.\ntypedef struct header_info_rw {\n\n    bool getLoaded() const {\n        return isLoaded;\n    }\n\n    void setLoaded(bool v) {\n        isLoaded = v ? 1: 0;\n    }\n\n    bool getAllClassesRealized() const {\n        return allClassesRealized;\n    }\n\n    void setAllClassesRealized(bool v) {\n        allClassesRealized = v ? 1: 0;\n    }\n\n    header_info *getNext() const {\n        return (header_info *)(next << 2);\n    }\n\n    void setNext(header_info *v) {\n        next = ((uintptr_t)v) >> 2;\n    }\n\nprivate:\n#ifdef __LP64__\n    uintptr_t isLoaded              : 1;\n    uintptr_t allClassesRealized    : 1;\n    uintptr_t next                  : 62;\n#else\n    uintptr_t isLoaded              : 1;\n    uintptr_t allClassesRealized    : 1;\n    uintptr_t next                  : 30;\n#endif\n} header_info_rw;\n\nstruct header_info_rw* getPreoptimizedHeaderRW(const struct header_info *const hdr);\n\ntypedef struct header_info {\nprivate:\n    // Note, this is no longer a pointer, but instead an offset to a pointer\n    // from this location.\n    intptr_t mhdr_offset;\n\n    // Note, this is no longer a pointer, but instead an offset to a pointer\n    // from this location.\n    intptr_t info_offset;\n\n    // Do not add fields without editing ObjCModernAbstraction.hpp\npublic:\n\n    header_info_rw *getHeaderInfoRW() {\n        header_info_rw *preopt =\n            isPreoptimized() ? getPreoptimizedHeaderRW(this) : nil;\n        if (preopt) return preopt;\n        else return &rw_data[0];\n    }\n\n    const headerType *mhdr() const {\n        return (const headerType *)(((intptr_t)&mhdr_offset) + mhdr_offset);\n    }\n\n    void setmhdr(const headerType *mhdr) {\n        mhdr_offset = (intptr_t)mhdr - (intptr_t)&mhdr_offset;\n    }\n\n    const objc_image_info *info() const {\n        return (const objc_image_info *)(((intptr_t)&info_offset) + info_offset);\n    }\n\n    void setinfo(const objc_image_info *info) {\n        info_offset = (intptr_t)info - (intptr_t)&info_offset;\n    }\n\n    bool isLoaded() {\n        return getHeaderInfoRW()->getLoaded();\n    }\n\n    void setLoaded(bool v) {\n        getHeaderInfoRW()->setLoaded(v);\n    }\n\n    bool areAllClassesRealized() {\n        return getHeaderInfoRW()->getAllClassesRealized();\n    }\n\n    void setAllClassesRealized(bool v) {\n        getHeaderInfoRW()->setAllClassesRealized(v);\n    }\n\n    header_info *getNext() {\n        return getHeaderInfoRW()->getNext();\n    }\n\n    void setNext(header_info *v) {\n        getHeaderInfoRW()->setNext(v);\n    }\n\n    bool isBundle() {\n        return mhdr()->filetype == MH_BUNDLE;\n    }\n\n    const char *fname() const {\n        return dyld_image_path_containing_address(mhdr());\n    }\n\n    bool isPreoptimized() const;\n\n#if !__OBJC2__\n    struct old_protocol **proto_refs;\n    struct objc_module *mod_ptr;\n    size_t              mod_count;\n# if TARGET_OS_WIN32\n    struct objc_module **modules;\n    size_t moduleCount;\n    struct old_protocol **protocols;\n    size_t protocolCount;\n    void *imageinfo;\n    size_t imageinfoBytes;\n    SEL *selrefs;\n    size_t selrefCount;\n    struct objc_class **clsrefs;\n    size_t clsrefCount;    \n    TCHAR *moduleName;\n# endif\n#endif\n\nprivate:\n    // Images in the shared cache will have an empty array here while those\n    // allocated at run time will allocate a single entry.\n    header_info_rw rw_data[];\n} header_info;\n\nextern header_info *FirstHeader;\nextern header_info *LastHeader;\nextern int HeaderCount;\n\nextern void appendHeader(header_info *hi);\nextern void removeHeader(header_info *hi);\n\nextern objc_image_info *_getObjcImageInfo(const headerType *head, size_t *size);\nextern bool _hasObjcContents(const header_info *hi);\n\n\n// Mach-O segment and section names are 16 bytes and may be un-terminated.\n\nstatic inline bool segnameEquals(const char *lhs, const char *rhs) {\n    return 0 == strncmp(lhs, rhs, 16);\n}\n\nstatic inline bool segnameStartsWith(const char *segname, const char *prefix) {\n    return 0 == strncmp(segname, prefix, strlen(prefix));\n}\n\nstatic inline bool sectnameEquals(const char *lhs, const char *rhs) {\n    return segnameEquals(lhs, rhs);\n}\n\nstatic inline bool sectnameStartsWith(const char *sectname, const char *prefix){\n    return segnameStartsWith(sectname, prefix);\n}\n\n\n/* selectors */\nextern void sel_init(size_t selrefCount);\nextern SEL sel_registerNameNoLock(const char *str, bool copy);\n\nextern SEL SEL_load;\nextern SEL SEL_initialize;\nextern SEL SEL_resolveClassMethod;\nextern SEL SEL_resolveInstanceMethod;\nextern SEL SEL_cxx_construct;\nextern SEL SEL_cxx_destruct;\nextern SEL SEL_retain;\nextern SEL SEL_release;\nextern SEL SEL_autorelease;\nextern SEL SEL_retainCount;\nextern SEL SEL_alloc;\nextern SEL SEL_allocWithZone;\nextern SEL SEL_dealloc;\nextern SEL SEL_copy;\nextern SEL SEL_new;\nextern SEL SEL_forwardInvocation;\nextern SEL SEL_tryRetain;\nextern SEL SEL_isDeallocating;\nextern SEL SEL_retainWeakReference;\nextern SEL SEL_allowsWeakReference;\n\n/* preoptimization */\nextern void preopt_init(void);\nextern void disableSharedCacheOptimizations(void);\nextern bool isPreoptimized(void);\nextern bool noMissingWeakSuperclasses(void);\nextern header_info *preoptimizedHinfoForHeader(const headerType *mhdr);\n\nextern objc_selopt_t *preoptimizedSelectors(void);\n\nextern Protocol *getPreoptimizedProtocol(const char *name);\n\nextern unsigned getPreoptimizedClassUnreasonableCount();\nextern Class getPreoptimizedClass(const char *name);\nextern Class* copyPreoptimizedClasses(const char *name, int *outCount);\n\nextern bool sharedRegionContains(const void *ptr);\n\nextern Class _calloc_class(size_t size);\n\n/* method lookup */\nextern IMP lookUpImpOrNil(Class, SEL, id obj, bool initialize, bool cache, bool resolver);\nextern IMP lookUpImpOrForward(Class, SEL, id obj, bool initialize, bool cache, bool resolver);\n\nextern IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel);\nextern bool class_respondsToSelector_inst(Class cls, SEL sel, id inst);\n\nextern bool objcMsgLogEnabled;\nextern bool logMessageSend(bool isClassMethod,\n                    const char *objectsClass,\n                    const char *implementingClass,\n                    SEL selector);\n\n/* message dispatcher */\nextern IMP _class_lookupMethodAndLoadCache3(id, SEL, Class);\n\n#if !OBJC_OLD_DISPATCH_PROTOTYPES\nextern void _objc_msgForward_impcache(void);\n#else\nextern id _objc_msgForward_impcache(id, SEL, ...);\n#endif\n\n/* errors */\nextern void __objc_error(id, const char *, ...) __attribute__((format (printf, 2, 3), noreturn));\nextern void _objc_inform(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\nextern void _objc_inform_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\nextern void _objc_inform_now_and_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2)));\nextern void _objc_inform_deprecated(const char *oldname, const char *newname) __attribute__((noinline));\nextern void inform_duplicate(const char *name, Class oldCls, Class cls);\n\n/* magic */\nextern Class _objc_getFreedObjectClass (void);\n\n/* map table additions */\nextern void *NXMapKeyCopyingInsert(NXMapTable *table, const void *key, const void *value);\nextern void *NXMapKeyFreeingRemove(NXMapTable *table, const void *key);\n\n/* hash table additions */\nextern unsigned _NXHashCapacity(NXHashTable *table);\nextern void _NXHashRehashToCapacity(NXHashTable *table, unsigned newCapacity);\n\n/* property attribute parsing */\nextern const char *copyPropertyAttributeString(const objc_property_attribute_t *attrs, unsigned int count);\nextern objc_property_attribute_t *copyPropertyAttributeList(const char *attrs, unsigned int *outCount);\nextern char *copyPropertyAttributeValue(const char *attrs, const char *name);\n\n/* locking */\nextern void lock_init(void);\n\nclass monitor_locker_t : nocopy_t {\n    monitor_t& lock;\n  public:\n    monitor_locker_t(monitor_t& newLock) : lock(newLock) { lock.enter(); }\n    ~monitor_locker_t() { lock.leave(); }\n};\n\nclass recursive_mutex_locker_t : nocopy_t {\n    recursive_mutex_t& lock;\n  public:\n    recursive_mutex_locker_t(recursive_mutex_t& newLock) \n        : lock(newLock) { lock.lock(); }\n    ~recursive_mutex_locker_t() { lock.unlock(); }\n};\n\n\n/* Exceptions */\nstruct alt_handler_list;\nextern void exception_init(void);\nextern void _destroyAltHandlerList(struct alt_handler_list *list);\n\n/* Class change notifications (gdb only for now) */\n#define OBJC_CLASS_ADDED (1<<0)\n#define OBJC_CLASS_REMOVED (1<<1)\n#define OBJC_CLASS_IVARS_CHANGED (1<<2)\n#define OBJC_CLASS_METHODS_CHANGED (1<<3)\nextern void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname)\n    __attribute__((noinline));\n\n\n// Settings from environment variables\n#define OPTION(var, env, help) extern bool var;\n#include \"objc-env.h\"\n#undef OPTION\n\nextern void environ_init(void);\n\nextern void logReplacedMethod(const char *className, SEL s, bool isMeta, const char *catName, IMP oldImp, IMP newImp);\n\n\n// objc per-thread storage\ntypedef struct {\n    struct _objc_initializing_classes *initializingClasses; // for +initialize\n    struct SyncCache *syncCache;  // for @synchronize\n    struct alt_handler_list *handlerList;  // for exception alt handlers\n    char *printableNames[4];  // temporary demangled names for logging\n\n    // If you add new fields here, don't forget to update \n    // _objc_pthread_destroyspecific()\n\n} _objc_pthread_data;\n\nextern _objc_pthread_data *_objc_fetch_pthread_data(bool create);\nextern void tls_init(void);\n\n// encoding.h\nextern unsigned int encoding_getNumberOfArguments(const char *typedesc);\nextern unsigned int encoding_getSizeOfArguments(const char *typedesc);\nextern unsigned int encoding_getArgumentInfo(const char *typedesc, unsigned int arg, const char **type, int *offset);\nextern void encoding_getReturnType(const char *t, char *dst, size_t dst_len);\nextern char * encoding_copyReturnType(const char *t);\nextern void encoding_getArgumentType(const char *t, unsigned int index, char *dst, size_t dst_len);\nextern char *encoding_copyArgumentType(const char *t, unsigned int index);\n\n// sync.h\nextern void _destroySyncCache(struct SyncCache *cache);\n\n// arr\nextern void arr_init(void);\nextern id objc_autoreleaseReturnValue(id obj);\n\n// block trampolines\nextern IMP _imp_implementationWithBlockNoCopy(id block);\n\n// layout.h\ntypedef struct {\n    uint8_t *bits;\n    size_t bitCount;\n    size_t bitsAllocated;\n    bool weak;\n} layout_bitmap;\nextern layout_bitmap layout_bitmap_create(const unsigned char *layout_string, size_t layoutStringInstanceSize, size_t instanceSize, bool weak);\nextern layout_bitmap layout_bitmap_create_empty(size_t instanceSize, bool weak);\nextern void layout_bitmap_free(layout_bitmap bits);\nextern const unsigned char *layout_string_create(layout_bitmap bits);\nextern void layout_bitmap_set_ivar(layout_bitmap bits, const char *type, size_t offset);\nextern void layout_bitmap_grow(layout_bitmap *bits, size_t newCount);\nextern void layout_bitmap_slide(layout_bitmap *bits, size_t oldPos, size_t newPos);\nextern void layout_bitmap_slide_anywhere(layout_bitmap *bits, size_t oldPos, size_t newPos);\nextern bool layout_bitmap_splat(layout_bitmap dst, layout_bitmap src, \n                                size_t oldSrcInstanceSize);\nextern bool layout_bitmap_or(layout_bitmap dst, layout_bitmap src, const char *msg);\nextern bool layout_bitmap_clear(layout_bitmap dst, layout_bitmap src, const char *msg);\nextern void layout_bitmap_print(layout_bitmap bits);\n\n\n// fixme runtime\nextern bool MultithreadedForkChild;\nextern id objc_noop_imp(id self, SEL _cmd);\nextern Class look_up_class(const char *aClassName, bool includeUnconnected, bool includeClassHandler);\nextern \"C\" void map_images(unsigned count, const char * const paths[],\n                           const struct mach_header * const mhdrs[]);\nextern void map_images_nolock(unsigned count, const char * const paths[],\n                              const struct mach_header * const mhdrs[]);\nextern void load_images(const char *path, const struct mach_header *mh);\nextern void unmap_image(const char *path, const struct mach_header *mh);\nextern void unmap_image_nolock(const struct mach_header *mh);\nextern void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClass);\nextern void _unload_image(header_info *hi);\n\nextern const header_info *_headerForClass(Class cls);\n\nextern Class _class_remap(Class cls);\nextern Class _class_getNonMetaClass(Class cls, id obj);\nextern Ivar _class_getVariable(Class cls, const char *name);\n\nextern unsigned _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone, id *results, unsigned num_requested);\nextern id _objc_constructOrFree(id bytes, Class cls);\n\nextern const char *_category_getName(Category cat);\nextern const char *_category_getClassName(Category cat);\nextern Class _category_getClass(Category cat);\nextern IMP _category_getLoadMethod(Category cat);\n\nextern id object_cxxConstructFromClass(id obj, Class cls);\nextern void object_cxxDestruct(id obj);\n\nextern void _class_resolveMethod(Class cls, SEL sel, id inst);\n\nextern void fixupCopiedIvars(id newObject, id oldObject);\nextern Class _class_getClassForIvar(Class cls, Ivar ivar);\n\n\n#define OBJC_WARN_DEPRECATED \\\n    do { \\\n        static int warned = 0; \\\n        if (!warned) { \\\n            warned = 1; \\\n            _objc_inform_deprecated(__FUNCTION__, NULL); \\\n        } \\\n    } while (0) \\\n\n__END_DECLS\n\n\n#ifndef STATIC_ASSERT\n#   define STATIC_ASSERT(x) _STATIC_ASSERT2(x, __LINE__)\n#   define _STATIC_ASSERT2(x, line) _STATIC_ASSERT3(x, line)\n#   define _STATIC_ASSERT3(x, line)                                     \\\n        typedef struct {                                                \\\n            int _static_assert[(x) ? 0 : -1];                           \\\n        } _static_assert_ ## line __attribute__((unavailable)) \n#endif\n\n#define countof(arr) (sizeof(arr) / sizeof((arr)[0]))\n\n\nstatic __inline uint32_t _objc_strhash(const char *s) {\n    uint32_t hash = 0;\n    for (;;) {\n    int a = *s++;\n    if (0 == a) break;\n    hash += (hash << 8) + a;\n    }\n    return hash;\n}\n\n#if __cplusplus\n\ntemplate <typename T>\nstatic inline T log2u(T x) {\n    return (x<2) ? 0 : log2u(x>>1)+1;\n}\n\ntemplate <typename T>\nstatic inline T exp2u(T x) {\n    return (1 << x);\n}\n\ntemplate <typename T>\nstatic T exp2m1u(T x) { \n    return (1 << x) - 1; \n}\n\n#endif\n\n// Misalignment-safe integer types\n__attribute__((aligned(1))) typedef uintptr_t unaligned_uintptr_t;\n__attribute__((aligned(1))) typedef  intptr_t unaligned_intptr_t;\n__attribute__((aligned(1))) typedef  uint64_t unaligned_uint64_t;\n__attribute__((aligned(1))) typedef   int64_t unaligned_int64_t;\n__attribute__((aligned(1))) typedef  uint32_t unaligned_uint32_t;\n__attribute__((aligned(1))) typedef   int32_t unaligned_int32_t;\n__attribute__((aligned(1))) typedef  uint16_t unaligned_uint16_t;\n__attribute__((aligned(1))) typedef   int16_t unaligned_int16_t;\n\n\n// Global operator new and delete. We must not use any app overrides.\n// This ALSO REQUIRES each of these be in libobjc's unexported symbol list.\n#if __cplusplus\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Winline-new-delete\"\n#include <new>\ninline void* operator new(std::size_t size) throw (std::bad_alloc) { return malloc(size); }\ninline void* operator new[](std::size_t size) throw (std::bad_alloc) { return malloc(size); }\ninline void* operator new(std::size_t size, const std::nothrow_t&) throw() { return malloc(size); }\ninline void* operator new[](std::size_t size, const std::nothrow_t&) throw() { return malloc(size); }\ninline void operator delete(void* p) throw() { free(p); }\ninline void operator delete[](void* p) throw() { free(p); }\ninline void operator delete(void* p, const std::nothrow_t&) throw() { free(p); }\ninline void operator delete[](void* p, const std::nothrow_t&) throw() { free(p); }\n#pragma clang diagnostic pop\n#endif\n\n\nclass TimeLogger {\n    uint64_t mStart;\n    bool mRecord;\n public:\n    TimeLogger(bool record = true) \n     : mStart(nanoseconds())\n     , mRecord(record) \n    { }\n\n    void log(const char *msg) {\n        if (mRecord) {\n            uint64_t end = nanoseconds();\n            _objc_inform(\"%.2f ms: %s\", (end - mStart) / 1000000.0, msg);\n            mStart = nanoseconds();\n        }\n    }\n};\n\nenum { CacheLineSize = 64 };\n\n// StripedMap<T> is a map of void* -> T, sized appropriately \n// for cache-friendly lock striping. \n// For example, this may be used as StripedMap<spinlock_t>\n// or as StripedMap<SomeStruct> where SomeStruct stores a spin lock.\ntemplate<typename T>\nclass StripedMap {\n#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n    enum { StripeCount = 8 };\n#else\n    enum { StripeCount = 64 };\n#endif\n\n    struct PaddedT {\n        T value alignas(CacheLineSize);\n    };\n\n    PaddedT array[StripeCount];\n\n    static unsigned int indexForPointer(const void *p) {\n        uintptr_t addr = reinterpret_cast<uintptr_t>(p);\n        return ((addr >> 4) ^ (addr >> 9)) % StripeCount;\n    }\n\n public:\n    T& operator[] (const void *p) { \n        return array[indexForPointer(p)].value; \n    }\n    const T& operator[] (const void *p) const { \n        return const_cast<StripedMap<T>>(this)[p]; \n    }\n\n    // Shortcuts for StripedMaps of locks.\n    void lockAll() {\n        for (unsigned int i = 0; i < StripeCount; i++) {\n            array[i].value.lock();\n        }\n    }\n\n    void unlockAll() {\n        for (unsigned int i = 0; i < StripeCount; i++) {\n            array[i].value.unlock();\n        }\n    }\n\n    void forceResetAll() {\n        for (unsigned int i = 0; i < StripeCount; i++) {\n            array[i].value.forceReset();\n        }\n    }\n\n    void defineLockOrder() {\n        for (unsigned int i = 1; i < StripeCount; i++) {\n            lockdebug_lock_precedes_lock(&array[i-1].value, &array[i].value);\n        }\n    }\n\n    void precedeLock(const void *newlock) {\n        // assumes defineLockOrder is also called\n        lockdebug_lock_precedes_lock(&array[StripeCount-1].value, newlock);\n    }\n\n    void succeedLock(const void *oldlock) {\n        // assumes defineLockOrder is also called\n        lockdebug_lock_precedes_lock(oldlock, &array[0].value);\n    }\n\n    const void *getLock(int i) {\n        if (i < StripeCount) return &array[i].value;\n        else return nil;\n    }\n    \n#if DEBUG\n    StripedMap() {\n        // Verify alignment expectations.\n        uintptr_t base = (uintptr_t)&array[0].value;\n        uintptr_t delta = (uintptr_t)&array[1].value - base;\n        assert(delta % CacheLineSize == 0);\n        assert(base % CacheLineSize == 0);\n    }\n#else\n    constexpr StripedMap() {}\n#endif\n};\n\n\n// DisguisedPtr<T> acts like pointer type T*, except the \n// stored value is disguised to hide it from tools like `leaks`.\n// nil is disguised as itself so zero-filled memory works as expected, \n// which means 0x80..00 is also disguised as itself but we don't care.\n// Note that weak_entry_t knows about this encoding.\ntemplate <typename T>\nclass DisguisedPtr {\n    uintptr_t value;\n\n    static uintptr_t disguise(T* ptr) {\n        return -(uintptr_t)ptr;\n    }\n\n    static T* undisguise(uintptr_t val) {\n        return (T*)-val;\n    }\n\n public:\n    DisguisedPtr() { }\n    DisguisedPtr(T* ptr) \n        : value(disguise(ptr)) { }\n    DisguisedPtr(const DisguisedPtr<T>& ptr) \n        : value(ptr.value) { }\n\n    DisguisedPtr<T>& operator = (T* rhs) {\n        value = disguise(rhs);\n        return *this;\n    }\n    DisguisedPtr<T>& operator = (const DisguisedPtr<T>& rhs) {\n        value = rhs.value;\n        return *this;\n    }\n\n    operator T* () const {\n        return undisguise(value);\n    }\n    T* operator -> () const { \n        return undisguise(value);\n    }\n    T& operator * () const { \n        return *undisguise(value);\n    }\n    T& operator [] (size_t i) const {\n        return undisguise(value)[i];\n    }\n\n    // pointer arithmetic operators omitted \n    // because we don't currently use them anywhere\n};\n\n// fixme type id is weird and not identical to objc_object*\nstatic inline bool operator == (DisguisedPtr<objc_object> lhs, id rhs) {\n    return lhs == (objc_object *)rhs;\n}\nstatic inline bool operator != (DisguisedPtr<objc_object> lhs, id rhs) {\n    return lhs != (objc_object *)rhs;\n}\n\n\n// Storage for a thread-safe chained hook function.\n// get() returns the value for calling.\n// set() installs a new function and returns the old one for chaining.\n// More precisely, set() writes the old value to a variable supplied by\n// the caller. get() and set() use appropriate barriers so that the\n// old value is safely written to the variable before the new value is\n// called to use it.\n//\n// T1: store to old variable; store-release to hook variable\n// T2: load-acquire from hook variable; call it; called hook loads old variable\n\ntemplate <typename Fn>\nclass ChainedHookFunction {\n    std::atomic<Fn> hook{nil};\n\npublic:\n    ChainedHookFunction(Fn f) : hook{f} { };\n\n    Fn get() {\n        return hook.load(std::memory_order_acquire);\n    }\n\n    void set(Fn newValue, Fn *oldVariable)\n    {\n        Fn oldValue = hook.load(std::memory_order_relaxed);\n        do {\n            *oldVariable = oldValue;\n        } while (!hook.compare_exchange_weak(oldValue, newValue,\n                                             std::memory_order_release,\n                                             std::memory_order_relaxed));\n    }\n};\n\n\n// Pointer hash function.\n// This is not a terrific hash, but it is fast \n// and not outrageously flawed for our purposes.\n\n// Based on principles from http://locklessinc.com/articles/fast_hash/\n// and evaluation ideas from http://floodyberry.com/noncryptohashzoo/\n#if __LP64__\nstatic inline uint32_t ptr_hash(uint64_t key)\n{\n    key ^= key >> 4;\n    key *= 0x8a970be7488fda55;\n    key ^= __builtin_bswap64(key);\n    return (uint32_t)key;\n}\n#else\nstatic inline uint32_t ptr_hash(uint32_t key)\n{\n    key ^= key >> 4;\n    key *= 0x5052acdb;\n    key ^= __builtin_bswap32(key);\n    return key;\n}\n#endif\n\n/*\n  Higher-quality hash function. This is measurably slower in some workloads.\n#if __LP64__\n uint32_t ptr_hash(uint64_t key)\n{\n    key -= __builtin_bswap64(key);\n    key *= 0x8a970be7488fda55;\n    key ^= __builtin_bswap64(key);\n    key *= 0x8a970be7488fda55;\n    key ^= __builtin_bswap64(key);\n    return (uint32_t)key;\n}\n#else\nstatic uint32_t ptr_hash(uint32_t key)\n{\n    key -= __builtin_bswap32(key);\n    key *= 0x5052acdb;\n    key ^= __builtin_bswap32(key);\n    key *= 0x5052acdb;\n    key ^= __builtin_bswap32(key);\n    return key;\n}\n#endif\n*/\n\n\n\n// Lock declarations\n#include \"objc-locks.h\"\n\n// Inlined parts of objc_object's implementation\n#include \"objc-object.h\"\n\n#endif /* _OBJC_PRIVATE_H_ */\n\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-probes.d",
    "content": "provider objc_runtime\n{\n    probe objc_exception_throw(void *id);\n    probe objc_exception_rethrow();\n};\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-ptrauth.h",
    "content": "/*\n * Copyright (c) 2017 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _OBJC_PTRAUTH_H_\n#define _OBJC_PTRAUTH_H_\n\n#include <objc/objc.h>\n\n// On some architectures, method lists and method caches store signed IMPs.\n\n// StorageSignedFunctionPointer is declared by libclosure.\n#include <Block_private.h>\n\n// fixme simply include ptrauth.h once all build trains have it\n#if __has_include (<ptrauth.h>)\n#include <ptrauth.h>\n#else\n#define ptrauth_strip(__value, __key) __value\n#define ptrauth_blend_discriminator(__pointer, __integer) ((uintptr_t)0)\n#define ptrauth_sign_constant(__value, __key, __data) __value\n#define ptrauth_sign_unauthenticated(__value, __key, __data) __value\n#define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, __new_data) __value\n#define ptrauth_auth_function(__value, __old_key, __old_data) __value\n#define ptrauth_auth_data(__value, __old_key, __old_data) __value\n#define ptrauth_string_discriminator(__string) ((int)0)\n#define ptrauth_sign_generic_data(__value, __data) ((ptrauth_generic_signature_t)0)\n\n#define __ptrauth_function_pointer\n#define __ptrauth_return_address\n#define __ptrauth_block_invocation_pointer\n#define __ptrauth_block_copy_helper\n#define __ptrauth_block_destroy_helper\n#define __ptrauth_block_byref_copy_helper\n#define __ptrauth_block_byref_destroy_helper\n#define __ptrauth_objc_method_list_imp\n#define __ptrauth_cxx_vtable_pointer\n#define __ptrauth_cxx_vtt_vtable_pointer\n#define __ptrauth_swift_heap_object_destructor\n#define __ptrauth_cxx_virtual_function_pointer(__declkey)\n#define __ptrauth_swift_function_pointer(__typekey)\n#define __ptrauth_swift_class_method_pointer(__declkey)\n#define __ptrauth_swift_protocol_witness_function_pointer(__declkey)\n#define __ptrauth_swift_value_witness_function_pointer(__key)\n#endif\n\n\n#if __has_feature(ptrauth_calls)\n\n// Method lists use process-independent signature for compatibility.\n// Method caches use process-dependent signature for extra protection.\n//   (fixme not yet __ptrauth(...) because of `stp` inline asm in objc-cache.mm)\nusing MethodListIMP = IMP __ptrauth_objc_method_list_imp;\nusing MethodCacheIMP =\n    StorageSignedFunctionPointer<IMP, ptrauth_key_process_dependent_code>;\n\n#else\n\nusing MethodListIMP = IMP;\nusing MethodCacheIMP = IMP;\n\n#endif\n\n// _OBJC_PTRAUTH_H_\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-references.h",
    "content": "/*\n * Copyright (c) 2008 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\n *\tobjc-references.h\n */\n\n#ifndef _OBJC_REFERENCES_H_\n#define _OBJC_REFERENCES_H_\n\n#include \"objc-api.h\"\n#include \"objc-config.h\"\n\n__BEGIN_DECLS\n\nextern void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy);\nextern id _object_get_associative_reference(id object, void *key);\nextern void _object_remove_assocations(id object);\n\n__END_DECLS\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-references.mm",
    "content": "/*\n * Copyright (c) 2004-2007 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\n  Implementation of the weak / associative references for non-GC mode.\n*/\n\n\n#include \"objc-private.h\"\n#include <objc/message.h>\n#include <map>\n\n#if _LIBCPP_VERSION\n#   include <unordered_map>\n#else\n#   include <tr1/unordered_map>\n    using namespace tr1;\n#endif\n\n\n// wrap all the murky C++ details in a namespace to get them out of the way.\n\nnamespace objc_references_support {\n    struct DisguisedPointerEqual {\n        bool operator()(uintptr_t p1, uintptr_t p2) const {\n            return p1 == p2;\n        }\n    };\n    \n    struct DisguisedPointerHash {\n        uintptr_t operator()(uintptr_t k) const {\n            // borrowed from CFSet.c\n#if __LP64__\n            uintptr_t a = 0x4368726973746F70ULL;\n            uintptr_t b = 0x686572204B616E65ULL;\n#else\n            uintptr_t a = 0x4B616E65UL;\n            uintptr_t b = 0x4B616E65UL; \n#endif\n            uintptr_t c = 1;\n            a += k;\n#if __LP64__\n            a -= b; a -= c; a ^= (c >> 43);\n            b -= c; b -= a; b ^= (a << 9);\n            c -= a; c -= b; c ^= (b >> 8);\n            a -= b; a -= c; a ^= (c >> 38);\n            b -= c; b -= a; b ^= (a << 23);\n            c -= a; c -= b; c ^= (b >> 5);\n            a -= b; a -= c; a ^= (c >> 35);\n            b -= c; b -= a; b ^= (a << 49);\n            c -= a; c -= b; c ^= (b >> 11);\n            a -= b; a -= c; a ^= (c >> 12);\n            b -= c; b -= a; b ^= (a << 18);\n            c -= a; c -= b; c ^= (b >> 22);\n#else\n            a -= b; a -= c; a ^= (c >> 13);\n            b -= c; b -= a; b ^= (a << 8);\n            c -= a; c -= b; c ^= (b >> 13);\n            a -= b; a -= c; a ^= (c >> 12);\n            b -= c; b -= a; b ^= (a << 16);\n            c -= a; c -= b; c ^= (b >> 5);\n            a -= b; a -= c; a ^= (c >> 3);\n            b -= c; b -= a; b ^= (a << 10);\n            c -= a; c -= b; c ^= (b >> 15);\n#endif\n            return c;\n        }\n    };\n    \n    struct ObjectPointerLess {\n        bool operator()(const void *p1, const void *p2) const {\n            return p1 < p2;\n        }\n    };\n    \n    struct ObjcPointerHash {\n        uintptr_t operator()(void *p) const {\n            return DisguisedPointerHash()(uintptr_t(p));\n        }\n    };\n\n    // STL allocator that uses the runtime's internal allocator.\n    \n    template <typename T> struct ObjcAllocator {\n        typedef T                 value_type;\n        typedef value_type*       pointer;\n        typedef const value_type *const_pointer;\n        typedef value_type&       reference;\n        typedef const value_type& const_reference;\n        typedef size_t            size_type;\n        typedef ptrdiff_t         difference_type;\n\n        template <typename U> struct rebind { typedef ObjcAllocator<U> other; };\n\n        template <typename U> ObjcAllocator(const ObjcAllocator<U>&) {}\n        ObjcAllocator() {}\n        ObjcAllocator(const ObjcAllocator&) {}\n        ~ObjcAllocator() {}\n\n        pointer address(reference x) const { return &x; }\n        const_pointer address(const_reference x) const { \n            return x;\n        }\n\n        pointer allocate(size_type n, const_pointer = 0) {\n            return static_cast<pointer>(::malloc(n * sizeof(T)));\n        }\n\n        void deallocate(pointer p, size_type) { ::free(p); }\n\n        size_type max_size() const { \n            return static_cast<size_type>(-1) / sizeof(T);\n        }\n\n        void construct(pointer p, const value_type& x) { \n            new(p) value_type(x); \n        }\n\n        void destroy(pointer p) { p->~value_type(); }\n\n        void operator=(const ObjcAllocator&);\n\n    };\n\n    template<> struct ObjcAllocator<void> {\n        typedef void        value_type;\n        typedef void*       pointer;\n        typedef const void *const_pointer;\n        template <typename U> struct rebind { typedef ObjcAllocator<U> other; };\n    };\n  \n    typedef uintptr_t disguised_ptr_t;\n    inline disguised_ptr_t DISGUISE(id value) { return ~uintptr_t(value); }\n    inline id UNDISGUISE(disguised_ptr_t dptr) { return id(~dptr); }\n  \n    class ObjcAssociation {\n        uintptr_t _policy;\n        id _value;\n    public:\n        ObjcAssociation(uintptr_t policy, id value) : _policy(policy), _value(value) {}\n        ObjcAssociation() : _policy(0), _value(nil) {}\n\n        uintptr_t policy() const { return _policy; }\n        id value() const { return _value; }\n        \n        bool hasValue() { return _value != nil; }\n    };\n\n#if TARGET_OS_WIN32\n    typedef hash_map<void *, ObjcAssociation> ObjectAssociationMap;\n    typedef hash_map<disguised_ptr_t, ObjectAssociationMap *> AssociationsHashMap;\n#else\n    typedef ObjcAllocator<std::pair<void * const, ObjcAssociation> > ObjectAssociationMapAllocator;\n    class ObjectAssociationMap : public std::map<void *, ObjcAssociation, ObjectPointerLess, ObjectAssociationMapAllocator> {\n    public:\n        void *operator new(size_t n) { return ::malloc(n); }\n        void operator delete(void *ptr) { ::free(ptr); }\n    };\n    typedef ObjcAllocator<std::pair<const disguised_ptr_t, ObjectAssociationMap*> > AssociationsHashMapAllocator;\n    class AssociationsHashMap : public unordered_map<disguised_ptr_t, ObjectAssociationMap *, DisguisedPointerHash, DisguisedPointerEqual, AssociationsHashMapAllocator> {\n    public:\n        void *operator new(size_t n) { return ::malloc(n); }\n        void operator delete(void *ptr) { ::free(ptr); }\n    };\n#endif\n}\n\nusing namespace objc_references_support;\n\n// class AssociationsManager manages a lock / hash table singleton pair.\n// Allocating an instance acquires the lock, and calling its assocations()\n// method lazily allocates the hash table.\n\nspinlock_t AssociationsManagerLock;\n\nclass AssociationsManager {\n    // associative references: object pointer -> PtrPtrHashMap.\n    static AssociationsHashMap *_map;\npublic:\n    AssociationsManager()   { AssociationsManagerLock.lock(); }\n    ~AssociationsManager()  { AssociationsManagerLock.unlock(); }\n    \n    AssociationsHashMap &associations() {\n        if (_map == NULL)\n            _map = new AssociationsHashMap();\n        return *_map;\n    }\n};\n\nAssociationsHashMap *AssociationsManager::_map = NULL;\n\n// expanded policy bits.\n\nenum { \n    OBJC_ASSOCIATION_SETTER_ASSIGN      = 0,\n    OBJC_ASSOCIATION_SETTER_RETAIN      = 1,\n    OBJC_ASSOCIATION_SETTER_COPY        = 3,            // NOTE:  both bits are set, so we can simply test 1 bit in releaseValue below.\n    OBJC_ASSOCIATION_GETTER_READ        = (0 << 8), \n    OBJC_ASSOCIATION_GETTER_RETAIN      = (1 << 8), \n    OBJC_ASSOCIATION_GETTER_AUTORELEASE = (2 << 8)\n}; \n\nid _object_get_associative_reference(id object, void *key) {\n    id value = nil;\n    uintptr_t policy = OBJC_ASSOCIATION_ASSIGN;\n    {\n        AssociationsManager manager;\n        AssociationsHashMap &associations(manager.associations());\n        disguised_ptr_t disguised_object = DISGUISE(object);\n        AssociationsHashMap::iterator i = associations.find(disguised_object);\n        if (i != associations.end()) {\n            ObjectAssociationMap *refs = i->second;\n            ObjectAssociationMap::iterator j = refs->find(key);\n            if (j != refs->end()) {\n                ObjcAssociation &entry = j->second;\n                value = entry.value();\n                policy = entry.policy();\n                if (policy & OBJC_ASSOCIATION_GETTER_RETAIN) {\n                    objc_retain(value);\n                }\n            }\n        }\n    }\n    if (value && (policy & OBJC_ASSOCIATION_GETTER_AUTORELEASE)) {\n        objc_autorelease(value);\n    }\n    return value;\n}\n\nstatic id acquireValue(id value, uintptr_t policy) {\n    switch (policy & 0xFF) {\n    case OBJC_ASSOCIATION_SETTER_RETAIN:\n        return objc_retain(value);\n    case OBJC_ASSOCIATION_SETTER_COPY:\n        return ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);\n    }\n    return value;\n}\n\nstatic void releaseValue(id value, uintptr_t policy) {\n    if (policy & OBJC_ASSOCIATION_SETTER_RETAIN) {\n        return objc_release(value);\n    }\n}\n\nstruct ReleaseValue {\n    void operator() (ObjcAssociation &association) {\n        releaseValue(association.value(), association.policy());\n    }\n};\n\nvoid _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {\n    // retain the new value (if any) outside the lock.\n    ObjcAssociation old_association(0, nil);\n    id new_value = value ? acquireValue(value, policy) : nil;\n    {\n        AssociationsManager manager;\n        AssociationsHashMap &associations(manager.associations());\n        disguised_ptr_t disguised_object = DISGUISE(object);\n        if (new_value) {\n            // break any existing association.\n            AssociationsHashMap::iterator i = associations.find(disguised_object);\n            if (i != associations.end()) {\n                // secondary table exists\n                ObjectAssociationMap *refs = i->second;\n                ObjectAssociationMap::iterator j = refs->find(key);\n                if (j != refs->end()) {\n                    old_association = j->second;\n                    j->second = ObjcAssociation(policy, new_value);\n                } else {\n                    (*refs)[key] = ObjcAssociation(policy, new_value);\n                }\n            } else {\n                // create the new association (first time).\n                ObjectAssociationMap *refs = new ObjectAssociationMap;\n                associations[disguised_object] = refs;\n                (*refs)[key] = ObjcAssociation(policy, new_value);\n                object->setHasAssociatedObjects();\n            }\n        } else {\n            // setting the association to nil breaks the association.\n            AssociationsHashMap::iterator i = associations.find(disguised_object);\n            if (i !=  associations.end()) {\n                ObjectAssociationMap *refs = i->second;\n                ObjectAssociationMap::iterator j = refs->find(key);\n                if (j != refs->end()) {\n                    old_association = j->second;\n                    refs->erase(j);\n                }\n            }\n        }\n    }\n    // release the old value (outside of the lock).\n    if (old_association.hasValue()) ReleaseValue()(old_association);\n}\n\nvoid _object_remove_assocations(id object) {\n    vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements;\n    {\n        AssociationsManager manager;\n        AssociationsHashMap &associations(manager.associations());\n        if (associations.size() == 0) return;\n        disguised_ptr_t disguised_object = DISGUISE(object);\n        AssociationsHashMap::iterator i = associations.find(disguised_object);\n        if (i != associations.end()) {\n            // copy all of the associations that need to be removed.\n            ObjectAssociationMap *refs = i->second;\n            for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {\n                elements.push_back(j->second);\n            }\n            // remove the secondary table.\n            delete refs;\n            associations.erase(i);\n        }\n    }\n    // the calls to releaseValue() happen outside of the lock.\n    for_each(elements.begin(), elements.end(), ReleaseValue());\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-runtime-new.h",
    "content": "/*\n * Copyright (c) 2005-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _OBJC_RUNTIME_NEW_H\n#define _OBJC_RUNTIME_NEW_H\n\n#if __LP64__\ntypedef uint32_t mask_t;  // x86_64 & arm64 asm are less efficient with 16-bits\n#else\ntypedef uint16_t mask_t;\n#endif\ntypedef uintptr_t cache_key_t;\n\nstruct swift_class_t;\n\n\nstruct bucket_t {\nprivate:\n    // IMP-first is better for arm64e ptrauth and no worse for arm64.\n    // SEL-first is better for armv7* and i386 and x86_64.\n#if __arm64__\n    MethodCacheIMP _imp;\n    cache_key_t _key;\n#else\n    cache_key_t _key;\n    MethodCacheIMP _imp;\n#endif\n\npublic:\n    inline cache_key_t key() const { return _key; }\n    inline IMP imp() const { return (IMP)_imp; }\n    inline void setKey(cache_key_t newKey) { _key = newKey; }\n    inline void setImp(IMP newImp) { _imp = newImp; }\n\n    void set(cache_key_t newKey, IMP newImp);\n};\n\n\nstruct cache_t {\n    struct bucket_t *_buckets;\n    mask_t _mask;\n    mask_t _occupied;\n\npublic:\n    struct bucket_t *buckets();\n    mask_t mask();\n    mask_t occupied();\n    void incrementOccupied();\n    void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);\n    void initializeToEmpty();\n\n    mask_t capacity();\n    bool isConstantEmptyCache();\n    bool canBeFreed();\n\n    static size_t bytesForCapacity(uint32_t cap);\n    static struct bucket_t * endMarker(struct bucket_t *b, uint32_t cap);\n\n    void expand();\n    void reallocate(mask_t oldCapacity, mask_t newCapacity);\n    struct bucket_t * find(cache_key_t key, id receiver);\n\n    static void bad_cache(id receiver, SEL sel, Class isa) __attribute__((noreturn));\n};\n\n\n// classref_t is unremapped class_t*\ntypedef struct classref * classref_t;\n\n/***********************************************************************\n* entsize_list_tt<Element, List, FlagMask>\n* Generic implementation of an array of non-fragile structs.\n*\n* Element is the struct type (e.g. method_t)\n* List is the specialization of entsize_list_tt (e.g. method_list_t)\n* FlagMask is used to stash extra bits in the entsize field\n*   (e.g. method list fixup markers)\n**********************************************************************/\ntemplate <typename Element, typename List, uint32_t FlagMask>\nstruct entsize_list_tt {\n    uint32_t entsizeAndFlags;\n    uint32_t count;\n    Element first;\n\n    uint32_t entsize() const {\n        return entsizeAndFlags & ~FlagMask;\n    }\n    uint32_t flags() const {\n        return entsizeAndFlags & FlagMask;\n    }\n\n    Element& getOrEnd(uint32_t i) const { \n        assert(i <= count);\n        return *(Element *)((uint8_t *)&first + i*entsize()); \n    }\n    Element& get(uint32_t i) const { \n        assert(i < count);\n        return getOrEnd(i);\n    }\n\n    size_t byteSize() const {\n        return byteSize(entsize(), count);\n    }\n    \n    static size_t byteSize(uint32_t entsize, uint32_t count) {\n        return sizeof(entsize_list_tt) + (count-1)*entsize;\n    }\n\n    List *duplicate() const {\n        auto *dup = (List *)calloc(this->byteSize(), 1);\n        dup->entsizeAndFlags = this->entsizeAndFlags;\n        dup->count = this->count;\n        std::copy(begin(), end(), dup->begin());\n        return dup;\n    }\n\n    struct iterator;\n    const iterator begin() const { \n        return iterator(*static_cast<const List*>(this), 0); \n    }\n    iterator begin() { \n        return iterator(*static_cast<const List*>(this), 0); \n    }\n    const iterator end() const { \n        return iterator(*static_cast<const List*>(this), count); \n    }\n    iterator end() { \n        return iterator(*static_cast<const List*>(this), count); \n    }\n\n    struct iterator {\n        uint32_t entsize;\n        uint32_t index;  // keeping track of this saves a divide in operator-\n        Element* element;\n\n        typedef std::random_access_iterator_tag iterator_category;\n        typedef Element value_type;\n        typedef ptrdiff_t difference_type;\n        typedef Element* pointer;\n        typedef Element& reference;\n\n        iterator() { }\n\n        iterator(const List& list, uint32_t start = 0)\n            : entsize(list.entsize())\n            , index(start)\n            , element(&list.getOrEnd(start))\n        { }\n\n        const iterator& operator += (ptrdiff_t delta) {\n            element = (Element*)((uint8_t *)element + delta*entsize);\n            index += (int32_t)delta;\n            return *this;\n        }\n        const iterator& operator -= (ptrdiff_t delta) {\n            element = (Element*)((uint8_t *)element - delta*entsize);\n            index -= (int32_t)delta;\n            return *this;\n        }\n        const iterator operator + (ptrdiff_t delta) const {\n            return iterator(*this) += delta;\n        }\n        const iterator operator - (ptrdiff_t delta) const {\n            return iterator(*this) -= delta;\n        }\n\n        iterator& operator ++ () { *this += 1; return *this; }\n        iterator& operator -- () { *this -= 1; return *this; }\n        iterator operator ++ (int) {\n            iterator result(*this); *this += 1; return result;\n        }\n        iterator operator -- (int) {\n            iterator result(*this); *this -= 1; return result;\n        }\n\n        ptrdiff_t operator - (const iterator& rhs) const {\n            return (ptrdiff_t)this->index - (ptrdiff_t)rhs.index;\n        }\n\n        Element& operator * () const { return *element; }\n        Element* operator -> () const { return element; }\n\n        operator Element& () const { return *element; }\n\n        bool operator == (const iterator& rhs) const {\n            return this->element == rhs.element;\n        }\n        bool operator != (const iterator& rhs) const {\n            return this->element != rhs.element;\n        }\n\n        bool operator < (const iterator& rhs) const {\n            return this->element < rhs.element;\n        }\n        bool operator > (const iterator& rhs) const {\n            return this->element > rhs.element;\n        }\n    };\n};\n\n\nstruct method_t {\n    SEL name;\n    const char *types;\n    MethodListIMP imp;\n\n    struct SortBySELAddress :\n        public std::binary_function<const method_t&,\n                                    const method_t&, bool>\n    {\n        bool operator() (const method_t& lhs,\n                         const method_t& rhs)\n        { return lhs.name < rhs.name; }\n    };\n};\n\nstruct ivar_t {\n#if __x86_64__\n    // *offset was originally 64-bit on some x86_64 platforms.\n    // We read and write only 32 bits of it.\n    // Some metadata provides all 64 bits. This is harmless for unsigned \n    // little-endian values.\n    // Some code uses all 64 bits. class_addIvar() over-allocates the \n    // offset for their benefit.\n#endif\n    int32_t *offset;\n    const char *name;\n    const char *type;\n    // alignment is sometimes -1; use alignment() instead\n    uint32_t alignment_raw;\n    uint32_t size;\n\n    uint32_t alignment() const {\n        if (alignment_raw == ~(uint32_t)0) return 1U << WORD_SHIFT;\n        return 1 << alignment_raw;\n    }\n};\n\nstruct property_t {\n    const char *name;\n    const char *attributes;\n};\n\n// Two bits of entsize are used for fixup markers.\nstruct method_list_t : entsize_list_tt<method_t, method_list_t, 0x3> {\n    bool isFixedUp() const;\n    void setFixedUp();\n\n    uint32_t indexOfMethod(const method_t *meth) const {\n        uint32_t i = \n            (uint32_t)(((uintptr_t)meth - (uintptr_t)this) / entsize());\n        assert(i < count);\n        return i;\n    }\n};\n\nstruct ivar_list_t : entsize_list_tt<ivar_t, ivar_list_t, 0> {\n    bool containsIvar(Ivar ivar) const {\n        return (ivar >= (Ivar)&*begin()  &&  ivar < (Ivar)&*end());\n    }\n};\n\nstruct property_list_t : entsize_list_tt<property_t, property_list_t, 0> {\n};\n\n\ntypedef uintptr_t protocol_ref_t;  // protocol_t *, but unremapped\n\n// Values for protocol_t->flags\n#define PROTOCOL_FIXED_UP_2 (1<<31)  // must never be set by compiler\n#define PROTOCOL_FIXED_UP_1 (1<<30)  // must never be set by compiler\n// Bits 0..15 are reserved for Swift's use.\n\n#define PROTOCOL_FIXED_UP_MASK (PROTOCOL_FIXED_UP_1 | PROTOCOL_FIXED_UP_2)\n\nstruct protocol_t : objc_object {\n    const char *mangledName;\n    struct protocol_list_t *protocols;\n    method_list_t *instanceMethods;\n    method_list_t *classMethods;\n    method_list_t *optionalInstanceMethods;\n    method_list_t *optionalClassMethods;\n    property_list_t *instanceProperties;\n    uint32_t size;   // sizeof(protocol_t)\n    uint32_t flags;\n    // Fields below this point are not always present on disk.\n    const char **_extendedMethodTypes;\n    const char *_demangledName;\n    property_list_t *_classProperties;\n\n    const char *demangledName();\n\n    const char *nameForLogging() {\n        return demangledName();\n    }\n\n    bool isFixedUp() const;\n    void setFixedUp();\n\n#   define HAS_FIELD(f) (size >= offsetof(protocol_t, f) + sizeof(f))\n\n    bool hasExtendedMethodTypesField() const {\n        return HAS_FIELD(_extendedMethodTypes);\n    }\n    bool hasDemangledNameField() const {\n        return HAS_FIELD(_demangledName);\n    }\n    bool hasClassPropertiesField() const {\n        return HAS_FIELD(_classProperties);\n    }\n\n#   undef HAS_FIELD\n\n    const char **extendedMethodTypes() const {\n        return hasExtendedMethodTypesField() ? _extendedMethodTypes : nil;\n    }\n\n    property_list_t *classProperties() const {\n        return hasClassPropertiesField() ? _classProperties : nil;\n    }\n};\n\nstruct protocol_list_t {\n    // count is 64-bit by accident. \n    uintptr_t count;\n    protocol_ref_t list[0]; // variable-size\n\n    size_t byteSize() const {\n        return sizeof(*this) + count*sizeof(list[0]);\n    }\n\n    protocol_list_t *duplicate() const {\n        return (protocol_list_t *)memdup(this, this->byteSize());\n    }\n\n    typedef protocol_ref_t* iterator;\n    typedef const protocol_ref_t* const_iterator;\n\n    const_iterator begin() const {\n        return list;\n    }\n    iterator begin() {\n        return list;\n    }\n    const_iterator end() const {\n        return list + count;\n    }\n    iterator end() {\n        return list + count;\n    }\n};\n\nstruct locstamped_category_t {\n    category_t *cat;\n    struct header_info *hi;\n};\n\nstruct locstamped_category_list_t {\n    uint32_t count;\n#if __LP64__\n    uint32_t reserved;\n#endif\n    locstamped_category_t list[0];\n};\n\n\n// class_data_bits_t is the class_t->data field (class_rw_t pointer plus flags)\n// The extra bits are optimized for the retain/release and alloc/dealloc paths.\n\n// Values for class_ro_t->flags\n// These are emitted by the compiler and are part of the ABI.\n// Note: See CGObjCNonFragileABIMac::BuildClassRoTInitializer in clang\n// class is a metaclass\n#define RO_META               (1<<0)\n// class is a root class\n#define RO_ROOT               (1<<1)\n// class has .cxx_construct/destruct implementations\n#define RO_HAS_CXX_STRUCTORS  (1<<2)\n// class has +load implementation\n// #define RO_HAS_LOAD_METHOD    (1<<3)\n// class has visibility=hidden set\n#define RO_HIDDEN             (1<<4)\n// class has attribute(objc_exception): OBJC_EHTYPE_$_ThisClass is non-weak\n#define RO_EXCEPTION          (1<<5)\n// this bit is available for reassignment\n// #define RO_REUSE_ME           (1<<6) \n// class compiled with ARC\n#define RO_IS_ARC             (1<<7)\n// class has .cxx_destruct but no .cxx_construct (with RO_HAS_CXX_STRUCTORS)\n#define RO_HAS_CXX_DTOR_ONLY  (1<<8)\n// class is not ARC but has ARC-style weak ivar layout \n#define RO_HAS_WEAK_WITHOUT_ARC (1<<9)\n\n// class is in an unloadable bundle - must never be set by compiler\n#define RO_FROM_BUNDLE        (1<<29)\n// class is unrealized future class - must never be set by compiler\n#define RO_FUTURE             (1<<30)\n// class is realized - must never be set by compiler\n#define RO_REALIZED           (1<<31)\n\n// Values for class_rw_t->flags\n// These are not emitted by the compiler and are never used in class_ro_t. \n// Their presence should be considered in future ABI versions.\n// class_t->data is class_rw_t, not class_ro_t\n#define RW_REALIZED           (1<<31)\n// class is unresolved future class\n#define RW_FUTURE             (1<<30)\n// class is initialized\n#define RW_INITIALIZED        (1<<29)\n// class is initializing\n#define RW_INITIALIZING       (1<<28)\n// class_rw_t->ro is heap copy of class_ro_t\n#define RW_COPIED_RO          (1<<27)\n// class allocated but not yet registered\n#define RW_CONSTRUCTING       (1<<26)\n// class allocated and registered\n#define RW_CONSTRUCTED        (1<<25)\n// available for use; was RW_FINALIZE_ON_MAIN_THREAD\n// #define RW_24 (1<<24)\n// class +load has been called\n#define RW_LOADED             (1<<23)\n#if !SUPPORT_NONPOINTER_ISA\n// class instances may have associative references\n#define RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS (1<<22)\n#endif\n// class has instance-specific GC layout\n#define RW_HAS_INSTANCE_SPECIFIC_LAYOUT (1 << 21)\n// available for use\n// #define RW_20       (1<<20)\n// class has started realizing but not yet completed it\n#define RW_REALIZING          (1<<19)\n\n// NOTE: MORE RW_ FLAGS DEFINED BELOW\n\n\n// Values for class_rw_t->flags or class_t->bits\n// These flags are optimized for retain/release and alloc/dealloc\n// 64-bit stores more of them in class_t->bits to reduce pointer indirection.\n\n#if !__LP64__\n\n// class or superclass has .cxx_construct implementation\n#define RW_HAS_CXX_CTOR       (1<<18)\n// class or superclass has .cxx_destruct implementation\n#define RW_HAS_CXX_DTOR       (1<<17)\n// class or superclass has default alloc/allocWithZone: implementation\n// Note this is is stored in the metaclass.\n#define RW_HAS_DEFAULT_AWZ    (1<<16)\n// class's instances requires raw isa\n#if SUPPORT_NONPOINTER_ISA\n#define RW_REQUIRES_RAW_ISA   (1<<15)\n#endif\n// class or superclass has default retain/release/autorelease/retainCount/\n//   _tryRetain/_isDeallocating/retainWeakReference/allowsWeakReference\n#define RW_HAS_DEFAULT_RR     (1<<14)\n\n// class is a Swift class from the pre-stable Swift ABI\n#define FAST_IS_SWIFT_LEGACY  (1UL<<0)\n// class is a Swift class from the stable Swift ABI\n#define FAST_IS_SWIFT_STABLE  (1UL<<1)\n// data pointer\n#define FAST_DATA_MASK        0xfffffffcUL\n\n#elif 1\n// Leaks-compatible version that steals low bits only.\n\n// class or superclass has .cxx_construct implementation\n#define RW_HAS_CXX_CTOR       (1<<18)\n// class or superclass has .cxx_destruct implementation\n#define RW_HAS_CXX_DTOR       (1<<17)\n// class or superclass has default alloc/allocWithZone: implementation\n// Note this is is stored in the metaclass.\n#define RW_HAS_DEFAULT_AWZ    (1<<16)\n// class's instances requires raw isa\n#define RW_REQUIRES_RAW_ISA   (1<<15)\n\n// class is a Swift class from the pre-stable Swift ABI\n#define FAST_IS_SWIFT_LEGACY    (1UL<<0)\n// class is a Swift class from the stable Swift ABI\n#define FAST_IS_SWIFT_STABLE    (1UL<<1)\n// class or superclass has default retain/release/autorelease/retainCount/\n//   _tryRetain/_isDeallocating/retainWeakReference/allowsWeakReference\n#define FAST_HAS_DEFAULT_RR     (1UL<<2)\n// data pointer\n#define FAST_DATA_MASK          0x00007ffffffffff8UL\n\n#else\n// Leaks-incompatible version that steals lots of bits.\n\n// class is a Swift class from the pre-stable Swift ABI\n#define FAST_IS_SWIFT_LEGACY    (1UL<<0)\n// class is a Swift class from the stable Swift ABI\n#define FAST_IS_SWIFT_STABLE    (1UL<<1)\n// summary bit for fast alloc path: !hasCxxCtor and \n//   !instancesRequireRawIsa and instanceSize fits into shiftedSize\n#define FAST_ALLOC              (1UL<<2)\n// data pointer\n#define FAST_DATA_MASK          0x00007ffffffffff8UL\n// class or superclass has .cxx_construct implementation\n#define FAST_HAS_CXX_CTOR       (1UL<<47)\n// class or superclass has default alloc/allocWithZone: implementation\n// Note this is is stored in the metaclass.\n#define FAST_HAS_DEFAULT_AWZ    (1UL<<48)\n// class or superclass has default retain/release/autorelease/retainCount/\n//   _tryRetain/_isDeallocating/retainWeakReference/allowsWeakReference\n#define FAST_HAS_DEFAULT_RR     (1UL<<49)\n// class's instances requires raw isa\n//   This bit is aligned with isa_t->hasCxxDtor to save an instruction.\n#define FAST_REQUIRES_RAW_ISA   (1UL<<50)\n// class or superclass has .cxx_destruct implementation\n#define FAST_HAS_CXX_DTOR       (1UL<<51)\n// instance size in units of 16 bytes\n//   or 0 if the instance size is too big in this field\n//   This field must be LAST\n#define FAST_SHIFTED_SIZE_SHIFT 52\n\n// FAST_ALLOC means\n//   FAST_HAS_CXX_CTOR is set\n//   FAST_REQUIRES_RAW_ISA is not set\n//   FAST_SHIFTED_SIZE is not zero\n// FAST_ALLOC does NOT check FAST_HAS_DEFAULT_AWZ because that \n// bit is stored on the metaclass.\n#define FAST_ALLOC_MASK  (FAST_HAS_CXX_CTOR | FAST_REQUIRES_RAW_ISA)\n#define FAST_ALLOC_VALUE (0)\n\n#endif\n\n// The Swift ABI requires that these bits be defined like this on all platforms.\nstatic_assert(FAST_IS_SWIFT_LEGACY == 1, \"resistance is futile\");\nstatic_assert(FAST_IS_SWIFT_STABLE == 2, \"resistance is futile\");\n\n\nstruct class_ro_t {\n    uint32_t flags;\n    uint32_t instanceStart;\n    uint32_t instanceSize;\n#ifdef __LP64__\n    uint32_t reserved;\n#endif\n\n    const uint8_t * ivarLayout;\n    \n    const char * name;\n    method_list_t * baseMethodList;\n    protocol_list_t * baseProtocols;\n    const ivar_list_t * ivars;\n\n    const uint8_t * weakIvarLayout;\n    property_list_t *baseProperties;\n\n    method_list_t *baseMethods() const {\n        return baseMethodList;\n    }\n};\n\n\n/***********************************************************************\n* list_array_tt<Element, List>\n* Generic implementation for metadata that can be augmented by categories.\n*\n* Element is the underlying metadata type (e.g. method_t)\n* List is the metadata's list type (e.g. method_list_t)\n*\n* A list_array_tt has one of three values:\n* - empty\n* - a pointer to a single list\n* - an array of pointers to lists\n*\n* countLists/beginLists/endLists iterate the metadata lists\n* count/begin/end iterate the underlying metadata elements\n**********************************************************************/\ntemplate <typename Element, typename List>\nclass list_array_tt {\n    struct array_t {\n        uint32_t count;\n        List* lists[0];\n\n        static size_t byteSize(uint32_t count) {\n            return sizeof(array_t) + count*sizeof(lists[0]);\n        }\n        size_t byteSize() {\n            return byteSize(count);\n        }\n    };\n\n protected:\n    class iterator {\n        List **lists;\n        List **listsEnd;\n        typename List::iterator m, mEnd;\n\n     public:\n        iterator(List **begin, List **end) \n            : lists(begin), listsEnd(end)\n        {\n            if (begin != end) {\n                m = (*begin)->begin();\n                mEnd = (*begin)->end();\n            }\n        }\n\n        const Element& operator * () const {\n            return *m;\n        }\n        Element& operator * () {\n            return *m;\n        }\n\n        bool operator != (const iterator& rhs) const {\n            if (lists != rhs.lists) return true;\n            if (lists == listsEnd) return false;  // m is undefined\n            if (m != rhs.m) return true;\n            return false;\n        }\n\n        const iterator& operator ++ () {\n            assert(m != mEnd);\n            m++;\n            if (m == mEnd) {\n                assert(lists != listsEnd);\n                lists++;\n                if (lists != listsEnd) {\n                    m = (*lists)->begin();\n                    mEnd = (*lists)->end();\n                }\n            }\n            return *this;\n        }\n    };\n\n private:\n    union {\n        List* list;\n        uintptr_t arrayAndFlag;\n    };\n\n    bool hasArray() const {\n        return arrayAndFlag & 1;\n    }\n\n    array_t *array() {\n        return (array_t *)(arrayAndFlag & ~1);\n    }\n\n    void setArray(array_t *array) {\n        arrayAndFlag = (uintptr_t)array | 1;\n    }\n\n public:\n\n    uint32_t count() {\n        uint32_t result = 0;\n        for (auto lists = beginLists(), end = endLists(); \n             lists != end;\n             ++lists)\n        {\n            result += (*lists)->count;\n        }\n        return result;\n    }\n\n    iterator begin() {\n        return iterator(beginLists(), endLists());\n    }\n\n    iterator end() {\n        List **e = endLists();\n        return iterator(e, e);\n    }\n\n\n    uint32_t countLists() {\n        if (hasArray()) {\n            return array()->count;\n        } else if (list) {\n            return 1;\n        } else {\n            return 0;\n        }\n    }\n\n    List** beginLists() {\n        if (hasArray()) {\n            return array()->lists;\n        } else {\n            return &list;\n        }\n    }\n\n    List** endLists() {\n        if (hasArray()) {\n            return array()->lists + array()->count;\n        } else if (list) {\n            return &list + 1;\n        } else {\n            return &list;\n        }\n    }\n\n    void attachLists(List* const * addedLists, uint32_t addedCount) {\n        if (addedCount == 0) return;\n\n        if (hasArray()) {\n            // many lists -> many lists\n            uint32_t oldCount = array()->count;\n            uint32_t newCount = oldCount + addedCount;\n            setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));\n            array()->count = newCount;\n            memmove(array()->lists + addedCount, array()->lists, \n                    oldCount * sizeof(array()->lists[0]));\n            memcpy(array()->lists, addedLists, \n                   addedCount * sizeof(array()->lists[0]));\n        }\n        else if (!list  &&  addedCount == 1) {\n            // 0 lists -> 1 list\n            list = addedLists[0];\n        } \n        else {\n            // 1 list -> many lists\n            List* oldList = list;\n            uint32_t oldCount = oldList ? 1 : 0;\n            uint32_t newCount = oldCount + addedCount;\n            setArray((array_t *)malloc(array_t::byteSize(newCount)));\n            array()->count = newCount;\n            if (oldList) array()->lists[addedCount] = oldList;\n            memcpy(array()->lists, addedLists, \n                   addedCount * sizeof(array()->lists[0]));\n        }\n    }\n\n    void tryFree() {\n        if (hasArray()) {\n            for (uint32_t i = 0; i < array()->count; i++) {\n                try_free(array()->lists[i]);\n            }\n            try_free(array());\n        }\n        else if (list) {\n            try_free(list);\n        }\n    }\n\n    template<typename Result>\n    Result duplicate() {\n        Result result;\n\n        if (hasArray()) {\n            array_t *a = array();\n            result.setArray((array_t *)memdup(a, a->byteSize()));\n            for (uint32_t i = 0; i < a->count; i++) {\n                result.array()->lists[i] = a->lists[i]->duplicate();\n            }\n        } else if (list) {\n            result.list = list->duplicate();\n        } else {\n            result.list = nil;\n        }\n\n        return result;\n    }\n};\n\n\nclass method_array_t : \n    public list_array_tt<method_t, method_list_t> \n{\n    typedef list_array_tt<method_t, method_list_t> Super;\n\n public:\n    method_list_t **beginCategoryMethodLists() {\n        return beginLists();\n    }\n    \n    method_list_t **endCategoryMethodLists(Class cls);\n\n    method_array_t duplicate() {\n        return Super::duplicate<method_array_t>();\n    }\n};\n\n\nclass property_array_t : \n    public list_array_tt<property_t, property_list_t> \n{\n    typedef list_array_tt<property_t, property_list_t> Super;\n\n public:\n    property_array_t duplicate() {\n        return Super::duplicate<property_array_t>();\n    }\n};\n\n\nclass protocol_array_t : \n    public list_array_tt<protocol_ref_t, protocol_list_t> \n{\n    typedef list_array_tt<protocol_ref_t, protocol_list_t> Super;\n\n public:\n    protocol_array_t duplicate() {\n        return Super::duplicate<protocol_array_t>();\n    }\n};\n\n\nstruct class_rw_t {\n    // Be warned that Symbolication knows the layout of this structure.\n    uint32_t flags;\n    uint32_t version;\n\n    const class_ro_t *ro;\n\n    method_array_t methods;\n    property_array_t properties;\n    protocol_array_t protocols;\n\n    Class firstSubclass;\n    Class nextSiblingClass;\n\n    char *demangledName;\n\n#if SUPPORT_INDEXED_ISA\n    uint32_t index;\n#endif\n\n    void setFlags(uint32_t set) \n    {\n        OSAtomicOr32Barrier(set, &flags);\n    }\n\n    void clearFlags(uint32_t clear) \n    {\n        OSAtomicXor32Barrier(clear, &flags);\n    }\n\n    // set and clear must not overlap\n    void changeFlags(uint32_t set, uint32_t clear) \n    {\n        assert((set & clear) == 0);\n\n        uint32_t oldf, newf;\n        do {\n            oldf = flags;\n            newf = (oldf | set) & ~clear;\n        } while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags));\n    }\n};\n\n\nstruct class_data_bits_t {\n\n    // Values are the FAST_ flags above.\n    uintptr_t bits;\nprivate:\n    bool getBit(uintptr_t bit)\n    {\n        return bits & bit;\n    }\n\n#if FAST_ALLOC\n    static uintptr_t updateFastAlloc(uintptr_t oldBits, uintptr_t change)\n    {\n        if (change & FAST_ALLOC_MASK) {\n            if (((oldBits & FAST_ALLOC_MASK) == FAST_ALLOC_VALUE)  &&  \n                ((oldBits >> FAST_SHIFTED_SIZE_SHIFT) != 0)) \n            {\n                oldBits |= FAST_ALLOC;\n            } else {\n                oldBits &= ~FAST_ALLOC;\n            }\n        }\n        return oldBits;\n    }\n#else\n    static uintptr_t updateFastAlloc(uintptr_t oldBits, uintptr_t change) {\n        return oldBits;\n    }\n#endif\n\n    void setBits(uintptr_t set) \n    {\n        uintptr_t oldBits;\n        uintptr_t newBits;\n        do {\n            oldBits = LoadExclusive(&bits);\n            newBits = updateFastAlloc(oldBits | set, set);\n        } while (!StoreReleaseExclusive(&bits, oldBits, newBits));\n    }\n\n    void clearBits(uintptr_t clear) \n    {\n        uintptr_t oldBits;\n        uintptr_t newBits;\n        do {\n            oldBits = LoadExclusive(&bits);\n            newBits = updateFastAlloc(oldBits & ~clear, clear);\n        } while (!StoreReleaseExclusive(&bits, oldBits, newBits));\n    }\n\npublic:\n\n    class_rw_t* data() {\n        return (class_rw_t *)(bits & FAST_DATA_MASK);\n    }\n    void setData(class_rw_t *newData)\n    {\n        assert(!data()  ||  (newData->flags & (RW_REALIZING | RW_FUTURE)));\n        // Set during realization or construction only. No locking needed.\n        // Use a store-release fence because there may be concurrent\n        // readers of data and data's contents.\n        uintptr_t newBits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData;\n        atomic_thread_fence(memory_order_release);\n        bits = newBits;\n    }\n\n#if FAST_HAS_DEFAULT_RR\n    bool hasDefaultRR() {\n        return getBit(FAST_HAS_DEFAULT_RR);\n    }\n    void setHasDefaultRR() {\n        setBits(FAST_HAS_DEFAULT_RR);\n    }\n    void setHasCustomRR() {\n        clearBits(FAST_HAS_DEFAULT_RR);\n    }\n#else\n    bool hasDefaultRR() {\n        return data()->flags & RW_HAS_DEFAULT_RR;\n    }\n    void setHasDefaultRR() {\n        data()->setFlags(RW_HAS_DEFAULT_RR);\n    }\n    void setHasCustomRR() {\n        data()->clearFlags(RW_HAS_DEFAULT_RR);\n    }\n#endif\n\n#if FAST_HAS_DEFAULT_AWZ\n    bool hasDefaultAWZ() {\n        return getBit(FAST_HAS_DEFAULT_AWZ);\n    }\n    void setHasDefaultAWZ() {\n        setBits(FAST_HAS_DEFAULT_AWZ);\n    }\n    void setHasCustomAWZ() {\n        clearBits(FAST_HAS_DEFAULT_AWZ);\n    }\n#else\n    bool hasDefaultAWZ() {\n        return data()->flags & RW_HAS_DEFAULT_AWZ;\n    }\n    void setHasDefaultAWZ() {\n        data()->setFlags(RW_HAS_DEFAULT_AWZ);\n    }\n    void setHasCustomAWZ() {\n        data()->clearFlags(RW_HAS_DEFAULT_AWZ);\n    }\n#endif\n\n#if FAST_HAS_CXX_CTOR\n    bool hasCxxCtor() {\n        return getBit(FAST_HAS_CXX_CTOR);\n    }\n    void setHasCxxCtor() {\n        setBits(FAST_HAS_CXX_CTOR);\n    }\n#else\n    bool hasCxxCtor() {\n        return data()->flags & RW_HAS_CXX_CTOR;\n    }\n    void setHasCxxCtor() {\n        data()->setFlags(RW_HAS_CXX_CTOR);\n    }\n#endif\n\n#if FAST_HAS_CXX_DTOR\n    bool hasCxxDtor() {\n        return getBit(FAST_HAS_CXX_DTOR);\n    }\n    void setHasCxxDtor() {\n        setBits(FAST_HAS_CXX_DTOR);\n    }\n#else\n    bool hasCxxDtor() {\n        return data()->flags & RW_HAS_CXX_DTOR;\n    }\n    void setHasCxxDtor() {\n        data()->setFlags(RW_HAS_CXX_DTOR);\n    }\n#endif\n\n#if FAST_REQUIRES_RAW_ISA\n    bool instancesRequireRawIsa() {\n        return getBit(FAST_REQUIRES_RAW_ISA);\n    }\n    void setInstancesRequireRawIsa() {\n        setBits(FAST_REQUIRES_RAW_ISA);\n    }\n#elif SUPPORT_NONPOINTER_ISA\n    bool instancesRequireRawIsa() {\n        return data()->flags & RW_REQUIRES_RAW_ISA;\n    }\n    void setInstancesRequireRawIsa() {\n        data()->setFlags(RW_REQUIRES_RAW_ISA);\n    }\n#else\n    bool instancesRequireRawIsa() {\n        return true;\n    }\n    void setInstancesRequireRawIsa() {\n        // nothing\n    }\n#endif\n\n#if FAST_ALLOC\n    size_t fastInstanceSize() \n    {\n        assert(bits & FAST_ALLOC);\n        return (bits >> FAST_SHIFTED_SIZE_SHIFT) * 16;\n    }\n    void setFastInstanceSize(size_t newSize) \n    {\n        // Set during realization or construction only. No locking needed.\n        assert(data()->flags & RW_REALIZING);\n\n        // Round up to 16-byte boundary, then divide to get 16-byte units\n        newSize = ((newSize + 15) & ~15) / 16;\n        \n        uintptr_t newBits = newSize << FAST_SHIFTED_SIZE_SHIFT;\n        if ((newBits >> FAST_SHIFTED_SIZE_SHIFT) == newSize) {\n            int shift = WORD_BITS - FAST_SHIFTED_SIZE_SHIFT;\n            uintptr_t oldBits = (bits << shift) >> shift;\n            if ((oldBits & FAST_ALLOC_MASK) == FAST_ALLOC_VALUE) {\n                newBits |= FAST_ALLOC;\n            }\n            bits = oldBits | newBits;\n        }\n    }\n\n    bool canAllocFast() {\n        return bits & FAST_ALLOC;\n    }\n#else\n    size_t fastInstanceSize() {\n        abort();\n    }\n    void setFastInstanceSize(size_t) {\n        // nothing\n    }\n    bool canAllocFast() {\n        return false;\n    }\n#endif\n\n    void setClassArrayIndex(unsigned Idx) {\n#if SUPPORT_INDEXED_ISA\n        // 0 is unused as then we can rely on zero-initialisation from calloc.\n        assert(Idx > 0);\n        data()->index = Idx;\n#endif\n    }\n\n    unsigned classArrayIndex() {\n#if SUPPORT_INDEXED_ISA\n        return data()->index;\n#else\n        return 0;\n#endif\n    }\n\n    bool isAnySwift() {\n        return isSwiftStable() || isSwiftLegacy();\n    }\n\n    bool isSwiftStable() {\n        return getBit(FAST_IS_SWIFT_STABLE);\n    }\n    void setIsSwiftStable() {\n        setBits(FAST_IS_SWIFT_STABLE);\n    }\n\n    bool isSwiftLegacy() {\n        return getBit(FAST_IS_SWIFT_LEGACY);\n    }\n    void setIsSwiftLegacy() {\n        setBits(FAST_IS_SWIFT_LEGACY);\n    }\n};\n\n\nstruct objc_class : objc_object {\n    // Class ISA;\n    Class superclass;\n    cache_t cache;             // formerly cache pointer and vtable\n    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags\n\n    class_rw_t *data() { \n        return bits.data();\n    }\n    void setData(class_rw_t *newData) {\n        bits.setData(newData);\n    }\n\n    void setInfo(uint32_t set) {\n        assert(isFuture()  ||  isRealized());\n        data()->setFlags(set);\n    }\n\n    void clearInfo(uint32_t clear) {\n        assert(isFuture()  ||  isRealized());\n        data()->clearFlags(clear);\n    }\n\n    // set and clear must not overlap\n    void changeInfo(uint32_t set, uint32_t clear) {\n        assert(isFuture()  ||  isRealized());\n        assert((set & clear) == 0);\n        data()->changeFlags(set, clear);\n    }\n\n    bool hasCustomRR() {\n        return ! bits.hasDefaultRR();\n    }\n    void setHasDefaultRR() {\n        assert(isInitializing());\n        bits.setHasDefaultRR();\n    }\n    void setHasCustomRR(bool inherited = false);\n    void printCustomRR(bool inherited);\n\n    bool hasCustomAWZ() {\n        return ! bits.hasDefaultAWZ();\n    }\n    void setHasDefaultAWZ() {\n        assert(isInitializing());\n        bits.setHasDefaultAWZ();\n    }\n    void setHasCustomAWZ(bool inherited = false);\n    void printCustomAWZ(bool inherited);\n\n    bool instancesRequireRawIsa() {\n        return bits.instancesRequireRawIsa();\n    }\n    void setInstancesRequireRawIsa(bool inherited = false);\n    void printInstancesRequireRawIsa(bool inherited);\n\n    bool canAllocNonpointer() {\n        assert(!isFuture());\n        return !instancesRequireRawIsa();\n    }\n    bool canAllocFast() {\n        assert(!isFuture());\n        return bits.canAllocFast();\n    }\n\n\n    bool hasCxxCtor() {\n        // addSubclass() propagates this flag from the superclass.\n        assert(isRealized());\n        return bits.hasCxxCtor();\n    }\n    void setHasCxxCtor() { \n        bits.setHasCxxCtor();\n    }\n\n    bool hasCxxDtor() {\n        // addSubclass() propagates this flag from the superclass.\n        assert(isRealized());\n        return bits.hasCxxDtor();\n    }\n    void setHasCxxDtor() { \n        bits.setHasCxxDtor();\n    }\n\n\n    bool isSwiftStable() {\n        return bits.isSwiftStable();\n    }\n\n    bool isSwiftLegacy() {\n        return bits.isSwiftLegacy();\n    }\n\n    bool isAnySwift() {\n        return bits.isAnySwift();\n    }\n\n\n    // Return YES if the class's ivars are managed by ARC, \n    // or the class is MRC but has ARC-style weak ivars.\n    bool hasAutomaticIvars() {\n        return data()->ro->flags & (RO_IS_ARC | RO_HAS_WEAK_WITHOUT_ARC);\n    }\n\n    // Return YES if the class's ivars are managed by ARC.\n    bool isARC() {\n        return data()->ro->flags & RO_IS_ARC;\n    }\n\n\n#if SUPPORT_NONPOINTER_ISA\n    // Tracked in non-pointer isas; not tracked otherwise\n#else\n    bool instancesHaveAssociatedObjects() {\n        // this may be an unrealized future class in the CF-bridged case\n        assert(isFuture()  ||  isRealized());\n        return data()->flags & RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS;\n    }\n\n    void setInstancesHaveAssociatedObjects() {\n        // this may be an unrealized future class in the CF-bridged case\n        assert(isFuture()  ||  isRealized());\n        setInfo(RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS);\n    }\n#endif\n\n    bool shouldGrowCache() {\n        return true;\n    }\n\n    void setShouldGrowCache(bool) {\n        // fixme good or bad for memory use?\n    }\n\n    bool isInitializing() {\n        return getMeta()->data()->flags & RW_INITIALIZING;\n    }\n\n    void setInitializing() {\n        assert(!isMetaClass());\n        ISA()->setInfo(RW_INITIALIZING);\n    }\n\n    bool isInitialized() {\n        return getMeta()->data()->flags & RW_INITIALIZED;\n    }\n\n    void setInitialized();\n\n    bool isLoadable() {\n        assert(isRealized());\n        return true;  // any class registered for +load is definitely loadable\n    }\n\n    IMP getLoadMethod();\n\n    // Locking: To prevent concurrent realization, hold runtimeLock.\n    bool isRealized() {\n        return data()->flags & RW_REALIZED;\n    }\n\n    // Returns true if this is an unrealized future class.\n    // Locking: To prevent concurrent realization, hold runtimeLock.\n    bool isFuture() { \n        return data()->flags & RW_FUTURE;\n    }\n\n    bool isMetaClass() {\n        assert(this);\n        assert(isRealized());\n        return data()->ro->flags & RO_META;\n    }\n\n    // NOT identical to this->ISA when this is a metaclass\n    Class getMeta() {\n        if (isMetaClass()) return (Class)this;\n        else return this->ISA();\n    }\n\n    bool isRootClass() {\n        return superclass == nil;\n    }\n    bool isRootMetaclass() {\n        return ISA() == (Class)this;\n    }\n\n    const char *mangledName() { \n        // fixme can't assert locks here\n        assert(this);\n\n        if (isRealized()  ||  isFuture()) {\n            return data()->ro->name;\n        } else {\n            return ((const class_ro_t *)data())->name;\n        }\n    }\n    \n    const char *demangledName(bool realize = false);\n    const char *nameForLogging();\n\n    // May be unaligned depending on class's ivars.\n    uint32_t unalignedInstanceStart() {\n        assert(isRealized());\n        return data()->ro->instanceStart;\n    }\n\n    // Class's instance start rounded up to a pointer-size boundary.\n    // This is used for ARC layout bitmaps.\n    uint32_t alignedInstanceStart() {\n        return word_align(unalignedInstanceStart());\n    }\n\n    // May be unaligned depending on class's ivars.\n    uint32_t unalignedInstanceSize() {\n        assert(isRealized());\n        return data()->ro->instanceSize;\n    }\n\n    // Class's ivar size rounded up to a pointer-size boundary.\n    uint32_t alignedInstanceSize() {\n        return word_align(unalignedInstanceSize());\n    }\n\n    size_t instanceSize(size_t extraBytes) {\n        size_t size = alignedInstanceSize() + extraBytes;\n        // CF requires all objects be at least 16 bytes.\n        if (size < 16) size = 16;\n        return size;\n    }\n    \n\n    void setInstanceSize(uint32_t newSize) {\n        assert(isRealized());\n        if (newSize != data()->ro->instanceSize) {\n            assert(data()->flags & RW_COPIED_RO);\n            *const_cast<uint32_t *>(&data()->ro->instanceSize) = newSize;\n        }\n        bits.setFastInstanceSize(newSize);\n    }\n\n    void chooseClassArrayIndex();\n\n    void setClassArrayIndex(unsigned Idx) {\n        bits.setClassArrayIndex(Idx);\n    }\n\n    unsigned classArrayIndex() {\n        return bits.classArrayIndex();\n    }\n\n};\n\n\nstruct swift_class_t : objc_class {\n    uint32_t flags;\n    uint32_t instanceAddressOffset;\n    uint32_t instanceSize;\n    uint16_t instanceAlignMask;\n    uint16_t reserved;\n\n    uint32_t classSize;\n    uint32_t classAddressOffset;\n    void *description;\n    // ...\n\n    void *baseAddress() {\n        return (void *)((uint8_t *)this - classAddressOffset);\n    }\n};\n\n\nstruct category_t {\n    const char *name;\n    classref_t cls;\n    struct method_list_t *instanceMethods;\n    struct method_list_t *classMethods;\n    struct protocol_list_t *protocols;\n    struct property_list_t *instanceProperties;\n    // Fields below this point are not always present on disk.\n    struct property_list_t *_classProperties;\n\n    method_list_t *methodsForMeta(bool isMeta) {\n        if (isMeta) return classMethods;\n        else return instanceMethods;\n    }\n\n    property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);\n};\n\nstruct objc_super2 {\n    id receiver;\n    Class current_class;\n};\n\nstruct message_ref_t {\n    IMP imp;\n    SEL sel;\n};\n\n\nextern Method protocol_getMethod(protocol_t *p, SEL sel, bool isRequiredMethod, bool isInstanceMethod, bool recursive);\n\nstatic inline void\nforeach_realized_class_and_subclass_2(Class top, unsigned& count,\n                                      std::function<bool (Class)> code) \n{\n    // runtimeLock.assertLocked();\n    assert(top);\n    Class cls = top;\n    while (1) {\n        if (--count == 0) {\n            _objc_fatal(\"Memory corruption in class list.\");\n        }\n        if (!code(cls)) break;\n\n        if (cls->data()->firstSubclass) {\n            cls = cls->data()->firstSubclass;\n        } else {\n            while (!cls->data()->nextSiblingClass  &&  cls != top) {\n                cls = cls->superclass;\n                if (--count == 0) {\n                    _objc_fatal(\"Memory corruption in class list.\");\n                }\n            }\n            if (cls == top) break;\n            cls = cls->data()->nextSiblingClass;\n        }\n    }\n}\n\nextern Class firstRealizedClass();\nextern unsigned int unreasonableClassCount();\n\n// Enumerates a class and all of its realized subclasses.\nstatic inline void\nforeach_realized_class_and_subclass(Class top,\n                                    std::function<void (Class)> code)\n{\n    unsigned int count = unreasonableClassCount();\n\n    foreach_realized_class_and_subclass_2(top, count,\n                                          [&code](Class cls) -> bool\n    {\n        code(cls);\n        return true; \n    });\n}\n\n// Enumerates all realized classes and metaclasses.\nstatic inline void\nforeach_realized_class_and_metaclass(std::function<void (Class)> code) \n{\n    unsigned int count = unreasonableClassCount();\n    \n    for (Class top = firstRealizedClass(); \n         top != nil; \n         top = top->data()->nextSiblingClass) \n    {\n        foreach_realized_class_and_subclass_2(top, count,\n                                              [&code](Class cls) -> bool\n        {\n            code(cls);\n            return true; \n        });\n    }\n\n}\n{\n    // Class‘s ivar size rounded up to a pointer-size boundary.\n    uint32_t alignedInstanceSize() {\n        return word_align(unalignedInstanceSize());\n    }\n}\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-runtime-new.mm",
    "content": "/*\n * Copyright (c) 2005-2009 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-runtime-new.m\n* Support for new-ABI classes and images.\n**********************************************************************/\n\n#if __OBJC2__\n\n#include \"objc-private.h\"\n#include \"objc-runtime-new.h\"\n#include \"objc-file.h\"\n#include \"objc-cache.h\"\n#include <Block.h>\n#include <objc/message.h>\n#include <mach/shared_region.h>\n\n#define newprotocol(p) ((protocol_t *)p)\n\nstatic void disableTaggedPointers();\nstatic void detach_class(Class cls, bool isMeta);\nstatic void free_class(Class cls);\nstatic Class setSuperclass(Class cls, Class newSuper);\nstatic Class realizeClass(Class cls);\nstatic method_t *getMethodNoSuper_nolock(Class cls, SEL sel);\nstatic method_t *getMethod_nolock(Class cls, SEL sel);\nstatic IMP addMethod(Class cls, SEL name, IMP imp, const char *types, bool replace);\nstatic bool isRRSelector(SEL sel);\nstatic bool isAWZSelector(SEL sel);\nstatic bool methodListImplementsRR(const method_list_t *mlist);\nstatic bool methodListImplementsAWZ(const method_list_t *mlist);\nstatic void updateCustomRR_AWZ(Class cls, method_t *meth);\nstatic method_t *search_method_list(const method_list_t *mlist, SEL sel);\nstatic void flushCaches(Class cls);\nstatic void initializeTaggedPointerObfuscator(void);\n#if SUPPORT_FIXUP\nstatic void fixupMessageRef(message_ref_t *msg);\n#endif\n\nstatic bool MetaclassNSObjectAWZSwizzled;\nstatic bool ClassNSObjectRRSwizzled;\n\n\n/***********************************************************************\n* Lock management\n**********************************************************************/\nmutex_t runtimeLock;\nmutex_t selLock;\nmutex_t cacheUpdateLock;\nrecursive_mutex_t loadMethodLock;\n\nvoid lock_init(void)\n{\n}\n\n\n/***********************************************************************\n* Class structure decoding\n**********************************************************************/\n\nconst uintptr_t objc_debug_class_rw_data_mask = FAST_DATA_MASK;\n\n\n/***********************************************************************\n* Non-pointer isa decoding\n**********************************************************************/\n#if SUPPORT_INDEXED_ISA\n\n// Indexed non-pointer isa.\n\n// These are used to mask the ISA and see if its got an index or not.\nconst uintptr_t objc_debug_indexed_isa_magic_mask  = ISA_INDEX_MAGIC_MASK;\nconst uintptr_t objc_debug_indexed_isa_magic_value = ISA_INDEX_MAGIC_VALUE;\n\n// die if masks overlap\nSTATIC_ASSERT((ISA_INDEX_MASK & ISA_INDEX_MAGIC_MASK) == 0);\n\n// die if magic is wrong\nSTATIC_ASSERT((~ISA_INDEX_MAGIC_MASK & ISA_INDEX_MAGIC_VALUE) == 0);\n\n// Then these are used to extract the index from the ISA.\nconst uintptr_t objc_debug_indexed_isa_index_mask  = ISA_INDEX_MASK;\nconst uintptr_t objc_debug_indexed_isa_index_shift  = ISA_INDEX_SHIFT;\n\nasm(\"\\n .globl _objc_absolute_indexed_isa_magic_mask\"                   \\\n    \"\\n _objc_absolute_indexed_isa_magic_mask = \" STRINGIFY2(ISA_INDEX_MAGIC_MASK));\nasm(\"\\n .globl _objc_absolute_indexed_isa_magic_value\" \\\n    \"\\n _objc_absolute_indexed_isa_magic_value = \" STRINGIFY2(ISA_INDEX_MAGIC_VALUE));\nasm(\"\\n .globl _objc_absolute_indexed_isa_index_mask\"                   \\\n    \"\\n _objc_absolute_indexed_isa_index_mask = \" STRINGIFY2(ISA_INDEX_MASK));\nasm(\"\\n .globl _objc_absolute_indexed_isa_index_shift\" \\\n    \"\\n _objc_absolute_indexed_isa_index_shift = \" STRINGIFY2(ISA_INDEX_SHIFT));\n\n\n// And then we can use that index to get the class from this array.  Note\n// the size is provided so that clients can ensure the index they get is in\n// bounds and not read off the end of the array.\n// Defined in the objc-msg-*.s files\n// const Class objc_indexed_classes[]\n\n// When we don't have enough bits to store a class*, we can instead store an\n// index in to this array.  Classes are added here when they are realized.\n// Note, an index of 0 is illegal.\nuintptr_t objc_indexed_classes_count = 0;\n\n// SUPPORT_INDEXED_ISA\n#else\n// not SUPPORT_INDEXED_ISA\n\n// These variables exist but are all set to 0 so that they are ignored.\nconst uintptr_t objc_debug_indexed_isa_magic_mask  = 0;\nconst uintptr_t objc_debug_indexed_isa_magic_value = 0;\nconst uintptr_t objc_debug_indexed_isa_index_mask  = 0;\nconst uintptr_t objc_debug_indexed_isa_index_shift = 0;\nClass objc_indexed_classes[1] = { nil };\nuintptr_t objc_indexed_classes_count = 0;\n\n// not SUPPORT_INDEXED_ISA\n#endif\n\n\n#if SUPPORT_PACKED_ISA\n\n// Packed non-pointer isa.\n\nasm(\"\\n .globl _objc_absolute_packed_isa_class_mask\" \\\n    \"\\n _objc_absolute_packed_isa_class_mask = \" STRINGIFY2(ISA_MASK));\n\nconst uintptr_t objc_debug_isa_class_mask  = ISA_MASK;\nconst uintptr_t objc_debug_isa_magic_mask  = ISA_MAGIC_MASK;\nconst uintptr_t objc_debug_isa_magic_value = ISA_MAGIC_VALUE;\n\n// die if masks overlap\nSTATIC_ASSERT((ISA_MASK & ISA_MAGIC_MASK) == 0);\n\n// die if magic is wrong\nSTATIC_ASSERT((~ISA_MAGIC_MASK & ISA_MAGIC_VALUE) == 0);\n\n// die if virtual address space bound goes up\nSTATIC_ASSERT((~ISA_MASK & MACH_VM_MAX_ADDRESS) == 0  ||  \n              ISA_MASK + sizeof(void*) == MACH_VM_MAX_ADDRESS);\n\n// SUPPORT_PACKED_ISA\n#else\n// not SUPPORT_PACKED_ISA\n\n// These variables exist but enforce pointer alignment only.\nconst uintptr_t objc_debug_isa_class_mask  = (~WORD_MASK);\nconst uintptr_t objc_debug_isa_magic_mask  = WORD_MASK;\nconst uintptr_t objc_debug_isa_magic_value = 0;\n\n// not SUPPORT_PACKED_ISA\n#endif\n\n\n/***********************************************************************\n* allocatedClasses\n* A table of all classes (and metaclasses) which have been allocated\n* with objc_allocateClassPair.\n**********************************************************************/\nstatic NXHashTable *allocatedClasses = nil;\n\n\ntypedef locstamped_category_list_t category_list;\n\n\n/*\n  Low two bits of mlist->entsize is used as the fixed-up marker.\n  PREOPTIMIZED VERSION:\n    Method lists from shared cache are 1 (uniqued) or 3 (uniqued and sorted).\n    (Protocol method lists are not sorted because of their extra parallel data)\n    Runtime fixed-up method lists get 3.\n  UN-PREOPTIMIZED VERSION:\n    Method lists from shared cache are 1 (uniqued) or 3 (uniqued and sorted)\n    Shared cache's sorting and uniquing are not trusted, but do affect the \n    location of the selector name string.\n    Runtime fixed-up method lists get 2.\n\n  High two bits of protocol->flags is used as the fixed-up marker.\n  PREOPTIMIZED VERSION:\n    Protocols from shared cache are 1<<30.\n    Runtime fixed-up protocols get 1<<30.\n  UN-PREOPTIMIZED VERSION:\n  Protocols from shared cache are 1<<30.\n    Shared cache's fixups are not trusted.\n    Runtime fixed-up protocols get 3<<30.\n*/\n\nstatic uint32_t fixed_up_method_list = 3;\nstatic uint32_t fixed_up_protocol = PROTOCOL_FIXED_UP_1;\n\nvoid\ndisableSharedCacheOptimizations(void)\n{\n    fixed_up_method_list = 2;\n    fixed_up_protocol = PROTOCOL_FIXED_UP_1 | PROTOCOL_FIXED_UP_2;\n}\n\nbool method_list_t::isFixedUp() const {\n    return flags() == fixed_up_method_list;\n}\n\nvoid method_list_t::setFixedUp() {\n    runtimeLock.assertLocked();\n    assert(!isFixedUp());\n    entsizeAndFlags = entsize() | fixed_up_method_list;\n}\n\nbool protocol_t::isFixedUp() const {\n    return (flags & PROTOCOL_FIXED_UP_MASK) == fixed_up_protocol;\n}\n\nvoid protocol_t::setFixedUp() {\n    runtimeLock.assertLocked();\n    assert(!isFixedUp());\n    flags = (flags & ~PROTOCOL_FIXED_UP_MASK) | fixed_up_protocol;\n}\n\n\nmethod_list_t **method_array_t::endCategoryMethodLists(Class cls) \n{\n    method_list_t **mlists = beginLists();\n    method_list_t **mlistsEnd = endLists();\n    \n    if (mlists == mlistsEnd  ||  !cls->data()->ro->baseMethods()) \n    {\n        // No methods, or no base methods. \n        // Everything here is a category method.\n        return mlistsEnd;\n    }\n    \n    // Have base methods. Category methods are \n    // everything except the last method list.\n    return mlistsEnd - 1;\n}\n\nstatic const char *sel_cname(SEL sel)\n{\n    return (const char *)(void *)sel;\n}\n\n\nstatic size_t protocol_list_size(const protocol_list_t *plist)\n{\n    return sizeof(protocol_list_t) + plist->count * sizeof(protocol_t *);\n}\n\n\nstatic void try_free(const void *p) \n{\n    if (p && malloc_size(p)) free((void *)p);\n}\n\n\nstatic void (*classCopyFixupHandler)(Class _Nonnull oldClass,\n                                     Class _Nonnull newClass);\n\nvoid _objc_setClassCopyFixupHandler(void (* _Nonnull newFixupHandler)\n    (Class _Nonnull oldClass, Class _Nonnull newClass)) {\n    classCopyFixupHandler = newFixupHandler;\n}\n\nstatic Class \nalloc_class_for_subclass(Class supercls, size_t extraBytes)\n{\n    if (!supercls  ||  !supercls->isAnySwift()) {\n        return _calloc_class(sizeof(objc_class) + extraBytes);\n    }\n\n    // Superclass is a Swift class. New subclass must duplicate its extra bits.\n\n    // Allocate the new class, with space for super's prefix and suffix\n    // and self's extraBytes.\n    swift_class_t *swiftSupercls = (swift_class_t *)supercls;\n    size_t superSize = swiftSupercls->classSize;\n    void *superBits = swiftSupercls->baseAddress();\n    void *bits = malloc(superSize + extraBytes);\n\n    // Copy all of the superclass's data to the new class.\n    memcpy(bits, superBits, superSize);\n\n    // Erase the objc data and the Swift description in the new class.\n    swift_class_t *swcls = (swift_class_t *)\n        ((uint8_t *)bits + swiftSupercls->classAddressOffset);\n    bzero(swcls, sizeof(objc_class));\n    swcls->description = nil;\n\n    if (classCopyFixupHandler) {\n        classCopyFixupHandler(supercls, (Class)swcls);\n    }\n\n    // Mark this class as Swift-enhanced.\n    if (supercls->isSwiftStable()) {\n        swcls->bits.setIsSwiftStable();\n    }\n    if (supercls->isSwiftLegacy()) {\n        swcls->bits.setIsSwiftLegacy();\n    }\n    \n    return (Class)swcls;\n}\n\n\n/***********************************************************************\n* object_getIndexedIvars.\n**********************************************************************/\nvoid *object_getIndexedIvars(id obj)\n{\n    uint8_t *base = (uint8_t *)obj;\n\n    if (!obj) return nil;\n    if (obj->isTaggedPointer()) return nil;\n\n    if (!obj->isClass()) return base + obj->ISA()->alignedInstanceSize();\n\n    Class cls = (Class)obj;\n    if (!cls->isAnySwift()) return base + sizeof(objc_class);\n    \n    swift_class_t *swcls = (swift_class_t *)cls;\n    return base - swcls->classAddressOffset + word_align(swcls->classSize);\n}\n\n\n/***********************************************************************\n* make_ro_writeable\n* Reallocates rw->ro if necessary to make it writeable.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic class_ro_t *make_ro_writeable(class_rw_t *rw)\n{\n    runtimeLock.assertLocked();\n\n    if (rw->flags & RW_COPIED_RO) {\n        // already writeable, do nothing\n    } else {\n        class_ro_t *ro = (class_ro_t *)\n            memdup(rw->ro, sizeof(*rw->ro));\n        rw->ro = ro;\n        rw->flags |= RW_COPIED_RO;\n    }\n    return (class_ro_t *)rw->ro;\n}\n\n\n/***********************************************************************\n* unattachedCategories\n* Returns the class => categories map of unattached categories.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic NXMapTable *unattachedCategories(void)\n{\n    runtimeLock.assertLocked();\n\n    static NXMapTable *category_map = nil;\n\n    if (category_map) return category_map;\n\n    // fixme initial map size\n    category_map = NXCreateMapTable(NXPtrValueMapPrototype, 16);\n\n    return category_map;\n}\n\n\n/***********************************************************************\n* dataSegmentsContain\n* Returns true if the given address lies within a data segment in any\n* loaded image.\n*\n* This is optimized for use where the return value is expected to be\n* true. A call where the return value is false always results in a\n* slow linear search of all loaded images. A call where the return\n* value is fast will often be fast due to caching.\n**********************************************************************/\nstatic bool dataSegmentsContain(const void *ptr) {\n    struct Range {\n        uintptr_t start, end;\n        bool contains(uintptr_t ptr) {\n            return start <= ptr && ptr <= end;\n        }\n    };\n    \n    // This is a really simple linear searched cache. On a cache hit,\n    // the hit entry is moved to the front of the array. On a cache\n    // miss where a range is successfully found on the slow path, the\n    // found range is inserted at the beginning of the cache. This gives\n    // us fast access to the most recently used elements, and LRU\n    // eviction.\n    enum { cacheCount = 16 };\n    static Range cache[cacheCount];\n    \n    uintptr_t addr = (uintptr_t)ptr;\n    \n    // Special case a hit on the first entry of the cache. No\n    // bookkeeping is required at all in this case.\n    if (cache[0].contains(addr)) {\n        return true;\n    }\n    \n    // Search the rest of the cache.\n    for (unsigned i = 1; i < cacheCount; i++) {\n        if (cache[i].contains(addr)) {\n            // Cache hit. Move all preceding entries down one element,\n            // then place this entry at the front.\n            Range r = cache[i];\n            memmove(&cache[1], &cache[0], i * sizeof(cache[0]));\n            cache[0] = r;\n            return true;\n        }\n    }\n    \n    // Cache miss. Find the image header containing the given address.\n    // If there isn't one, then we're definitely not in any image,\n    // so return false.\n    Range found = { 0, 0 };\n    auto *h = (headerType *)dyld_image_header_containing_address(ptr);\n    if (h == nullptr)\n        return false;\n    \n    // Iterate over the data segments in the found image. If the address\n    // lies within one, note the data segment range in `found`.\n    // TODO: this is more work than we'd like to do. All we really need\n    // is the full range of the image. Addresses within the TEXT segment\n    // would also be acceptable for our use case. If possible, we should\n    // change this to work with the full address range of the found\n    // image header. Another possibility would be to use the range\n    // from `h` to the end of the page containing `addr`.\n    foreach_data_segment(h, [&](const segmentType *seg, intptr_t slide) {\n        Range r;\n        r.start = seg->vmaddr + slide;\n        r.end = r.start + seg->vmsize;\n        if (r.contains(addr))\n            found = r;\n    });\n    \n    if (found.start != 0) {\n        memmove(&cache[1], &cache[0], (cacheCount - 1) * sizeof(cache[0]));\n        cache[0] = found;\n        return true;\n    }\n    \n    return false;\n}\n\n\n/***********************************************************************\n* isKnownClass\n* Return true if the class is known to the runtime (located within the\n* shared cache, within the data segment of a loaded image, or has been\n* allocated with obj_allocateClassPair).\n**********************************************************************/\nstatic bool isKnownClass(Class cls) {\n    // The order of conditionals here is important for speed. We want to\n    // put the most common cases first, but also the fastest cases\n    // first. Checking the shared region is both fast and common.\n    // Checking allocatedClasses is fast, but may not be common,\n    // depending on what the program is doing. Checking if data segments\n    // contain the address is slow, so do it last.\n    return (sharedRegionContains(cls) ||\n            NXHashMember(allocatedClasses, cls) ||\n            dataSegmentsContain(cls));\n}\n\n\n/***********************************************************************\n* addClassTableEntry\n* Add a class to the table of all classes. If addMeta is true,\n* automatically adds the metaclass of the class as well.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic void addClassTableEntry(Class cls, bool addMeta = true) {\n    runtimeLock.assertLocked();\n\n    // This class is allowed to be a known class via the shared cache or via\n    // data segments, but it is not allowed to be in the dynamic table already.\n    assert(!NXHashMember(allocatedClasses, cls));\n\n    if (!isKnownClass(cls))\n        NXHashInsert(allocatedClasses, cls);\n    if (addMeta)\n        addClassTableEntry(cls->ISA(), false);\n}\n\n\n/***********************************************************************\n* checkIsKnownClass\n* Checks the given class against the list of all known classes. Dies\n* with a fatal error if the class is not known.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic void checkIsKnownClass(Class cls)\n{\n    if (!isKnownClass(cls))\n        _objc_fatal(\"Attempt to use unknown class %p.\", cls);\n}\n\n\n/***********************************************************************\n* addUnattachedCategoryForClass\n* Records an unattached category.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic void addUnattachedCategoryForClass(category_t *cat, Class cls, \n                                          header_info *catHeader)\n{\n    runtimeLock.assertLocked();\n\n    // DO NOT use cat->cls! cls may be cat->cls->isa instead\n    NXMapTable *cats = unattachedCategories();\n    category_list *list;\n\n    list = (category_list *)NXMapGet(cats, cls);\n    if (!list) {\n        list = (category_list *)\n            calloc(sizeof(*list) + sizeof(list->list[0]), 1);\n    } else {\n        list = (category_list *)\n            realloc(list, sizeof(*list) + sizeof(list->list[0]) * (list->count + 1));\n    }\n    list->list[list->count++] = (locstamped_category_t){cat, catHeader};\n    NXMapInsert(cats, cls, list);\n}\n\n\n/***********************************************************************\n* removeUnattachedCategoryForClass\n* Removes an unattached category.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic void removeUnattachedCategoryForClass(category_t *cat, Class cls)\n{\n    runtimeLock.assertLocked();\n\n    // DO NOT use cat->cls! cls may be cat->cls->isa instead\n    NXMapTable *cats = unattachedCategories();\n    category_list *list;\n\n    list = (category_list *)NXMapGet(cats, cls);\n    if (!list) return;\n\n    uint32_t i;\n    for (i = 0; i < list->count; i++) {\n        if (list->list[i].cat == cat) {\n            // shift entries to preserve list order\n            memmove(&list->list[i], &list->list[i+1], \n                    (list->count-i-1) * sizeof(list->list[i]));\n            list->count--;\n            return;\n        }\n    }\n}\n\n\n/***********************************************************************\n* unattachedCategoriesForClass\n* Returns the list of unattached categories for a class, and \n* deletes them from the list. \n* The result must be freed by the caller. \n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic category_list *\nunattachedCategoriesForClass(Class cls, bool realizing)\n{\n    runtimeLock.assertLocked();\n    return (category_list *)NXMapRemove(unattachedCategories(), cls);\n}\n\n\n/***********************************************************************\n* removeAllUnattachedCategoriesForClass\n* Deletes all unattached categories (loaded or not) for a class.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic void removeAllUnattachedCategoriesForClass(Class cls)\n{\n    runtimeLock.assertLocked();\n\n    void *list = NXMapRemove(unattachedCategories(), cls);\n    if (list) free(list);\n}\n\n\n/***********************************************************************\n* classNSObject\n* Returns class NSObject.\n* Locking: none\n**********************************************************************/\nstatic Class classNSObject(void)\n{\n    extern objc_class OBJC_CLASS_$_NSObject;\n    return (Class)&OBJC_CLASS_$_NSObject;\n}\n\n\n/***********************************************************************\n* printReplacements\n* Implementation of PrintReplacedMethods / OBJC_PRINT_REPLACED_METHODS.\n* Warn about methods from cats that override other methods in cats or cls.\n* Assumes no methods from cats have been added to cls yet.\n**********************************************************************/\nstatic void printReplacements(Class cls, category_list *cats)\n{\n    uint32_t c;\n    bool isMeta = cls->isMetaClass();\n\n    if (!cats) return;\n\n    // Newest categories are LAST in cats\n    // Later categories override earlier ones.\n    for (c = 0; c < cats->count; c++) {\n        category_t *cat = cats->list[c].cat;\n\n        method_list_t *mlist = cat->methodsForMeta(isMeta);\n        if (!mlist) continue;\n\n        for (const auto& meth : *mlist) {\n            SEL s = sel_registerName(sel_cname(meth.name));\n\n            // Search for replaced methods in method lookup order.\n            // Complain about the first duplicate only.\n\n            // Look for method in earlier categories\n            for (uint32_t c2 = 0; c2 < c; c2++) {\n                category_t *cat2 = cats->list[c2].cat;\n\n                const method_list_t *mlist2 = cat2->methodsForMeta(isMeta);\n                if (!mlist2) continue;\n\n                for (const auto& meth2 : *mlist2) {\n                    SEL s2 = sel_registerName(sel_cname(meth2.name));\n                    if (s == s2) {\n                        logReplacedMethod(cls->nameForLogging(), s, \n                                          cls->isMetaClass(), cat->name, \n                                          meth2.imp, meth.imp);\n                        goto complained;\n                    }\n                }\n            }\n\n            // Look for method in cls\n            for (const auto& meth2 : cls->data()->methods) {\n                SEL s2 = sel_registerName(sel_cname(meth2.name));\n                if (s == s2) {\n                    logReplacedMethod(cls->nameForLogging(), s, \n                                      cls->isMetaClass(), cat->name, \n                                      meth2.imp, meth.imp);\n                    goto complained;\n                }\n            }\n\n        complained:\n            ;\n        }\n    }\n}\n\n\nstatic bool isBundleClass(Class cls)\n{\n    return cls->data()->ro->flags & RO_FROM_BUNDLE;\n}\n\n\nstatic void \nfixupMethodList(method_list_t *mlist, bool bundleCopy, bool sort)\n{\n    runtimeLock.assertLocked();\n    assert(!mlist->isFixedUp());\n\n    // fixme lock less in attachMethodLists ?\n    {\n        mutex_locker_t lock(selLock);\n    \n        // Unique selectors in list.\n        for (auto& meth : *mlist) {\n            const char *name = sel_cname(meth.name);\n            meth.name = sel_registerNameNoLock(name, bundleCopy);\n        }\n    }\n\n    // Sort by selector address.\n    if (sort) {\n        method_t::SortBySELAddress sorter;\n        std::stable_sort(mlist->begin(), mlist->end(), sorter);\n    }\n    \n    // Mark method list as uniqued and sorted\n    mlist->setFixedUp();\n}\n\n\nstatic void \nprepareMethodLists(Class cls, method_list_t **addedLists, int addedCount, \n                   bool baseMethods, bool methodsFromBundle)\n{\n    runtimeLock.assertLocked();\n\n    if (addedCount == 0) return;\n\n    // Don't scan redundantly\n    bool scanForCustomRR = !cls->hasCustomRR();\n    bool scanForCustomAWZ = !cls->hasCustomAWZ();\n\n    // There exist RR/AWZ special cases for some class's base methods. \n    // But this code should never need to scan base methods for RR/AWZ: \n    // default RR/AWZ cannot be set before setInitialized().\n    // Therefore we need not handle any special cases here.\n    if (baseMethods) {\n        assert(!scanForCustomRR  &&  !scanForCustomAWZ);\n    }\n\n    // Add method lists to array.\n    // Reallocate un-fixed method lists.\n    // The new methods are PREPENDED to the method list array.\n\n    for (int i = 0; i < addedCount; i++) {\n        method_list_t *mlist = addedLists[i];\n        assert(mlist);\n\n        // Fixup selectors if necessary\n        if (!mlist->isFixedUp()) {\n            fixupMethodList(mlist, methodsFromBundle, true/*sort*/);\n        }\n\n        // Scan for method implementations tracked by the class's flags\n        if (scanForCustomRR  &&  methodListImplementsRR(mlist)) {\n            cls->setHasCustomRR();\n            scanForCustomRR = false;\n        }\n        if (scanForCustomAWZ  &&  methodListImplementsAWZ(mlist)) {\n            cls->setHasCustomAWZ();\n            scanForCustomAWZ = false;\n        }\n    }\n}\n\n\n// Attach method lists and properties and protocols from categories to a class.\n// Assumes the categories in cats are all loaded and sorted by load order, \n// oldest categories first.\nstatic void \nattachCategories(Class cls, category_list *cats, bool flush_caches)\n{\n    if (!cats) return;\n    if (PrintReplacedMethods) printReplacements(cls, cats);\n\n    bool isMeta = cls->isMetaClass();\n\n    // fixme rearrange to remove these intermediate allocations\n    method_list_t **mlists = (method_list_t **)\n        malloc(cats->count * sizeof(*mlists));\n    property_list_t **proplists = (property_list_t **)\n        malloc(cats->count * sizeof(*proplists));\n    protocol_list_t **protolists = (protocol_list_t **)\n        malloc(cats->count * sizeof(*protolists));\n\n    // Count backwards through cats to get newest categories first\n    int mcount = 0;\n    int propcount = 0;\n    int protocount = 0;\n    int i = cats->count;\n    bool fromBundle = NO;\n    while (i--) {\n        auto& entry = cats->list[i];\n\n        method_list_t *mlist = entry.cat->methodsForMeta(isMeta);\n        if (mlist) {\n            mlists[mcount++] = mlist;\n            fromBundle |= entry.hi->isBundle();\n        }\n\n        property_list_t *proplist = \n            entry.cat->propertiesForMeta(isMeta, entry.hi);\n        if (proplist) {\n            proplists[propcount++] = proplist;\n        }\n\n        protocol_list_t *protolist = entry.cat->protocols;\n        if (protolist) {\n            protolists[protocount++] = protolist;\n        }\n    }\n\n    auto rw = cls->data();\n\n    prepareMethodLists(cls, mlists, mcount, NO, fromBundle);\n    rw->methods.attachLists(mlists, mcount);\n    free(mlists);\n    if (flush_caches  &&  mcount > 0) flushCaches(cls);\n\n    rw->properties.attachLists(proplists, propcount);\n    free(proplists);\n\n    rw->protocols.attachLists(protolists, protocount);\n    free(protolists);\n}\n\n\n/***********************************************************************\n* methodizeClass\n* Fixes up cls's method list, protocol list, and property list.\n* Attaches any outstanding categories.\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nstatic void methodizeClass(Class cls)\n{\n    runtimeLock.assertLocked();\n\n    bool isMeta = cls->isMetaClass();\n    auto rw = cls->data();\n    auto ro = rw->ro;\n\n    // Methodizing for the first time\n    if (PrintConnecting) {\n        _objc_inform(\"CLASS: methodizing class '%s' %s\", \n                     cls->nameForLogging(), isMeta ? \"(meta)\" : \"\");\n    }\n\n    // Install methods and properties that the class implements itself.\n    method_list_t *list = ro->baseMethods();\n    if (list) {\n        prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));\n        rw->methods.attachLists(&list, 1);\n    }\n\n    property_list_t *proplist = ro->baseProperties;\n    if (proplist) {\n        rw->properties.attachLists(&proplist, 1);\n    }\n\n    protocol_list_t *protolist = ro->baseProtocols;\n    if (protolist) {\n        rw->protocols.attachLists(&protolist, 1);\n    }\n\n    // Root classes get bonus method implementations if they don't have \n    // them already. These apply before category replacements.\n    if (cls->isRootMetaclass()) {\n        // root metaclass\n        addMethod(cls, SEL_initialize, (IMP)&objc_noop_imp, \"\", NO);\n    }\n\n    // Attach categories.\n    category_list *cats = unattachedCategoriesForClass(cls, true /*realizing*/);\n    attachCategories(cls, cats, false /*don't flush caches*/);\n\n    if (PrintConnecting) {\n        if (cats) {\n            for (uint32_t i = 0; i < cats->count; i++) {\n                _objc_inform(\"CLASS: attached category %c%s(%s)\", \n                             isMeta ? '+' : '-', \n                             cls->nameForLogging(), cats->list[i].cat->name);\n            }\n        }\n    }\n    \n    if (cats) free(cats);\n\n#if DEBUG\n    // Debug: sanity-check all SELs; log method list contents\n    for (const auto& meth : rw->methods) {\n        if (PrintConnecting) {\n            _objc_inform(\"METHOD %c[%s %s]\", isMeta ? '+' : '-', \n                         cls->nameForLogging(), sel_getName(meth.name));\n        }\n        assert(sel_registerName(sel_getName(meth.name)) == meth.name); \n    }\n#endif\n}\n\n\n/***********************************************************************\n* remethodizeClass\n* Attach outstanding categories to an existing class.\n* Fixes up cls's method list, protocol list, and property list.\n* Updates method caches for cls and its subclasses.\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nstatic void remethodizeClass(Class cls)\n{\n    category_list *cats;\n    bool isMeta;\n\n    runtimeLock.assertLocked();\n\n    isMeta = cls->isMetaClass();\n\n    // Re-methodizing: check for more categories\n    if ((cats = unattachedCategoriesForClass(cls, false/*not realizing*/))) {\n        if (PrintConnecting) {\n            _objc_inform(\"CLASS: attaching categories to class '%s' %s\", \n                         cls->nameForLogging(), isMeta ? \"(meta)\" : \"\");\n        }\n        \n        attachCategories(cls, cats, true /*flush caches*/);        \n        free(cats);\n    }\n}\n\n\n/***********************************************************************\n* nonMetaClasses\n* Returns the secondary metaclass => class map\n* Used for some cases of +initialize and +resolveClassMethod:.\n* This map does not contain all class and metaclass pairs. It only \n* contains metaclasses whose classes would be in the runtime-allocated \n* named-class table, but are not because some other class with the same name \n* is in that table.\n* Classes with no duplicates are not included.\n* Classes in the preoptimized named-class table are not included.\n* Classes whose duplicates are in the preoptimized table are not included.\n* Most code should use getNonMetaClass() instead of reading this table.\n* Locking: runtimeLock must be read- or write-locked by the caller\n**********************************************************************/\nstatic NXMapTable *nonmeta_class_map = nil;\nstatic NXMapTable *nonMetaClasses(void)\n{\n    runtimeLock.assertLocked();\n\n    if (nonmeta_class_map) return nonmeta_class_map;\n\n    // nonmeta_class_map is typically small\n    INIT_ONCE_PTR(nonmeta_class_map, \n                  NXCreateMapTable(NXPtrValueMapPrototype, 32), \n                  NXFreeMapTable(v));\n\n    return nonmeta_class_map;\n}\n\n\n/***********************************************************************\n* addNonMetaClass\n* Adds metacls => cls to the secondary metaclass map\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nstatic void addNonMetaClass(Class cls)\n{\n    runtimeLock.assertLocked();\n    void *old;\n    old = NXMapInsert(nonMetaClasses(), cls->ISA(), cls);\n\n    assert(!cls->isMetaClass());\n    assert(cls->ISA()->isMetaClass());\n    assert(!old);\n}\n\n\nstatic void removeNonMetaClass(Class cls)\n{\n    runtimeLock.assertLocked();\n    NXMapRemove(nonMetaClasses(), cls->ISA());\n}\n\n\nstatic bool scanMangledField(const char *&string, const char *end, \n                             const char *&field, int& length)\n{\n    // Leading zero not allowed.\n    if (*string == '0') return false;\n\n    length = 0;\n    field = string;\n    while (field < end) {\n        char c = *field;\n        if (!isdigit(c)) break;\n        field++;\n        if (__builtin_smul_overflow(length, 10, &length)) return false;\n        if (__builtin_sadd_overflow(length, c - '0', &length)) return false;\n    }\n\n    string = field + length;\n    return length > 0  &&  string <= end;\n}\n\n\n/***********************************************************************\n* copySwiftV1DemangledName\n* Returns the pretty form of the given Swift-v1-mangled class or protocol name. \n* Returns nil if the string doesn't look like a mangled Swift v1 name.\n* The result must be freed with free().\n**********************************************************************/\nstatic char *copySwiftV1DemangledName(const char *string, bool isProtocol = false)\n{\n    if (!string) return nil;\n\n    // Swift mangling prefix.\n    if (strncmp(string, isProtocol ? \"_TtP\" : \"_TtC\", 4) != 0) return nil;\n    string += 4;\n\n    const char *end = string + strlen(string);\n\n    // Module name.\n    const char *prefix;\n    int prefixLength;\n    if (string[0] == 's') {\n        // \"s\" is the Swift module.\n        prefix = \"Swift\";\n        prefixLength = 5;\n        string += 1;\n    } else {\n        if (! scanMangledField(string, end, prefix, prefixLength)) return nil;\n    }\n\n    // Class or protocol name.\n    const char *suffix;\n    int suffixLength;\n    if (! scanMangledField(string, end, suffix, suffixLength)) return nil;\n\n    if (isProtocol) {\n        // Remainder must be \"_\".\n        if (strcmp(string, \"_\") != 0) return nil;\n    } else {\n        // Remainder must be empty.\n        if (string != end) return nil;\n    }\n\n    char *result;\n    asprintf(&result, \"%.*s.%.*s\", prefixLength,prefix, suffixLength,suffix);\n    return result;\n}\n\n\n/***********************************************************************\n* copySwiftV1MangledName\n* Returns the Swift 1.0 mangled form of the given class or protocol name. \n* Returns nil if the string doesn't look like an unmangled Swift name.\n* The result must be freed with free().\n**********************************************************************/\nstatic char *copySwiftV1MangledName(const char *string, bool isProtocol = false)\n{\n    if (!string) return nil;\n\n    size_t dotCount = 0;\n    size_t dotIndex;\n    const char *s;\n    for (s = string; *s; s++) {\n        if (*s == '.') {\n            dotCount++;\n            dotIndex = s - string;\n        }\n    }\n    size_t stringLength = s - string;\n\n    if (dotCount != 1  ||  dotIndex == 0  ||  dotIndex >= stringLength-1) {\n        return nil;\n    }\n    \n    const char *prefix = string;\n    size_t prefixLength = dotIndex;\n    const char *suffix = string + dotIndex + 1;\n    size_t suffixLength = stringLength - (dotIndex + 1);\n    \n    char *name;\n\n    if (prefixLength == 5  &&  memcmp(prefix, \"Swift\", 5) == 0) {\n        asprintf(&name, \"_Tt%cs%zu%.*s%s\", \n                 isProtocol ? 'P' : 'C', \n                 suffixLength, (int)suffixLength, suffix, \n                 isProtocol ? \"_\" : \"\");\n    } else {\n        asprintf(&name, \"_Tt%c%zu%.*s%zu%.*s%s\", \n                 isProtocol ? 'P' : 'C', \n                 prefixLength, (int)prefixLength, prefix, \n                 suffixLength, (int)suffixLength, suffix, \n                 isProtocol ? \"_\" : \"\");\n    }\n    return name;\n}\n\n\n/***********************************************************************\n* getClass\n* Looks up a class by name. The class MIGHT NOT be realized.\n* Demangled Swift names are recognized.\n* Locking: runtimeLock must be read- or write-locked by the caller.\n**********************************************************************/\n\n// This is a misnomer: gdb_objc_realized_classes is actually a list of \n// named classes not in the dyld shared cache, whether realized or not.\nNXMapTable *gdb_objc_realized_classes;  // exported for debuggers in objc-gdb.h\n\nstatic Class getClass_impl(const char *name)\n{\n    runtimeLock.assertLocked();\n\n    // allocated in _read_images\n    assert(gdb_objc_realized_classes);\n\n    // Try runtime-allocated table\n    Class result = (Class)NXMapGet(gdb_objc_realized_classes, name);\n    if (result) return result;\n\n    // Try table from dyld shared cache\n    return getPreoptimizedClass(name);\n}\n\nstatic Class getClass(const char *name)\n{\n    runtimeLock.assertLocked();\n\n    // Try name as-is\n    Class result = getClass_impl(name);\n    if (result) return result;\n\n    // Try Swift-mangled equivalent of the given name.\n    if (char *swName = copySwiftV1MangledName(name)) {\n        result = getClass_impl(swName);\n        free(swName);\n        return result;\n    }\n\n    return nil;\n}\n\n\n/***********************************************************************\n* addNamedClass\n* Adds name => cls to the named non-meta class map.\n* Warns about duplicate class names and keeps the old mapping.\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nstatic void addNamedClass(Class cls, const char *name, Class replacing = nil)\n{\n    runtimeLock.assertLocked();\n    Class old;\n    if ((old = getClass(name))  &&  old != replacing) {\n        inform_duplicate(name, old, cls);\n\n        // getNonMetaClass uses name lookups. Classes not found by name \n        // lookup must be in the secondary meta->nonmeta table.\n        addNonMetaClass(cls);\n    } else {\n        NXMapInsert(gdb_objc_realized_classes, name, cls);\n    }\n    assert(!(cls->data()->flags & RO_META));\n\n    // wrong: constructed classes are already realized when they get here\n    // assert(!cls->isRealized());\n}\n\n\n/***********************************************************************\n* removeNamedClass\n* Removes cls from the name => cls map.\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nstatic void removeNamedClass(Class cls, const char *name)\n{\n    runtimeLock.assertLocked();\n    assert(!(cls->data()->flags & RO_META));\n    if (cls == NXMapGet(gdb_objc_realized_classes, name)) {\n        NXMapRemove(gdb_objc_realized_classes, name);\n    } else {\n        // cls has a name collision with another class - don't remove the other\n        // but do remove cls from the secondary metaclass->class map.\n        removeNonMetaClass(cls);\n    }\n}\n\n\n/***********************************************************************\n* unreasonableClassCount\n* Provides an upper bound for any iteration of classes, \n* to prevent spins when runtime metadata is corrupted.\n**********************************************************************/\nunsigned unreasonableClassCount()\n{\n    runtimeLock.assertLocked();\n\n    int base = NXCountMapTable(gdb_objc_realized_classes) +\n        getPreoptimizedClassUnreasonableCount();\n\n    // Provide lots of slack here. Some iterations touch metaclasses too.\n    // Some iterations backtrack (like realized class iteration).\n    // We don't need an efficient bound, merely one that prevents spins.\n    return (base + 1) * 16;\n}\n\n\n/***********************************************************************\n* futureNamedClasses\n* Returns the classname => future class map for unrealized future classes.\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nstatic NXMapTable *future_named_class_map = nil;\nstatic NXMapTable *futureNamedClasses()\n{\n    runtimeLock.assertLocked();\n    \n    if (future_named_class_map) return future_named_class_map;\n\n    // future_named_class_map is big enough for CF's classes and a few others\n    future_named_class_map = \n        NXCreateMapTable(NXStrValueMapPrototype, 32);\n\n    return future_named_class_map;\n}\n\n\nstatic bool haveFutureNamedClasses() {\n    return future_named_class_map  &&  NXCountMapTable(future_named_class_map);\n}\n\n\n/***********************************************************************\n* addFutureNamedClass\n* Installs cls as the class structure to use for the named class if it appears.\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nstatic void addFutureNamedClass(const char *name, Class cls)\n{\n    void *old;\n\n    runtimeLock.assertLocked();\n\n    if (PrintFuture) {\n        _objc_inform(\"FUTURE: reserving %p for %s\", (void*)cls, name);\n    }\n\n    class_rw_t *rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);\n    class_ro_t *ro = (class_ro_t *)calloc(sizeof(class_ro_t), 1);\n    ro->name = strdupIfMutable(name);\n    rw->ro = ro;\n    cls->setData(rw);\n    cls->data()->flags = RO_FUTURE;\n\n    old = NXMapKeyCopyingInsert(futureNamedClasses(), name, cls);\n    assert(!old);\n}\n\n\n/***********************************************************************\n* popFutureNamedClass\n* Removes the named class from the unrealized future class list, \n* because it has been realized.\n* Returns nil if the name is not used by a future class.\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nstatic Class popFutureNamedClass(const char *name)\n{\n    runtimeLock.assertLocked();\n\n    Class cls = nil;\n\n    if (future_named_class_map) {\n        cls = (Class)NXMapKeyFreeingRemove(future_named_class_map, name);\n        if (cls && NXCountMapTable(future_named_class_map) == 0) {\n            NXFreeMapTable(future_named_class_map);\n            future_named_class_map = nil;\n        }\n    }\n\n    return cls;\n}\n\n\n/***********************************************************************\n* remappedClasses\n* Returns the oldClass => newClass map for realized future classes.\n* Returns the oldClass => nil map for ignored weak-linked classes.\n* Locking: runtimeLock must be read- or write-locked by the caller\n**********************************************************************/\nstatic NXMapTable *remappedClasses(bool create)\n{\n    static NXMapTable *remapped_class_map = nil;\n\n    runtimeLock.assertLocked();\n\n    if (remapped_class_map) return remapped_class_map;\n    if (!create) return nil;\n\n    // remapped_class_map is big enough to hold CF's classes and a few others\n    INIT_ONCE_PTR(remapped_class_map, \n                  NXCreateMapTable(NXPtrValueMapPrototype, 32), \n                  NXFreeMapTable(v));\n\n    return remapped_class_map;\n}\n\n\n/***********************************************************************\n* noClassesRemapped\n* Returns YES if no classes have been remapped\n* Locking: runtimeLock must be read- or write-locked by the caller\n**********************************************************************/\nstatic bool noClassesRemapped(void)\n{\n    runtimeLock.assertLocked();\n\n    bool result = (remappedClasses(NO) == nil);\n#if DEBUG\n    // Catch construction of an empty table, which defeats optimization.\n    NXMapTable *map = remappedClasses(NO);\n    if (map) assert(NXCountMapTable(map) > 0);\n#endif\n    return result;\n}\n\n\n/***********************************************************************\n* addRemappedClass\n* newcls is a realized future class, replacing oldcls.\n* OR newcls is nil, replacing ignored weak-linked class oldcls.\n* Locking: runtimeLock must be write-locked by the caller\n**********************************************************************/\nstatic void addRemappedClass(Class oldcls, Class newcls)\n{\n    runtimeLock.assertLocked();\n\n    if (PrintFuture) {\n        _objc_inform(\"FUTURE: using %p instead of %p for %s\", \n                     (void*)newcls, (void*)oldcls, oldcls->nameForLogging());\n    }\n\n    void *old;\n    old = NXMapInsert(remappedClasses(YES), oldcls, newcls);\n    assert(!old);\n}\n\n\n/***********************************************************************\n* remapClass\n* Returns the live class pointer for cls, which may be pointing to \n* a class struct that has been reallocated.\n* Returns nil if cls is ignored because of weak linking.\n* Locking: runtimeLock must be read- or write-locked by the caller\n**********************************************************************/\nstatic Class remapClass(Class cls)\n{\n    runtimeLock.assertLocked();\n\n    Class c2;\n\n    if (!cls) return nil;\n\n    NXMapTable *map = remappedClasses(NO);\n    if (!map  ||  NXMapMember(map, cls, (void**)&c2) == NX_MAPNOTAKEY) {\n        return cls;\n    } else {\n        return c2;\n    }\n}\n\nstatic Class remapClass(classref_t cls)\n{\n    return remapClass((Class)cls);\n}\n\nClass _class_remap(Class cls)\n{\n    mutex_locker_t lock(runtimeLock);\n    return remapClass(cls);\n}\n\n/***********************************************************************\n* remapClassRef\n* Fix up a class ref, in case the class referenced has been reallocated \n* or is an ignored weak-linked class.\n* Locking: runtimeLock must be read- or write-locked by the caller\n**********************************************************************/\nstatic void remapClassRef(Class *clsref)\n{\n    runtimeLock.assertLocked();\n\n    Class newcls = remapClass(*clsref);    \n    if (*clsref != newcls) *clsref = newcls;\n}\n\n\n/***********************************************************************\n* getNonMetaClass\n* Return the ordinary class for this class or metaclass. \n* `inst` is an instance of `cls` or a subclass thereof, or nil. \n* Non-nil inst is faster.\n* Used by +initialize. \n* Locking: runtimeLock must be read- or write-locked by the caller\n**********************************************************************/\nstatic Class getNonMetaClass(Class metacls, id inst)\n{\n    static int total, named, secondary, sharedcache;\n    runtimeLock.assertLocked();\n\n    realizeClass(metacls);\n\n    total++;\n\n    // return cls itself if it's already a non-meta class\n    if (!metacls->isMetaClass()) return metacls;\n\n    // metacls really is a metaclass\n\n    // special case for root metaclass\n    // where inst == inst->ISA() == metacls is possible\n    if (metacls->ISA() == metacls) {\n        Class cls = metacls->superclass;\n        assert(cls->isRealized());\n        assert(!cls->isMetaClass());\n        assert(cls->ISA() == metacls);\n        if (cls->ISA() == metacls) return cls;\n    }\n\n    // use inst if available\n    if (inst) {\n        Class cls = (Class)inst;\n        realizeClass(cls);\n        // cls may be a subclass - find the real class for metacls\n        while (cls  &&  cls->ISA() != metacls) {\n            cls = cls->superclass;\n            realizeClass(cls);\n        }\n        if (cls) {\n            assert(!cls->isMetaClass());\n            assert(cls->ISA() == metacls);\n            return cls;\n        }\n#if DEBUG\n        _objc_fatal(\"cls is not an instance of metacls\");\n#else\n        // release build: be forgiving and fall through to slow lookups\n#endif\n    }\n\n    // try name lookup\n    {\n        Class cls = getClass(metacls->mangledName());\n        if (cls->ISA() == metacls) {\n            named++;\n            if (PrintInitializing) {\n                _objc_inform(\"INITIALIZE: %d/%d (%g%%) \"\n                             \"successful by-name metaclass lookups\",\n                             named, total, named*100.0/total);\n            }\n\n            realizeClass(cls);\n            return cls;\n        }\n    }\n\n    // try secondary table\n    {\n        Class cls = (Class)NXMapGet(nonMetaClasses(), metacls);\n        if (cls) {\n            secondary++;\n            if (PrintInitializing) {\n                _objc_inform(\"INITIALIZE: %d/%d (%g%%) \"\n                             \"successful secondary metaclass lookups\",\n                             secondary, total, secondary*100.0/total);\n            }\n\n            assert(cls->ISA() == metacls);            \n            realizeClass(cls);\n            return cls;\n        }\n    }\n\n    // try any duplicates in the dyld shared cache\n    {\n        Class cls = nil;\n\n        int count;\n        Class *classes = copyPreoptimizedClasses(metacls->mangledName(),&count);\n        if (classes) {\n            for (int i = 0; i < count; i++) {\n                if (classes[i]->ISA() == metacls) {\n                    cls = classes[i];\n                    break;\n                }\n            }\n            free(classes);\n        }\n\n        if (cls) {\n            sharedcache++;\n            if (PrintInitializing) {\n                _objc_inform(\"INITIALIZE: %d/%d (%g%%) \"\n                             \"successful shared cache metaclass lookups\",\n                             sharedcache, total, sharedcache*100.0/total);\n            }\n\n            realizeClass(cls);\n            return cls;\n        }\n    }\n\n    _objc_fatal(\"no class for metaclass %p\", (void*)metacls);\n}\n\n\n/***********************************************************************\n* _class_getNonMetaClass\n* Return the ordinary class for this class or metaclass. \n* Used by +initialize. \n* Locking: acquires runtimeLock\n**********************************************************************/\nClass _class_getNonMetaClass(Class cls, id obj)\n{\n    mutex_locker_t lock(runtimeLock);\n    cls = getNonMetaClass(cls, obj);\n    assert(cls->isRealized());\n    return cls;\n}\n\n\n/***********************************************************************\n* addRootClass\n* Adds cls as a new realized root class.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic Class _firstRealizedClass = nil;\nClass firstRealizedClass() \n{\n    runtimeLock.assertLocked();\n    return _firstRealizedClass;\n}\n\nstatic void addRootClass(Class cls)\n{\n    runtimeLock.assertLocked();\n\n    assert(cls->isRealized());\n    cls->data()->nextSiblingClass = _firstRealizedClass;\n    _firstRealizedClass = cls;\n}\n\nstatic void removeRootClass(Class cls)\n{\n    runtimeLock.assertLocked();\n\n    Class *classp;\n    for (classp = &_firstRealizedClass; \n         *classp != cls; \n         classp = &(*classp)->data()->nextSiblingClass)\n    { }\n    \n    *classp = (*classp)->data()->nextSiblingClass;\n}\n\n\n/***********************************************************************\n* addSubclass\n* Adds subcls as a subclass of supercls.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic void addSubclass(Class supercls, Class subcls)\n{\n    runtimeLock.assertLocked();\n\n    if (supercls  &&  subcls) {\n        assert(supercls->isRealized());\n        assert(subcls->isRealized());\n        subcls->data()->nextSiblingClass = supercls->data()->firstSubclass;\n        supercls->data()->firstSubclass = subcls;\n\n        if (supercls->hasCxxCtor()) {\n            subcls->setHasCxxCtor();\n        }\n\n        if (supercls->hasCxxDtor()) {\n            subcls->setHasCxxDtor();\n        }\n\n        if (supercls->hasCustomRR()) {\n            subcls->setHasCustomRR(true);\n        }\n\n        if (supercls->hasCustomAWZ()) {\n            subcls->setHasCustomAWZ(true);\n        }\n\n        // Special case: instancesRequireRawIsa does not propagate \n        // from root class to root metaclass\n        if (supercls->instancesRequireRawIsa()  &&  supercls->superclass) {\n            subcls->setInstancesRequireRawIsa(true);\n        }\n    }\n}\n\n\n/***********************************************************************\n* removeSubclass\n* Removes subcls as a subclass of supercls.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic void removeSubclass(Class supercls, Class subcls)\n{\n    runtimeLock.assertLocked();\n    assert(supercls->isRealized());\n    assert(subcls->isRealized());\n    assert(subcls->superclass == supercls);\n\n    Class *cp;\n    for (cp = &supercls->data()->firstSubclass; \n         *cp  &&  *cp != subcls; \n         cp = &(*cp)->data()->nextSiblingClass)\n        ;\n    assert(*cp == subcls);\n    *cp = subcls->data()->nextSiblingClass;\n}\n\n\n\n/***********************************************************************\n* protocols\n* Returns the protocol name => protocol map for protocols.\n* Locking: runtimeLock must read- or write-locked by the caller\n**********************************************************************/\nstatic NXMapTable *protocols(void)\n{\n    static NXMapTable *protocol_map = nil;\n    \n    runtimeLock.assertLocked();\n\n    INIT_ONCE_PTR(protocol_map, \n                  NXCreateMapTable(NXStrValueMapPrototype, 16), \n                  NXFreeMapTable(v) );\n\n    return protocol_map;\n}\n\n\n/***********************************************************************\n* getProtocol\n* Looks up a protocol by name. Demangled Swift names are recognized.\n* Locking: runtimeLock must be read- or write-locked by the caller.\n**********************************************************************/\nstatic Protocol *getProtocol(const char *name)\n{\n    runtimeLock.assertLocked();\n\n    // Try name as-is.\n    Protocol *result = (Protocol *)NXMapGet(protocols(), name);\n    if (result) return result;\n\n    // Try Swift-mangled equivalent of the given name.\n    if (char *swName = copySwiftV1MangledName(name, true/*isProtocol*/)) {\n        result = (Protocol *)NXMapGet(protocols(), swName);\n        free(swName);\n        return result;\n    }\n\n    return nil;\n}\n\n\n/***********************************************************************\n* remapProtocol\n* Returns the live protocol pointer for proto, which may be pointing to \n* a protocol struct that has been reallocated.\n* Locking: runtimeLock must be read- or write-locked by the caller\n**********************************************************************/\nstatic protocol_t *remapProtocol(protocol_ref_t proto)\n{\n    runtimeLock.assertLocked();\n\n    protocol_t *newproto = (protocol_t *)\n        getProtocol(((protocol_t *)proto)->mangledName);\n    return newproto ? newproto : (protocol_t *)proto;\n}\n\n\n/***********************************************************************\n* remapProtocolRef\n* Fix up a protocol ref, in case the protocol referenced has been reallocated.\n* Locking: runtimeLock must be read- or write-locked by the caller\n**********************************************************************/\nstatic size_t UnfixedProtocolReferences;\nstatic void remapProtocolRef(protocol_t **protoref)\n{\n    runtimeLock.assertLocked();\n\n    protocol_t *newproto = remapProtocol((protocol_ref_t)*protoref);\n    if (*protoref != newproto) {\n        *protoref = newproto;\n        UnfixedProtocolReferences++;\n    }\n}\n\n\n/***********************************************************************\n* moveIvars\n* Slides a class's ivars to accommodate the given superclass size.\n* Ivars are NOT compacted to compensate for a superclass that shrunk.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic void moveIvars(class_ro_t *ro, uint32_t superSize)\n{\n    runtimeLock.assertLocked();\n\n    uint32_t diff;\n\n    assert(superSize > ro->instanceStart);\n    diff = superSize - ro->instanceStart;\n\n    if (ro->ivars) {\n        // Find maximum alignment in this class's ivars\n        uint32_t maxAlignment = 1;\n        for (const auto& ivar : *ro->ivars) {\n            if (!ivar.offset) continue;  // anonymous bitfield\n\n            uint32_t alignment = ivar.alignment();\n            if (alignment > maxAlignment) maxAlignment = alignment;\n        }\n\n        // Compute a slide value that preserves that alignment\n        uint32_t alignMask = maxAlignment - 1;\n        diff = (diff + alignMask) & ~alignMask;\n\n        // Slide all of this class's ivars en masse\n        for (const auto& ivar : *ro->ivars) {\n            if (!ivar.offset) continue;  // anonymous bitfield\n\n            uint32_t oldOffset = (uint32_t)*ivar.offset;\n            uint32_t newOffset = oldOffset + diff;\n            *ivar.offset = newOffset;\n\n            if (PrintIvars) {\n                _objc_inform(\"IVARS:    offset %u -> %u for %s \"\n                             \"(size %u, align %u)\", \n                             oldOffset, newOffset, ivar.name, \n                             ivar.size, ivar.alignment());\n            }\n        }\n    }\n\n    *(uint32_t *)&ro->instanceStart += diff;\n    *(uint32_t *)&ro->instanceSize += diff;\n}\n\n\nstatic void reconcileInstanceVariables(Class cls, Class supercls, const class_ro_t*& ro) \n{\n    class_rw_t *rw = cls->data();\n\n    assert(supercls);\n    assert(!cls->isMetaClass());\n\n    /* debug: print them all before sliding\n    if (ro->ivars) {\n        for (const auto& ivar : *ro->ivars) {\n            if (!ivar.offset) continue;  // anonymous bitfield\n\n            _objc_inform(\"IVARS: %s.%s (offset %u, size %u, align %u)\", \n                         ro->name, ivar.name, \n                         *ivar.offset, ivar.size, ivar.alignment());\n        }\n    }\n    */\n\n    // Non-fragile ivars - reconcile this class with its superclass\n    const class_ro_t *super_ro = supercls->data()->ro;\n    \n    if (DebugNonFragileIvars) {\n        // Debugging: Force non-fragile ivars to slide.\n        // Intended to find compiler, runtime, and program bugs.\n        // If it fails with this and works without, you have a problem.\n        \n        // Operation: Reset everything to 0 + misalignment. \n        // Then force the normal sliding logic to push everything back.\n        \n        // Exceptions: root classes, metaclasses, *NSCF* classes, \n        // __CF* classes, NSConstantString, NSSimpleCString\n        \n        // (already know it's not root because supercls != nil)\n        const char *clsname = cls->mangledName();\n        if (!strstr(clsname, \"NSCF\")  &&  \n            0 != strncmp(clsname, \"__CF\", 4)  &&  \n            0 != strcmp(clsname, \"NSConstantString\")  &&  \n            0 != strcmp(clsname, \"NSSimpleCString\")) \n        {\n            uint32_t oldStart = ro->instanceStart;\n            class_ro_t *ro_w = make_ro_writeable(rw);\n            ro = rw->ro;\n            \n            // Find max ivar alignment in class.\n            // default to word size to simplify ivar update\n            uint32_t alignment = 1<<WORD_SHIFT;\n            if (ro->ivars) {\n                for (const auto& ivar : *ro->ivars) {\n                    if (ivar.alignment() > alignment) {\n                        alignment = ivar.alignment();\n                    }\n                }\n            }\n            uint32_t misalignment = ro->instanceStart % alignment;\n            uint32_t delta = ro->instanceStart - misalignment;\n            ro_w->instanceStart = misalignment;\n            ro_w->instanceSize -= delta;\n            \n            if (PrintIvars) {\n                _objc_inform(\"IVARS: DEBUG: forcing ivars for class '%s' \"\n                             \"to slide (instanceStart %zu -> %zu)\", \n                             cls->nameForLogging(), (size_t)oldStart, \n                             (size_t)ro->instanceStart);\n            }\n            \n            if (ro->ivars) {\n                for (const auto& ivar : *ro->ivars) {\n                    if (!ivar.offset) continue;  // anonymous bitfield\n                    *ivar.offset -= delta;\n                }\n            }\n        }\n    }\n\n    if (ro->instanceStart >= super_ro->instanceSize) {\n        // Superclass has not overgrown its space. We're done here.\n        return;\n    }\n    // fixme can optimize for \"class has no new ivars\", etc\n\n    if (ro->instanceStart < super_ro->instanceSize) {\n        // Superclass has changed size. This class's ivars must move.\n        // Also slide layout bits in parallel.\n        // This code is incapable of compacting the subclass to \n        //   compensate for a superclass that shrunk, so don't do that.\n        if (PrintIvars) {\n            _objc_inform(\"IVARS: sliding ivars for class %s \"\n                         \"(superclass was %u bytes, now %u)\", \n                         cls->nameForLogging(), ro->instanceStart, \n                         super_ro->instanceSize);\n        }\n        class_ro_t *ro_w = make_ro_writeable(rw);\n        ro = rw->ro;\n        moveIvars(ro_w, super_ro->instanceSize);\n        gdb_objc_class_changed(cls, OBJC_CLASS_IVARS_CHANGED, ro->name);\n    } \n}\n\n\n/***********************************************************************\n* realizeClass\n* Performs first-time initialization on class cls, \n* including allocating its read-write data.\n* Returns the real class structure for the class. \n* Locking: runtimeLock must be write-locked by the caller\n**********************************************************************/\nstatic Class realizeClass(Class cls)\n{\n    runtimeLock.assertLocked();\n\n    const class_ro_t *ro;\n    class_rw_t *rw;\n    Class supercls;\n    Class metacls;\n    bool isMeta;\n\n    if (!cls) return nil;\n    if (cls->isRealized()) return cls;\n    assert(cls == remapClass(cls));\n\n    // fixme verify class is not in an un-dlopened part of the shared cache?\n\n    ro = (const class_ro_t *)cls->data();\n    if (ro->flags & RO_FUTURE) {\n        // This was a future class. rw data is already allocated.\n        rw = cls->data();\n        ro = cls->data()->ro;\n        cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);\n    } else {\n        // Normal class. Allocate writeable class data.\n        rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);\n        rw->ro = ro;\n        rw->flags = RW_REALIZED|RW_REALIZING;\n        cls->setData(rw);\n    }\n\n    isMeta = ro->flags & RO_META;\n\n    rw->version = isMeta ? 7 : 0;  // old runtime went up to 6\n\n\n    // Choose an index for this class.\n    // Sets cls->instancesRequireRawIsa if indexes no more indexes are available\n    cls->chooseClassArrayIndex();\n\n    if (PrintConnecting) {\n        _objc_inform(\"CLASS: realizing class '%s'%s %p %p #%u\", \n                     cls->nameForLogging(), isMeta ? \" (meta)\" : \"\", \n                     (void*)cls, ro, cls->classArrayIndex());\n    }\n\n    // Realize superclass and metaclass, if they aren't already.\n    // This needs to be done after RW_REALIZED is set above, for root classes.\n    // This needs to be done after class index is chosen, for root metaclasses.\n    supercls = realizeClass(remapClass(cls->superclass));\n    metacls = realizeClass(remapClass(cls->ISA()));\n\n#if SUPPORT_NONPOINTER_ISA\n    // Disable non-pointer isa for some classes and/or platforms.\n    // Set instancesRequireRawIsa.\n    bool instancesRequireRawIsa = cls->instancesRequireRawIsa();\n    bool rawIsaIsInherited = false;\n    static bool hackedDispatch = false;\n\n    if (DisableNonpointerIsa) {\n        // Non-pointer isa disabled by environment or app SDK version\n        instancesRequireRawIsa = true;\n    }\n    else if (!hackedDispatch  &&  !(ro->flags & RO_META)  &&  \n             0 == strcmp(ro->name, \"OS_object\")) \n    {\n        // hack for libdispatch et al - isa also acts as vtable pointer\n        hackedDispatch = true;\n        instancesRequireRawIsa = true;\n    }\n    else if (supercls  &&  supercls->superclass  &&  \n             supercls->instancesRequireRawIsa()) \n    {\n        // This is also propagated by addSubclass() \n        // but nonpointer isa setup needs it earlier.\n        // Special case: instancesRequireRawIsa does not propagate \n        // from root class to root metaclass\n        instancesRequireRawIsa = true;\n        rawIsaIsInherited = true;\n    }\n    \n    if (instancesRequireRawIsa) {\n        cls->setInstancesRequireRawIsa(rawIsaIsInherited);\n    }\n// SUPPORT_NONPOINTER_ISA\n#endif\n\n    // Update superclass and metaclass in case of remapping\n    cls->superclass = supercls;\n    cls->initClassIsa(metacls);\n\n    // Reconcile instance variable offsets / layout.\n    // This may reallocate class_ro_t, updating our ro variable.\n    if (supercls  &&  !isMeta) reconcileInstanceVariables(cls, supercls, ro);\n\n    // Set fastInstanceSize if it wasn't set already.\n    cls->setInstanceSize(ro->instanceSize);\n\n    // Copy some flags from ro to rw\n    if (ro->flags & RO_HAS_CXX_STRUCTORS) {\n        cls->setHasCxxDtor();\n        if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {\n            cls->setHasCxxCtor();\n        }\n    }\n\n    // Connect this class to its superclass's subclass lists\n    if (supercls) {\n        addSubclass(supercls, cls);\n    } else {\n        addRootClass(cls);\n    }\n\n    // Attach categories\n    methodizeClass(cls);\n\n    return cls;\n}\n\n\n/***********************************************************************\n* missingWeakSuperclass\n* Return YES if some superclass of cls was weak-linked and is missing.\n**********************************************************************/\nstatic bool \nmissingWeakSuperclass(Class cls)\n{\n    assert(!cls->isRealized());\n\n    if (!cls->superclass) {\n        // superclass nil. This is normal for root classes only.\n        return (!(cls->data()->flags & RO_ROOT));\n    } else {\n        // superclass not nil. Check if a higher superclass is missing.\n        Class supercls = remapClass(cls->superclass);\n        assert(cls != cls->superclass);\n        assert(cls != supercls);\n        if (!supercls) return YES;\n        if (supercls->isRealized()) return NO;\n        return missingWeakSuperclass(supercls);\n    }\n}\n\n\n/***********************************************************************\n* realizeAllClassesInImage\n* Non-lazily realizes all unrealized classes in the given image.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic void realizeAllClassesInImage(header_info *hi)\n{\n    runtimeLock.assertLocked();\n\n    size_t count, i;\n    classref_t *classlist;\n\n    if (hi->areAllClassesRealized()) return;\n\n    classlist = _getObjc2ClassList(hi, &count);\n\n    for (i = 0; i < count; i++) {\n        realizeClass(remapClass(classlist[i]));\n    }\n\n    hi->setAllClassesRealized(YES);\n}\n\n\n/***********************************************************************\n* realizeAllClasses\n* Non-lazily realizes all unrealized classes in all known images.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic void realizeAllClasses(void)\n{\n    runtimeLock.assertLocked();\n\n    header_info *hi;\n    for (hi = FirstHeader; hi; hi = hi->getNext()) {\n        realizeAllClassesInImage(hi);\n    }\n}\n\n\n/***********************************************************************\n* _objc_allocateFutureClass\n* Allocate an unresolved future class for the given class name.\n* Returns any existing allocation if one was already made.\n* Assumes the named class doesn't exist yet.\n* Locking: acquires runtimeLock\n**********************************************************************/\nClass _objc_allocateFutureClass(const char *name)\n{\n    mutex_locker_t lock(runtimeLock);\n\n    Class cls;\n    NXMapTable *map = futureNamedClasses();\n\n    if ((cls = (Class)NXMapGet(map, name))) {\n        // Already have a future class for this name.\n        return cls;\n    }\n\n    cls = _calloc_class(sizeof(objc_class));\n    addFutureNamedClass(name, cls);\n\n    return cls;\n}\n\n\n/***********************************************************************\n* objc_getFutureClass.  Return the id of the named class.\n* If the class does not exist, return an uninitialized class \n* structure that will be used for the class when and if it \n* does get loaded.\n* Not thread safe. \n**********************************************************************/\nClass objc_getFutureClass(const char *name)\n{\n    Class cls;\n\n    // YES unconnected, NO class handler\n    // (unconnected is OK because it will someday be the real class)\n    cls = look_up_class(name, YES, NO);\n    if (cls) {\n        if (PrintFuture) {\n            _objc_inform(\"FUTURE: found %p already in use for %s\", \n                         (void*)cls, name);\n        }\n\n        return cls;\n    }\n    \n    // No class or future class with that name yet. Make one.\n    // fixme not thread-safe with respect to \n    // simultaneous library load or getFutureClass.\n    return _objc_allocateFutureClass(name);\n}\n\n\nBOOL _class_isFutureClass(Class cls)\n{\n    return cls  &&  cls->isFuture();\n}\n\n\n/***********************************************************************\n* _objc_flush_caches\n* Flushes all caches.\n* (Historical behavior: flush caches for cls, its metaclass, \n* and subclasses thereof. Nil flushes all classes.)\n* Locking: acquires runtimeLock\n**********************************************************************/\nstatic void flushCaches(Class cls)\n{\n    runtimeLock.assertLocked();\n\n    mutex_locker_t lock(cacheUpdateLock);\n\n    if (cls) {\n        foreach_realized_class_and_subclass(cls, ^(Class c){\n            cache_erase_nolock(c);\n        });\n    }\n    else {\n        foreach_realized_class_and_metaclass(^(Class c){\n            cache_erase_nolock(c);\n        });\n    }\n}\n\n\nvoid _objc_flush_caches(Class cls)\n{\n    {\n        mutex_locker_t lock(runtimeLock);\n        flushCaches(cls);\n        if (cls  &&  cls->superclass  &&  cls != cls->getIsa()) {\n            flushCaches(cls->getIsa());\n        } else {\n            // cls is a root class or root metaclass. Its metaclass is itself\n            // or a subclass so the metaclass caches were already flushed.\n        }\n    }\n\n    if (!cls) {\n        // collectALot if cls==nil\n        mutex_locker_t lock(cacheUpdateLock);\n        cache_collect(true);\n    }\n}\n\n\n/***********************************************************************\n* map_images\n* Process the given images which are being mapped in by dyld.\n* Calls ABI-agnostic code after taking ABI-specific locks.\n*\n* Locking: write-locks runtimeLock\n**********************************************************************/\nvoid\nmap_images(unsigned count, const char * const paths[],\n           const struct mach_header * const mhdrs[])\n{\n    mutex_locker_t lock(runtimeLock);\n    return map_images_nolock(count, paths, mhdrs);\n}\n\n\n/***********************************************************************\n* load_images\n* Process +load in the given images which are being mapped in by dyld.\n*\n* Locking: write-locks runtimeLock and loadMethodLock\n**********************************************************************/\nextern bool hasLoadMethods(const headerType *mhdr);\nextern void prepare_load_methods(const headerType *mhdr);\n\nvoid\nload_images(const char *path __unused, const struct mach_header *mh)\n{\n    // Return without taking locks if there are no +load methods here.\n    if (!hasLoadMethods((const headerType *)mh)) return;\n\n    recursive_mutex_locker_t lock(loadMethodLock);\n\n    // Discover load methods\n    {\n        mutex_locker_t lock2(runtimeLock);\n        prepare_load_methods((const headerType *)mh);\n    }\n\n    // Call +load methods (without runtimeLock - re-entrant)\n    call_load_methods();\n}\n\n\n/***********************************************************************\n* unmap_image\n* Process the given image which is about to be unmapped by dyld.\n*\n* Locking: write-locks runtimeLock and loadMethodLock\n**********************************************************************/\nvoid \nunmap_image(const char *path __unused, const struct mach_header *mh)\n{\n    recursive_mutex_locker_t lock(loadMethodLock);\n    mutex_locker_t lock2(runtimeLock);\n    unmap_image_nolock(mh);\n}\n\n\n\n\n/***********************************************************************\n* mustReadClasses\n* Preflight check in advance of readClass() from an image.\n**********************************************************************/\nbool mustReadClasses(header_info *hi)\n{\n    const char *reason;\n\n    // If the image is not preoptimized then we must read classes.\n    if (!hi->isPreoptimized()) {\n        reason = nil; // Don't log this one because it is noisy.\n        goto readthem;\n    }\n\n    // If iOS simulator then we must read classes.\n#if TARGET_OS_SIMULATOR\n    reason = \"the image is for iOS simulator\";\n    goto readthem;\n#endif\n\n    assert(!hi->isBundle());  // no MH_BUNDLE in shared cache\n\n    // If the image may have missing weak superclasses then we must read classes\n    if (!noMissingWeakSuperclasses()) {\n        reason = \"the image may contain classes with missing weak superclasses\";\n        goto readthem;\n    }\n\n    // If there are unresolved future classes then we must read classes.\n    if (haveFutureNamedClasses()) {\n        reason = \"there are unresolved future classes pending\";\n        goto readthem;\n    }\n\n    // readClass() does not need to do anything.\n    return NO;\n\n readthem:\n    if (PrintPreopt  &&  reason) {\n        _objc_inform(\"PREOPTIMIZATION: reading classes manually from %s \"\n                     \"because %s\", hi->fname(), reason);\n    }\n    return YES;\n}\n\n\n/***********************************************************************\n* readClass\n* Read a class and metaclass as written by a compiler.\n* Returns the new class pointer. This could be: \n* - cls\n* - nil  (cls has a missing weak-linked superclass)\n* - something else (space for this class was reserved by a future class)\n*\n* Note that all work performed by this function is preflighted by \n* mustReadClasses(). Do not change this function without updating that one.\n*\n* Locking: runtimeLock acquired by map_images or objc_readClassPair\n**********************************************************************/\nClass readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)\n{\n    const char *mangledName = cls->mangledName();\n    \n    if (missingWeakSuperclass(cls)) {\n        // No superclass (probably weak-linked). \n        // Disavow any knowledge of this subclass.\n        if (PrintConnecting) {\n            _objc_inform(\"CLASS: IGNORING class '%s' with \"\n                         \"missing weak-linked superclass\", \n                         cls->nameForLogging());\n        }\n        addRemappedClass(cls, nil);\n        cls->superclass = nil;\n        return nil;\n    }\n    \n    // Note: Class __ARCLite__'s hack does not go through here. \n    // Class structure fixups that apply to it also need to be \n    // performed in non-lazy realization below.\n    \n    // These fields should be set to zero because of the \n    // binding of _objc_empty_vtable, but OS X 10.8's dyld \n    // does not bind shared cache absolute symbols as expected.\n    // This (and the __ARCLite__ hack below) can be removed \n    // once the simulator drops 10.8 support.\n#if TARGET_OS_SIMULATOR\n    if (cls->cache._mask) cls->cache._mask = 0;\n    if (cls->cache._occupied) cls->cache._occupied = 0;\n    if (cls->ISA()->cache._mask) cls->ISA()->cache._mask = 0;\n    if (cls->ISA()->cache._occupied) cls->ISA()->cache._occupied = 0;\n#endif\n\n    Class replacing = nil;\n    if (Class newCls = popFutureNamedClass(mangledName)) {\n        // This name was previously allocated as a future class.\n        // Copy objc_class to future class's struct.\n        // Preserve future's rw data block.\n        \n        if (newCls->isAnySwift()) {\n            _objc_fatal(\"Can't complete future class request for '%s' \"\n                        \"because the real class is too big.\", \n                        cls->nameForLogging());\n        }\n        \n        class_rw_t *rw = newCls->data();\n        const class_ro_t *old_ro = rw->ro;\n        memcpy(newCls, cls, sizeof(objc_class));\n        rw->ro = (class_ro_t *)newCls->data();\n        newCls->setData(rw);\n        freeIfMutable((char *)old_ro->name);\n        free((void *)old_ro);\n        \n        addRemappedClass(cls, newCls);\n        \n        replacing = cls;\n        cls = newCls;\n    }\n    \n    if (headerIsPreoptimized  &&  !replacing) {\n        // class list built in shared cache\n        // fixme strict assert doesn't work because of duplicates\n        // assert(cls == getClass(name));\n        assert(getClass(mangledName));\n    } else {\n        addNamedClass(cls, mangledName, replacing);\n        addClassTableEntry(cls);\n    }\n\n    // for future reference: shared cache never contains MH_BUNDLEs\n    if (headerIsBundle) {\n        cls->data()->flags |= RO_FROM_BUNDLE;\n        cls->ISA()->data()->flags |= RO_FROM_BUNDLE;\n    }\n    \n    return cls;\n}\n\n\n/***********************************************************************\n* readProtocol\n* Read a protocol as written by a compiler.\n**********************************************************************/\nstatic void\nreadProtocol(protocol_t *newproto, Class protocol_class,\n             NXMapTable *protocol_map, \n             bool headerIsPreoptimized, bool headerIsBundle)\n{\n    // This is not enough to make protocols in unloaded bundles safe, \n    // but it does prevent crashes when looking up unrelated protocols.\n    auto insertFn = headerIsBundle ? NXMapKeyCopyingInsert : NXMapInsert;\n\n    protocol_t *oldproto = (protocol_t *)getProtocol(newproto->mangledName);\n\n    if (oldproto) {\n        // Some other definition already won.\n        if (PrintProtocols) {\n            _objc_inform(\"PROTOCOLS: protocol at %p is %s  \"\n                         \"(duplicate of %p)\",\n                         newproto, oldproto->nameForLogging(), oldproto);\n        }\n    }\n    else if (headerIsPreoptimized) {\n        // Shared cache initialized the protocol object itself, \n        // but in order to allow out-of-cache replacement we need \n        // to add it to the protocol table now.\n\n        protocol_t *cacheproto = (protocol_t *)\n            getPreoptimizedProtocol(newproto->mangledName);\n        protocol_t *installedproto;\n        if (cacheproto  &&  cacheproto != newproto) {\n            // Another definition in the shared cache wins (because \n            // everything in the cache was fixed up to point to it).\n            installedproto = cacheproto;\n        }\n        else {\n            // This definition wins.\n            installedproto = newproto;\n        }\n        \n        assert(installedproto->getIsa() == protocol_class);\n        assert(installedproto->size >= sizeof(protocol_t));\n        insertFn(protocol_map, installedproto->mangledName, \n                 installedproto);\n        \n        if (PrintProtocols) {\n            _objc_inform(\"PROTOCOLS: protocol at %p is %s\", \n                         installedproto, installedproto->nameForLogging());\n            if (newproto != installedproto) {\n                _objc_inform(\"PROTOCOLS: protocol at %p is %s  \"\n                             \"(duplicate of %p)\", \n                             newproto, installedproto->nameForLogging(), \n                             installedproto);\n            }\n        }\n    }\n    else if (newproto->size >= sizeof(protocol_t)) {\n        // New protocol from an un-preoptimized image\n        // with sufficient storage. Fix it up in place.\n        // fixme duplicate protocols from unloadable bundle\n        newproto->initIsa(protocol_class);  // fixme pinned\n        insertFn(protocol_map, newproto->mangledName, newproto);\n        if (PrintProtocols) {\n            _objc_inform(\"PROTOCOLS: protocol at %p is %s\",\n                         newproto, newproto->nameForLogging());\n        }\n    }\n    else {\n        // New protocol from an un-preoptimized image \n        // with insufficient storage. Reallocate it.\n        // fixme duplicate protocols from unloadable bundle\n        size_t size = max(sizeof(protocol_t), (size_t)newproto->size);\n        protocol_t *installedproto = (protocol_t *)calloc(size, 1);\n        memcpy(installedproto, newproto, newproto->size);\n        installedproto->size = (typeof(installedproto->size))size;\n        \n        installedproto->initIsa(protocol_class);  // fixme pinned\n        insertFn(protocol_map, installedproto->mangledName, installedproto);\n        if (PrintProtocols) {\n            _objc_inform(\"PROTOCOLS: protocol at %p is %s  \", \n                         installedproto, installedproto->nameForLogging());\n            _objc_inform(\"PROTOCOLS: protocol at %p is %s  \"\n                         \"(reallocated to %p)\", \n                         newproto, installedproto->nameForLogging(), \n                         installedproto);\n        }\n    }\n}\n\n/***********************************************************************\n* _read_images\n* Perform initial processing of the headers in the linked \n* list beginning with headerList. \n*\n* Called by: map_images_nolock\n*\n* Locking: runtimeLock acquired by map_images\n**********************************************************************/\nvoid _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses)\n{\n    header_info *hi;\n    uint32_t hIndex;\n    size_t count;\n    size_t i;\n    Class *resolvedFutureClasses = nil;\n    size_t resolvedFutureClassCount = 0;\n    static bool doneOnce;\n    TimeLogger ts(PrintImageTimes);\n\n    runtimeLock.assertLocked();\n\n#define EACH_HEADER \\\n    hIndex = 0;         \\\n    hIndex < hCount && (hi = hList[hIndex]); \\\n    hIndex++\n\n    if (!doneOnce) {\n        doneOnce = YES;\n\n#if SUPPORT_NONPOINTER_ISA\n        // Disable non-pointer isa under some conditions.\n\n# if SUPPORT_INDEXED_ISA\n        // Disable nonpointer isa if any image contains old Swift code\n        for (EACH_HEADER) {\n            if (hi->info()->containsSwift()  &&\n                hi->info()->swiftVersion() < objc_image_info::SwiftVersion3)\n            {\n                DisableNonpointerIsa = true;\n                if (PrintRawIsa) {\n                    _objc_inform(\"RAW ISA: disabling non-pointer isa because \"\n                                 \"the app or a framework contains Swift code \"\n                                 \"older than Swift 3.0\");\n                }\n                break;\n            }\n        }\n# endif\n\n# if TARGET_OS_OSX\n        // Disable non-pointer isa if the app is too old\n        // (linked before OS X 10.11)\n        if (dyld_get_program_sdk_version() < DYLD_MACOSX_VERSION_10_11) {\n            DisableNonpointerIsa = true;\n            if (PrintRawIsa) {\n                _objc_inform(\"RAW ISA: disabling non-pointer isa because \"\n                             \"the app is too old (SDK version \" SDK_FORMAT \")\",\n                             FORMAT_SDK(dyld_get_program_sdk_version()));\n            }\n        }\n\n        // Disable non-pointer isa if the app has a __DATA,__objc_rawisa section\n        // New apps that load old extensions may need this.\n        for (EACH_HEADER) {\n            if (hi->mhdr()->filetype != MH_EXECUTE) continue;\n            unsigned long size;\n            if (getsectiondata(hi->mhdr(), \"__DATA\", \"__objc_rawisa\", &size)) {\n                DisableNonpointerIsa = true;\n                if (PrintRawIsa) {\n                    _objc_inform(\"RAW ISA: disabling non-pointer isa because \"\n                                 \"the app has a __DATA,__objc_rawisa section\");\n                }\n            }\n            break;  // assume only one MH_EXECUTE image\n        }\n# endif\n\n#endif\n\n        if (DisableTaggedPointers) {\n            disableTaggedPointers();\n        }\n        \n        initializeTaggedPointerObfuscator();\n\n        if (PrintConnecting) {\n            _objc_inform(\"CLASS: found %d classes during launch\", totalClasses);\n        }\n\n        // namedClasses\n        // Preoptimized classes don't go in this table.\n        // 4/3 is NXMapTable's load factor\n        int namedClassesSize = \n            (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;\n        gdb_objc_realized_classes =\n            NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);\n        \n        allocatedClasses = NXCreateHashTable(NXPtrPrototype, 0, nil);\n        \n        ts.log(\"IMAGE TIMES: first time tasks\");\n    }\n\n\n    // Discover classes. Fix up unresolved future classes. Mark bundle classes.\n\n    for (EACH_HEADER) {\n        classref_t *classlist = _getObjc2ClassList(hi, &count);\n        \n        if (! mustReadClasses(hi)) {\n            // Image is sufficiently optimized that we need not call readClass()\n            continue;\n        }\n\n        bool headerIsBundle = hi->isBundle();\n        bool headerIsPreoptimized = hi->isPreoptimized();\n\n        for (i = 0; i < count; i++) {\n            Class cls = (Class)classlist[i];\n            Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);\n\n            if (newCls != cls  &&  newCls) {\n                // Class was moved but not deleted. Currently this occurs \n                // only when the new class resolved a future class.\n                // Non-lazily realize the class below.\n                resolvedFutureClasses = (Class *)\n                    realloc(resolvedFutureClasses, \n                            (resolvedFutureClassCount+1) * sizeof(Class));\n                resolvedFutureClasses[resolvedFutureClassCount++] = newCls;\n            }\n        }\n    }\n\n    ts.log(\"IMAGE TIMES: discover classes\");\n\n    // Fix up remapped classes\n    // Class list and nonlazy class list remain unremapped.\n    // Class refs and super refs are remapped for message dispatching.\n    \n    if (!noClassesRemapped()) {\n        for (EACH_HEADER) {\n            Class *classrefs = _getObjc2ClassRefs(hi, &count);\n            for (i = 0; i < count; i++) {\n                remapClassRef(&classrefs[i]);\n            }\n            // fixme why doesn't test future1 catch the absence of this?\n            classrefs = _getObjc2SuperRefs(hi, &count);\n            for (i = 0; i < count; i++) {\n                remapClassRef(&classrefs[i]);\n            }\n        }\n    }\n\n    ts.log(\"IMAGE TIMES: remap classes\");\n\n    // Fix up @selector references\n    static size_t UnfixedSelectors;\n    {\n        mutex_locker_t lock(selLock);\n        for (EACH_HEADER) {\n            if (hi->isPreoptimized()) continue;\n            \n            bool isBundle = hi->isBundle();\n            SEL *sels = _getObjc2SelectorRefs(hi, &count);\n            UnfixedSelectors += count;\n            for (i = 0; i < count; i++) {\n                const char *name = sel_cname(sels[i]);\n                sels[i] = sel_registerNameNoLock(name, isBundle);\n            }\n        }\n    }\n\n    ts.log(\"IMAGE TIMES: fix up selector references\");\n\n#if SUPPORT_FIXUP\n    // Fix up old objc_msgSend_fixup call sites\n    for (EACH_HEADER) {\n        message_ref_t *refs = _getObjc2MessageRefs(hi, &count);\n        if (count == 0) continue;\n\n        if (PrintVtables) {\n            _objc_inform(\"VTABLES: repairing %zu unsupported vtable dispatch \"\n                         \"call sites in %s\", count, hi->fname());\n        }\n        for (i = 0; i < count; i++) {\n            fixupMessageRef(refs+i);\n        }\n    }\n\n    ts.log(\"IMAGE TIMES: fix up objc_msgSend_fixup\");\n#endif\n\n    // Discover protocols. Fix up protocol refs.\n    for (EACH_HEADER) {\n        extern objc_class OBJC_CLASS_$_Protocol;\n        Class cls = (Class)&OBJC_CLASS_$_Protocol;\n        assert(cls);\n        NXMapTable *protocol_map = protocols();\n        bool isPreoptimized = hi->isPreoptimized();\n        bool isBundle = hi->isBundle();\n\n        protocol_t **protolist = _getObjc2ProtocolList(hi, &count);\n        for (i = 0; i < count; i++) {\n            readProtocol(protolist[i], cls, protocol_map, \n                         isPreoptimized, isBundle);\n        }\n    }\n\n    ts.log(\"IMAGE TIMES: discover protocols\");\n\n    // Fix up @protocol references\n    // Preoptimized images may have the right \n    // answer already but we don't know for sure.\n    for (EACH_HEADER) {\n        protocol_t **protolist = _getObjc2ProtocolRefs(hi, &count);\n        for (i = 0; i < count; i++) {\n            remapProtocolRef(&protolist[i]);\n        }\n    }\n\n    ts.log(\"IMAGE TIMES: fix up @protocol references\");\n\n    // Realize non-lazy classes (for +load methods and static instances)\n    for (EACH_HEADER) {\n        classref_t *classlist = \n            _getObjc2NonlazyClassList(hi, &count);\n        for (i = 0; i < count; i++) {\n            Class cls = remapClass(classlist[i]);\n            if (!cls) continue;\n\n            // hack for class __ARCLite__, which didn't get this above\n#if TARGET_OS_SIMULATOR\n            if (cls->cache._buckets == (void*)&_objc_empty_cache  &&  \n                (cls->cache._mask  ||  cls->cache._occupied)) \n            {\n                cls->cache._mask = 0;\n                cls->cache._occupied = 0;\n            }\n            if (cls->ISA()->cache._buckets == (void*)&_objc_empty_cache  &&  \n                (cls->ISA()->cache._mask  ||  cls->ISA()->cache._occupied)) \n            {\n                cls->ISA()->cache._mask = 0;\n                cls->ISA()->cache._occupied = 0;\n            }\n#endif\n            \n            addClassTableEntry(cls);\n            realizeClass(cls);\n        }\n    }\n\n    ts.log(\"IMAGE TIMES: realize non-lazy classes\");\n\n    // Realize newly-resolved future classes, in case CF manipulates them\n    if (resolvedFutureClasses) {\n        for (i = 0; i < resolvedFutureClassCount; i++) {\n            realizeClass(resolvedFutureClasses[i]);\n            resolvedFutureClasses[i]->setInstancesRequireRawIsa(false/*inherited*/);\n        }\n        free(resolvedFutureClasses);\n    }    \n\n    ts.log(\"IMAGE TIMES: realize future classes\");\n\n    // Discover categories. \n    for (EACH_HEADER) {\n        category_t **catlist = \n            _getObjc2CategoryList(hi, &count);\n        bool hasClassProperties = hi->info()->hasCategoryClassProperties();\n\n        for (i = 0; i < count; i++) {\n            category_t *cat = catlist[i];\n            Class cls = remapClass(cat->cls);\n\n            if (!cls) {\n                // Category's target class is missing (probably weak-linked).\n                // Disavow any knowledge of this category.\n                catlist[i] = nil;\n                if (PrintConnecting) {\n                    _objc_inform(\"CLASS: IGNORING category \\?\\?\\?(%s) %p with \"\n                                 \"missing weak-linked target class\", \n                                 cat->name, cat);\n                }\n                continue;\n            }\n\n            // Process this category. \n            // First, register the category with its target class. \n            // Then, rebuild the class's method lists (etc) if \n            // the class is realized. \n            bool classExists = NO;\n            if (cat->instanceMethods ||  cat->protocols  \n                ||  cat->instanceProperties) \n            {\n                addUnattachedCategoryForClass(cat, cls, hi);\n                if (cls->isRealized()) {\n                    remethodizeClass(cls);\n                    classExists = YES;\n                }\n                if (PrintConnecting) {\n                    _objc_inform(\"CLASS: found category -%s(%s) %s\", \n                                 cls->nameForLogging(), cat->name, \n                                 classExists ? \"on existing class\" : \"\");\n                }\n            }\n\n            if (cat->classMethods  ||  cat->protocols  \n                ||  (hasClassProperties && cat->_classProperties)) \n            {\n                addUnattachedCategoryForClass(cat, cls->ISA(), hi);\n                if (cls->ISA()->isRealized()) {\n                    remethodizeClass(cls->ISA());\n                }\n                if (PrintConnecting) {\n                    _objc_inform(\"CLASS: found category +%s(%s)\", \n                                 cls->nameForLogging(), cat->name);\n                }\n            }\n        }\n    }\n\n    ts.log(\"IMAGE TIMES: discover categories\");\n\n    // Category discovery MUST BE LAST to avoid potential races \n    // when other threads call the new category code before \n    // this thread finishes its fixups.\n\n    // +load handled by prepare_load_methods()\n\n    if (DebugNonFragileIvars) {\n        realizeAllClasses();\n    }\n\n\n    // Print preoptimization statistics\n    if (PrintPreopt) {\n        static unsigned int PreoptTotalMethodLists;\n        static unsigned int PreoptOptimizedMethodLists;\n        static unsigned int PreoptTotalClasses;\n        static unsigned int PreoptOptimizedClasses;\n\n        for (EACH_HEADER) {\n            if (hi->isPreoptimized()) {\n                _objc_inform(\"PREOPTIMIZATION: honoring preoptimized selectors \"\n                             \"in %s\", hi->fname());\n            }\n            else if (hi->info()->optimizedByDyld()) {\n                _objc_inform(\"PREOPTIMIZATION: IGNORING preoptimized selectors \"\n                             \"in %s\", hi->fname());\n            }\n\n            classref_t *classlist = _getObjc2ClassList(hi, &count);\n            for (i = 0; i < count; i++) {\n                Class cls = remapClass(classlist[i]);\n                if (!cls) continue;\n\n                PreoptTotalClasses++;\n                if (hi->isPreoptimized()) {\n                    PreoptOptimizedClasses++;\n                }\n                \n                const method_list_t *mlist;\n                if ((mlist = ((class_ro_t *)cls->data())->baseMethods())) {\n                    PreoptTotalMethodLists++;\n                    if (mlist->isFixedUp()) {\n                        PreoptOptimizedMethodLists++;\n                    }\n                }\n                if ((mlist=((class_ro_t *)cls->ISA()->data())->baseMethods())) {\n                    PreoptTotalMethodLists++;\n                    if (mlist->isFixedUp()) {\n                        PreoptOptimizedMethodLists++;\n                    }\n                }\n            }\n        }\n\n        _objc_inform(\"PREOPTIMIZATION: %zu selector references not \"\n                     \"pre-optimized\", UnfixedSelectors);\n        _objc_inform(\"PREOPTIMIZATION: %u/%u (%.3g%%) method lists pre-sorted\",\n                     PreoptOptimizedMethodLists, PreoptTotalMethodLists, \n                     PreoptTotalMethodLists\n                     ? 100.0*PreoptOptimizedMethodLists/PreoptTotalMethodLists \n                     : 0.0);\n        _objc_inform(\"PREOPTIMIZATION: %u/%u (%.3g%%) classes pre-registered\",\n                     PreoptOptimizedClasses, PreoptTotalClasses, \n                     PreoptTotalClasses \n                     ? 100.0*PreoptOptimizedClasses/PreoptTotalClasses\n                     : 0.0);\n        _objc_inform(\"PREOPTIMIZATION: %zu protocol references not \"\n                     \"pre-optimized\", UnfixedProtocolReferences);\n    }\n\n#undef EACH_HEADER\n}\n\n\n/***********************************************************************\n* prepare_load_methods\n* Schedule +load for classes in this image, any un-+load-ed \n* superclasses in other images, and any categories in this image.\n**********************************************************************/\n// Recursively schedule +load for cls and any un-+load-ed superclasses.\n// cls must already be connected.\nstatic void schedule_class_load(Class cls)\n{\n    if (!cls) return;\n    assert(cls->isRealized());  // _read_images should realize\n\n    if (cls->data()->flags & RW_LOADED) return;\n\n    // Ensure superclass-first ordering\n    schedule_class_load(cls->superclass);\n\n    add_class_to_loadable_list(cls);\n    cls->setInfo(RW_LOADED); \n}\n\n// Quick scan for +load methods that doesn't take a lock.\nbool hasLoadMethods(const headerType *mhdr)\n{\n    size_t count;\n    if (_getObjc2NonlazyClassList(mhdr, &count)  &&  count > 0) return true;\n    if (_getObjc2NonlazyCategoryList(mhdr, &count)  &&  count > 0) return true;\n    return false;\n}\n\nvoid prepare_load_methods(const headerType *mhdr)\n{\n    size_t count, i;\n\n    runtimeLock.assertLocked();\n\n    classref_t *classlist = \n        _getObjc2NonlazyClassList(mhdr, &count);\n    for (i = 0; i < count; i++) {\n        schedule_class_load(remapClass(classlist[i]));\n    }\n\n    category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);\n    for (i = 0; i < count; i++) {\n        category_t *cat = categorylist[i];\n        Class cls = remapClass(cat->cls);\n        if (!cls) continue;  // category for ignored weak-linked class\n        realizeClass(cls);\n        assert(cls->ISA()->isRealized());\n        add_category_to_loadable_list(cat);\n    }\n}\n\n\n/***********************************************************************\n* _unload_image\n* Only handles MH_BUNDLE for now.\n* Locking: write-lock and loadMethodLock acquired by unmap_image\n**********************************************************************/\nvoid _unload_image(header_info *hi)\n{\n    size_t count, i;\n\n    loadMethodLock.assertLocked();\n    runtimeLock.assertLocked();\n\n    // Unload unattached categories and categories waiting for +load.\n\n    category_t **catlist = _getObjc2CategoryList(hi, &count);\n    for (i = 0; i < count; i++) {\n        category_t *cat = catlist[i];\n        if (!cat) continue;  // category for ignored weak-linked class\n        Class cls = remapClass(cat->cls);\n        assert(cls);  // shouldn't have live category for dead class\n\n        // fixme for MH_DYLIB cat's class may have been unloaded already\n\n        // unattached list\n        removeUnattachedCategoryForClass(cat, cls);\n\n        // +load queue\n        remove_category_from_loadable_list(cat);\n    }\n\n    // Unload classes.\n\n    // Gather classes from both __DATA,__objc_clslist \n    // and __DATA,__objc_nlclslist. arclite's hack puts a class in the latter\n    // only, and we need to unload that class if we unload an arclite image.\n\n    NXHashTable *classes = NXCreateHashTable(NXPtrPrototype, 0, nil);\n    classref_t *classlist;\n\n    classlist = _getObjc2ClassList(hi, &count);\n    for (i = 0; i < count; i++) {\n        Class cls = remapClass(classlist[i]);\n        if (cls) NXHashInsert(classes, cls);\n    }\n\n    classlist = _getObjc2NonlazyClassList(hi, &count);\n    for (i = 0; i < count; i++) {\n        Class cls = remapClass(classlist[i]);\n        if (cls) NXHashInsert(classes, cls);\n    }\n\n    // First detach classes from each other. Then free each class.\n    // This avoid bugs where this loop unloads a subclass before its superclass\n\n    NXHashState hs;\n    Class cls;\n\n    hs = NXInitHashState(classes);\n    while (NXNextHashState(classes, &hs, (void**)&cls)) {\n        remove_class_from_loadable_list(cls);\n        detach_class(cls->ISA(), YES);\n        detach_class(cls, NO);\n    }\n    hs = NXInitHashState(classes);\n    while (NXNextHashState(classes, &hs, (void**)&cls)) {\n        free_class(cls->ISA());\n        free_class(cls);\n    }\n\n    NXFreeHashTable(classes);\n    \n    // XXX FIXME -- Clean up protocols:\n    // <rdar://problem/9033191> Support unloading protocols at dylib/image unload time\n\n    // fixme DebugUnload\n}\n\n\n/***********************************************************************\n* method_getDescription\n* Returns a pointer to this method's objc_method_description.\n* Locking: none\n**********************************************************************/\nstruct objc_method_description *\nmethod_getDescription(Method m)\n{\n    if (!m) return nil;\n    return (struct objc_method_description *)m;\n}\n\n\nIMP \nmethod_getImplementation(Method m)\n{\n    return m ? m->imp : nil;\n}\n\n\n/***********************************************************************\n* method_getName\n* Returns this method's selector.\n* The method must not be nil.\n* The method must already have been fixed-up.\n* Locking: none\n**********************************************************************/\nSEL \nmethod_getName(Method m)\n{\n    if (!m) return nil;\n\n    assert(m->name == sel_registerName(sel_getName(m->name)));\n    return m->name;\n}\n\n\n/***********************************************************************\n* method_getTypeEncoding\n* Returns this method's old-style type encoding string.\n* The method must not be nil.\n* Locking: none\n**********************************************************************/\nconst char *\nmethod_getTypeEncoding(Method m)\n{\n    if (!m) return nil;\n    return m->types;\n}\n\n\n/***********************************************************************\n* method_setImplementation\n* Sets this method's implementation to imp.\n* The previous implementation is returned.\n**********************************************************************/\nstatic IMP \n_method_setImplementation(Class cls, method_t *m, IMP imp)\n{\n    runtimeLock.assertLocked();\n\n    if (!m) return nil;\n    if (!imp) return nil;\n\n    IMP old = m->imp;\n    m->imp = imp;\n\n    // Cache updates are slow if cls is nil (i.e. unknown)\n    // RR/AWZ updates are slow if cls is nil (i.e. unknown)\n    // fixme build list of classes whose Methods are known externally?\n\n    flushCaches(cls);\n\n    updateCustomRR_AWZ(cls, m);\n\n    return old;\n}\n\nIMP \nmethod_setImplementation(Method m, IMP imp)\n{\n    // Don't know the class - will be slow if RR/AWZ are affected\n    // fixme build list of classes whose Methods are known externally?\n    mutex_locker_t lock(runtimeLock);\n    return _method_setImplementation(Nil, m, imp);\n}\n\n\nvoid method_exchangeImplementations(Method m1, Method m2)\n{\n    if (!m1  ||  !m2) return;\n\n    mutex_locker_t lock(runtimeLock);\n\n    IMP m1_imp = m1->imp;\n    m1->imp = m2->imp;\n    m2->imp = m1_imp;\n\n\n    // RR/AWZ updates are slow because class is unknown\n    // Cache updates are slow because class is unknown\n    // fixme build list of classes whose Methods are known externally?\n\n    flushCaches(nil);\n\n    updateCustomRR_AWZ(nil, m1);\n    updateCustomRR_AWZ(nil, m2);\n}\n\n\n/***********************************************************************\n* ivar_getOffset\n* fixme\n* Locking: none\n**********************************************************************/\nptrdiff_t\nivar_getOffset(Ivar ivar)\n{\n    if (!ivar) return 0;\n    return *ivar->offset;\n}\n\n\n/***********************************************************************\n* ivar_getName\n* fixme\n* Locking: none\n**********************************************************************/\nconst char *\nivar_getName(Ivar ivar)\n{\n    if (!ivar) return nil;\n    return ivar->name;\n}\n\n\n/***********************************************************************\n* ivar_getTypeEncoding\n* fixme\n* Locking: none\n**********************************************************************/\nconst char *\nivar_getTypeEncoding(Ivar ivar)\n{\n    if (!ivar) return nil;\n    return ivar->type;\n}\n\n\n\nconst char *property_getName(objc_property_t prop)\n{\n    return prop->name;\n}\n\nconst char *property_getAttributes(objc_property_t prop)\n{\n    return prop->attributes;\n}\n\nobjc_property_attribute_t *property_copyAttributeList(objc_property_t prop, \n                                                      unsigned int *outCount)\n{\n    if (!prop) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    mutex_locker_t lock(runtimeLock);\n    return copyPropertyAttributeList(prop->attributes,outCount);\n}\n\nchar * property_copyAttributeValue(objc_property_t prop, const char *name)\n{\n    if (!prop  ||  !name  ||  *name == '\\0') return nil;\n    \n    mutex_locker_t lock(runtimeLock);\n    return copyPropertyAttributeValue(prop->attributes, name);\n}\n\n\n/***********************************************************************\n* getExtendedTypesIndexesForMethod\n* Returns:\n* a is the count of methods in all method lists before m's method list\n* b is the index of m in m's method list\n* a+b is the index of m's extended types in the extended types array\n**********************************************************************/\nstatic void getExtendedTypesIndexesForMethod(protocol_t *proto, const method_t *m, bool isRequiredMethod, bool isInstanceMethod, uint32_t& a, uint32_t &b)\n{\n    a = 0;\n\n    if (proto->instanceMethods) {\n        if (isRequiredMethod && isInstanceMethod) {\n            b = proto->instanceMethods->indexOfMethod(m);\n            return;\n        }\n        a += proto->instanceMethods->count;\n    }\n\n    if (proto->classMethods) {\n        if (isRequiredMethod && !isInstanceMethod) {\n            b = proto->classMethods->indexOfMethod(m);\n            return;\n        }\n        a += proto->classMethods->count;\n    }\n\n    if (proto->optionalInstanceMethods) {\n        if (!isRequiredMethod && isInstanceMethod) {\n            b = proto->optionalInstanceMethods->indexOfMethod(m);\n            return;\n        }\n        a += proto->optionalInstanceMethods->count;\n    }\n\n    if (proto->optionalClassMethods) {\n        if (!isRequiredMethod && !isInstanceMethod) {\n            b = proto->optionalClassMethods->indexOfMethod(m);\n            return;\n        }\n        a += proto->optionalClassMethods->count;\n    }\n}\n\n\n/***********************************************************************\n* getExtendedTypesIndexForMethod\n* Returns the index of m's extended types in proto's extended types array.\n**********************************************************************/\nstatic uint32_t getExtendedTypesIndexForMethod(protocol_t *proto, const method_t *m, bool isRequiredMethod, bool isInstanceMethod)\n{\n    uint32_t a;\n    uint32_t b;\n    getExtendedTypesIndexesForMethod(proto, m, isRequiredMethod, \n                                     isInstanceMethod, a, b);\n    return a + b;\n}\n\n\n/***********************************************************************\n* fixupProtocolMethodList\n* Fixes up a single method list in a protocol.\n**********************************************************************/\nstatic void\nfixupProtocolMethodList(protocol_t *proto, method_list_t *mlist,  \n                        bool required, bool instance)\n{\n    runtimeLock.assertLocked();\n\n    if (!mlist) return;\n    if (mlist->isFixedUp()) return;\n\n    const char **extTypes = proto->extendedMethodTypes();\n    fixupMethodList(mlist, true/*always copy for simplicity*/,\n                    !extTypes/*sort if no extended method types*/);\n    \n    if (extTypes) {\n        // Sort method list and extended method types together.\n        // fixupMethodList() can't do this.\n        // fixme COW stomp\n        uint32_t count = mlist->count;\n        uint32_t prefix;\n        uint32_t junk;\n        getExtendedTypesIndexesForMethod(proto, &mlist->get(0), \n                                         required, instance, prefix, junk);\n        for (uint32_t i = 0; i < count; i++) {\n            for (uint32_t j = i+1; j < count; j++) {\n                method_t& mi = mlist->get(i);\n                method_t& mj = mlist->get(j);\n                if (mi.name > mj.name) {\n                    std::swap(mi, mj);\n                    std::swap(extTypes[prefix+i], extTypes[prefix+j]);\n                }\n            }\n        }\n    }\n}\n\n\n/***********************************************************************\n* fixupProtocol\n* Fixes up all of a protocol's method lists.\n**********************************************************************/\nstatic void \nfixupProtocol(protocol_t *proto)\n{\n    runtimeLock.assertLocked();\n\n    if (proto->protocols) {\n        for (uintptr_t i = 0; i < proto->protocols->count; i++) {\n            protocol_t *sub = remapProtocol(proto->protocols->list[i]);\n            if (!sub->isFixedUp()) fixupProtocol(sub);\n        }\n    }\n\n    fixupProtocolMethodList(proto, proto->instanceMethods, YES, YES);\n    fixupProtocolMethodList(proto, proto->classMethods, YES, NO);\n    fixupProtocolMethodList(proto, proto->optionalInstanceMethods, NO, YES);\n    fixupProtocolMethodList(proto, proto->optionalClassMethods, NO, NO);\n\n    // fixme memory barrier so we can check this with no lock\n    proto->setFixedUp();\n}\n\n\n/***********************************************************************\n* fixupProtocolIfNeeded\n* Fixes up all of a protocol's method lists if they aren't fixed up already.\n* Locking: write-locks runtimeLock.\n**********************************************************************/\nstatic void \nfixupProtocolIfNeeded(protocol_t *proto)\n{\n    runtimeLock.assertUnlocked();\n    assert(proto);\n\n    if (!proto->isFixedUp()) {\n        mutex_locker_t lock(runtimeLock);\n        fixupProtocol(proto);\n    }\n}\n\n\nstatic method_list_t *\ngetProtocolMethodList(protocol_t *proto, bool required, bool instance)\n{\n    method_list_t **mlistp = nil;\n    if (required) {\n        if (instance) {\n            mlistp = &proto->instanceMethods;\n        } else {\n            mlistp = &proto->classMethods;\n        }\n    } else {\n        if (instance) {\n            mlistp = &proto->optionalInstanceMethods;\n        } else {\n            mlistp = &proto->optionalClassMethods;\n        }\n    }\n\n    return *mlistp;\n}\n\n\n/***********************************************************************\n* protocol_getMethod_nolock\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nstatic method_t *\nprotocol_getMethod_nolock(protocol_t *proto, SEL sel, \n                          bool isRequiredMethod, bool isInstanceMethod, \n                          bool recursive)\n{\n    runtimeLock.assertLocked();\n\n    if (!proto  ||  !sel) return nil;\n\n    assert(proto->isFixedUp());\n\n    method_list_t *mlist = \n        getProtocolMethodList(proto, isRequiredMethod, isInstanceMethod);\n    if (mlist) {\n        method_t *m = search_method_list(mlist, sel);\n        if (m) return m;\n    }\n\n    if (recursive  &&  proto->protocols) {\n        method_t *m;\n        for (uint32_t i = 0; i < proto->protocols->count; i++) {\n            protocol_t *realProto = remapProtocol(proto->protocols->list[i]);\n            m = protocol_getMethod_nolock(realProto, sel, \n                                          isRequiredMethod, isInstanceMethod, \n                                          true);\n            if (m) return m;\n        }\n    }\n\n    return nil;\n}\n\n\n/***********************************************************************\n* protocol_getMethod\n* fixme\n* Locking: acquires runtimeLock\n**********************************************************************/\nMethod \nprotocol_getMethod(protocol_t *proto, SEL sel, bool isRequiredMethod, bool isInstanceMethod, bool recursive)\n{\n    if (!proto) return nil;\n    fixupProtocolIfNeeded(proto);\n\n    mutex_locker_t lock(runtimeLock);\n    return protocol_getMethod_nolock(proto, sel, isRequiredMethod, \n                                     isInstanceMethod, recursive);\n}\n\n\n/***********************************************************************\n* protocol_getMethodTypeEncoding_nolock\n* Return the @encode string for the requested protocol method.\n* Returns nil if the compiler did not emit any extended @encode data.\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nconst char * \nprotocol_getMethodTypeEncoding_nolock(protocol_t *proto, SEL sel, \n                                      bool isRequiredMethod, \n                                      bool isInstanceMethod)\n{\n    runtimeLock.assertLocked();\n\n    if (!proto) return nil;\n    if (!proto->extendedMethodTypes()) return nil;\n\n    assert(proto->isFixedUp());\n\n    method_t *m = \n        protocol_getMethod_nolock(proto, sel, \n                                  isRequiredMethod, isInstanceMethod, false);\n    if (m) {\n        uint32_t i = getExtendedTypesIndexForMethod(proto, m, \n                                                    isRequiredMethod, \n                                                    isInstanceMethod);\n        return proto->extendedMethodTypes()[i];\n    }\n\n    // No method with that name. Search incorporated protocols.\n    if (proto->protocols) {\n        for (uintptr_t i = 0; i < proto->protocols->count; i++) {\n            const char *enc = \n                protocol_getMethodTypeEncoding_nolock(remapProtocol(proto->protocols->list[i]), sel, isRequiredMethod, isInstanceMethod);\n            if (enc) return enc;\n        }\n    }\n\n    return nil;\n}\n\n/***********************************************************************\n* _protocol_getMethodTypeEncoding\n* Return the @encode string for the requested protocol method.\n* Returns nil if the compiler did not emit any extended @encode data.\n* Locking: acquires runtimeLock\n**********************************************************************/\nconst char * \n_protocol_getMethodTypeEncoding(Protocol *proto_gen, SEL sel, \n                                BOOL isRequiredMethod, BOOL isInstanceMethod)\n{\n    protocol_t *proto = newprotocol(proto_gen);\n\n    if (!proto) return nil;\n    fixupProtocolIfNeeded(proto);\n\n    mutex_locker_t lock(runtimeLock);\n    return protocol_getMethodTypeEncoding_nolock(proto, sel, \n                                                 isRequiredMethod, \n                                                 isInstanceMethod);\n}\n\n\n/***********************************************************************\n* protocol_t::demangledName\n* Returns the (Swift-demangled) name of the given protocol.\n* Locking: none\n**********************************************************************/\nconst char *\nprotocol_t::demangledName() \n{\n    assert(hasDemangledNameField());\n    \n    if (! _demangledName) {\n        char *de = copySwiftV1DemangledName(mangledName, true/*isProtocol*/);\n        if (! OSAtomicCompareAndSwapPtrBarrier(nil, (void*)(de ?: mangledName), \n                                               (void**)&_demangledName)) \n        {\n            if (de) free(de);\n        }\n    }\n    return _demangledName;\n}\n\n/***********************************************************************\n* protocol_getName\n* Returns the (Swift-demangled) name of the given protocol.\n* Locking: runtimeLock must not be held by the caller\n**********************************************************************/\nconst char *\nprotocol_getName(Protocol *proto)\n{\n    if (!proto) return \"nil\";\n    else return newprotocol(proto)->demangledName();\n}\n\n\n/***********************************************************************\n* protocol_getInstanceMethodDescription\n* Returns the description of a named instance method.\n* Locking: runtimeLock must not be held by the caller\n**********************************************************************/\nstruct objc_method_description \nprotocol_getMethodDescription(Protocol *p, SEL aSel, \n                              BOOL isRequiredMethod, BOOL isInstanceMethod)\n{\n    Method m = \n        protocol_getMethod(newprotocol(p), aSel, \n                           isRequiredMethod, isInstanceMethod, true);\n    if (m) return *method_getDescription(m);\n    else return (struct objc_method_description){nil, nil};\n}\n\n\n/***********************************************************************\n* protocol_conformsToProtocol_nolock\n* Returns YES if self conforms to other.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic bool \nprotocol_conformsToProtocol_nolock(protocol_t *self, protocol_t *other)\n{\n    runtimeLock.assertLocked();\n\n    if (!self  ||  !other) {\n        return NO;\n    }\n\n    // protocols need not be fixed up\n\n    if (0 == strcmp(self->mangledName, other->mangledName)) {\n        return YES;\n    }\n\n    if (self->protocols) {\n        uintptr_t i;\n        for (i = 0; i < self->protocols->count; i++) {\n            protocol_t *proto = remapProtocol(self->protocols->list[i]);\n            if (0 == strcmp(other->mangledName, proto->mangledName)) {\n                return YES;\n            }\n            if (protocol_conformsToProtocol_nolock(proto, other)) {\n                return YES;\n            }\n        }\n    }\n\n    return NO;\n}\n\n\n/***********************************************************************\n* protocol_conformsToProtocol\n* Returns YES if self conforms to other.\n* Locking: acquires runtimeLock\n**********************************************************************/\nBOOL protocol_conformsToProtocol(Protocol *self, Protocol *other)\n{\n    mutex_locker_t lock(runtimeLock);\n    return protocol_conformsToProtocol_nolock(newprotocol(self), \n                                              newprotocol(other));\n}\n\n\n/***********************************************************************\n* protocol_isEqual\n* Return YES if two protocols are equal (i.e. conform to each other)\n* Locking: acquires runtimeLock\n**********************************************************************/\nBOOL protocol_isEqual(Protocol *self, Protocol *other)\n{\n    if (self == other) return YES;\n    if (!self  ||  !other) return NO;\n\n    if (!protocol_conformsToProtocol(self, other)) return NO;\n    if (!protocol_conformsToProtocol(other, self)) return NO;\n\n    return YES;\n}\n\n\n/***********************************************************************\n* protocol_copyMethodDescriptionList\n* Returns descriptions of a protocol's methods.\n* Locking: acquires runtimeLock\n**********************************************************************/\nstruct objc_method_description *\nprotocol_copyMethodDescriptionList(Protocol *p, \n                                   BOOL isRequiredMethod,BOOL isInstanceMethod,\n                                   unsigned int *outCount)\n{\n    protocol_t *proto = newprotocol(p);\n    struct objc_method_description *result = nil;\n    unsigned int count = 0;\n\n    if (!proto) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    fixupProtocolIfNeeded(proto);\n\n    mutex_locker_t lock(runtimeLock);\n\n    method_list_t *mlist = \n        getProtocolMethodList(proto, isRequiredMethod, isInstanceMethod);\n\n    if (mlist) {\n        result = (struct objc_method_description *)\n            calloc(mlist->count + 1, sizeof(struct objc_method_description));\n        for (const auto& meth : *mlist) {\n            result[count].name = meth.name;\n            result[count].types = (char *)meth.types;\n            count++;\n        }\n    }\n\n    if (outCount) *outCount = count;\n    return result;\n}\n\n\n/***********************************************************************\n* protocol_getProperty\n* fixme\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nstatic property_t * \nprotocol_getProperty_nolock(protocol_t *proto, const char *name, \n                            bool isRequiredProperty, bool isInstanceProperty)\n{\n    runtimeLock.assertLocked();\n\n    if (!isRequiredProperty) {\n        // Only required properties are currently supported.\n        return nil;\n    }\n\n    property_list_t *plist = isInstanceProperty ? \n        proto->instanceProperties : proto->classProperties();\n    if (plist) {\n        for (auto& prop : *plist) {\n            if (0 == strcmp(name, prop.name)) {\n                return &prop;\n            }\n        }\n    }\n\n    if (proto->protocols) {\n        uintptr_t i;\n        for (i = 0; i < proto->protocols->count; i++) {\n            protocol_t *p = remapProtocol(proto->protocols->list[i]);\n            property_t *prop = \n                protocol_getProperty_nolock(p, name, \n                                            isRequiredProperty, \n                                            isInstanceProperty);\n            if (prop) return prop;\n        }\n    }\n\n    return nil;\n}\n\nobjc_property_t protocol_getProperty(Protocol *p, const char *name, \n                              BOOL isRequiredProperty, BOOL isInstanceProperty)\n{\n    if (!p  ||  !name) return nil;\n\n    mutex_locker_t lock(runtimeLock);\n    return (objc_property_t)\n        protocol_getProperty_nolock(newprotocol(p), name, \n                                    isRequiredProperty, isInstanceProperty);\n}\n\n\n/***********************************************************************\n* protocol_copyPropertyList\n* protocol_copyPropertyList2\n* fixme\n* Locking: acquires runtimeLock\n**********************************************************************/\nstatic property_t **\ncopyPropertyList(property_list_t *plist, unsigned int *outCount)\n{\n    property_t **result = nil;\n    unsigned int count = 0;\n\n    if (plist) {\n        count = plist->count;\n    }\n\n    if (count > 0) {\n        result = (property_t **)malloc((count+1) * sizeof(property_t *));\n\n        count = 0;\n        for (auto& prop : *plist) {\n            result[count++] = &prop;\n        }\n        result[count] = nil;\n    }\n\n    if (outCount) *outCount = count;\n    return result;\n}\n\nobjc_property_t *\nprotocol_copyPropertyList2(Protocol *proto, unsigned int *outCount, \n                           BOOL isRequiredProperty, BOOL isInstanceProperty)\n{\n    if (!proto  ||  !isRequiredProperty) {\n        // Optional properties are not currently supported.\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    mutex_locker_t lock(runtimeLock);\n\n    property_list_t *plist = isInstanceProperty\n        ? newprotocol(proto)->instanceProperties\n        : newprotocol(proto)->classProperties();\n    return (objc_property_t *)copyPropertyList(plist, outCount);\n}\n\nobjc_property_t *\nprotocol_copyPropertyList(Protocol *proto, unsigned int *outCount)\n{\n    return protocol_copyPropertyList2(proto, outCount, \n                                      YES/*required*/, YES/*instance*/);\n}\n\n\n/***********************************************************************\n* protocol_copyProtocolList\n* Copies this protocol's incorporated protocols. \n* Does not copy those protocol's incorporated protocols in turn.\n* Locking: acquires runtimeLock\n**********************************************************************/\nProtocol * __unsafe_unretained * \nprotocol_copyProtocolList(Protocol *p, unsigned int *outCount)\n{\n    unsigned int count = 0;\n    Protocol **result = nil;\n    protocol_t *proto = newprotocol(p);\n    \n    if (!proto) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    mutex_locker_t lock(runtimeLock);\n\n    if (proto->protocols) {\n        count = (unsigned int)proto->protocols->count;\n    }\n    if (count > 0) {\n        result = (Protocol **)malloc((count+1) * sizeof(Protocol *));\n\n        unsigned int i;\n        for (i = 0; i < count; i++) {\n            result[i] = (Protocol *)remapProtocol(proto->protocols->list[i]);\n        }\n        result[i] = nil;\n    }\n\n    if (outCount) *outCount = count;\n    return result;\n}\n\n\n/***********************************************************************\n* objc_allocateProtocol\n* Creates a new protocol. The protocol may not be used until \n* objc_registerProtocol() is called.\n* Returns nil if a protocol with the same name already exists.\n* Locking: acquires runtimeLock\n**********************************************************************/\nProtocol *\nobjc_allocateProtocol(const char *name)\n{\n    mutex_locker_t lock(runtimeLock);\n\n    if (getProtocol(name)) {\n        return nil;\n    }\n\n    protocol_t *result = (protocol_t *)calloc(sizeof(protocol_t), 1);\n\n    extern objc_class OBJC_CLASS_$___IncompleteProtocol;\n    Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;\n    result->initProtocolIsa(cls);\n    result->size = sizeof(protocol_t);\n    // fixme mangle the name if it looks swift-y?\n    result->mangledName = strdupIfMutable(name);\n\n    // fixme reserve name without installing\n\n    return (Protocol *)result;\n}\n\n\n/***********************************************************************\n* objc_registerProtocol\n* Registers a newly-constructed protocol. The protocol is now \n* ready for use and immutable.\n* Locking: acquires runtimeLock\n**********************************************************************/\nvoid objc_registerProtocol(Protocol *proto_gen) \n{\n    protocol_t *proto = newprotocol(proto_gen);\n\n    mutex_locker_t lock(runtimeLock);\n\n    extern objc_class OBJC_CLASS_$___IncompleteProtocol;\n    Class oldcls = (Class)&OBJC_CLASS_$___IncompleteProtocol;\n    extern objc_class OBJC_CLASS_$_Protocol;\n    Class cls = (Class)&OBJC_CLASS_$_Protocol;\n\n    if (proto->ISA() == cls) {\n        _objc_inform(\"objc_registerProtocol: protocol '%s' was already \"\n                     \"registered!\", proto->nameForLogging());\n        return;\n    }\n    if (proto->ISA() != oldcls) {\n        _objc_inform(\"objc_registerProtocol: protocol '%s' was not allocated \"\n                     \"with objc_allocateProtocol!\", proto->nameForLogging());\n        return;\n    }\n\n    // NOT initProtocolIsa(). The protocol object may already \n    // have been retained and we must preserve that count.\n    proto->changeIsa(cls);\n\n    NXMapKeyCopyingInsert(protocols(), proto->mangledName, proto);\n}\n\n\n/***********************************************************************\n* protocol_addProtocol\n* Adds an incorporated protocol to another protocol.\n* No method enforcement is performed.\n* `proto` must be under construction. `addition` must not.\n* Locking: acquires runtimeLock\n**********************************************************************/\nvoid \nprotocol_addProtocol(Protocol *proto_gen, Protocol *addition_gen) \n{\n    protocol_t *proto = newprotocol(proto_gen);\n    protocol_t *addition = newprotocol(addition_gen);\n\n    extern objc_class OBJC_CLASS_$___IncompleteProtocol;\n    Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;\n\n    if (!proto_gen) return;\n    if (!addition_gen) return;\n\n    mutex_locker_t lock(runtimeLock);\n\n    if (proto->ISA() != cls) {\n        _objc_inform(\"protocol_addProtocol: modified protocol '%s' is not \"\n                     \"under construction!\", proto->nameForLogging());\n        return;\n    }\n    if (addition->ISA() == cls) {\n        _objc_inform(\"protocol_addProtocol: added protocol '%s' is still \"\n                     \"under construction!\", addition->nameForLogging());\n        return;        \n    }\n    \n    protocol_list_t *protolist = proto->protocols;\n    if (!protolist) {\n        protolist = (protocol_list_t *)\n            calloc(1, sizeof(protocol_list_t) \n                             + sizeof(protolist->list[0]));\n    } else {\n        protolist = (protocol_list_t *)\n            realloc(protolist, protocol_list_size(protolist) \n                              + sizeof(protolist->list[0]));\n    }\n\n    protolist->list[protolist->count++] = (protocol_ref_t)addition;\n    proto->protocols = protolist;\n}\n\n\n/***********************************************************************\n* protocol_addMethodDescription\n* Adds a method to a protocol. The protocol must be under construction.\n* Locking: acquires runtimeLock\n**********************************************************************/\nstatic void\nprotocol_addMethod_nolock(method_list_t*& list, SEL name, const char *types)\n{\n    if (!list) {\n        list = (method_list_t *)calloc(sizeof(method_list_t), 1);\n        list->entsizeAndFlags = sizeof(list->first);\n        list->setFixedUp();\n    } else {\n        size_t size = list->byteSize() + list->entsize();\n        list = (method_list_t *)realloc(list, size);\n    }\n\n    method_t& meth = list->get(list->count++);\n    meth.name = name;\n    meth.types = types ? strdupIfMutable(types) : \"\";\n    meth.imp = nil;\n}\n\nvoid \nprotocol_addMethodDescription(Protocol *proto_gen, SEL name, const char *types,\n                              BOOL isRequiredMethod, BOOL isInstanceMethod) \n{\n    protocol_t *proto = newprotocol(proto_gen);\n\n    extern objc_class OBJC_CLASS_$___IncompleteProtocol;\n    Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;\n\n    if (!proto_gen) return;\n\n    mutex_locker_t lock(runtimeLock);\n\n    if (proto->ISA() != cls) {\n        _objc_inform(\"protocol_addMethodDescription: protocol '%s' is not \"\n                     \"under construction!\", proto->nameForLogging());\n        return;\n    }\n\n    if (isRequiredMethod  &&  isInstanceMethod) {\n        protocol_addMethod_nolock(proto->instanceMethods, name, types);\n    } else if (isRequiredMethod  &&  !isInstanceMethod) {\n        protocol_addMethod_nolock(proto->classMethods, name, types);\n    } else if (!isRequiredMethod  &&  isInstanceMethod) {\n        protocol_addMethod_nolock(proto->optionalInstanceMethods, name,types);\n    } else /*  !isRequiredMethod  &&  !isInstanceMethod) */ {\n        protocol_addMethod_nolock(proto->optionalClassMethods, name, types);\n    }\n}\n\n\n/***********************************************************************\n* protocol_addProperty\n* Adds a property to a protocol. The protocol must be under construction.\n* Locking: acquires runtimeLock\n**********************************************************************/\nstatic void \nprotocol_addProperty_nolock(property_list_t *&plist, const char *name, \n                            const objc_property_attribute_t *attrs, \n                            unsigned int count)\n{\n    if (!plist) {\n        plist = (property_list_t *)calloc(sizeof(property_list_t), 1);\n        plist->entsizeAndFlags = sizeof(property_t);\n    } else {\n        plist = (property_list_t *)\n            realloc(plist, sizeof(property_list_t) \n                    + plist->count * plist->entsize());\n    }\n\n    property_t& prop = plist->get(plist->count++);\n    prop.name = strdupIfMutable(name);\n    prop.attributes = copyPropertyAttributeString(attrs, count);\n}\n\nvoid \nprotocol_addProperty(Protocol *proto_gen, const char *name, \n                     const objc_property_attribute_t *attrs, \n                     unsigned int count,\n                     BOOL isRequiredProperty, BOOL isInstanceProperty)\n{\n    protocol_t *proto = newprotocol(proto_gen);\n\n    extern objc_class OBJC_CLASS_$___IncompleteProtocol;\n    Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;\n\n    if (!proto) return;\n    if (!name) return;\n\n    mutex_locker_t lock(runtimeLock);\n\n    if (proto->ISA() != cls) {\n        _objc_inform(\"protocol_addProperty: protocol '%s' is not \"\n                     \"under construction!\", proto->nameForLogging());\n        return;\n    }\n\n    if (isRequiredProperty  &&  isInstanceProperty) {\n        protocol_addProperty_nolock(proto->instanceProperties, name, attrs, count);\n    }\n    else if (isRequiredProperty  &&  !isInstanceProperty) {\n        protocol_addProperty_nolock(proto->_classProperties, name, attrs, count);\n    }\n    //else if (!isRequiredProperty  &&  isInstanceProperty) {\n    //    protocol_addProperty_nolock(proto->optionalInstanceProperties, name, attrs, count);\n    //}\n    //else /*  !isRequiredProperty  &&  !isInstanceProperty) */ {\n    //    protocol_addProperty_nolock(proto->optionalClassProperties, name, attrs, count);\n    //}\n}\n\n\n/***********************************************************************\n* objc_getClassList\n* Returns pointers to all classes.\n* This requires all classes be realized, which is regretfully non-lazy.\n* Locking: acquires runtimeLock\n**********************************************************************/\nint \nobjc_getClassList(Class *buffer, int bufferLen) \n{\n    mutex_locker_t lock(runtimeLock);\n\n    realizeAllClasses();\n\n    __block int count = 0;\n    foreach_realized_class_and_metaclass(^(Class cls) { \n        if (!cls->isMetaClass()) count++; \n    });\n\n    if (buffer) {\n        __block int c = 0;\n        foreach_realized_class_and_metaclass(^(Class cls) { \n            if (c < bufferLen && !cls->isMetaClass()) {\n                buffer[c++] = cls; \n            }\n        });\n    }\n\n    return count;\n}\n\n\n/***********************************************************************\n* objc_copyClassList\n* Returns pointers to all classes.\n* This requires all classes be realized, which is regretfully non-lazy.\n* \n* outCount may be nil. *outCount is the number of classes returned. \n* If the returned array is not nil, it is nil-terminated and must be \n* freed with free().\n* Locking: write-locks runtimeLock\n**********************************************************************/\nClass *\nobjc_copyClassList(unsigned int *outCount)\n{\n    mutex_locker_t lock(runtimeLock);\n\n    realizeAllClasses();\n\n    Class *result = nil;\n\n    __block unsigned int count = 0;\n    foreach_realized_class_and_metaclass(^(Class cls) {\n        if (!cls->isMetaClass()) count++; \n    });\n\n    if (count > 0) {\n        result = (Class *)malloc((1+count) * sizeof(Class));\n        __block unsigned int c = 0;\n        foreach_realized_class_and_metaclass(^(Class cls) {\n            if (!cls->isMetaClass()) {\n                result[c++] = cls;\n            }\n        });\n        result[c] = nil;\n    }\n\n    if (outCount) *outCount = count;\n    return result;\n}\n\n\n/***********************************************************************\n* objc_copyProtocolList\n* Returns pointers to all protocols.\n* Locking: read-locks runtimeLock\n**********************************************************************/\nProtocol * __unsafe_unretained * \nobjc_copyProtocolList(unsigned int *outCount) \n{\n    mutex_locker_t lock(runtimeLock);\n\n    NXMapTable *protocol_map = protocols();\n\n    unsigned int count = NXCountMapTable(protocol_map);\n    if (count == 0) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    Protocol **result = (Protocol **)malloc((count+1) * sizeof(Protocol*));\n\n    unsigned int i = 0;\n    Protocol *proto;\n    const char *name;\n    NXMapState state = NXInitMapState(protocol_map);\n    while (NXNextMapState(protocol_map, &state, \n                          (const void **)&name, (const void **)&proto))\n    {\n        result[i++] = proto;\n    }\n    \n    result[i++] = nil;\n    assert(i == count+1);\n\n    if (outCount) *outCount = count;\n    return result;\n}\n\n\n/***********************************************************************\n* objc_getProtocol\n* Get a protocol by name, or return nil\n* Locking: read-locks runtimeLock\n**********************************************************************/\nProtocol *objc_getProtocol(const char *name)\n{\n    mutex_locker_t lock(runtimeLock); \n    return getProtocol(name);\n}\n\n\n/***********************************************************************\n* class_copyMethodList\n* fixme\n* Locking: read-locks runtimeLock\n**********************************************************************/\nMethod *\nclass_copyMethodList(Class cls, unsigned int *outCount)\n{\n    unsigned int count = 0;\n    Method *result = nil;\n\n    if (!cls) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    mutex_locker_t lock(runtimeLock);\n    \n    assert(cls->isRealized());\n\n    count = cls->data()->methods.count();\n\n    if (count > 0) {\n        result = (Method *)malloc((count + 1) * sizeof(Method));\n        \n        count = 0;\n        for (auto& meth : cls->data()->methods) {\n            result[count++] = &meth;\n        }\n        result[count] = nil;\n    }\n\n    if (outCount) *outCount = count;\n    return result;\n}\n\n\n/***********************************************************************\n* class_copyIvarList\n* fixme\n* Locking: read-locks runtimeLock\n**********************************************************************/\nIvar *\nclass_copyIvarList(Class cls, unsigned int *outCount)\n{\n    const ivar_list_t *ivars;\n    Ivar *result = nil;\n    unsigned int count = 0;\n\n    if (!cls) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    mutex_locker_t lock(runtimeLock);\n\n    assert(cls->isRealized());\n    \n    if ((ivars = cls->data()->ro->ivars)  &&  ivars->count) {\n        result = (Ivar *)malloc((ivars->count+1) * sizeof(Ivar));\n        \n        for (auto& ivar : *ivars) {\n            if (!ivar.offset) continue;  // anonymous bitfield\n            result[count++] = &ivar;\n        }\n        result[count] = nil;\n    }\n    \n    if (outCount) *outCount = count;\n    return result;\n}\n\n\n/***********************************************************************\n* class_copyPropertyList. Returns a heap block containing the \n* properties declared in the class, or nil if the class \n* declares no properties. Caller must free the block.\n* Does not copy any superclass's properties.\n* Locking: read-locks runtimeLock\n**********************************************************************/\nobjc_property_t *\nclass_copyPropertyList(Class cls, unsigned int *outCount)\n{\n    if (!cls) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    mutex_locker_t lock(runtimeLock);\n\n    checkIsKnownClass(cls);\n    assert(cls->isRealized());\n    \n    auto rw = cls->data();\n\n    property_t **result = nil;\n    unsigned int count = rw->properties.count();\n    if (count > 0) {\n        result = (property_t **)malloc((count + 1) * sizeof(property_t *));\n\n        count = 0;\n        for (auto& prop : rw->properties) {\n            result[count++] = &prop;\n        }\n        result[count] = nil;\n    }\n\n    if (outCount) *outCount = count;\n    return (objc_property_t *)result;\n}\n\n\n/***********************************************************************\n* objc_class::getLoadMethod\n* fixme\n* Called only from add_class_to_loadable_list.\n* Locking: runtimeLock must be read- or write-locked by the caller.\n**********************************************************************/\nIMP \nobjc_class::getLoadMethod()\n{\n    runtimeLock.assertLocked();\n\n    const method_list_t *mlist;\n\n    assert(isRealized());\n    assert(ISA()->isRealized());\n    assert(!isMetaClass());\n    assert(ISA()->isMetaClass());\n\n    mlist = ISA()->data()->ro->baseMethods();\n    if (mlist) {\n        for (const auto& meth : *mlist) {\n            const char *name = sel_cname(meth.name);\n            if (0 == strcmp(name, \"load\")) {\n                return meth.imp;\n            }\n        }\n    }\n\n    return nil;\n}\n\n\n/***********************************************************************\n* _category_getName\n* Returns a category's name.\n* Locking: none\n**********************************************************************/\nconst char *\n_category_getName(Category cat)\n{\n    return cat->name;\n}\n\n\n/***********************************************************************\n* _category_getClassName\n* Returns a category's class's name\n* Called only from add_category_to_loadable_list and \n* remove_category_from_loadable_list for logging purposes.\n* Locking: runtimeLock must be read- or write-locked by the caller\n**********************************************************************/\nconst char *\n_category_getClassName(Category cat)\n{\n    runtimeLock.assertLocked();\n    return remapClass(cat->cls)->nameForLogging();\n}\n\n\n/***********************************************************************\n* _category_getClass\n* Returns a category's class\n* Called only by call_category_loads.\n* Locking: read-locks runtimeLock\n**********************************************************************/\nClass \n_category_getClass(Category cat)\n{\n    mutex_locker_t lock(runtimeLock);\n    Class result = remapClass(cat->cls);\n    assert(result->isRealized());  // ok for call_category_loads' usage\n    return result;\n}\n\n\n/***********************************************************************\n* _category_getLoadMethod\n* fixme\n* Called only from add_category_to_loadable_list\n* Locking: runtimeLock must be read- or write-locked by the caller\n**********************************************************************/\nIMP \n_category_getLoadMethod(Category cat)\n{\n    runtimeLock.assertLocked();\n\n    const method_list_t *mlist;\n\n    mlist = cat->classMethods;\n    if (mlist) {\n        for (const auto& meth : *mlist) {\n            const char *name = sel_cname(meth.name);\n            if (0 == strcmp(name, \"load\")) {\n                return meth.imp;\n            }\n        }\n    }\n\n    return nil;\n}\n\n\n/***********************************************************************\n* category_t::propertiesForMeta\n* Return a category's instance or class properties.\n* hi is the image containing the category.\n**********************************************************************/\nproperty_list_t *\ncategory_t::propertiesForMeta(bool isMeta, struct header_info *hi)\n{\n    if (!isMeta) return instanceProperties;\n    else if (hi->info()->hasCategoryClassProperties()) return _classProperties;\n    else return nil;\n}\n\n\n/***********************************************************************\n* class_copyProtocolList\n* fixme\n* Locking: read-locks runtimeLock\n**********************************************************************/\nProtocol * __unsafe_unretained * \nclass_copyProtocolList(Class cls, unsigned int *outCount)\n{\n    unsigned int count = 0;\n    Protocol **result = nil;\n    \n    if (!cls) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    mutex_locker_t lock(runtimeLock);\n\n    checkIsKnownClass(cls);\n\n    assert(cls->isRealized());\n    \n    count = cls->data()->protocols.count();\n\n    if (count > 0) {\n        result = (Protocol **)malloc((count+1) * sizeof(Protocol *));\n\n        count = 0;\n        for (const auto& proto : cls->data()->protocols) {\n            result[count++] = (Protocol *)remapProtocol(proto);\n        }\n        result[count] = nil;\n    }\n\n    if (outCount) *outCount = count;\n    return result;\n}\n\n\n/***********************************************************************\n* objc_copyImageNames\n* Copies names of loaded images with ObjC contents.\n*\n* Locking: acquires runtimeLock\n**********************************************************************/\nconst char **objc_copyImageNames(unsigned int *outCount)\n{\n    mutex_locker_t lock(runtimeLock);\n    \n#if TARGET_OS_WIN32\n    const TCHAR **names = (const TCHAR **)\n        malloc((HeaderCount+1) * sizeof(TCHAR *));\n#else\n    const char **names = (const char **)\n        malloc((HeaderCount+1) * sizeof(char *));\n#endif\n\n    unsigned int count = 0;\n    for (header_info *hi = FirstHeader; hi != nil; hi = hi->getNext()) {\n#if TARGET_OS_WIN32\n        if (hi->moduleName) {\n            names[count++] = hi->moduleName;\n        }\n#else\n        const char *fname = hi->fname();\n        if (fname) {\n            names[count++] = fname;\n        }\n#endif\n    }\n    names[count] = nil;\n    \n    if (count == 0) {\n        // Return nil instead of empty list if there are no images\n        free((void *)names);\n        names = nil;\n    }\n\n    if (outCount) *outCount = count;\n    return names;\n}\n\n\n/***********************************************************************\n* copyClassNamesForImage_nolock\n* Copies class names from the given image.\n* Missing weak-import classes are omitted.\n* Swift class names are demangled.\n*\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nconst char **\ncopyClassNamesForImage_nolock(header_info *hi, unsigned int *outCount)\n{\n    runtimeLock.assertLocked();\n    assert(hi);\n\n    size_t count;\n    classref_t *classlist = _getObjc2ClassList(hi, &count);\n    const char **names = (const char **)\n        malloc((count+1) * sizeof(const char *));\n\n    size_t shift = 0;\n    for (size_t i = 0; i < count; i++) {\n        Class cls = remapClass(classlist[i]);\n        if (cls) {\n            names[i-shift] = cls->demangledName(true/*realize*/);\n        } else {\n            shift++;  // ignored weak-linked class\n        }\n    }\n    count -= shift;\n    names[count] = nil;\n\n    if (outCount) *outCount = (unsigned int)count;\n    return names;\n}\n\n\n\n/***********************************************************************\n* objc_copyClassNamesForImage\n* Copies class names from the named image.\n* The image name must be identical to dladdr's dli_fname value.\n* Missing weak-import classes are omitted.\n* Swift class names are demangled.\n*\n* Locking: acquires runtimeLock\n**********************************************************************/\nconst char **\nobjc_copyClassNamesForImage(const char *image, unsigned int *outCount)\n{\n    if (!image) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    mutex_locker_t lock(runtimeLock);\n\n    // Find the image.\n    header_info *hi;\n    for (hi = FirstHeader; hi != nil; hi = hi->getNext()) {\n#if TARGET_OS_WIN32\n        if (0 == wcscmp((TCHAR *)image, hi->moduleName)) break;\n#else\n        if (0 == strcmp(image, hi->fname())) break;\n#endif\n    }\n\n    if (!hi) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    return copyClassNamesForImage_nolock(hi, outCount);\n}\n\n\n/***********************************************************************\n* objc_copyClassNamesForImageHeader\n* Copies class names from the given image.\n* Missing weak-import classes are omitted.\n* Swift class names are demangled.\n*\n* Locking: acquires runtimeLock\n**********************************************************************/\nconst char **\nobjc_copyClassNamesForImageHeader(const struct mach_header *mh, unsigned int *outCount)\n{\n    if (!mh) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    mutex_locker_t lock(runtimeLock);\n\n    // Find the image.\n    header_info *hi;\n    for (hi = FirstHeader; hi != nil; hi = hi->getNext()) {\n        if (hi->mhdr() == (const headerType *)mh) break;\n    }\n\n    if (!hi) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    return copyClassNamesForImage_nolock(hi, outCount);\n}\n\n\n/***********************************************************************\n* saveTemporaryString\n* Save a string in a thread-local FIFO buffer. \n* This is suitable for temporary strings generated for logging purposes.\n**********************************************************************/\nstatic void\nsaveTemporaryString(char *str)\n{\n    // Fixed-size FIFO. We free the first string, shift \n    // the rest, and add the new string to the end.\n    _objc_pthread_data *data = _objc_fetch_pthread_data(true);\n    if (data->printableNames[0]) {\n        free(data->printableNames[0]);\n    }\n    int last = countof(data->printableNames) - 1;\n    for (int i = 0; i < last; i++) {\n        data->printableNames[i] = data->printableNames[i+1];\n    }\n    data->printableNames[last] = str;\n}\n\n\n/***********************************************************************\n* objc_class::nameForLogging\n* Returns the class's name, suitable for display.\n* The returned memory is TEMPORARY. Print it or copy it immediately.\n* Locking: none\n**********************************************************************/\nconst char *\nobjc_class::nameForLogging()\n{\n    // Handle the easy case directly.\n    if (isRealized()  ||  isFuture()) {\n        if (data()->demangledName) return data()->demangledName;\n    }\n\n    char *result;\n\n    const char *name = mangledName();\n    char *de = copySwiftV1DemangledName(name);\n    if (de) result = de;\n    else result = strdup(name);\n\n    saveTemporaryString(result);\n    return result;\n}\n\n\n/***********************************************************************\n* objc_class::demangledName\n* If realize=false, the class must already be realized or future.\n* Locking: If realize=true, runtimeLock must be held by the caller.\n**********************************************************************/\nmutex_t DemangleCacheLock;\nstatic NXHashTable *DemangleCache;\nconst char *\nobjc_class::demangledName(bool realize)\n{\n    // Return previously demangled name if available.\n    if (isRealized()  ||  isFuture()) {\n        if (data()->demangledName) return data()->demangledName;\n    }\n\n    // Try demangling the mangled name.\n    const char *mangled = mangledName();\n    char *de = copySwiftV1DemangledName(mangled);\n    if (isRealized()  ||  isFuture()) {\n        // Class is already realized or future. \n        // Save demangling result in rw data.\n        // We may not own runtimeLock so use an atomic operation instead.\n        if (! OSAtomicCompareAndSwapPtrBarrier(nil, (void*)(de ?: mangled), \n                                               (void**)&data()->demangledName)) \n        {\n            if (de) free(de);\n        }\n        return data()->demangledName;\n    }\n\n    // Class is not yet realized.\n    if (!de) {\n        // Name is not mangled. Return it without caching.\n        return mangled;\n    }\n\n    // Class is not yet realized and name is mangled. Realize the class.\n    // Only objc_copyClassNamesForImage() should get here.\n    \n    // fixme lldb's calls to class_getName() can also get here when\n    // interrogating the dyld shared cache. (rdar://27258517)\n    // fixme runtimeLock.assertLocked();\n    // fixme assert(realize);\n    \n    if (realize) {\n        runtimeLock.assertLocked();\n        realizeClass((Class)this);\n        data()->demangledName = de;\n        return de;\n    }\n    else {\n        // Save the string to avoid leaks.\n        char *cached;\n        {\n            mutex_locker_t lock(DemangleCacheLock);\n            if (!DemangleCache) {\n                DemangleCache = NXCreateHashTable(NXStrPrototype, 0, nil);\n            }\n            cached = (char *)NXHashInsertIfAbsent(DemangleCache, de);\n        }\n        if (cached != de) free(de);\n        return cached;\n    }\n}\n\n\n/***********************************************************************\n* class_getName\n* fixme\n* Locking: acquires runtimeLock\n**********************************************************************/\nconst char *class_getName(Class cls)\n{\n    if (!cls) return \"nil\";\n    // fixme lldb calls class_getName() on unrealized classes (rdar://27258517)\n    // assert(cls->isRealized()  ||  cls->isFuture());\n    return cls->demangledName();\n}\n\n\n/***********************************************************************\n* class_getVersion\n* fixme\n* Locking: none\n**********************************************************************/\nint \nclass_getVersion(Class cls)\n{\n    if (!cls) return 0;\n    assert(cls->isRealized());\n    return cls->data()->version;\n}\n\n\n/***********************************************************************\n* class_setVersion\n* fixme\n* Locking: none\n**********************************************************************/\nvoid \nclass_setVersion(Class cls, int version)\n{\n    if (!cls) return;\n    assert(cls->isRealized());\n    cls->data()->version = version;\n}\n\n\nstatic method_t *findMethodInSortedMethodList(SEL key, const method_list_t *list)\n{\n    assert(list);\n\n    const method_t * const first = &list->first;\n    const method_t *base = first;\n    const method_t *probe;\n    uintptr_t keyValue = (uintptr_t)key;\n    uint32_t count;\n    \n    for (count = list->count; count != 0; count >>= 1) {\n        probe = base + (count >> 1);\n        \n        uintptr_t probeValue = (uintptr_t)probe->name;\n        \n        if (keyValue == probeValue) {\n            // `probe` is a match.\n            // Rewind looking for the *first* occurrence of this value.\n            // This is required for correct category overrides.\n            while (probe > first && keyValue == (uintptr_t)probe[-1].name) {\n                probe--;\n            }\n            return (method_t *)probe;\n        }\n        \n        if (keyValue > probeValue) {\n            base = probe + 1;\n            count--;\n        }\n    }\n    \n    return nil;\n}\n\n/***********************************************************************\n* getMethodNoSuper_nolock\n* fixme\n* Locking: runtimeLock must be read- or write-locked by the caller\n**********************************************************************/\nstatic method_t *search_method_list(const method_list_t *mlist, SEL sel)\n{\n    int methodListIsFixedUp = mlist->isFixedUp();\n    int methodListHasExpectedSize = mlist->entsize() == sizeof(method_t);\n    \n    if (__builtin_expect(methodListIsFixedUp && methodListHasExpectedSize, 1)) {\n        return findMethodInSortedMethodList(sel, mlist);\n    } else {\n        // Linear search of unsorted method list\n        for (auto& meth : *mlist) {\n            if (meth.name == sel) return &meth;\n        }\n    }\n\n#if DEBUG\n    // sanity-check negative results\n    if (mlist->isFixedUp()) {\n        for (auto& meth : *mlist) {\n            if (meth.name == sel) {\n                _objc_fatal(\"linear search worked when binary search did not\");\n            }\n        }\n    }\n#endif\n\n    return nil;\n}\n\nstatic method_t *\ngetMethodNoSuper_nolock(Class cls, SEL sel)\n{\n    runtimeLock.assertLocked();\n\n    assert(cls->isRealized());\n    // fixme nil cls? \n    // fixme nil sel?\n\n    for (auto mlists = cls->data()->methods.beginLists(), \n              end = cls->data()->methods.endLists(); \n         mlists != end;\n         ++mlists)\n    {\n        method_t *m = search_method_list(*mlists, sel);\n        if (m) return m;\n    }\n\n    return nil;\n}\n\n\n/***********************************************************************\n* getMethod_nolock\n* fixme\n* Locking: runtimeLock must be read- or write-locked by the caller\n**********************************************************************/\nstatic method_t *\ngetMethod_nolock(Class cls, SEL sel)\n{\n    method_t *m = nil;\n\n    runtimeLock.assertLocked();\n\n    // fixme nil cls?\n    // fixme nil sel?\n\n    assert(cls->isRealized());\n\n    while (cls  &&  ((m = getMethodNoSuper_nolock(cls, sel))) == nil) {\n        cls = cls->superclass;\n    }\n\n    return m;\n}\n\n\n/***********************************************************************\n* _class_getMethod\n* fixme\n* Locking: read-locks runtimeLock\n**********************************************************************/\nstatic Method _class_getMethod(Class cls, SEL sel)\n{\n    mutex_locker_t lock(runtimeLock);\n    return getMethod_nolock(cls, sel);\n}\n\n\n/***********************************************************************\n* class_getInstanceMethod.  Return the instance method for the\n* specified class and selector.\n**********************************************************************/\nMethod class_getInstanceMethod(Class cls, SEL sel)\n{\n    if (!cls  ||  !sel) return nil;\n\n    // This deliberately avoids +initialize because it historically did so.\n\n    // This implementation is a bit weird because it's the only place that \n    // wants a Method instead of an IMP.\n\n#warning fixme build and search caches\n        \n    // Search method lists, try method resolver, etc.\n    lookUpImpOrNil(cls, sel, nil, \n                   NO/*initialize*/, NO/*cache*/, YES/*resolver*/);\n\n#warning fixme build and search caches\n\n    return _class_getMethod(cls, sel);\n}\n\n\n/***********************************************************************\n* log_and_fill_cache\n* Log this method call. If the logger permits it, fill the method cache.\n* cls is the method whose cache should be filled. \n* implementer is the class that owns the implementation in question.\n**********************************************************************/\nstatic void\nlog_and_fill_cache(Class cls, IMP imp, SEL sel, id receiver, Class implementer)\n{\n#if SUPPORT_MESSAGE_LOGGING\n    if (objcMsgLogEnabled) {\n        bool cacheIt = logMessageSend(implementer->isMetaClass(), \n                                      cls->nameForLogging(),\n                                      implementer->nameForLogging(), \n                                      sel);\n        if (!cacheIt) return;\n    }\n#endif\n    cache_fill (cls, sel, imp, receiver);\n}\n\n\n/***********************************************************************\n* _class_lookupMethodAndLoadCache.\n* Method lookup for dispatchers ONLY. OTHER CODE SHOULD USE lookUpImp().\n* This lookup avoids optimistic cache scan because the dispatcher \n* already tried that.\n**********************************************************************/\nIMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls)\n{\n    return lookUpImpOrForward(cls, sel, obj, \n                              YES/*initialize*/, NO/*cache*/, YES/*resolver*/);\n}\n\n\n/***********************************************************************\n* lookUpImpOrForward.\n* The standard IMP lookup. \n* initialize==NO tries to avoid +initialize (but sometimes fails)\n* cache==NO skips optimistic unlocked lookup (but uses cache elsewhere)\n* Most callers should use initialize==YES and cache==YES.\n* inst is an instance of cls or a subclass thereof, or nil if none is known. \n*   If cls is an un-initialized metaclass then a non-nil inst is faster.\n* May return _objc_msgForward_impcache. IMPs destined for external use \n*   must be converted to _objc_msgForward or _objc_msgForward_stret.\n*   If you don't want forwarding at all, use lookUpImpOrNil() instead.\n**********************************************************************/\nIMP lookUpImpOrForward(Class cls, SEL sel, id inst, \n                       bool initialize, bool cache, bool resolver)\n{\n    IMP imp = nil;\n    bool triedResolver = NO;\n\n    runtimeLock.assertUnlocked();\n\n    // Optimistic cache lookup\n    if (cache) {\n        imp = cache_getImp(cls, sel);\n        if (imp) return imp;\n    }\n\n    // runtimeLock is held during isRealized and isInitialized checking\n    // to prevent races against concurrent realization.\n\n    // runtimeLock is held during method search to make\n    // method-lookup + cache-fill atomic with respect to method addition.\n    // Otherwise, a category could be added but ignored indefinitely because\n    // the cache was re-filled with the old value after the cache flush on\n    // behalf of the category.\n\n    runtimeLock.lock();\n    checkIsKnownClass(cls);\n\n    if (!cls->isRealized()) {\n        realizeClass(cls);\n    }\n\n    if (initialize  &&  !cls->isInitialized()) {\n        runtimeLock.unlock();\n        _class_initialize (_class_getNonMetaClass(cls, inst));\n        runtimeLock.lock();\n        // If sel == initialize, _class_initialize will send +initialize and \n        // then the messenger will send +initialize again after this \n        // procedure finishes. Of course, if this is not being called \n        // from the messenger then it won't happen. 2778172\n    }\n\n    \n retry:    \n    runtimeLock.assertLocked();\n\n    // Try this class's cache.\n\n    imp = cache_getImp(cls, sel);\n    if (imp) goto done;\n\n    // Try this class's method lists.\n    {\n        Method meth = getMethodNoSuper_nolock(cls, sel);\n        if (meth) {\n            log_and_fill_cache(cls, meth->imp, sel, inst, cls);\n            imp = meth->imp;\n            goto done;\n        }\n    }\n\n    // Try superclass caches and method lists.\n    {\n        unsigned attempts = unreasonableClassCount();\n        for (Class curClass = cls->superclass;\n             curClass != nil;\n             curClass = curClass->superclass)\n        {\n            // Halt if there is a cycle in the superclass chain.\n            if (--attempts == 0) {\n                _objc_fatal(\"Memory corruption in class list.\");\n            }\n            \n            // Superclass cache.\n            imp = cache_getImp(curClass, sel);\n            if (imp) {\n                if (imp != (IMP)_objc_msgForward_impcache) {\n                    // Found the method in a superclass. Cache it in this class.\n                    log_and_fill_cache(cls, imp, sel, inst, curClass);\n                    goto done;\n                }\n                else {\n                    // Found a forward:: entry in a superclass.\n                    // Stop searching, but don't cache yet; call method \n                    // resolver for this class first.\n                    break;\n                }\n            }\n            \n            // Superclass method list.\n            Method meth = getMethodNoSuper_nolock(curClass, sel);\n            if (meth) {\n                log_and_fill_cache(cls, meth->imp, sel, inst, curClass);\n                imp = meth->imp;\n                goto done;\n            }\n        }\n    }\n\n    // No implementation found. Try method resolver once.\n\n    if (resolver  &&  !triedResolver) {\n        runtimeLock.unlock();\n        _class_resolveMethod(cls, sel, inst);\n        runtimeLock.lock();\n        // Don't cache the result; we don't hold the lock so it may have \n        // changed already. Re-do the search from scratch instead.\n        triedResolver = YES;\n        goto retry;\n    }\n\n    // No implementation found, and method resolver didn't help. \n    // Use forwarding.\n\n    imp = (IMP)_objc_msgForward_impcache;\n    cache_fill(cls, sel, imp, inst);\n\n done:\n    runtimeLock.unlock();\n\n    return imp;\n}\n\n\n/***********************************************************************\n* lookUpImpOrNil.\n* Like lookUpImpOrForward, but returns nil instead of _objc_msgForward_impcache\n**********************************************************************/\nIMP lookUpImpOrNil(Class cls, SEL sel, id inst, \n                   bool initialize, bool cache, bool resolver)\n{\n    IMP imp = lookUpImpOrForward(cls, sel, inst, initialize, cache, resolver);\n    if (imp == _objc_msgForward_impcache) return nil;\n    else return imp;\n}\n\n\n/***********************************************************************\n* lookupMethodInClassAndLoadCache.\n* Like _class_lookupMethodAndLoadCache, but does not search superclasses.\n* Caches and returns objc_msgForward if the method is not found in the class.\n**********************************************************************/\nIMP lookupMethodInClassAndLoadCache(Class cls, SEL sel)\n{\n    Method meth;\n    IMP imp;\n\n    // fixme this is incomplete - no resolver, +initialize - \n    // but it's only used for .cxx_construct/destruct so we don't care\n    assert(sel == SEL_cxx_construct  ||  sel == SEL_cxx_destruct);\n\n    // Search cache first.\n    imp = cache_getImp(cls, sel);\n    if (imp) return imp;\n\n    // Cache miss. Search method list.\n\n    mutex_locker_t lock(runtimeLock);\n\n    meth = getMethodNoSuper_nolock(cls, sel);\n\n    if (meth) {\n        // Hit in method list. Cache it.\n        cache_fill(cls, sel, meth->imp, nil);\n        return meth->imp;\n    } else {\n        // Miss in method list. Cache objc_msgForward.\n        cache_fill(cls, sel, _objc_msgForward_impcache, nil);\n        return _objc_msgForward_impcache;\n    }\n}\n\n\n/***********************************************************************\n* class_getProperty\n* fixme\n* Locking: read-locks runtimeLock\n**********************************************************************/\nobjc_property_t class_getProperty(Class cls, const char *name)\n{\n    if (!cls  ||  !name) return nil;\n\n    mutex_locker_t lock(runtimeLock);\n\n    checkIsKnownClass(cls);\n    \n    assert(cls->isRealized());\n\n    for ( ; cls; cls = cls->superclass) {\n        for (auto& prop : cls->data()->properties) {\n            if (0 == strcmp(name, prop.name)) {\n                return (objc_property_t)&prop;\n            }\n        }\n    }\n    \n    return nil;\n}\n\n\n/***********************************************************************\n* Locking: fixme\n**********************************************************************/\n\nClass gdb_class_getClass(Class cls)\n{\n    const char *className = cls->mangledName();\n    if(!className || !strlen(className)) return Nil;\n    Class rCls = look_up_class(className, NO, NO);\n    return rCls;\n}\n\nClass gdb_object_getClass(id obj)\n{\n    if (!obj) return nil;\n    return gdb_class_getClass(obj->getIsa());\n}\n\n\n/***********************************************************************\n* Locking: write-locks runtimeLock\n**********************************************************************/\nvoid \nobjc_class::setInitialized()\n{\n    Class metacls;\n    Class cls;\n\n    assert(!isMetaClass());\n\n    cls = (Class)this;\n    metacls = cls->ISA();\n\n    mutex_locker_t lock(runtimeLock);\n\n    // Scan metaclass for custom AWZ.\n    // Scan metaclass for custom RR.\n    // Scan class for custom RR.\n    // Also print custom RR/AWZ because we probably haven't done it yet.\n\n    // Special cases:\n    // NSObject AWZ class methods are default.\n    // NSObject RR instance methods are default.\n    // updateCustomRR_AWZ() also knows these special cases.\n    // attachMethodLists() also knows these special cases.\n\n    bool inherited;\n    bool metaCustomAWZ = NO;\n    if (MetaclassNSObjectAWZSwizzled) {\n        // Somebody already swizzled NSObject's methods\n        metaCustomAWZ = YES;\n        inherited = NO;\n    }\n    else if (metacls == classNSObject()->ISA()) {\n        // NSObject's metaclass AWZ is default, but we still need to check cats\n        auto& methods = metacls->data()->methods;\n        for (auto mlists = methods.beginCategoryMethodLists(), \n                  end = methods.endCategoryMethodLists(metacls); \n             mlists != end;\n             ++mlists)\n        {\n            if (methodListImplementsAWZ(*mlists)) {\n                metaCustomAWZ = YES;\n                inherited = NO;\n                break;\n            }\n        }\n    }\n    else if (metacls->superclass->hasCustomAWZ()) {\n        // Superclass is custom AWZ, therefore we are too.\n        metaCustomAWZ = YES;\n        inherited = YES;\n    } \n    else {\n        // Not metaclass NSObject.\n        auto& methods = metacls->data()->methods;\n        for (auto mlists = methods.beginLists(),\n                  end = methods.endLists(); \n             mlists != end;\n             ++mlists)\n        {\n            if (methodListImplementsAWZ(*mlists)) {\n                metaCustomAWZ = YES;\n                inherited = NO;\n                break;\n            }\n        }\n    }\n    if (!metaCustomAWZ) metacls->setHasDefaultAWZ();\n\n    if (PrintCustomAWZ  &&  metaCustomAWZ) metacls->printCustomAWZ(inherited);\n    // metacls->printCustomRR();\n\n\n    bool clsCustomRR = NO;\n    if (ClassNSObjectRRSwizzled) {\n        // Somebody already swizzled NSObject's methods\n        clsCustomRR = YES;\n        inherited = NO;\n    }\n    if (cls == classNSObject()) {\n        // NSObject's RR is default, but we still need to check categories\n        auto& methods = cls->data()->methods;\n        for (auto mlists = methods.beginCategoryMethodLists(), \n                  end = methods.endCategoryMethodLists(cls); \n             mlists != end;\n             ++mlists)\n        {\n            if (methodListImplementsRR(*mlists)) {\n                clsCustomRR = YES;\n                inherited = NO;\n                break;\n            }\n        }\n    }\n    else if (!cls->superclass) {\n        // Custom root class\n        clsCustomRR = YES;\n        inherited = NO;\n    } \n    else if (cls->superclass->hasCustomRR()) {\n        // Superclass is custom RR, therefore we are too.\n        clsCustomRR = YES;\n        inherited = YES;\n    } \n    else {\n        // Not class NSObject.\n        auto& methods = cls->data()->methods;\n        for (auto mlists = methods.beginLists(), \n                  end = methods.endLists(); \n             mlists != end;\n             ++mlists)\n        {\n            if (methodListImplementsRR(*mlists)) {\n                clsCustomRR = YES;\n                inherited = NO;\n                break;\n            }\n        }\n    }\n    if (!clsCustomRR) cls->setHasDefaultRR();\n\n    // cls->printCustomAWZ();\n    if (PrintCustomRR  &&  clsCustomRR) cls->printCustomRR(inherited);\n\n    // Update the +initialize flags.\n    // Do this last.\n    metacls->changeInfo(RW_INITIALIZED, RW_INITIALIZING);\n}\n\n\n/***********************************************************************\n* Return YES if sel is used by retain/release implementors\n**********************************************************************/\nstatic bool \nisRRSelector(SEL sel)\n{\n    return (sel == SEL_retain          ||  sel == SEL_release              ||  \n            sel == SEL_autorelease     ||  sel == SEL_retainCount          ||  \n            sel == SEL_tryRetain       ||  sel == SEL_retainWeakReference  ||  \n            sel == SEL_isDeallocating  ||  sel == SEL_allowsWeakReference);\n}\n\n\n/***********************************************************************\n* Return YES if mlist implements one of the isRRSelector() methods\n**********************************************************************/\nstatic bool \nmethodListImplementsRR(const method_list_t *mlist)\n{\n    return (search_method_list(mlist, SEL_retain)               ||  \n            search_method_list(mlist, SEL_release)              ||  \n            search_method_list(mlist, SEL_autorelease)          ||  \n            search_method_list(mlist, SEL_retainCount)          ||  \n            search_method_list(mlist, SEL_tryRetain)            ||  \n            search_method_list(mlist, SEL_isDeallocating)       ||  \n            search_method_list(mlist, SEL_retainWeakReference)  ||  \n            search_method_list(mlist, SEL_allowsWeakReference));\n}\n\n\n/***********************************************************************\n* Return YES if sel is used by alloc or allocWithZone implementors\n**********************************************************************/\nstatic bool \nisAWZSelector(SEL sel)\n{\n    return (sel == SEL_allocWithZone  ||  sel == SEL_alloc);\n}\n\n\n/***********************************************************************\n* Return YES if mlist implements one of the isAWZSelector() methods\n**********************************************************************/\nstatic bool \nmethodListImplementsAWZ(const method_list_t *mlist)\n{\n    return (search_method_list(mlist, SEL_allocWithZone)  ||\n            search_method_list(mlist, SEL_alloc));\n}\n\n\nvoid \nobjc_class::printCustomRR(bool inherited)\n{\n    assert(PrintCustomRR);\n    assert(hasCustomRR());\n    _objc_inform(\"CUSTOM RR:  %s%s%s\", nameForLogging(), \n                 isMetaClass() ? \" (meta)\" : \"\", \n                 inherited ? \" (inherited)\" : \"\");\n}\n\nvoid \nobjc_class::printCustomAWZ(bool inherited)\n{\n    assert(PrintCustomAWZ);\n    assert(hasCustomAWZ());\n    _objc_inform(\"CUSTOM AWZ:  %s%s%s\", nameForLogging(), \n                 isMetaClass() ? \" (meta)\" : \"\", \n                 inherited ? \" (inherited)\" : \"\");\n}\n\nvoid \nobjc_class::printInstancesRequireRawIsa(bool inherited)\n{\n    assert(PrintRawIsa);\n    assert(instancesRequireRawIsa());\n    _objc_inform(\"RAW ISA:  %s%s%s\", nameForLogging(), \n                 isMetaClass() ? \" (meta)\" : \"\", \n                 inherited ? \" (inherited)\" : \"\");\n}\n\n\n/***********************************************************************\n* Mark this class and all of its subclasses as implementors or \n* inheritors of custom RR (retain/release/autorelease/retainCount)\n**********************************************************************/\nvoid objc_class::setHasCustomRR(bool inherited) \n{\n    Class cls = (Class)this;\n    runtimeLock.assertLocked();\n\n    if (hasCustomRR()) return;\n    \n    foreach_realized_class_and_subclass(cls, ^(Class c){\n        if (c != cls  &&  !c->isInitialized()) {\n            // Subclass not yet initialized. Wait for setInitialized() to do it\n            // fixme short circuit recursion?\n            return;\n        }\n        if (c->hasCustomRR()) {\n            // fixme short circuit recursion?\n            return;\n        }\n\n        c->bits.setHasCustomRR();\n\n        if (PrintCustomRR) c->printCustomRR(inherited  ||  c != cls);\n    });\n}\n\n/***********************************************************************\n* Mark this class and all of its subclasses as implementors or \n* inheritors of custom alloc/allocWithZone:\n**********************************************************************/\nvoid objc_class::setHasCustomAWZ(bool inherited) \n{\n    Class cls = (Class)this;\n    runtimeLock.assertLocked();\n\n    if (hasCustomAWZ()) return;\n    \n    foreach_realized_class_and_subclass(cls, ^(Class c){\n        if (c != cls  &&  !c->isInitialized()) {\n            // Subclass not yet initialized. Wait for setInitialized() to do it\n            // fixme short circuit recursion?\n            return;\n        }\n        if (c->hasCustomAWZ()) {\n            // fixme short circuit recursion?\n            return;\n        }\n\n        c->bits.setHasCustomAWZ();\n\n        if (PrintCustomAWZ) c->printCustomAWZ(inherited  ||  c != cls);\n    });\n}\n\n\n/***********************************************************************\n* Mark this class and all of its subclasses as requiring raw isa pointers\n**********************************************************************/\nvoid objc_class::setInstancesRequireRawIsa(bool inherited) \n{\n    Class cls = (Class)this;\n    runtimeLock.assertLocked();\n\n    if (instancesRequireRawIsa()) return;\n    \n    foreach_realized_class_and_subclass(cls, ^(Class c){\n        if (c->instancesRequireRawIsa()) {\n            // fixme short circuit recursion?\n            return;\n        }\n\n        c->bits.setInstancesRequireRawIsa();\n\n        if (PrintRawIsa) c->printInstancesRequireRawIsa(inherited || c != cls);\n    });\n}\n\n\n/***********************************************************************\n* Choose a class index. \n* Set instancesRequireRawIsa if no more class indexes are available.\n**********************************************************************/\nvoid objc_class::chooseClassArrayIndex()\n{\n#if SUPPORT_INDEXED_ISA\n    Class cls = (Class)this;\n    runtimeLock.assertLocked();\n\n    if (objc_indexed_classes_count >= ISA_INDEX_COUNT) {\n        // No more indexes available.\n        assert(cls->classArrayIndex() == 0);\n        cls->setInstancesRequireRawIsa(false/*not inherited*/);\n        return;\n    }\n\n    unsigned index = objc_indexed_classes_count++;\n    if (index == 0) index = objc_indexed_classes_count++;  // index 0 is unused\n    classForIndex(index) = cls;\n    cls->setClassArrayIndex(index);\n#endif\n}\n\n\n/***********************************************************************\n* Update custom RR and AWZ when a method changes its IMP\n**********************************************************************/\nstatic void\nupdateCustomRR_AWZ(Class cls, method_t *meth)\n{\n    // In almost all cases, IMP swizzling does not affect custom RR/AWZ bits. \n    // Custom RR/AWZ search will already find the method whether or not \n    // it is swizzled, so it does not transition from non-custom to custom.\n    // \n    // The only cases where IMP swizzling can affect the RR/AWZ bits is \n    // if the swizzled method is one of the methods that is assumed to be \n    // non-custom. These special cases are listed in setInitialized().\n    // We look for such cases here.\n\n    if (isRRSelector(meth->name)) {\n        \n        if ((classNSObject()->isInitialized() && \n             classNSObject()->hasCustomRR())  \n            ||  \n            ClassNSObjectRRSwizzled) \n        {\n            // already custom, nothing would change\n            return;\n        }\n\n        bool swizzlingNSObject = NO;\n        if (cls == classNSObject()) {\n            swizzlingNSObject = YES;\n        } else {\n            // Don't know the class. \n            // The only special case is class NSObject.\n            for (const auto& meth2 : classNSObject()->data()->methods) {\n                if (meth == &meth2) {\n                    swizzlingNSObject = YES;\n                    break;\n                }\n            }\n        }\n        if (swizzlingNSObject) {\n            if (classNSObject()->isInitialized()) {\n                classNSObject()->setHasCustomRR();\n            } else {\n                // NSObject not yet +initialized, so custom RR has not yet \n                // been checked, and setInitialized() will not notice the \n                // swizzle. \n                ClassNSObjectRRSwizzled = YES;\n            }\n        }\n    }\n    else if (isAWZSelector(meth->name)) {\n        Class metaclassNSObject = classNSObject()->ISA();\n\n        if ((metaclassNSObject->isInitialized() && \n             metaclassNSObject->hasCustomAWZ())  \n            ||  \n            MetaclassNSObjectAWZSwizzled) \n        {\n            // already custom, nothing would change\n            return;\n        }\n\n        bool swizzlingNSObject = NO;\n        if (cls == metaclassNSObject) {\n            swizzlingNSObject = YES;\n        } else {\n            // Don't know the class. \n            // The only special case is metaclass NSObject.\n            for (const auto& meth2 : metaclassNSObject->data()->methods) {\n                if (meth == &meth2) {\n                    swizzlingNSObject = YES;\n                    break;\n                }\n            }\n        }\n        if (swizzlingNSObject) {\n            if (metaclassNSObject->isInitialized()) {\n                metaclassNSObject->setHasCustomAWZ();\n            } else {\n                // NSObject not yet +initialized, so custom RR has not yet \n                // been checked, and setInitialized() will not notice the \n                // swizzle. \n                MetaclassNSObjectAWZSwizzled = YES;\n            }\n        }\n    }\n}\n\n\n/***********************************************************************\n* class_getIvarLayout\n* Called by the garbage collector. \n* The class must be nil or already realized. \n* Locking: none\n**********************************************************************/\nconst uint8_t *\nclass_getIvarLayout(Class cls)\n{\n    if (cls) return cls->data()->ro->ivarLayout;\n    else return nil;\n}\n\n\n/***********************************************************************\n* class_getWeakIvarLayout\n* Called by the garbage collector. \n* The class must be nil or already realized. \n* Locking: none\n**********************************************************************/\nconst uint8_t *\nclass_getWeakIvarLayout(Class cls)\n{\n    if (cls) return cls->data()->ro->weakIvarLayout;\n    else return nil;\n}\n\n\n/***********************************************************************\n* class_setIvarLayout\n* Changes the class's ivar layout.\n* nil layout means no unscanned ivars\n* The class must be under construction.\n* fixme: sanity-check layout vs instance size?\n* fixme: sanity-check layout vs superclass?\n* Locking: acquires runtimeLock\n**********************************************************************/\nvoid\nclass_setIvarLayout(Class cls, const uint8_t *layout)\n{\n    if (!cls) return;\n\n    mutex_locker_t lock(runtimeLock);\n    \n    checkIsKnownClass(cls);\n\n    // Can only change layout of in-construction classes.\n    // note: if modifications to post-construction classes were \n    //   allowed, there would be a race below (us vs. concurrent object_setIvar)\n    if (!(cls->data()->flags & RW_CONSTRUCTING)) {\n        _objc_inform(\"*** Can't set ivar layout for already-registered \"\n                     \"class '%s'\", cls->nameForLogging());\n        return;\n    }\n\n    class_ro_t *ro_w = make_ro_writeable(cls->data());\n\n    try_free(ro_w->ivarLayout);\n    ro_w->ivarLayout = ustrdupMaybeNil(layout);\n}\n\n\n/***********************************************************************\n* class_setWeakIvarLayout\n* Changes the class's weak ivar layout.\n* nil layout means no weak ivars\n* The class must be under construction.\n* fixme: sanity-check layout vs instance size?\n* fixme: sanity-check layout vs superclass?\n* Locking: acquires runtimeLock\n**********************************************************************/\nvoid\nclass_setWeakIvarLayout(Class cls, const uint8_t *layout)\n{\n    if (!cls) return;\n\n    mutex_locker_t lock(runtimeLock);\n    \n    checkIsKnownClass(cls);\n\n    // Can only change layout of in-construction classes.\n    // note: if modifications to post-construction classes were \n    //   allowed, there would be a race below (us vs. concurrent object_setIvar)\n    if (!(cls->data()->flags & RW_CONSTRUCTING)) {\n        _objc_inform(\"*** Can't set weak ivar layout for already-registered \"\n                     \"class '%s'\", cls->nameForLogging());\n        return;\n    }\n\n    class_ro_t *ro_w = make_ro_writeable(cls->data());\n\n    try_free(ro_w->weakIvarLayout);\n    ro_w->weakIvarLayout = ustrdupMaybeNil(layout);\n}\n\n\n/***********************************************************************\n* getIvar\n* Look up an ivar by name.\n* Locking: runtimeLock must be read- or write-locked by the caller.\n**********************************************************************/\nstatic ivar_t *getIvar(Class cls, const char *name)\n{\n    runtimeLock.assertLocked();\n\n    const ivar_list_t *ivars;\n    assert(cls->isRealized());\n    if ((ivars = cls->data()->ro->ivars)) {\n        for (auto& ivar : *ivars) {\n            if (!ivar.offset) continue;  // anonymous bitfield\n\n            // ivar.name may be nil for anonymous bitfields etc.\n            if (ivar.name  &&  0 == strcmp(name, ivar.name)) {\n                return &ivar;\n            }\n        }\n    }\n\n    return nil;\n}\n\n\n/***********************************************************************\n* _class_getClassForIvar\n* Given a class and an ivar that is in it or one of its superclasses, \n* find the actual class that defined the ivar.\n**********************************************************************/\nClass _class_getClassForIvar(Class cls, Ivar ivar)\n{\n    mutex_locker_t lock(runtimeLock);\n\n    for ( ; cls; cls = cls->superclass) {\n        if (auto ivars = cls->data()->ro->ivars) {\n            if (ivars->containsIvar(ivar)) {\n                return cls;\n            }\n        }\n    }\n\n    return nil;\n}\n\n\n/***********************************************************************\n* _class_getVariable\n* fixme\n* Locking: read-locks runtimeLock\n**********************************************************************/\nIvar \n_class_getVariable(Class cls, const char *name)\n{\n    mutex_locker_t lock(runtimeLock);\n\n    for ( ; cls; cls = cls->superclass) {\n        ivar_t *ivar = getIvar(cls, name);\n        if (ivar) {\n            return ivar;\n        }\n    }\n\n    return nil;\n}\n\n\n/***********************************************************************\n* class_conformsToProtocol\n* fixme\n* Locking: read-locks runtimeLock\n**********************************************************************/\nBOOL class_conformsToProtocol(Class cls, Protocol *proto_gen)\n{\n    protocol_t *proto = newprotocol(proto_gen);\n    \n    if (!cls) return NO;\n    if (!proto_gen) return NO;\n\n    mutex_locker_t lock(runtimeLock);\n\n    checkIsKnownClass(cls);\n    \n    assert(cls->isRealized());\n    \n    for (const auto& proto_ref : cls->data()->protocols) {\n        protocol_t *p = remapProtocol(proto_ref);\n        if (p == proto || protocol_conformsToProtocol_nolock(p, proto)) {\n            return YES;\n        }\n    }\n\n    return NO;\n}\n\n\n/**********************************************************************\n* addMethod\n* fixme\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nstatic IMP \naddMethod(Class cls, SEL name, IMP imp, const char *types, bool replace)\n{\n    IMP result = nil;\n\n    runtimeLock.assertLocked();\n\n    checkIsKnownClass(cls);\n    \n    assert(types);\n    assert(cls->isRealized());\n\n    method_t *m;\n    if ((m = getMethodNoSuper_nolock(cls, name))) {\n        // already exists\n        if (!replace) {\n            result = m->imp;\n        } else {\n            result = _method_setImplementation(cls, m, imp);\n        }\n    } else {\n        // fixme optimize\n        method_list_t *newlist;\n        newlist = (method_list_t *)calloc(sizeof(*newlist), 1);\n        newlist->entsizeAndFlags = \n            (uint32_t)sizeof(method_t) | fixed_up_method_list;\n        newlist->count = 1;\n        newlist->first.name = name;\n        newlist->first.types = strdupIfMutable(types);\n        newlist->first.imp = imp;\n\n        prepareMethodLists(cls, &newlist, 1, NO, NO);\n        cls->data()->methods.attachLists(&newlist, 1);\n        flushCaches(cls);\n\n        result = nil;\n    }\n\n    return result;\n}\n\n/**********************************************************************\n* addMethods\n* Add the given methods to a class in bulk.\n* Returns the selectors which could not be added, when replace == NO and a\n* method already exists. The returned selectors are NULL terminated and must be\n* freed by the caller. They are NULL if no failures occurred.\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nstatic SEL *\naddMethods(Class cls, const SEL *names, const IMP *imps, const char **types,\n           uint32_t count, bool replace, uint32_t *outFailedCount)\n{\n    runtimeLock.assertLocked();\n    \n    assert(names);\n    assert(imps);\n    assert(types);\n    assert(cls->isRealized());\n    \n    method_list_t *newlist;\n    size_t newlistSize = method_list_t::byteSize(sizeof(method_t), count);\n    newlist = (method_list_t *)calloc(newlistSize, 1);\n    newlist->entsizeAndFlags =\n        (uint32_t)sizeof(method_t) | fixed_up_method_list;\n    newlist->count = 0;\n    \n    method_t *newlistMethods = &newlist->first;\n    \n    SEL *failedNames = nil;\n    uint32_t failedCount = 0;\n    \n    for (uint32_t i = 0; i < count; i++) {\n        method_t *m;\n        if ((m = getMethodNoSuper_nolock(cls, names[i]))) {\n            // already exists\n            if (!replace) {\n                // report failure\n                if (failedNames == nil) {\n                    // allocate an extra entry for a trailing NULL in case\n                    // every method fails\n                    failedNames = (SEL *)calloc(sizeof(*failedNames),\n                                                count + 1);\n                }\n                failedNames[failedCount] = m->name;\n                failedCount++;\n            } else {\n                _method_setImplementation(cls, m, imps[i]);\n            }\n        } else {\n            method_t *newmethod = &newlistMethods[newlist->count];\n            newmethod->name = names[i];\n            newmethod->types = strdupIfMutable(types[i]);\n            newmethod->imp = imps[i];\n            newlist->count++;\n        }\n    }\n    \n    if (newlist->count > 0) {\n        // fixme resize newlist because it may have been over-allocated above.\n        // Note that realloc() alone doesn't work due to ptrauth.\n        \n        method_t::SortBySELAddress sorter;\n        std::stable_sort(newlist->begin(), newlist->end(), sorter);\n        \n        prepareMethodLists(cls, &newlist, 1, NO, NO);\n        cls->data()->methods.attachLists(&newlist, 1);\n        flushCaches(cls);\n    } else {\n        // Attaching the method list to the class consumes it. If we don't\n        // do that, we have to free the memory ourselves.\n        free(newlist);\n    }\n    \n    if (outFailedCount) *outFailedCount = failedCount;\n    \n    return failedNames;\n}\n\n\nBOOL \nclass_addMethod(Class cls, SEL name, IMP imp, const char *types)\n{\n    if (!cls) return NO;\n\n    mutex_locker_t lock(runtimeLock);\n    return ! addMethod(cls, name, imp, types ?: \"\", NO);\n}\n\n\nIMP \nclass_replaceMethod(Class cls, SEL name, IMP imp, const char *types)\n{\n    if (!cls) return nil;\n\n    mutex_locker_t lock(runtimeLock);\n    return addMethod(cls, name, imp, types ?: \"\", YES);\n}\n\n\nSEL *\nclass_addMethodsBulk(Class cls, const SEL *names, const IMP *imps,\n                     const char **types, uint32_t count,\n                     uint32_t *outFailedCount)\n{\n    if (!cls) {\n        if (outFailedCount) *outFailedCount = count;\n        return (SEL *)memdup(names, count * sizeof(*names));\n    }\n    \n    mutex_locker_t lock(runtimeLock);\n    return addMethods(cls, names, imps, types, count, NO, outFailedCount);\n}\n\nvoid\nclass_replaceMethodsBulk(Class cls, const SEL *names, const IMP *imps,\n                         const char **types, uint32_t count)\n{\n    if (!cls) return;\n    \n    mutex_locker_t lock(runtimeLock);\n    addMethods(cls, names, imps, types, count, YES, nil);\n}\n\n\n/***********************************************************************\n* class_addIvar\n* Adds an ivar to a class.\n* Locking: acquires runtimeLock\n**********************************************************************/\nBOOL \nclass_addIvar(Class cls, const char *name, size_t size, \n              uint8_t alignment, const char *type)\n{\n    if (!cls) return NO;\n\n    if (!type) type = \"\";\n    if (name  &&  0 == strcmp(name, \"\")) name = nil;\n\n    mutex_locker_t lock(runtimeLock);\n\n    checkIsKnownClass(cls);\n    assert(cls->isRealized());\n\n    // No class variables\n    if (cls->isMetaClass()) {\n        return NO;\n    }\n\n    // Can only add ivars to in-construction classes.\n    if (!(cls->data()->flags & RW_CONSTRUCTING)) {\n        return NO;\n    }\n\n    // Check for existing ivar with this name, unless it's anonymous.\n    // Check for too-big ivar.\n    // fixme check for superclass ivar too?\n    if ((name  &&  getIvar(cls, name))  ||  size > UINT32_MAX) {\n        return NO;\n    }\n\n    class_ro_t *ro_w = make_ro_writeable(cls->data());\n\n    // fixme allocate less memory here\n    \n    ivar_list_t *oldlist, *newlist;\n    if ((oldlist = (ivar_list_t *)cls->data()->ro->ivars)) {\n        size_t oldsize = oldlist->byteSize();\n        newlist = (ivar_list_t *)calloc(oldsize + oldlist->entsize(), 1);\n        memcpy(newlist, oldlist, oldsize);\n        free(oldlist);\n    } else {\n        newlist = (ivar_list_t *)calloc(sizeof(ivar_list_t), 1);\n        newlist->entsizeAndFlags = (uint32_t)sizeof(ivar_t);\n    }\n\n    uint32_t offset = cls->unalignedInstanceSize();\n    uint32_t alignMask = (1<<alignment)-1;\n    offset = (offset + alignMask) & ~alignMask;\n\n    ivar_t& ivar = newlist->get(newlist->count++);\n#if __x86_64__\n    // Deliberately over-allocate the ivar offset variable. \n    // Use calloc() to clear all 64 bits. See the note in struct ivar_t.\n    ivar.offset = (int32_t *)(int64_t *)calloc(sizeof(int64_t), 1);\n#else\n    ivar.offset = (int32_t *)malloc(sizeof(int32_t));\n#endif\n    *ivar.offset = offset;\n    ivar.name = name ? strdupIfMutable(name) : nil;\n    ivar.type = strdupIfMutable(type);\n    ivar.alignment_raw = alignment;\n    ivar.size = (uint32_t)size;\n\n    ro_w->ivars = newlist;\n    cls->setInstanceSize((uint32_t)(offset + size));\n\n    // Ivar layout updated in registerClass.\n\n    return YES;\n}\n\n\n/***********************************************************************\n* class_addProtocol\n* Adds a protocol to a class.\n* Locking: acquires runtimeLock\n**********************************************************************/\nBOOL class_addProtocol(Class cls, Protocol *protocol_gen)\n{\n    protocol_t *protocol = newprotocol(protocol_gen);\n\n    if (!cls) return NO;\n    if (class_conformsToProtocol(cls, protocol_gen)) return NO;\n\n    mutex_locker_t lock(runtimeLock);\n\n    assert(cls->isRealized());\n    \n    // fixme optimize\n    protocol_list_t *protolist = (protocol_list_t *)\n        malloc(sizeof(protocol_list_t) + sizeof(protocol_t *));\n    protolist->count = 1;\n    protolist->list[0] = (protocol_ref_t)protocol;\n\n    cls->data()->protocols.attachLists(&protolist, 1);\n\n    // fixme metaclass?\n\n    return YES;\n}\n\n\n/***********************************************************************\n* class_addProperty\n* Adds a property to a class.\n* Locking: acquires runtimeLock\n**********************************************************************/\nstatic bool \n_class_addProperty(Class cls, const char *name, \n                   const objc_property_attribute_t *attrs, unsigned int count, \n                   bool replace)\n{\n    if (!cls) return NO;\n    if (!name) return NO;\n\n    property_t *prop = class_getProperty(cls, name);\n    if (prop  &&  !replace) {\n        // already exists, refuse to replace\n        return NO;\n    } \n    else if (prop) {\n        // replace existing\n        mutex_locker_t lock(runtimeLock);\n        try_free(prop->attributes);\n        prop->attributes = copyPropertyAttributeString(attrs, count);\n        return YES;\n    }\n    else {\n        mutex_locker_t lock(runtimeLock);\n        \n        assert(cls->isRealized());\n        \n        property_list_t *proplist = (property_list_t *)\n            malloc(sizeof(*proplist));\n        proplist->count = 1;\n        proplist->entsizeAndFlags = sizeof(proplist->first);\n        proplist->first.name = strdupIfMutable(name);\n        proplist->first.attributes = copyPropertyAttributeString(attrs, count);\n        \n        cls->data()->properties.attachLists(&proplist, 1);\n        \n        return YES;\n    }\n}\n\nBOOL \nclass_addProperty(Class cls, const char *name, \n                  const objc_property_attribute_t *attrs, unsigned int n)\n{\n    return _class_addProperty(cls, name, attrs, n, NO);\n}\n\nvoid \nclass_replaceProperty(Class cls, const char *name, \n                      const objc_property_attribute_t *attrs, unsigned int n)\n{\n    _class_addProperty(cls, name, attrs, n, YES);\n}\n\n\n/***********************************************************************\n* look_up_class\n* Look up a class by name, and realize it.\n* Locking: acquires runtimeLock\n**********************************************************************/\nClass \nlook_up_class(const char *name, \n              bool includeUnconnected __attribute__((unused)), \n              bool includeClassHandler __attribute__((unused)))\n{\n    if (!name) return nil;\n\n    Class result;\n    bool unrealized;\n    {\n        mutex_locker_t lock(runtimeLock);\n        result = getClass(name);\n        unrealized = result  &&  !result->isRealized();\n    }\n    if (unrealized) {\n        mutex_locker_t lock(runtimeLock);\n        realizeClass(result);\n    }\n    return result;\n}\n\n\n/***********************************************************************\n* objc_duplicateClass\n* fixme\n* Locking: acquires runtimeLock\n**********************************************************************/\nClass \nobjc_duplicateClass(Class original, const char *name, \n                    size_t extraBytes)\n{\n    Class duplicate;\n\n    mutex_locker_t lock(runtimeLock);\n\n    checkIsKnownClass(original);\n\n    assert(original->isRealized());\n    assert(!original->isMetaClass());\n\n    duplicate = alloc_class_for_subclass(original, extraBytes);\n\n    duplicate->initClassIsa(original->ISA());\n    duplicate->superclass = original->superclass;\n\n    duplicate->cache.initializeToEmpty();\n\n    class_rw_t *rw = (class_rw_t *)calloc(sizeof(*original->data()), 1);\n    rw->flags = (original->data()->flags | RW_COPIED_RO | RW_REALIZING);\n    rw->version = original->data()->version;\n    rw->firstSubclass = nil;\n    rw->nextSiblingClass = nil;\n\n    duplicate->bits = original->bits;\n    duplicate->setData(rw);\n\n    rw->ro = (class_ro_t *)\n        memdup(original->data()->ro, sizeof(*original->data()->ro));\n    *(char **)&rw->ro->name = strdupIfMutable(name);\n\n    rw->methods = original->data()->methods.duplicate();\n\n    // fixme dies when categories are added to the base\n    rw->properties = original->data()->properties;\n    rw->protocols = original->data()->protocols;\n\n    duplicate->chooseClassArrayIndex();\n\n    if (duplicate->superclass) {\n        addSubclass(duplicate->superclass, duplicate);\n        // duplicate->isa == original->isa so don't addSubclass() for it\n    } else {\n        addRootClass(duplicate);\n    }\n\n    // Don't methodize class - construction above is correct\n\n    addNamedClass(duplicate, duplicate->data()->ro->name);\n    addClassTableEntry(duplicate, /*addMeta=*/false);\n    \n    if (PrintConnecting) {\n        _objc_inform(\"CLASS: realizing class '%s' (duplicate of %s) %p %p\", \n                     name, original->nameForLogging(), \n                     (void*)duplicate, duplicate->data()->ro);\n    }\n\n    duplicate->clearInfo(RW_REALIZING);\n\n    return duplicate;\n}\n\n/***********************************************************************\n* objc_initializeClassPair\n* Locking: runtimeLock must be write-locked by the caller\n**********************************************************************/\n\n// &UnsetLayout is the default ivar layout during class construction\nstatic const uint8_t UnsetLayout = 0;\n\nstatic void objc_initializeClassPair_internal(Class superclass, const char *name, Class cls, Class meta)\n{\n    runtimeLock.assertLocked();\n\n    class_ro_t *cls_ro_w, *meta_ro_w;\n    \n    cls->setData((class_rw_t *)calloc(sizeof(class_rw_t), 1));\n    meta->setData((class_rw_t *)calloc(sizeof(class_rw_t), 1));\n    cls_ro_w   = (class_ro_t *)calloc(sizeof(class_ro_t), 1);\n    meta_ro_w  = (class_ro_t *)calloc(sizeof(class_ro_t), 1);\n    cls->data()->ro = cls_ro_w;\n    meta->data()->ro = meta_ro_w;\n\n    // Set basic info\n\n    cls->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;\n    meta->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;\n    cls->data()->version = 0;\n    meta->data()->version = 7;\n\n    cls_ro_w->flags = 0;\n    meta_ro_w->flags = RO_META;\n    if (!superclass) {\n        cls_ro_w->flags |= RO_ROOT;\n        meta_ro_w->flags |= RO_ROOT;\n    }\n    if (superclass) {\n        cls_ro_w->instanceStart = superclass->unalignedInstanceSize();\n        meta_ro_w->instanceStart = superclass->ISA()->unalignedInstanceSize();\n        cls->setInstanceSize(cls_ro_w->instanceStart);\n        meta->setInstanceSize(meta_ro_w->instanceStart);\n    } else {\n        cls_ro_w->instanceStart = 0;\n        meta_ro_w->instanceStart = (uint32_t)sizeof(objc_class);\n        cls->setInstanceSize((uint32_t)sizeof(id));  // just an isa\n        meta->setInstanceSize(meta_ro_w->instanceStart);\n    }\n\n    cls_ro_w->name = strdupIfMutable(name);\n    meta_ro_w->name = strdupIfMutable(name);\n\n    cls_ro_w->ivarLayout = &UnsetLayout;\n    cls_ro_w->weakIvarLayout = &UnsetLayout;\n\n    meta->chooseClassArrayIndex();\n    cls->chooseClassArrayIndex();\n\n    // Connect to superclasses and metaclasses\n    cls->initClassIsa(meta);\n    if (superclass) {\n        meta->initClassIsa(superclass->ISA()->ISA());\n        cls->superclass = superclass;\n        meta->superclass = superclass->ISA();\n        addSubclass(superclass, cls);\n        addSubclass(superclass->ISA(), meta);\n    } else {\n        meta->initClassIsa(meta);\n        cls->superclass = Nil;\n        meta->superclass = cls;\n        addRootClass(cls);\n        addSubclass(cls, meta);\n    }\n\n    cls->cache.initializeToEmpty();\n    meta->cache.initializeToEmpty();\n    \n    addClassTableEntry(cls);\n}\n\n\n/***********************************************************************\n* verifySuperclass\n* Sanity-check the superclass provided to \n* objc_allocateClassPair, objc_initializeClassPair, or objc_readClassPair.\n**********************************************************************/\nbool\nverifySuperclass(Class superclass, bool rootOK)\n{\n    if (!superclass) {\n        // Superclass does not exist.\n        // If subclass may be a root class, this is OK.\n        // If subclass must not be a root class, this is bad.\n        return rootOK;\n    }\n\n    // Superclass must be realized.\n    if (! superclass->isRealized()) return false;\n\n    // Superclass must not be under construction.\n    if (superclass->data()->flags & RW_CONSTRUCTING) return false;\n\n    return true;\n}\n\n\n/***********************************************************************\n* objc_initializeClassPair\n**********************************************************************/\nClass objc_initializeClassPair(Class superclass, const char *name, Class cls, Class meta)\n{\n    mutex_locker_t lock(runtimeLock);\n\n    // Fail if the class name is in use.\n    // Fail if the superclass isn't kosher.\n    if (getClass(name)  ||  !verifySuperclass(superclass, true/*rootOK*/)) {\n        return nil;\n    }\n\n    objc_initializeClassPair_internal(superclass, name, cls, meta);\n\n    return cls;\n}\n\n\n/***********************************************************************\n* objc_allocateClassPair\n* fixme\n* Locking: acquires runtimeLock\n**********************************************************************/\nClass objc_allocateClassPair(Class superclass, const char *name, \n                             size_t extraBytes)\n{\n    Class cls, meta;\n\n    mutex_locker_t lock(runtimeLock);\n\n    // Fail if the class name is in use.\n    // Fail if the superclass isn't kosher.\n    if (getClass(name)  ||  !verifySuperclass(superclass, true/*rootOK*/)) {\n        return nil;\n    }\n\n    // Allocate new classes.\n    cls  = alloc_class_for_subclass(superclass, extraBytes);\n    meta = alloc_class_for_subclass(superclass, extraBytes);\n\n    // fixme mangle the name if it looks swift-y?\n    objc_initializeClassPair_internal(superclass, name, cls, meta);\n\n    return cls;\n}\n\n\n/***********************************************************************\n* objc_registerClassPair\n* fixme\n* Locking: acquires runtimeLock\n**********************************************************************/\nvoid objc_registerClassPair(Class cls)\n{\n    mutex_locker_t lock(runtimeLock);\n\n    checkIsKnownClass(cls);\n\n    if ((cls->data()->flags & RW_CONSTRUCTED)  ||\n        (cls->ISA()->data()->flags & RW_CONSTRUCTED)) \n    {\n        _objc_inform(\"objc_registerClassPair: class '%s' was already \"\n                     \"registered!\", cls->data()->ro->name);\n        return;\n    }\n\n    if (!(cls->data()->flags & RW_CONSTRUCTING)  ||  \n        !(cls->ISA()->data()->flags & RW_CONSTRUCTING))\n    {\n        _objc_inform(\"objc_registerClassPair: class '%s' was not \"\n                     \"allocated with objc_allocateClassPair!\", \n                     cls->data()->ro->name);\n        return;\n    }\n\n    // Clear \"under construction\" bit, set \"done constructing\" bit\n    cls->ISA()->changeInfo(RW_CONSTRUCTED, RW_CONSTRUCTING | RW_REALIZING);\n    cls->changeInfo(RW_CONSTRUCTED, RW_CONSTRUCTING | RW_REALIZING);\n\n    // Add to named class table.\n    addNamedClass(cls, cls->data()->ro->name);\n}\n\n\n/***********************************************************************\n* objc_readClassPair()\n* Read a class and metaclass as written by a compiler.\n* Assumes the class and metaclass are not referenced by other things \n* that might need to be fixed up (such as categories and subclasses).\n* Does not call +load.\n* Returns the class pointer, or nil.\n*\n* Locking: runtimeLock acquired by map_images\n**********************************************************************/\nClass objc_readClassPair(Class bits, const struct objc_image_info *info)\n{\n    mutex_locker_t lock(runtimeLock);\n\n    // No info bits are significant yet.\n    (void)info;\n\n    // Fail if the superclass isn't kosher.\n    bool rootOK = bits->data()->flags & RO_ROOT;\n    if (!verifySuperclass(bits->superclass, rootOK)){\n        return nil;\n    }\n\n    // Duplicate classes are allowed, just like they are for image loading.\n    // readClass will complain about the duplicate.\n\n    Class cls = readClass(bits, false/*bundle*/, false/*shared cache*/);\n    if (cls != bits) {\n        // This function isn't allowed to remap anything.\n        _objc_fatal(\"objc_readClassPair for class %s changed %p to %p\", \n                    cls->nameForLogging(), bits, cls);\n    }\n    realizeClass(cls);\n\n    return cls;\n}\n\n\n/***********************************************************************\n* detach_class\n* Disconnect a class from other data structures.\n* Exception: does not remove the class from the +load list\n* Call this before free_class.\n* Locking: runtimeLock must be held by the caller.\n**********************************************************************/\nstatic void detach_class(Class cls, bool isMeta)\n{\n    runtimeLock.assertLocked();\n\n    // categories not yet attached to this class\n    removeAllUnattachedCategoriesForClass(cls);\n\n    // superclass's subclass list\n    if (cls->isRealized()) {\n        Class supercls = cls->superclass;\n        if (supercls) {\n            removeSubclass(supercls, cls);\n        } else {\n            removeRootClass(cls);\n        }\n    }\n\n    // class tables and +load queue\n    if (!isMeta) {\n        removeNamedClass(cls, cls->mangledName());\n    }\n    NXHashRemove(allocatedClasses, cls);\n}\n\n\n/***********************************************************************\n* free_class\n* Frees a class's data structures.\n* Call this after detach_class.\n* Locking: runtimeLock must be held by the caller\n**********************************************************************/\nstatic void free_class(Class cls)\n{\n    runtimeLock.assertLocked();\n\n    if (! cls->isRealized()) return;\n\n    auto rw = cls->data();\n    auto ro = rw->ro;\n\n    cache_delete(cls);\n    \n    for (auto& meth : rw->methods) {\n        try_free(meth.types);\n    }\n    rw->methods.tryFree();\n    \n    const ivar_list_t *ivars = ro->ivars;\n    if (ivars) {\n        for (auto& ivar : *ivars) {\n            try_free(ivar.offset);\n            try_free(ivar.name);\n            try_free(ivar.type);\n        }\n        try_free(ivars);\n    }\n\n    for (auto& prop : rw->properties) {\n        try_free(prop.name);\n        try_free(prop.attributes);\n    }\n    rw->properties.tryFree();\n\n    rw->protocols.tryFree();\n    \n    try_free(ro->ivarLayout);\n    try_free(ro->weakIvarLayout);\n    try_free(ro->name);\n    try_free(ro);\n    try_free(rw);\n    try_free(cls);\n}\n\n\nvoid objc_disposeClassPair(Class cls)\n{\n    mutex_locker_t lock(runtimeLock);\n\n    checkIsKnownClass(cls);\n\n    if (!(cls->data()->flags & (RW_CONSTRUCTED|RW_CONSTRUCTING))  ||\n        !(cls->ISA()->data()->flags & (RW_CONSTRUCTED|RW_CONSTRUCTING))) \n    {\n        // class not allocated with objc_allocateClassPair\n        // disposing still-unregistered class is OK!\n        _objc_inform(\"objc_disposeClassPair: class '%s' was not \"\n                     \"allocated with objc_allocateClassPair!\", \n                     cls->data()->ro->name);\n        return;\n    }\n\n    if (cls->isMetaClass()) {\n        _objc_inform(\"objc_disposeClassPair: class '%s' is a metaclass, \"\n                     \"not a class!\", cls->data()->ro->name);\n        return;\n    }\n\n    // Shouldn't have any live subclasses.\n    if (cls->data()->firstSubclass) {\n        _objc_inform(\"objc_disposeClassPair: class '%s' still has subclasses, \"\n                     \"including '%s'!\", cls->data()->ro->name, \n                     cls->data()->firstSubclass->nameForLogging());\n    }\n    if (cls->ISA()->data()->firstSubclass) {\n        _objc_inform(\"objc_disposeClassPair: class '%s' still has subclasses, \"\n                     \"including '%s'!\", cls->data()->ro->name, \n                     cls->ISA()->data()->firstSubclass->nameForLogging());\n    }\n\n    // don't remove_class_from_loadable_list() \n    // - it's not there and we don't have the lock\n    detach_class(cls->ISA(), YES);\n    detach_class(cls, NO);\n    free_class(cls->ISA());\n    free_class(cls);\n}\n\n\n/***********************************************************************\n* objc_constructInstance\n* Creates an instance of `cls` at the location pointed to by `bytes`. \n* `bytes` must point to at least class_getInstanceSize(cls) bytes of \n*   well-aligned zero-filled memory.\n* The new object's isa is set. Any C++ constructors are called.\n* Returns `bytes` if successful. Returns nil if `cls` or `bytes` is \n*   nil, or if C++ constructors fail.\n* Note: class_createInstance() and class_createInstances() preflight this.\n**********************************************************************/\nid \nobjc_constructInstance(Class cls, void *bytes) \n{\n    if (!cls  ||  !bytes) return nil;\n\n    id obj = (id)bytes;\n\n    // Read class's info bits all at once for performance\n    bool hasCxxCtor = cls->hasCxxCtor();\n    bool hasCxxDtor = cls->hasCxxDtor();\n    bool fast = cls->canAllocNonpointer();\n    \n    if (fast) {\n        obj->initInstanceIsa(cls, hasCxxDtor);\n    } else {\n        obj->initIsa(cls);\n    }\n\n    if (hasCxxCtor) {\n        return object_cxxConstructFromClass(obj, cls);\n    } else {\n        return obj;\n    }\n}\n\n\n/***********************************************************************\n* class_createInstance\n* fixme\n* Locking: none\n**********************************************************************/\n\nstatic __attribute__((always_inline)) \nid\n_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, \n                              bool cxxConstruct = true, \n                              size_t *outAllocatedSize = nil)\n{\n    if (!cls) return nil;\n\n    assert(cls->isRealized());\n\n    // Read class's info bits all at once for performance\n    bool hasCxxCtor = cls->hasCxxCtor();\n    bool hasCxxDtor = cls->hasCxxDtor();\n    bool fast = cls->canAllocNonpointer();\n\n    size_t size = cls->instanceSize(extraBytes);\n    if (outAllocatedSize) *outAllocatedSize = size;\n\n    id obj;\n    if (!zone  &&  fast) {\n        obj = (id)calloc(1, size);\n        if (!obj) return nil;\n        obj->initInstanceIsa(cls, hasCxxDtor);\n    } \n    else {\n        if (zone) {\n            obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);\n        } else {\n            obj = (id)calloc(1, size);\n        }\n        if (!obj) return nil;\n\n        // Use raw pointer isa on the assumption that they might be \n        // doing something weird with the zone or RR.\n        obj->initIsa(cls);\n    }\n\n    if (cxxConstruct && hasCxxCtor) {\n        obj = _objc_constructOrFree(obj, cls);\n    }\n\n    return obj;\n}\n\n\nid \nclass_createInstance(Class cls, size_t extraBytes)\n{\n    return _class_createInstanceFromZone(cls, extraBytes, nil);\n}\n\n\n/***********************************************************************\n* class_createInstances\n* fixme\n* Locking: none\n**********************************************************************/\n#if SUPPORT_NONPOINTER_ISA\n#warning fixme optimize class_createInstances\n#endif\nunsigned \nclass_createInstances(Class cls, size_t extraBytes, \n                      id *results, unsigned num_requested)\n{\n    return _class_createInstancesFromZone(cls, extraBytes, nil, \n                                          results, num_requested);\n}\n\n/***********************************************************************\n* object_copyFromZone\n* fixme\n* Locking: none\n**********************************************************************/\nstatic id \n_object_copyFromZone(id oldObj, size_t extraBytes, void *zone)\n{\n    if (!oldObj) return nil;\n    if (oldObj->isTaggedPointer()) return oldObj;\n\n    // fixme this doesn't handle C++ ivars correctly (#4619414)\n\n    Class cls = oldObj->ISA();\n    size_t size;\n    id obj = _class_createInstanceFromZone(cls, extraBytes, zone, false, &size);\n    if (!obj) return nil;\n\n    // Copy everything except the isa, which was already set above.\n    uint8_t *copyDst = (uint8_t *)obj + sizeof(Class);\n    uint8_t *copySrc = (uint8_t *)oldObj + sizeof(Class);\n    size_t copySize = size - sizeof(Class);\n    memmove(copyDst, copySrc, copySize);\n\n    fixupCopiedIvars(obj, oldObj);\n\n    return obj;\n}\n\n\n/***********************************************************************\n* object_copy\n* fixme\n* Locking: none\n**********************************************************************/\nid \nobject_copy(id oldObj, size_t extraBytes)\n{\n    return _object_copyFromZone(oldObj, extraBytes, malloc_default_zone());\n}\n\n\n#if SUPPORT_ZONES\n\n/***********************************************************************\n* class_createInstanceFromZone\n* fixme\n* Locking: none\n**********************************************************************/\nid\nclass_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)\n{\n    return _class_createInstanceFromZone(cls, extraBytes, zone);\n}\n\n/***********************************************************************\n* object_copyFromZone\n* fixme\n* Locking: none\n**********************************************************************/\nid \nobject_copyFromZone(id oldObj, size_t extraBytes, void *zone)\n{\n    return _object_copyFromZone(oldObj, extraBytes, zone);\n}\n\n#endif\n\n\n/***********************************************************************\n* objc_destructInstance\n* Destroys an instance without freeing memory. \n* Calls C++ destructors.\n* Calls ARC ivar cleanup.\n* Removes associative references.\n* Returns `obj`. Does nothing if `obj` is nil.\n**********************************************************************/\nvoid *objc_destructInstance(id obj) \n{\n    if (obj) {\n        // Read all of the flags at once for performance.\n        bool cxx = obj->hasCxxDtor();\n        bool assoc = obj->hasAssociatedObjects();\n\n        // This order is important.\n        if (cxx) object_cxxDestruct(obj);\n        if (assoc) _object_remove_assocations(obj);\n        obj->clearDeallocating();\n    }\n\n    return obj;\n}\n\n\n/***********************************************************************\n* object_dispose\n* fixme\n* Locking: none\n**********************************************************************/\nid \nobject_dispose(id obj)\n{\n    if (!obj) return nil;\n\n    objc_destructInstance(obj);    \n    free(obj);\n\n    return nil;\n}\n\n\n/***********************************************************************\n* _objc_getFreedObjectClass\n* fixme\n* Locking: none\n**********************************************************************/\nClass _objc_getFreedObjectClass (void)\n{\n    return nil;\n}\n\n\n\n/***********************************************************************\n* Tagged pointer objects.\n*\n* Tagged pointer objects store the class and the object value in the \n* object pointer; the \"pointer\" does not actually point to anything.\n* \n* Tagged pointer objects currently use this representation:\n* (LSB)\n*  1 bit   set if tagged, clear if ordinary object pointer\n*  3 bits  tag index\n* 60 bits  payload\n* (MSB)\n* The tag index defines the object's class. \n* The payload format is defined by the object's class.\n*\n* If the tag index is 0b111, the tagged pointer object uses an \n* \"extended\" representation, allowing more classes but with smaller payloads:\n* (LSB)\n*  1 bit   set if tagged, clear if ordinary object pointer\n*  3 bits  0b111\n*  8 bits  extended tag index\n* 52 bits  payload\n* (MSB)\n*\n* Some architectures reverse the MSB and LSB in these representations.\n*\n* This representation is subject to change. Representation-agnostic SPI is:\n* objc-internal.h for class implementers.\n* objc-gdb.h for debuggers.\n**********************************************************************/\n#if !SUPPORT_TAGGED_POINTERS\n\n// These variables are always provided for debuggers.\nuintptr_t objc_debug_taggedpointer_obfuscator = 0;\nuintptr_t objc_debug_taggedpointer_mask = 0;\nunsigned  objc_debug_taggedpointer_slot_shift = 0;\nuintptr_t objc_debug_taggedpointer_slot_mask = 0;\nunsigned  objc_debug_taggedpointer_payload_lshift = 0;\nunsigned  objc_debug_taggedpointer_payload_rshift = 0;\nClass objc_debug_taggedpointer_classes[1] = { nil };\n\nuintptr_t objc_debug_taggedpointer_ext_mask = 0;\nunsigned  objc_debug_taggedpointer_ext_slot_shift = 0;\nuintptr_t objc_debug_taggedpointer_ext_slot_mask = 0;\nunsigned  objc_debug_taggedpointer_ext_payload_lshift = 0;\nunsigned  objc_debug_taggedpointer_ext_payload_rshift = 0;\nClass objc_debug_taggedpointer_ext_classes[1] = { nil };\n\nstatic void\ndisableTaggedPointers() { }\n\nstatic void\ninitializeTaggedPointerObfuscator(void) { }\n\n#else\n\n// The \"slot\" used in the class table and given to the debugger \n// includes the is-tagged bit. This makes objc_msgSend faster.\n// The \"ext\" representation doesn't do that.\n\nuintptr_t objc_debug_taggedpointer_obfuscator;\nuintptr_t objc_debug_taggedpointer_mask = _OBJC_TAG_MASK;\nunsigned  objc_debug_taggedpointer_slot_shift = _OBJC_TAG_SLOT_SHIFT;\nuintptr_t objc_debug_taggedpointer_slot_mask = _OBJC_TAG_SLOT_MASK;\nunsigned  objc_debug_taggedpointer_payload_lshift = _OBJC_TAG_PAYLOAD_LSHIFT;\nunsigned  objc_debug_taggedpointer_payload_rshift = _OBJC_TAG_PAYLOAD_RSHIFT;\n// objc_debug_taggedpointer_classes is defined in objc-msg-*.s\n\nuintptr_t objc_debug_taggedpointer_ext_mask = _OBJC_TAG_EXT_MASK;\nunsigned  objc_debug_taggedpointer_ext_slot_shift = _OBJC_TAG_EXT_SLOT_SHIFT;\nuintptr_t objc_debug_taggedpointer_ext_slot_mask = _OBJC_TAG_EXT_SLOT_MASK;\nunsigned  objc_debug_taggedpointer_ext_payload_lshift = _OBJC_TAG_EXT_PAYLOAD_LSHIFT;\nunsigned  objc_debug_taggedpointer_ext_payload_rshift = _OBJC_TAG_EXT_PAYLOAD_RSHIFT;\n// objc_debug_taggedpointer_ext_classes is defined in objc-msg-*.s\n\nstatic void\ndisableTaggedPointers()\n{\n    objc_debug_taggedpointer_mask = 0;\n    objc_debug_taggedpointer_slot_shift = 0;\n    objc_debug_taggedpointer_slot_mask = 0;\n    objc_debug_taggedpointer_payload_lshift = 0;\n    objc_debug_taggedpointer_payload_rshift = 0;\n\n    objc_debug_taggedpointer_ext_mask = 0;\n    objc_debug_taggedpointer_ext_slot_shift = 0;\n    objc_debug_taggedpointer_ext_slot_mask = 0;\n    objc_debug_taggedpointer_ext_payload_lshift = 0;\n    objc_debug_taggedpointer_ext_payload_rshift = 0;\n}\n\n\n// Returns a pointer to the class's storage in the tagged class arrays.\n// Assumes the tag is a valid basic tag.\nstatic Class *\nclassSlotForBasicTagIndex(objc_tag_index_t tag)\n{\n    uintptr_t tagObfuscator = ((objc_debug_taggedpointer_obfuscator\n                                >> _OBJC_TAG_INDEX_SHIFT)\n                               & _OBJC_TAG_INDEX_MASK);\n    uintptr_t obfuscatedTag = tag ^ tagObfuscator;\n    // Array index in objc_tag_classes includes the tagged bit itself\n#if SUPPORT_MSB_TAGGED_POINTERS\n    return &objc_tag_classes[0x8 | obfuscatedTag];\n#else\n    return &objc_tag_classes[(obfuscatedTag << 1) | 1];\n#endif\n}\n\n\n// Returns a pointer to the class's storage in the tagged class arrays, \n// or nil if the tag is out of range.\nstatic Class *  \nclassSlotForTagIndex(objc_tag_index_t tag)\n{\n    if (tag >= OBJC_TAG_First60BitPayload && tag <= OBJC_TAG_Last60BitPayload) {\n        return classSlotForBasicTagIndex(tag);\n    }\n\n    if (tag >= OBJC_TAG_First52BitPayload && tag <= OBJC_TAG_Last52BitPayload) {\n        int index = tag - OBJC_TAG_First52BitPayload;\n        uintptr_t tagObfuscator = ((objc_debug_taggedpointer_obfuscator\n                                    >> _OBJC_TAG_EXT_INDEX_SHIFT)\n                                   & _OBJC_TAG_EXT_INDEX_MASK);\n        return &objc_tag_ext_classes[index ^ tagObfuscator];\n    }\n\n    return nil;\n}\n\n/***********************************************************************\n* initializeTaggedPointerObfuscator\n* Initialize objc_debug_taggedpointer_obfuscator with randomness.\n*\n* The tagged pointer obfuscator is intended to make it more difficult\n* for an attacker to construct a particular object as a tagged pointer,\n* in the presence of a buffer overflow or other write control over some\n* memory. The obfuscator is XORed with the tagged pointers when setting\n* or retrieving payload values. They are filled with randomness on first\n* use.\n**********************************************************************/\nstatic void\ninitializeTaggedPointerObfuscator(void)\n{\n    if (sdkIsOlderThan(10_14, 12_0, 12_0, 5_0, 3_0) ||\n        // Set the obfuscator to zero for apps linked against older SDKs,\n        // in case they're relying on the tagged pointer representation.\n        DisableTaggedPointerObfuscation) {\n        objc_debug_taggedpointer_obfuscator = 0;\n    } else {\n        // Pull random data into the variable, then shift away all non-payload bits.\n        arc4random_buf(&objc_debug_taggedpointer_obfuscator,\n                       sizeof(objc_debug_taggedpointer_obfuscator));\n        objc_debug_taggedpointer_obfuscator &= ~_OBJC_TAG_MASK;\n    }\n}\n\n\n/***********************************************************************\n* _objc_registerTaggedPointerClass\n* Set the class to use for the given tagged pointer index.\n* Aborts if the tag is out of range, or if the tag is already \n* used by some other class.\n**********************************************************************/\nvoid\n_objc_registerTaggedPointerClass(objc_tag_index_t tag, Class cls)\n{\n    if (objc_debug_taggedpointer_mask == 0) {\n        _objc_fatal(\"tagged pointers are disabled\");\n    }\n\n    Class *slot = classSlotForTagIndex(tag);\n    if (!slot) {\n        _objc_fatal(\"tag index %u is invalid\", (unsigned int)tag);\n    }\n\n    Class oldCls = *slot;\n    \n    if (cls  &&  oldCls  &&  cls != oldCls) {\n        _objc_fatal(\"tag index %u used for two different classes \"\n                    \"(was %p %s, now %p %s)\", tag, \n                    oldCls, oldCls->nameForLogging(), \n                    cls, cls->nameForLogging());\n    }\n\n    *slot = cls;\n\n    // Store a placeholder class in the basic tag slot that is \n    // reserved for the extended tag space, if it isn't set already.\n    // Do this lazily when the first extended tag is registered so \n    // that old debuggers characterize bogus pointers correctly more often.\n    if (tag < OBJC_TAG_First60BitPayload || tag > OBJC_TAG_Last60BitPayload) {\n        Class *extSlot = classSlotForBasicTagIndex(OBJC_TAG_RESERVED_7);\n        if (*extSlot == nil) {\n            extern objc_class OBJC_CLASS_$___NSUnrecognizedTaggedPointer;\n            *extSlot = (Class)&OBJC_CLASS_$___NSUnrecognizedTaggedPointer;\n        }\n    }\n}\n\n\n/***********************************************************************\n* _objc_getClassForTag\n* Returns the class that is using the given tagged pointer tag.\n* Returns nil if no class is using that tag or the tag is out of range.\n**********************************************************************/\nClass\n_objc_getClassForTag(objc_tag_index_t tag)\n{\n    Class *slot = classSlotForTagIndex(tag);\n    if (slot) return *slot;\n    else return nil;\n}\n\n#endif\n\n\n#if SUPPORT_FIXUP\n\nOBJC_EXTERN void objc_msgSend_fixup(void);\nOBJC_EXTERN void objc_msgSendSuper2_fixup(void);\nOBJC_EXTERN void objc_msgSend_stret_fixup(void);\nOBJC_EXTERN void objc_msgSendSuper2_stret_fixup(void);\n#if defined(__i386__)  ||  defined(__x86_64__)\nOBJC_EXTERN void objc_msgSend_fpret_fixup(void);\n#endif\n#if defined(__x86_64__)\nOBJC_EXTERN void objc_msgSend_fp2ret_fixup(void);\n#endif\n\nOBJC_EXTERN void objc_msgSend_fixedup(void);\nOBJC_EXTERN void objc_msgSendSuper2_fixedup(void);\nOBJC_EXTERN void objc_msgSend_stret_fixedup(void);\nOBJC_EXTERN void objc_msgSendSuper2_stret_fixedup(void);\n#if defined(__i386__)  ||  defined(__x86_64__)\nOBJC_EXTERN void objc_msgSend_fpret_fixedup(void);\n#endif\n#if defined(__x86_64__)\nOBJC_EXTERN void objc_msgSend_fp2ret_fixedup(void);\n#endif\n\n/***********************************************************************\n* fixupMessageRef\n* Repairs an old vtable dispatch call site. \n* vtable dispatch itself is not supported.\n**********************************************************************/\nstatic void \nfixupMessageRef(message_ref_t *msg)\n{    \n    msg->sel = sel_registerName((const char *)msg->sel);\n\n    if (msg->imp == &objc_msgSend_fixup) { \n        if (msg->sel == SEL_alloc) {\n            msg->imp = (IMP)&objc_alloc;\n        } else if (msg->sel == SEL_allocWithZone) {\n            msg->imp = (IMP)&objc_allocWithZone;\n        } else if (msg->sel == SEL_retain) {\n            msg->imp = (IMP)&objc_retain;\n        } else if (msg->sel == SEL_release) {\n            msg->imp = (IMP)&objc_release;\n        } else if (msg->sel == SEL_autorelease) {\n            msg->imp = (IMP)&objc_autorelease;\n        } else {\n            msg->imp = &objc_msgSend_fixedup;\n        }\n    } \n    else if (msg->imp == &objc_msgSendSuper2_fixup) { \n        msg->imp = &objc_msgSendSuper2_fixedup;\n    } \n    else if (msg->imp == &objc_msgSend_stret_fixup) { \n        msg->imp = &objc_msgSend_stret_fixedup;\n    } \n    else if (msg->imp == &objc_msgSendSuper2_stret_fixup) { \n        msg->imp = &objc_msgSendSuper2_stret_fixedup;\n    } \n#if defined(__i386__)  ||  defined(__x86_64__)\n    else if (msg->imp == &objc_msgSend_fpret_fixup) { \n        msg->imp = &objc_msgSend_fpret_fixedup;\n    } \n#endif\n#if defined(__x86_64__)\n    else if (msg->imp == &objc_msgSend_fp2ret_fixup) { \n        msg->imp = &objc_msgSend_fp2ret_fixedup;\n    } \n#endif\n}\n\n// SUPPORT_FIXUP\n#endif\n\n\n// ProKit SPI\nstatic Class setSuperclass(Class cls, Class newSuper)\n{\n    Class oldSuper;\n\n    runtimeLock.assertLocked();\n\n    assert(cls->isRealized());\n    assert(newSuper->isRealized());\n\n    oldSuper = cls->superclass;\n    removeSubclass(oldSuper, cls);\n    removeSubclass(oldSuper->ISA(), cls->ISA());\n\n    cls->superclass = newSuper;\n    cls->ISA()->superclass = newSuper->ISA();\n    addSubclass(newSuper, cls);\n    addSubclass(newSuper->ISA(), cls->ISA());\n\n    // Flush subclass's method caches.\n    flushCaches(cls);\n    flushCaches(cls->ISA());\n    \n    return oldSuper;\n}\n\n\nClass class_setSuperclass(Class cls, Class newSuper)\n{\n    mutex_locker_t lock(runtimeLock);\n    return setSuperclass(cls, newSuper);\n}\n\n\n// __OBJC2__\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-runtime-old.h",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _OBJC_RUNTIME_OLD_H\n#define _OBJC_RUNTIME_OLD_H\n\n#include \"objc-private.h\"\n\n#define CLS_CLASS\t\t0x1\n#define CLS_META\t\t0x2\n#define CLS_INITIALIZED\t\t0x4\n#define CLS_POSING\t\t0x8\n#define CLS_MAPPED\t\t0x10\n#define CLS_FLUSH_CACHE\t\t0x20\n#define CLS_GROW_CACHE\t\t0x40\n#define CLS_NEED_BIND\t\t0x80\n#define CLS_METHOD_ARRAY        0x100\n// the JavaBridge constructs classes with these markers\n#define CLS_JAVA_HYBRID\t\t0x200\n#define CLS_JAVA_CLASS\t\t0x400\n// thread-safe +initialize\n#define CLS_INITIALIZING\t0x800\n// bundle unloading\n#define CLS_FROM_BUNDLE\t\t0x1000\n// C++ ivar support\n#define CLS_HAS_CXX_STRUCTORS\t0x2000\n// Lazy method list arrays\n#define CLS_NO_METHOD_ARRAY\t0x4000\n// +load implementation\n#define CLS_HAS_LOAD_METHOD     0x8000\n// objc_allocateClassPair API\n#define CLS_CONSTRUCTING        0x10000\n// visibility=hidden\n#define CLS_HIDDEN              0x20000\n// available for use; was CLS_FINALIZE_ON_MAIN_THREAD\n#define CLS_40000               0x40000\n// Lazy property list arrays\n#define CLS_NO_PROPERTY_ARRAY\t0x80000\n// +load implementation\n#define CLS_CONNECTED           0x100000\n#define CLS_LOADED              0x200000\n// objc_allocateClassPair API\n#define CLS_CONSTRUCTED         0x400000\n// class is leaf for cache flushing\n#define CLS_LEAF                0x800000\n// class instances may have associative references\n#define CLS_INSTANCES_HAVE_ASSOCIATED_OBJECTS 0x1000000\n// available for use; was CLS_HAS_INSTANCE_SPECIFIC_LAYOUT\n#define CLS_2000000 0x2000000\n// class compiled with ARC\n#define CLS_IS_ARC              0x4000000\n// class is not ARC but has ARC-style weak ivar layout\n#define CLS_HAS_WEAK_WITHOUT_ARC 0x8000000\n\n\n// Terminator for array of method lists\n#define END_OF_METHODS_LIST ((struct old_method_list*)-1)\n\n#define ISCLASS(cls)\t\t(((cls)->info & CLS_CLASS) != 0)\n#define ISMETA(cls)\t\t(((cls)->info & CLS_META) != 0)\n#define GETMETA(cls)\t\t(ISMETA(cls) ? (cls) : (cls)->ISA())\n\n\nstruct old_class_ext {\n    uint32_t size;\n    const uint8_t *weak_ivar_layout;\n    struct old_property_list **propertyLists;\n};\n\nstruct old_category {\n    char *category_name;\n    char *class_name;\n    struct old_method_list *instance_methods;\n    struct old_method_list *class_methods;\n    struct old_protocol_list *protocols;\n    // Fields below this point are in version 7 or later only.\n    uint32_t size;\n    struct old_property_list *instance_properties;\n    // Check size for fields below this point.\n    struct old_property_list *class_properties;\n\n    bool hasClassPropertiesField() const { \n        return size >= offsetof(old_category, class_properties) + sizeof(class_properties);\n    }\n};\n\nstruct old_ivar {\n    char *ivar_name;\n    char *ivar_type;\n    int ivar_offset;\n#ifdef __LP64__\n    int space;\n#endif\n};\n\nstruct old_ivar_list {\n    int ivar_count;\n#ifdef __LP64__\n    int space;\n#endif\n    /* variable length structure */\n    struct old_ivar ivar_list[1];\n};\n\n\nstruct old_method {\n    SEL method_name;\n    char *method_types;\n    IMP method_imp;\n};\n\nstruct old_method_list {\n    void *obsolete;\n\n    int method_count;\n#ifdef __LP64__\n    int space;\n#endif\n    /* variable length structure */\n    struct old_method method_list[1];\n};\n\nstruct old_protocol {\n    Class isa;\n    const char *protocol_name;\n    struct old_protocol_list *protocol_list;\n    struct objc_method_description_list *instance_methods;\n    struct objc_method_description_list *class_methods;\n};\n\nstruct old_protocol_list {\n    struct old_protocol_list *next;\n    long count;\n    struct old_protocol *list[1];\n};\n\nstruct old_protocol_ext {\n    uint32_t size;\n    struct objc_method_description_list *optional_instance_methods;\n    struct objc_method_description_list *optional_class_methods;\n    struct old_property_list *instance_properties;\n    const char **extendedMethodTypes;\n    struct old_property_list *class_properties;\n\n    bool hasClassPropertiesField() const { \n        return size >= offsetof(old_protocol_ext, class_properties) + sizeof(class_properties);\n    }\n};\n\n\nstruct old_property {\n    const char *name;\n    const char *attributes;\n};\n\nstruct old_property_list {\n    uint32_t entsize;\n    uint32_t count;\n    struct old_property first;\n};\n\n\nstruct objc_class : objc_object {\n    Class superclass;\n    const char *name;\n    uint32_t version;\n    uint32_t info;\n    uint32_t instance_size;\n    struct old_ivar_list *ivars;\n    struct old_method_list **methodLists;\n    Cache cache;\n    struct old_protocol_list *protocols;\n    // CLS_EXT only\n    const uint8_t *ivar_layout;\n    struct old_class_ext *ext;\n\n    void setInfo(uint32_t set) {\n        OSAtomicOr32Barrier(set, (volatile uint32_t *)&info);\n    }\n\n    void clearInfo(uint32_t clear) {\n        OSAtomicXor32Barrier(clear, (volatile uint32_t *)&info);\n    }\n\n\n    // set and clear must not overlap\n    void changeInfo(uint32_t set, uint32_t clear) {\n        assert((set & clear) == 0);\n\n        uint32_t oldf, newf;\n        do {\n            oldf = this->info;\n            newf = (oldf | set) & ~clear;\n        } while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&info));\n    }\n\n    bool hasCxxCtor() {\n        // set_superclass propagates the flag from the superclass.\n        return info & CLS_HAS_CXX_STRUCTORS;\n    }\n\n    bool hasCxxDtor() {\n        return hasCxxCtor();  // one bit for both ctor and dtor\n    }\n\n    // Return YES if the class's ivars are managed by ARC, \n    // or the class is MRC but has ARC-style weak ivars.\n    bool hasAutomaticIvars() {\n        return info & (CLS_IS_ARC | CLS_HAS_WEAK_WITHOUT_ARC);\n    }\n\n    // Return YES if the class's ivars are managed by ARC.\n    bool isARC() {\n        return info & CLS_IS_ARC;\n    }\n\n    bool hasCustomRR() { \n        return true;\n    }\n    void setHasCustomRR(bool = false) { }\n    void setHasDefaultRR() { }\n    void printCustomRR(bool) { }\n\n    bool hasCustomAWZ() { \n        return true;\n    }\n    void setHasCustomAWZ(bool = false) { }\n    void setHasDefaultAWZ() { }\n    void printCustomAWZ(bool) { }\n\n    bool instancesHaveAssociatedObjects() {\n        return info & CLS_INSTANCES_HAVE_ASSOCIATED_OBJECTS;\n    }\n\n    void setInstancesHaveAssociatedObjects() {\n        setInfo(CLS_INSTANCES_HAVE_ASSOCIATED_OBJECTS);\n    }\n\n    bool shouldGrowCache() {\n        return info & CLS_GROW_CACHE;\n    }\n\n    void setShouldGrowCache(bool grow) {\n        if (grow) setInfo(CLS_GROW_CACHE);\n        else clearInfo(CLS_GROW_CACHE);\n    }\n\n    // +initialize bits are stored on the metaclass only\n    bool isInitializing() {\n        return getMeta()->info & CLS_INITIALIZING;\n    }\n\n    // +initialize bits are stored on the metaclass only\n    void setInitializing() {\n        getMeta()->setInfo(CLS_INITIALIZING);\n    }\n\n    // +initialize bits are stored on the metaclass only\n    bool isInitialized() {\n        return getMeta()->info & CLS_INITIALIZED;\n    }\n\n    // +initialize bits are stored on the metaclass only\n    void setInitialized() {\n        getMeta()->changeInfo(CLS_INITIALIZED, CLS_INITIALIZING);\n    }\n\n    bool isLoadable() {\n        // A class registered for +load is ready for +load to be called\n        // if it is connected.\n        return isConnected();\n    }\n\n    IMP getLoadMethod();\n\n    bool isFuture();\n\n    bool isConnected();\n\n    const char *mangledName() { return name; }\n    const char *demangledName() { return name; }\n    const char *nameForLogging() { return name; }\n    \n    bool isRootClass() {\n        return superclass == nil;\n    }\n\n    bool isRootMetaclass() {\n        return ISA() == (Class)this;\n    }\n\n    bool isMetaClass() {\n        return info & CLS_META;\n    }\n\n    // NOT identical to this->ISA() when this is a metaclass\n    Class getMeta() {\n        if (isMetaClass()) return (Class)this;\n        else return this->ISA();\n    }\n\n    // May be unaligned depending on class's ivars.\n    uint32_t unalignedInstanceStart() {\n        // This is not simply superclass->instance_size.\n        // superclass->instance_size is padded to its sizeof() boundary, \n        // which may envelop one of this class's ivars. \n        // That in turn would break ARC-style ivar layouts.\n        // Instead, we use the address of this class's first ivar when possible.\n        if (!superclass) return 0;\n        if (!ivars || ivars->ivar_count == 0) return superclass->instance_size;\n        return ivars->ivar_list[0].ivar_offset;\n    }\n\n    // Class's instance start rounded up to a pointer-size boundary.\n    // This is used for ARC layout bitmaps.\n    uint32_t alignedInstanceStart() {\n        return word_align(unalignedInstanceStart());\n    }\n\n\n    // May be unaligned depending on class's ivars.\n    uint32_t unalignedInstanceSize() {\n        return instance_size;\n    }\n\n    // Class's ivar size rounded up to a pointer-size boundary.\n    uint32_t alignedInstanceSize() {\n        return word_align(unalignedInstanceSize());\n    }\n\n    size_t instanceSize(size_t extraBytes) {\n        size_t size = alignedInstanceSize() + extraBytes;\n        // CF requires all objects be at least 16 bytes.\n        if (size < 16) size = 16;\n        return size;\n    }\n\n};\n\n\n#include \"hashtable2.h\"\n\n__BEGIN_DECLS\n\n#define oldprotocol(proto) ((struct old_protocol *)proto)\n#define oldmethod(meth) ((struct old_method *)meth)\n#define oldcategory(cat) ((struct old_category *)cat)\n#define oldivar(ivar) ((struct old_ivar *)ivar)\n#define oldproperty(prop) ((struct old_property *)prop)\n\nextern NXHashTable *class_hash;\n\nextern void unload_class(Class cls);\n\nextern IMP lookupNamedMethodInMethodList(struct old_method_list *mlist, const char *meth_name);\nextern void _objc_insertMethods(Class cls, struct old_method_list *mlist, struct old_category *cat);\nextern void _objc_removeMethods(Class cls, struct old_method_list *mlist);\nextern void _objc_flush_caches (Class cls);\nextern bool _class_addProperties(Class cls, struct old_property_list *additions);\nextern bool _class_hasLoadMethod(Class cls);\nextern void change_class_references(Class imposter, Class original, Class copy, bool changeSuperRefs);\nextern void flush_marked_caches(void);\nextern void set_superclass(Class cls, Class supercls, bool cls_is_new);\nextern void try_free(const void *p);\n\nextern struct old_property *property_list_nth(const struct old_property_list *plist, uint32_t i);\nextern struct old_property **copyPropertyList(struct old_property_list *plist, unsigned int *outCount);\n\nextern struct objc_method_description * lookup_protocol_method(struct old_protocol *proto, SEL aSel, bool isRequiredMethod, bool isInstanceMethod, bool recursive);\n\n// used by flush_caches outside objc-cache.m\nextern void _cache_flush(Class cls);\n#ifdef OBJC_INSTRUMENTED\nextern unsigned int LinearFlushCachesCount;\nextern unsigned int LinearFlushCachesVisitedCount;\nextern unsigned int MaxLinearFlushCachesVisitedCount;\nextern unsigned int NonlinearFlushCachesCount;\nextern unsigned int NonlinearFlushCachesClassCount;\nextern unsigned int NonlinearFlushCachesVisitedCount;\nextern unsigned int MaxNonlinearFlushCachesVisitedCount;\nextern unsigned int IdealFlushCachesCount;\nextern unsigned int MaxIdealFlushCachesCount;\n#endif\n\n__END_DECLS\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-runtime-old.mm",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-runtime-old.m\n* Support for old-ABI classes and images.\n**********************************************************************/\n\n/***********************************************************************\n * Class loading and connecting (GrP 2004-2-11)\n *\n * When images are loaded (during program startup or otherwise), the \n * runtime needs to load classes and categories from the images, connect \n * classes to superclasses and categories to parent classes, and call \n * +load methods. \n * \n * The Objective-C runtime can cope with classes arriving in any order. \n * That is, a class may be discovered by the runtime before some \n * superclass is known. To handle out-of-order class loads, the \n * runtime uses a \"pending class\" system. \n * \n * (Historical note)\n * Panther and earlier: many classes arrived out-of-order because of \n *   the poorly-ordered callback from dyld. However, the runtime's \n *   pending mechanism only handled \"missing superclass\" and not \n *   \"present superclass but missing higher class\". See Radar #3225652. \n * Tiger: The runtime's pending mechanism was augmented to handle \n *   arbitrary missing classes. In addition, dyld was rewritten and \n *   now sends the callbacks in strictly bottom-up link order. \n *   The pending mechanism may now be needed only for rare and \n *   hard to construct programs.\n * (End historical note)\n * \n * A class when first seen in an image is considered \"unconnected\". \n * It is stored in `unconnected_class_hash`. If all of the class's \n * superclasses exist and are already \"connected\", then the new class \n * can be connected to its superclasses and moved to `class_hash` for \n * normal use. Otherwise, the class waits in `unconnected_class_hash` \n * until the superclasses finish connecting.\n * \n * A \"connected\" class is \n * (1) in `class_hash`, \n * (2) connected to its superclasses, \n * (3) has no unconnected superclasses, \n * (4) is otherwise initialized and ready for use, and \n * (5) is eligible for +load if +load has not already been called. \n * \n * An \"unconnected\" class is \n * (1) in `unconnected_class_hash`, \n * (2) not connected to its superclasses, \n * (3) has an immediate superclass which is either missing or unconnected, \n * (4) is not ready for use, and \n * (5) is not yet eligible for +load.\n * \n * Image mapping is NOT CURRENTLY THREAD-SAFE with respect to just about \n * anything. Image mapping IS RE-ENTRANT in several places: superclass \n * lookup may cause ZeroLink to load another image, and +load calls may \n * cause dyld to load another image.\n * \n * Image mapping sequence:\n * \n * Read all classes in all new images. \n *   Add them all to unconnected_class_hash. \n *   Note any +load implementations before categories are attached.\n *   Attach any pending categories.\n * Read all categories in all new images. \n *   Attach categories whose parent class exists (connected or not), \n *     and pend the rest.\n *   Mark them all eligible for +load (if implemented), even if the \n *     parent class is missing.\n * Try to connect all classes in all new images. \n *   If the superclass is missing, pend the class\n *   If the superclass is unconnected, try to recursively connect it\n *   If the superclass is connected:\n *     connect the class\n *     mark the class eligible for +load, if implemented\n *     fix up any pended classrefs referring to the class\n *     connect any pended subclasses of the class\n * Resolve selector refs and class refs in all new images.\n *   Class refs whose classes still do not exist are pended.\n * Fix up protocol objects in all new images.\n * Call +load for classes and categories.\n *   May include classes or categories that are not in these images, \n *     but are newly eligible because of these image.\n *   Class +loads will be called superclass-first because of the \n *     superclass-first nature of the connecting process.\n *   Category +load needs to be deferred until the parent class is \n *     connected and has had its +load called.\n * \n * Performance: all classes are read before any categories are read. \n * Fewer categories need be pended for lack of a parent class.\n * \n * Performance: all categories are attempted to be attached before \n * any classes are connected. Fewer class caches need be flushed. \n * (Unconnected classes and their respective subclasses are guaranteed \n * to be un-messageable, so their caches will be empty.)\n * \n * Performance: all classes are read before any classes are connected. \n * Fewer classes need be pended for lack of a superclass.\n * \n * Correctness: all selector and class refs are fixed before any \n * protocol fixups or +load methods. libobjc itself contains selector \n * and class refs which are used in protocol fixup and +load.\n * \n * Correctness: +load methods are scheduled in bottom-up link order. \n * This constraint is in addition to superclass order. Some +load \n * implementations expect to use another class in a linked-to library, \n * even if the two classes don't share a direct superclass relationship.\n * \n * Correctness: all classes are scanned for +load before any categories \n * are attached. Otherwise, if a category implements +load and its class \n * has no class methods, the class's +load scan would find the category's \n * +load method, which would then be called twice.\n *\n * Correctness: pended class refs are not fixed up until the class is \n * connected. Classes with missing weak superclasses remain unconnected. \n * Class refs to classes with missing weak superclasses must be nil. \n * Therefore class refs to unconnected classes must remain un-fixed.\n * \n **********************************************************************/\n\n#if !__OBJC2__\n\n#include \"objc-private.h\"\n#include \"objc-runtime-old.h\"\n#include \"objc-file-old.h\"\n#include \"objc-cache-old.h\"\n#include \"objc-loadmethod.h\"\n\n\ntypedef struct _objc_unresolved_category\n{\n    struct _objc_unresolved_category *next;\n    old_category *cat;  // may be nil\n    long version;\n} _objc_unresolved_category;\n\ntypedef struct _PendingSubclass\n{\n    Class subclass;  // subclass to finish connecting; may be nil\n    struct _PendingSubclass *next;\n} PendingSubclass;\n\ntypedef struct _PendingClassRef\n{\n    Class *ref;  // class reference to fix up; may be nil\n                             // (ref & 1) is a metaclass reference\n    struct _PendingClassRef *next;\n} PendingClassRef;\n\n\nstatic uintptr_t classHash(void *info, Class data);\nstatic int classIsEqual(void *info, Class name, Class cls);\nstatic int _objc_defaultClassHandler(const char *clsName);\nstatic inline NXMapTable *pendingClassRefsMapTable(void);\nstatic inline NXMapTable *pendingSubclassesMapTable(void);\nstatic void pendClassInstallation(Class cls, const char *superName);\nstatic void pendClassReference(Class *ref, const char *className, bool isMeta);\nstatic void resolve_references_to_class(Class cls);\nstatic void resolve_subclasses_of_class(Class cls);\nstatic void really_connect_class(Class cls, Class supercls);\nstatic bool connect_class(Class cls);\nstatic void  map_method_descs (struct objc_method_description_list * methods, bool copy);\nstatic void _objcTweakMethodListPointerForClass(Class cls);\nstatic inline void _objc_add_category(Class cls, old_category *category, int version);\nstatic bool _objc_add_category_flush_caches(Class cls, old_category *category, int version);\nstatic _objc_unresolved_category *reverse_cat(_objc_unresolved_category *cat);\nstatic void resolve_categories_for_class(Class cls);\nstatic bool _objc_register_category(old_category *cat, int version);\n\n\n// Function called when a class is loaded from an image\nvoid (*callbackFunction)(Class, Category) = 0;\n\n// Hash table of classes\nNXHashTable *\t\tclass_hash = 0;\nstatic NXHashTablePrototype\tclassHashPrototype =\n{\n    (uintptr_t (*) (const void *, const void *))\t\t\tclassHash,\n    (int (*)(const void *, const void *, const void *))\tclassIsEqual,\n    NXNoEffectFree, 0\n};\n\n// Hash table of unconnected classes\nstatic NXHashTable *unconnected_class_hash = nil;\n\n// Exported copy of class_hash variable (hook for debugging tools)\nNXHashTable *_objc_debug_class_hash = nil;\n\n// Category and class registries\n// Keys are COPIES of strings, to prevent stale pointers with unloaded bundles\n// Use NXMapKeyCopyingInsert and NXMapKeyFreeingRemove\nstatic NXMapTable *\t\tcategory_hash = nil;\n\n// Keys are COPIES of strings, to prevent stale pointers with unloaded bundles\n// Use NXMapKeyCopyingInsert and NXMapKeyFreeingRemove\nstatic NXMapTable *\t\tpendingClassRefsMap = nil;\nstatic NXMapTable *\t\tpendingSubclassesMap = nil;\n\n// Protocols\nstatic NXMapTable *protocol_map = nil;      // name -> protocol\nstatic NXMapTable *protocol_ext_map = nil;  // protocol -> protocol ext\n\n// Function pointer objc_getClass calls through when class is not found\nstatic int\t\t\t(*objc_classHandler) (const char *) = _objc_defaultClassHandler;\n\n// Function pointer called by objc_getClass and objc_lookupClass when \n// class is not found. _objc_classLoader is called before objc_classHandler.\nstatic BOOL (*_objc_classLoader)(const char *) = nil;\n\n\n/***********************************************************************\n* objc_dump_class_hash.  Log names of all known classes.\n**********************************************************************/\nvoid objc_dump_class_hash(void)\n{\n    NXHashTable *table;\n    unsigned count;\n    Class data;\n    NXHashState state;\n\n    table = class_hash;\n    count = 0;\n    state = NXInitHashState (table);\n    while (NXNextHashState (table, &state, (void **) &data))\n        printf (\"class %d: %s\\n\", ++count, data->nameForLogging());\n}\n\n\n/***********************************************************************\n* _objc_init_class_hash.  Return the class lookup table, create it if\n* necessary.\n**********************************************************************/\nvoid _objc_init_class_hash(void)\n{\n    // Do nothing if class hash table already exists\n    if (class_hash)\n        return;\n\n    // class_hash starts small, with only enough capacity for libobjc itself. \n    // If a second library is found by map_images(), class_hash is immediately \n    // resized to capacity 1024 to cut down on rehashes. \n    // Old numbers: A smallish Foundation+AppKit program will have\n    // about 520 classes.  Larger apps (like IB or WOB) have more like\n    // 800 classes.  Some customers have massive quantities of classes.\n    // Foundation-only programs aren't likely to notice the ~6K loss.\n    class_hash = NXCreateHashTable(classHashPrototype, 16, nil);\n    _objc_debug_class_hash = class_hash;\n}\n\n\n/***********************************************************************\n* objc_getClassList.  Return the known classes.\n**********************************************************************/\nint objc_getClassList(Class *buffer, int bufferLen) \n{\n    NXHashState state;\n    Class cls;\n    int cnt, num;\n\n    mutex_locker_t lock(classLock);\n    if (!class_hash) return 0;\n\n    num = NXCountHashTable(class_hash);\n    if (nil == buffer) return num;\n\n    cnt = 0;\n    state = NXInitHashState(class_hash);\n    while (cnt < bufferLen  &&  \n           NXNextHashState(class_hash, &state, (void **)&cls)) \n    {\n        buffer[cnt++] = cls;\n    }\n\n    return num;\n}\n\n\n/***********************************************************************\n* objc_copyClassList\n* Returns pointers to all classes.\n* This requires all classes be realized, which is regretfully non-lazy.\n* \n* outCount may be nil. *outCount is the number of classes returned. \n* If the returned array is not nil, it is nil-terminated and must be \n* freed with free().\n* Locking: acquires classLock\n**********************************************************************/\nClass *\nobjc_copyClassList(unsigned int *outCount)\n{\n    Class *result;\n    unsigned int count;\n\n    mutex_locker_t lock(classLock);\n    result = nil;\n    count = class_hash ? NXCountHashTable(class_hash) : 0;\n\n    if (count > 0) {\n        Class cls;\n        NXHashState state = NXInitHashState(class_hash);\n        result = (Class *)malloc((1+count) * sizeof(Class));\n        count = 0;\n        while (NXNextHashState(class_hash, &state, (void **)&cls)) {\n            result[count++] = cls;\n        }\n        result[count] = nil;\n    }\n        \n    if (outCount) *outCount = count;\n    return result;\n}\n\n\n/***********************************************************************\n* objc_copyProtocolList\n* Returns pointers to all protocols.\n* Locking: acquires classLock\n**********************************************************************/\nProtocol * __unsafe_unretained *\nobjc_copyProtocolList(unsigned int *outCount) \n{\n    int count, i;\n    Protocol *proto;\n    const char *name;\n    NXMapState state;\n    Protocol **result;\n\n    mutex_locker_t lock(classLock);\n\n    count = NXCountMapTable(protocol_map);\n    if (count == 0) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    result = (Protocol **)calloc(1 + count, sizeof(Protocol *));\n\n    i = 0;\n    state = NXInitMapState(protocol_map);\n    while (NXNextMapState(protocol_map, &state, \n                          (const void **)&name, (const void **)&proto))\n    {\n        result[i++] = proto;\n    }\n    \n    result[i++] = nil;\n    assert(i == count+1);\n\n    if (outCount) *outCount = count;\n    return result;\n}\n\n\n/***********************************************************************\n* objc_getClasses.  Return class lookup table.\n*\n* NOTE: This function is very dangerous, since you cannot safely use\n* the hashtable without locking it, and the lock is private!\n**********************************************************************/\nvoid *objc_getClasses(void)\n{\n    OBJC_WARN_DEPRECATED;\n\n    // Return the class lookup hash table\n    return class_hash;\n}\n\n\n/***********************************************************************\n* classHash.\n**********************************************************************/\nstatic uintptr_t classHash(void *info, Class data)\n{\n    // Nil classes hash to zero\n    if (!data)\n        return 0;\n\n    // Call through to real hash function\n    return _objc_strhash (data->mangledName());\n}\n\n/***********************************************************************\n* classIsEqual.  Returns whether the class names match.  If we ever\n* check more than the name, routines like objc_lookUpClass have to\n* change as well.\n**********************************************************************/\nstatic int classIsEqual(void *info, Class name, Class cls)\n{\n    // Standard string comparison\n    return strcmp(name->mangledName(), cls->mangledName()) == 0;\n}\n\n\n// Unresolved future classes\nstatic NXHashTable *future_class_hash = nil;\n\n// Resolved future<->original classes\nstatic NXMapTable *future_class_to_original_class_map = nil;\nstatic NXMapTable *original_class_to_future_class_map = nil;\n\n// CF requests about 20 future classes; HIToolbox requests one.\n#define FUTURE_COUNT 32\n\n\n/***********************************************************************\n* setOriginalClassForFutureClass\n* Record resolution of a future class. \n**********************************************************************/\nstatic void setOriginalClassForFutureClass(Class futureClass, \n                                           Class originalClass)\n{\n    if (!future_class_to_original_class_map) {\n        future_class_to_original_class_map =\n            NXCreateMapTable(NXPtrValueMapPrototype, FUTURE_COUNT);\n        original_class_to_future_class_map =\n            NXCreateMapTable(NXPtrValueMapPrototype, FUTURE_COUNT);\n    }\n\n    NXMapInsert (future_class_to_original_class_map,\n                 futureClass, originalClass);\n    NXMapInsert (original_class_to_future_class_map,\n                 originalClass, futureClass);\n\n    if (PrintFuture) {\n        _objc_inform(\"FUTURE: using %p instead of %p for %s\", (void*)futureClass, (void*)originalClass, originalClass->name);\n    }\n}\n\n/***********************************************************************\n* getOriginalClassForFutureClass\n* getFutureClassForOriginalClass\n* Switch between a future class and its corresponding original class.\n* The future class is the one actually in use.\n* The original class is the one from disk.\n**********************************************************************/\n/*\nstatic Class\ngetOriginalClassForFutureClass(Class futureClass)\n{\n    if (!future_class_to_original_class_map) return Nil;\n    return NXMapGet (future_class_to_original_class_map, futureClass);\n}\n*/\nstatic Class\ngetFutureClassForOriginalClass(Class originalClass)\n{\n    if (!original_class_to_future_class_map) return Nil;\n    return (Class)NXMapGet(original_class_to_future_class_map, originalClass);\n}\n\n\n/***********************************************************************\n* makeFutureClass\n* Initialize the memory in *cls with an unresolved future class with the \n* given name. The memory is recorded in future_class_hash.\n**********************************************************************/\nstatic void makeFutureClass(Class cls, const char *name)\n{\n    // CF requests about 20 future classes, plus HIToolbox has one.\n    if (!future_class_hash) {\n        future_class_hash = \n            NXCreateHashTable(classHashPrototype, FUTURE_COUNT, nil);\n    }\n\n    cls->name = strdup(name);\n    NXHashInsert(future_class_hash, cls);\n\n    if (PrintFuture) {\n        _objc_inform(\"FUTURE: reserving %p for %s\", (void*)cls, name);\n    }\n}\n\n\n/***********************************************************************\n* _objc_allocateFutureClass\n* Allocate an unresolved future class for the given class name.\n* Returns any existing allocation if one was already made.\n* Assumes the named class doesn't exist yet.\n* Not thread safe.\n**********************************************************************/\nClass _objc_allocateFutureClass(const char *name)\n{\n    Class cls;\n\n    if (future_class_hash) {\n        objc_class query;\n        query.name = name;\n        if ((cls = (Class)NXHashGet(future_class_hash, &query))) {\n            // Already have a future class for this name.\n            return cls;\n        }\n    } \n\n    cls = _calloc_class(sizeof(objc_class));\n    makeFutureClass(cls, name);\n    return cls;\n}\n\n\n/***********************************************************************\n* objc_getFutureClass.  Return the id of the named class.\n* If the class does not exist, return an uninitialized class \n* structure that will be used for the class when and if it \n* does get loaded.\n* Not thread safe. \n**********************************************************************/\nClass objc_getFutureClass(const char *name)\n{\n    Class cls;\n\n    // YES unconnected, NO class handler\n    // (unconnected is OK because it will someday be the real class)\n    cls = look_up_class(name, YES, NO);\n    if (cls) {\n        if (PrintFuture) {\n            _objc_inform(\"FUTURE: found %p already in use for %s\", \n                         (void*)cls, name);\n        }\n        return cls;\n    }\n    \n    // No class or future class with that name yet. Make one.\n    // fixme not thread-safe with respect to \n    // simultaneous library load or getFutureClass.\n    return _objc_allocateFutureClass(name);\n}\n\n\nBOOL _class_isFutureClass(Class cls)\n{\n    return cls  &&  cls->isFuture();\n}\n\nbool objc_class::isFuture() \n{\n    return future_class_hash  &&  NXHashGet(future_class_hash, this);\n}\n\n\n/***********************************************************************\n* _objc_defaultClassHandler.  Default objc_classHandler.  Does nothing.\n**********************************************************************/\nstatic int _objc_defaultClassHandler(const char *clsName)\n{\n    // Return zero so objc_getClass doesn't bother re-searching\n    return 0;\n}\n\n/***********************************************************************\n* objc_setClassHandler.  Set objc_classHandler to the specified value.\n*\n* NOTE: This should probably deal with userSuppliedHandler being nil,\n* because the objc_classHandler caller does not check... it would bus\n* error.  It would make sense to handle nil by restoring the default\n* handler.  Is anyone hacking with this, though?\n**********************************************************************/\nvoid objc_setClassHandler(int (*userSuppliedHandler)(const char *))\n{\n    OBJC_WARN_DEPRECATED;\n\n    objc_classHandler = userSuppliedHandler;\n}\n\n\n/***********************************************************************\n* _objc_setClassLoader\n* Similar to objc_setClassHandler, but objc_classLoader is used for \n* both objc_getClass() and objc_lookupClass(), and objc_classLoader \n* pre-empts objc_classHandler. \n**********************************************************************/\nvoid _objc_setClassLoader(BOOL (*newClassLoader)(const char *))\n{\n    _objc_classLoader = newClassLoader;\n}\n\n\n/***********************************************************************\n* objc_getProtocol\n* Get a protocol by name, or nil.\n**********************************************************************/\nProtocol *objc_getProtocol(const char *name)\n{\n    mutex_locker_t lock(classLock);\n    if (!protocol_map) return nil;\n    return (Protocol *)NXMapGet(protocol_map, name);\n}\n\n\n/***********************************************************************\n* look_up_class\n* Map a class name to a class using various methods.\n* This is the common implementation of objc_lookUpClass and objc_getClass, \n* and is also used internally to get additional search options.\n* Sequence:\n* 1. class_hash\n* 2. unconnected_class_hash (optional)\n* 3. classLoader callback\n* 4. classHandler callback (optional)\n**********************************************************************/\nClass look_up_class(const char *aClassName, bool includeUnconnected, \n                    bool includeClassHandler)\n{\n    bool includeClassLoader = YES; // class loader cannot be skipped\n    Class result = nil;\n    struct objc_class query;\n\n    query.name = aClassName;\n\n retry:\n\n    if (!result  &&  class_hash) {\n        // Check ordinary classes\n        mutex_locker_t lock(classLock);\n        result = (Class)NXHashGet(class_hash, &query);\n    }\n\n    if (!result  &&  includeUnconnected  &&  unconnected_class_hash) {\n        // Check not-yet-connected classes\n        mutex_locker_t lock(classLock);\n        result = (Class)NXHashGet(unconnected_class_hash, &query);\n    }\n\n    if (!result  &&  includeClassLoader  &&  _objc_classLoader) {\n        // Try class loader callback\n        if ((*_objc_classLoader)(aClassName)) {\n            // Re-try lookup without class loader\n            includeClassLoader = NO;\n            goto retry;\n        }\n    }\n\n    if (!result  &&  includeClassHandler  &&  objc_classHandler) {\n        // Try class handler callback\n        if ((*objc_classHandler)(aClassName)) {\n            // Re-try lookup without class handler or class loader\n            includeClassLoader = NO;\n            includeClassHandler = NO;\n            goto retry;\n        }\n    }\n\n    return result;\n}\n\n\n/***********************************************************************\n* objc_class::isConnected\n* Returns TRUE if class cls is connected. \n* A connected class has either a connected superclass or a nil superclass, \n* and is present in class_hash.\n**********************************************************************/\nbool objc_class::isConnected()\n{\n    mutex_locker_t lock(classLock);\n    return NXHashMember(class_hash, this);\n}\n\n\n/***********************************************************************\n* pendingClassRefsMapTable.  Return a pointer to the lookup table for\n* pending class refs.\n**********************************************************************/\nstatic inline NXMapTable *pendingClassRefsMapTable(void)\n{\n    // Allocate table if needed\n    if (!pendingClassRefsMap) {\n        pendingClassRefsMap = NXCreateMapTable(NXStrValueMapPrototype, 10);\n    }\n    \n    // Return table pointer\n    return pendingClassRefsMap;\n}\n\n\n/***********************************************************************\n* pendingSubclassesMapTable.  Return a pointer to the lookup table for\n* pending subclasses.\n**********************************************************************/\nstatic inline NXMapTable *pendingSubclassesMapTable(void)\n{\n    // Allocate table if needed\n    if (!pendingSubclassesMap) {\n        pendingSubclassesMap = NXCreateMapTable(NXStrValueMapPrototype, 10);\n    }\n    \n    // Return table pointer\n    return pendingSubclassesMap;\n}\n\n\n/***********************************************************************\n* pendClassInstallation\n* Finish connecting class cls when its superclass becomes connected.\n* Check for multiple pends of the same class because connect_class does not.\n**********************************************************************/\nstatic void pendClassInstallation(Class cls, const char *superName)\n{\n    NXMapTable *table;\n    PendingSubclass *pending;\n    PendingSubclass *oldList;\n    PendingSubclass *l;\n    \n    // Create and/or locate pending class lookup table\n    table = pendingSubclassesMapTable ();\n\n    // Make sure this class isn't already in the pending list.\n    oldList = (PendingSubclass *)NXMapGet(table, superName);\n    for (l = oldList; l != nil; l = l->next) {\n        if (l->subclass == cls) return;  // already here, nothing to do\n    }\n    \n    // Create entry referring to this class\n    pending = (PendingSubclass *)malloc(sizeof(PendingSubclass));\n    pending->subclass = cls;\n    \n    // Link new entry into head of list of entries for this class\n    pending->next = oldList;\n    \n    // (Re)place entry list in the table\n    NXMapKeyCopyingInsert (table, superName, pending);\n}\n\n\n/***********************************************************************\n* pendClassReference\n* Fix up a class ref when the class with the given name becomes connected.\n**********************************************************************/\nstatic void pendClassReference(Class *ref, const char *className, bool isMeta)\n{\n    NXMapTable *table;\n    PendingClassRef *pending;\n    \n    // Create and/or locate pending class lookup table\n    table = pendingClassRefsMapTable ();\n    \n    // Create entry containing the class reference\n    pending = (PendingClassRef *)malloc(sizeof(PendingClassRef));\n    pending->ref = ref;\n    if (isMeta) {\n        pending->ref = (Class *)((uintptr_t)pending->ref | 1);\n    }\n    \n    // Link new entry into head of list of entries for this class\n    pending->next = (PendingClassRef *)NXMapGet(table, className);\n    \n    // (Re)place entry list in the table\n    NXMapKeyCopyingInsert (table, className, pending);\n\n    if (PrintConnecting) {\n        _objc_inform(\"CONNECT: pended reference to class '%s%s' at %p\", \n                     className, isMeta ? \" (meta)\" : \"\", (void *)ref);\n    }\n}\n\n\n/***********************************************************************\n* resolve_references_to_class\n* Fix up any pending class refs to this class.\n**********************************************************************/\nstatic void resolve_references_to_class(Class cls)\n{\n    PendingClassRef *pending;\n    \n    if (!pendingClassRefsMap) return;  // no unresolved refs for any class\n\n    pending = (PendingClassRef *)NXMapGet(pendingClassRefsMap, cls->name); \n    if (!pending) return;  // no unresolved refs for this class\n\n    NXMapKeyFreeingRemove(pendingClassRefsMap, cls->name);\n\n    if (PrintConnecting) {\n        _objc_inform(\"CONNECT: resolving references to class '%s'\", cls->name);\n    }\n\n    while (pending) {\n        PendingClassRef *next = pending->next;\n        if (pending->ref) {\n            bool isMeta = (uintptr_t)pending->ref & 1;\n            Class *ref = \n                (Class *)((uintptr_t)pending->ref & ~(uintptr_t)1);\n            *ref = isMeta ? cls->ISA() : cls;\n        }\n        free(pending);\n        pending = next;\n    }\n\n    if (NXCountMapTable(pendingClassRefsMap) == 0) {\n        NXFreeMapTable(pendingClassRefsMap);\n        pendingClassRefsMap = nil;\n    }\n}\n\n\n/***********************************************************************\n* resolve_subclasses_of_class\n* Fix up any pending subclasses of this class.\n**********************************************************************/\nstatic void resolve_subclasses_of_class(Class cls)\n{\n    PendingSubclass *pending;\n    \n    if (!pendingSubclassesMap) return;  // no unresolved subclasses \n\n    pending = (PendingSubclass *)NXMapGet(pendingSubclassesMap, cls->name); \n    if (!pending) return;  // no unresolved subclasses for this class\n\n    NXMapKeyFreeingRemove(pendingSubclassesMap, cls->name);\n\n    // Destroy the pending table if it's now empty, to save memory.\n    if (NXCountMapTable(pendingSubclassesMap) == 0) {\n        NXFreeMapTable(pendingSubclassesMap);\n        pendingSubclassesMap = nil;\n    }\n\n    if (PrintConnecting) {\n        _objc_inform(\"CONNECT: resolving subclasses of class '%s'\", cls->name);\n    }\n\n    while (pending) {\n        PendingSubclass *next = pending->next;\n        if (pending->subclass) connect_class(pending->subclass);\n        free(pending);\n        pending = next;\n    }\n}\n\n\n/***********************************************************************\n* really_connect_class\n* Connect cls to superclass supercls unconditionally.\n* Also adjust the class hash tables and handle pended subclasses.\n*\n* This should be called from connect_class() ONLY.\n**********************************************************************/\nstatic void really_connect_class(Class cls,\n                                 Class supercls)\n{\n    Class oldCls;\n\n    // Connect superclass pointers.\n    set_superclass(cls, supercls, YES);\n\n    // Done!\n    cls->info |= CLS_CONNECTED;\n\n    {\n        mutex_locker_t lock(classLock);\n        \n        // Update hash tables. \n        NXHashRemove(unconnected_class_hash, cls);\n        oldCls = (Class)NXHashInsert(class_hash, cls);\n        \n        // Delete unconnected_class_hash if it is now empty.\n        if (NXCountHashTable(unconnected_class_hash) == 0) {\n            NXFreeHashTable(unconnected_class_hash);\n            unconnected_class_hash = nil;\n        }\n        \n        // No duplicate classes allowed. \n        // Duplicates should have been rejected by _objc_read_classes_from_image\n        assert(!oldCls);\n    }        \n \n    // Fix up pended class refs to this class, if any\n    resolve_references_to_class(cls);\n\n    // Connect newly-connectable subclasses\n    resolve_subclasses_of_class(cls);\n\n    // Debugging: if this class has ivars, make sure this class's ivars don't \n    // overlap with its super's. This catches some broken fragile base classes.\n    // Do not use super->instance_size vs. self->ivar[0] to check this. \n    // Ivars may be packed across instance_size boundaries.\n    if (DebugFragileSuperclasses  &&  cls->ivars  &&  cls->ivars->ivar_count) {\n        Class ivar_cls = supercls;\n\n        // Find closest superclass that has some ivars, if one exists.\n        while (ivar_cls  &&  \n               (!ivar_cls->ivars || ivar_cls->ivars->ivar_count == 0))\n        {\n            ivar_cls = ivar_cls->superclass;\n        }\n\n        if (ivar_cls) {\n            // Compare superclass's last ivar to this class's first ivar\n            old_ivar *super_ivar = \n                &ivar_cls->ivars->ivar_list[ivar_cls->ivars->ivar_count - 1];\n            old_ivar *self_ivar = \n                &cls->ivars->ivar_list[0];\n\n            // fixme could be smarter about super's ivar size\n            if (self_ivar->ivar_offset <= super_ivar->ivar_offset) {\n                _objc_inform(\"WARNING: ivars of superclass '%s' and \"\n                             \"subclass '%s' overlap; superclass may have \"\n                             \"changed since subclass was compiled\", \n                             ivar_cls->name, cls->name);\n            }\n        }\n    }\n}\n\n\n/***********************************************************************\n* connect_class\n* Connect class cls to its superclasses, if possible.\n* If cls becomes connected, move it from unconnected_class_hash \n*   to connected_class_hash.\n* Returns TRUE if cls is connected.\n* Returns FALSE if cls could not be connected for some reason \n*   (missing superclass or still-unconnected superclass)\n**********************************************************************/\nstatic bool connect_class(Class cls)\n{\n    if (cls->isConnected()) {\n        // This class is already connected to its superclass.\n        // Do nothing.\n        return TRUE;\n    }\n    else if (cls->superclass == nil) {\n        // This class is a root class. \n        // Connect it to itself. \n\n        if (PrintConnecting) {\n            _objc_inform(\"CONNECT: class '%s' now connected (root class)\", \n                        cls->name);\n        }\n\n        really_connect_class(cls, nil);\n        return TRUE;\n    }\n    else {\n        // This class is not a root class and is not yet connected.\n        // Connect it if its superclass and root class are already connected. \n        // Otherwise, add this class to the to-be-connected list, \n        // pending the completion of its superclass and root class.\n\n        // At this point, cls->superclass and cls->ISA()->ISA() are still STRINGS\n        char *supercls_name = (char *)cls->superclass;\n        Class supercls;\n\n        // YES unconnected, YES class handler\n        if (nil == (supercls = look_up_class(supercls_name, YES, YES))) {\n            // Superclass does not exist yet.\n            // pendClassInstallation will handle duplicate pends of this class\n            pendClassInstallation(cls, supercls_name);\n\n            if (PrintConnecting) {\n                _objc_inform(\"CONNECT: class '%s' NOT connected (missing super)\", cls->name);\n            }\n            return FALSE;\n        }\n        \n        if (! connect_class(supercls)) {\n            // Superclass exists but is not yet connected.\n            // pendClassInstallation will handle duplicate pends of this class\n            pendClassInstallation(cls, supercls_name);\n\n            if (PrintConnecting) {\n                _objc_inform(\"CONNECT: class '%s' NOT connected (unconnected super)\", cls->name);\n            }\n            return FALSE;\n        }\n\n        // Superclass exists and is connected. \n        // Connect this class to the superclass.\n        \n        if (PrintConnecting) {\n            _objc_inform(\"CONNECT: class '%s' now connected\", cls->name);\n        }\n\n        really_connect_class(cls, supercls);\n        return TRUE;\n    } \n}\n\n\n/***********************************************************************\n* _objc_read_categories_from_image.\n* Read all categories from the given image. \n* Install them on their parent classes, or register them for later \n*   installation. \n* Returns YES if some method caches now need to be flushed.\n**********************************************************************/\nstatic bool _objc_read_categories_from_image (header_info *  hi)\n{\n    Module\t\tmods;\n    size_t\tmidx;\n    bool needFlush = NO;\n\n    if (hi->info()->isReplacement()) {\n        // Ignore any categories in this image\n        return NO;\n    }\n\n    // Major loop - process all modules in the header\n    mods = hi->mod_ptr;\n\n    // NOTE: The module and category lists are traversed backwards \n    // to preserve the pre-10.4 processing order. Changing the order \n    // would have a small chance of introducing binary compatibility bugs.\n    midx = hi->mod_count;\n    while (midx-- > 0) {\n        unsigned int\tindex;\n        unsigned int\ttotal;\n        \n        // Nothing to do for a module without a symbol table\n        if (mods[midx].symtab == nil)\n            continue;\n        \n        // Total entries in symbol table (class entries followed\n        // by category entries)\n        total = mods[midx].symtab->cls_def_cnt +\n            mods[midx].symtab->cat_def_cnt;\n        \n        // Minor loop - register all categories from given module\n        index = total;\n        while (index-- > mods[midx].symtab->cls_def_cnt) {\n            old_category *cat = (old_category *)mods[midx].symtab->defs[index];\n            needFlush |= _objc_register_category(cat, (int)mods[midx].version);\n        }\n    }\n\n    return needFlush;\n}\n\n\n/***********************************************************************\n* _objc_read_classes_from_image.\n* Read classes from the given image, perform assorted minor fixups, \n*   scan for +load implementation.\n* Does not connect classes to superclasses. \n* Does attach pended categories to the classes.\n* Adds all classes to unconnected_class_hash. class_hash is unchanged.\n**********************************************************************/\nstatic void _objc_read_classes_from_image(header_info *hi)\n{\n    unsigned int\tindex;\n    unsigned int\tmidx;\n    Module\t\tmods;\n    int \t\tisBundle = headerIsBundle(hi);\n\n    if (hi->info()->isReplacement()) {\n        // Ignore any classes in this image\n        return;\n    }\n\n    // class_hash starts small, enough only for libobjc itself. \n    // If other Objective-C libraries are found, immediately resize \n    // class_hash, assuming that Foundation and AppKit are about \n    // to add lots of classes.\n    {\n        mutex_locker_t lock(classLock);\n        if (hi->mhdr() != libobjc_header && _NXHashCapacity(class_hash) < 1024) {\n            _NXHashRehashToCapacity(class_hash, 1024);\n        }\n    }\n\n    // Major loop - process all modules in the image\n    mods = hi->mod_ptr;\n    for (midx = 0; midx < hi->mod_count; midx += 1)\n    {\n        // Skip module containing no classes\n        if (mods[midx].symtab == nil)\n            continue;\n\n        // Minor loop - process all the classes in given module\n        for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)\n        {\n            Class newCls, oldCls;\n            bool rejected;\n\n            // Locate the class description pointer\n            newCls = (Class)mods[midx].symtab->defs[index];\n\n            // Classes loaded from Mach-O bundles can be unloaded later.\n            // Nothing uses this class yet, so cls->setInfo is not needed.\n            if (isBundle) newCls->info |= CLS_FROM_BUNDLE;\n            if (isBundle) newCls->ISA()->info |= CLS_FROM_BUNDLE;\n\n            // Use common static empty cache instead of nil\n            if (newCls->cache == nil)\n                newCls->cache = (Cache) &_objc_empty_cache;\n            if (newCls->ISA()->cache == nil)\n                newCls->ISA()->cache = (Cache) &_objc_empty_cache;\n\n            // Set metaclass version\n            newCls->ISA()->version = mods[midx].version;\n\n            // methodLists is nil or a single list, not an array\n            newCls->info |= CLS_NO_METHOD_ARRAY|CLS_NO_PROPERTY_ARRAY;\n            newCls->ISA()->info |= CLS_NO_METHOD_ARRAY|CLS_NO_PROPERTY_ARRAY;\n\n            // class has no subclasses for cache flushing\n            newCls->info |= CLS_LEAF;\n            newCls->ISA()->info |= CLS_LEAF;\n\n            if (mods[midx].version >= 6) {\n                // class structure has ivar_layout and ext fields\n                newCls->info |= CLS_EXT;\n                newCls->ISA()->info |= CLS_EXT;\n            }\n\n            // Check for +load implementation before categories are attached\n            if (_class_hasLoadMethod(newCls)) {\n                newCls->ISA()->info |= CLS_HAS_LOAD_METHOD;\n            }\n\n            // Install into unconnected_class_hash.\n            {\n                mutex_locker_t lock(classLock);\n\n                if (future_class_hash) {\n                    Class futureCls = (Class)\n                        NXHashRemove(future_class_hash, newCls);\n                    if (futureCls) {\n                        // Another class structure for this class was already \n                        // prepared by objc_getFutureClass(). Use it instead.\n                        free((char *)futureCls->name);\n                        memcpy(futureCls, newCls, sizeof(objc_class));\n                        setOriginalClassForFutureClass(futureCls, newCls);\n                        newCls = futureCls;\n                        \n                        if (NXCountHashTable(future_class_hash) == 0) {\n                            NXFreeHashTable(future_class_hash);\n                            future_class_hash = nil;\n                        }\n                    }\n                }\n                \n                if (!unconnected_class_hash) {\n                    unconnected_class_hash = \n                        NXCreateHashTable(classHashPrototype, 128, nil);\n                }\n                \n                if ((oldCls = (Class)NXHashGet(class_hash, newCls))  ||  \n                    (oldCls = (Class)NXHashGet(unconnected_class_hash, newCls)))\n                {\n                    // Another class with this name exists. Complain and reject.\n                    inform_duplicate(newCls->name, oldCls, newCls);\n                    rejected = YES;\n                }\n                else {\n                    NXHashInsert(unconnected_class_hash, newCls); \n                    rejected = NO;\n                }\n            }\n\n            if (!rejected) {\n                // Attach pended categories for this class, if any\n                resolve_categories_for_class(newCls);\n            }\n        }\n    }\n}\n\n\n/***********************************************************************\n* _objc_connect_classes_from_image.\n* Connect the classes in the given image to their superclasses,\n* or register them for later connection if any superclasses are missing.\n**********************************************************************/\nstatic void _objc_connect_classes_from_image(header_info *hi)\n{\n    unsigned int index;\n    unsigned int midx;\n    Module mods;\n    bool replacement = hi->info()->isReplacement();\n\n    // Major loop - process all modules in the image\n    mods = hi->mod_ptr;\n    for (midx = 0; midx < hi->mod_count; midx += 1)\n    {\n        // Skip module containing no classes\n        if (mods[midx].symtab == nil)\n            continue;\n\n        // Minor loop - process all the classes in given module\n        for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)\n        {\n            Class cls = (Class)mods[midx].symtab->defs[index];\n            if (! replacement) {\n                bool connected;\n                Class futureCls = getFutureClassForOriginalClass(cls);\n                if (futureCls) {\n                    // objc_getFutureClass() requested a different class \n                    // struct. Fix up the original struct's superclass \n                    // field for [super ...] use, but otherwise perform \n                    // fixups on the new class struct only.\n                    const char *super_name = (const char *) cls->superclass;\n                    if (super_name) cls->superclass = objc_getClass(super_name);\n                    cls = futureCls;\n                }\n                connected = connect_class(cls);\n                if (connected  &&  callbackFunction) {\n                    (*callbackFunction)(cls, 0);\n                }\n            } else {\n                // Replacement image - fix up superclass only (#3704817)\n                // And metaclass's superclass (#5351107)\n                const char *super_name = (const char *) cls->superclass;\n                if (super_name) {\n                    cls->superclass = objc_getClass(super_name);\n                    // metaclass's superclass is superclass's metaclass\n                    cls->ISA()->superclass = cls->superclass->ISA();\n                } else {\n                    // Replacement for a root class\n                    // cls->superclass already nil\n                    // root metaclass's superclass is root class\n                    cls->ISA()->superclass = cls;\n                }\n            }\n        }\n    }\n}\n\n\n/***********************************************************************\n* _objc_map_class_refs_for_image.  Convert the class ref entries from\n* a class name string pointer to a class pointer.  If the class does\n* not yet exist, the reference is added to a list of pending references\n* to be fixed up at a later date.\n**********************************************************************/\nstatic void fix_class_ref(Class *ref, const char *name, bool isMeta)\n{\n    Class cls;\n\n    // Get pointer to class of this name\n    // NO unconnected, YES class loader\n    // (real class with weak-missing superclass is unconnected now)\n    cls = look_up_class(name, NO, YES);\n    if (cls) {\n        // Referenced class exists. Fix up the reference.\n        *ref = isMeta ? cls->ISA() : cls;\n    } else {\n        // Referenced class does not exist yet. Insert nil for now \n        // (weak-linking) and fix up the reference if the class arrives later.\n        pendClassReference (ref, name, isMeta);\n        *ref = nil;\n    }\n}\n\nstatic void _objc_map_class_refs_for_image (header_info * hi)\n{\n    Class *cls_refs;\n    size_t\tcount;\n    unsigned int\tindex;\n\n    // Locate class refs in image\n    cls_refs = _getObjcClassRefs (hi, &count);\n    if (cls_refs) {\n        // Process each class ref\n        for (index = 0; index < count; index += 1) {\n            // Ref is initially class name char*\n            const char *name = (const char *) cls_refs[index];\n            if (!name) continue;\n            fix_class_ref(&cls_refs[index], name, NO /*never meta*/);\n        }\n    }\n}\n\n\n/***********************************************************************\n* _objc_remove_pending_class_refs_in_image\n* Delete any pending class ref fixups for class refs in the given image, \n* because the image is about to be unloaded.\n**********************************************************************/\nstatic void removePendingReferences(Class *refs, size_t count)\n{\n    Class *end = refs + count;\n\n    if (!refs) return;\n    if (!pendingClassRefsMap) return;\n\n    // Search the pending class ref table for class refs in this range.\n    // The class refs may have already been stomped with nil, \n    // so there's no way to recover the original class name.\n\n    {    \n        const char *key;\n        PendingClassRef *pending;\n        NXMapState  state = NXInitMapState(pendingClassRefsMap);\n        while(NXNextMapState(pendingClassRefsMap, &state, \n                             (const void **)&key, (const void **)&pending)) \n        {\n            for ( ; pending != nil; pending = pending->next) {\n                if (pending->ref >= refs  &&  pending->ref < end) {\n                    pending->ref = nil;\n                }\n            }\n        }\n    } \n}\n\nstatic void _objc_remove_pending_class_refs_in_image(header_info *hi)\n{\n    Class *cls_refs;\n    size_t count;\n\n    // Locate class refs in this image\n    cls_refs = _getObjcClassRefs(hi, &count);\n    removePendingReferences(cls_refs, count);\n}\n\n\n/***********************************************************************\n* map_selrefs.  For each selector in the specified array,\n* replace the name pointer with a uniqued selector.\n* If copy is TRUE, all selector data is always copied. This is used \n* for registering selectors from unloadable bundles, so the selector \n* can still be used after the bundle's data segment is unmapped.\n* Returns YES if dst was written to, NO if it was unchanged.\n**********************************************************************/\nstatic inline void map_selrefs(SEL *sels, size_t count, bool copy)\n{\n    size_t index;\n\n    if (!sels) return;\n\n    mutex_locker_t lock(selLock);\n\n    // Process each selector\n    for (index = 0; index < count; index += 1)\n    {\n        SEL sel;\n\n        // Lookup pointer to uniqued string\n        sel = sel_registerNameNoLock((const char *) sels[index], copy);\n\n        // Replace this selector with uniqued one (avoid\n        // modifying the VM page if this would be a NOP)\n        if (sels[index] != sel) {\n            sels[index] = sel;\n        }\n    }\n}\n\n\n/***********************************************************************\n* map_method_descs.  For each method in the specified method list,\n* replace the name pointer with a uniqued selector.\n* If copy is TRUE, all selector data is always copied. This is used \n* for registering selectors from unloadable bundles, so the selector \n* can still be used after the bundle's data segment is unmapped.\n**********************************************************************/\nstatic void  map_method_descs (struct objc_method_description_list * methods, bool copy)\n{\n    int index;\n\n    if (!methods) return;\n\n    mutex_locker_t lock(selLock);\n\n    // Process each method\n    for (index = 0; index < methods->count; index += 1)\n    {\n        struct objc_method_description *\tmethod;\n        SEL\t\t\t\t\tsel;\n\n        // Get method entry to fix up\n        method = &methods->list[index];\n\n        // Lookup pointer to uniqued string\n        sel = sel_registerNameNoLock((const char *) method->name, copy);\n\n        // Replace this selector with uniqued one (avoid\n        // modifying the VM page if this would be a NOP)\n        if (method->name != sel)\n            method->name = sel;\n    }\n}\n\n\n/***********************************************************************\n* ext_for_protocol\n* Returns the protocol extension for the given protocol.\n* Returns nil if the protocol has no extension.\n**********************************************************************/\nstatic old_protocol_ext *ext_for_protocol(old_protocol *proto)\n{\n    if (!proto) return nil;\n    if (!protocol_ext_map) return nil;\n    else return (old_protocol_ext *)NXMapGet(protocol_ext_map, proto);\n}\n\n\n/***********************************************************************\n* lookup_method\n* Search a protocol method list for a selector.\n**********************************************************************/\nstatic struct objc_method_description *\nlookup_method(struct objc_method_description_list *mlist, SEL aSel)\n{\n   if (mlist) {\n       int i;\n       for (i = 0; i < mlist->count; i++) {\n           if (mlist->list[i].name == aSel) {\n               return mlist->list+i;\n           }\n       }\n   }\n   return nil;\n}\n\n\n/***********************************************************************\n* lookup_protocol_method\n* Search for a selector in a protocol \n* (and optionally recursively all incorporated protocols)\n**********************************************************************/\nstruct objc_method_description *\nlookup_protocol_method(old_protocol *proto, SEL aSel, \n                       bool isRequiredMethod, bool isInstanceMethod, \n                       bool recursive)\n{\n    struct objc_method_description *m = nil;\n    old_protocol_ext *ext;\n\n    if (isRequiredMethod) {\n        if (isInstanceMethod) {\n            m = lookup_method(proto->instance_methods, aSel);\n        } else {\n            m = lookup_method(proto->class_methods, aSel);\n        }\n    } else if ((ext = ext_for_protocol(proto))) {\n        if (isInstanceMethod) {\n            m = lookup_method(ext->optional_instance_methods, aSel);\n        } else {\n            m = lookup_method(ext->optional_class_methods, aSel);\n        }\n    }\n\n    if (!m  &&  recursive  &&  proto->protocol_list) {\n        int i;\n        for (i = 0; !m  &&  i < proto->protocol_list->count; i++) {\n            m = lookup_protocol_method(proto->protocol_list->list[i], aSel, \n                                       isRequiredMethod,isInstanceMethod,true);\n        }\n    }\n\n    return m;\n}\n\n\n/***********************************************************************\n* protocol_getName\n* Returns the name of the given protocol.\n**********************************************************************/\nconst char *protocol_getName(Protocol *p)\n{\n    old_protocol *proto = oldprotocol(p);\n    if (!proto) return \"nil\";\n    return proto->protocol_name;\n}\n\n\n/***********************************************************************\n* protocol_getMethodDescription\n* Returns the description of a named method.\n* Searches either required or optional methods.\n* Searches either instance or class methods.\n**********************************************************************/\nstruct objc_method_description \nprotocol_getMethodDescription(Protocol *p, SEL aSel, \n                              BOOL isRequiredMethod, BOOL isInstanceMethod)\n{\n    struct objc_method_description empty = {nil, nil};\n    old_protocol *proto = oldprotocol(p);\n    struct objc_method_description *desc;\n    if (!proto) return empty;\n\n    desc = lookup_protocol_method(proto, aSel, \n                                  isRequiredMethod, isInstanceMethod, true);\n    if (desc) return *desc;\n    else return empty;\n}\n\n\n/***********************************************************************\n* protocol_copyMethodDescriptionList\n* Returns an array of method descriptions from a protocol.\n* Copies either required or optional methods.\n* Copies either instance or class methods.\n**********************************************************************/\nstruct objc_method_description *\nprotocol_copyMethodDescriptionList(Protocol *p, \n                                   BOOL isRequiredMethod, \n                                   BOOL isInstanceMethod, \n                                   unsigned int *outCount)\n{\n    struct objc_method_description_list *mlist = nil;\n    old_protocol *proto = oldprotocol(p);\n    old_protocol_ext *ext;\n    unsigned int i, count;\n    struct objc_method_description *result;\n\n    if (!proto) {\n        if (outCount) *outCount = 0;\n        return nil;\n    } \n\n    if (isRequiredMethod) {\n        if (isInstanceMethod) {\n            mlist = proto->instance_methods;\n        } else {\n            mlist = proto->class_methods;\n        }\n    } else if ((ext = ext_for_protocol(proto))) {\n        if (isInstanceMethod) {\n            mlist = ext->optional_instance_methods;\n        } else {\n            mlist = ext->optional_class_methods;\n        }\n    }\n\n    if (!mlist) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n    \n    count = mlist->count;\n    result = (struct objc_method_description *)\n        calloc(count + 1, sizeof(struct objc_method_description));\n    for (i = 0; i < count; i++) {\n        result[i] = mlist->list[i];\n    }\n\n    if (outCount) *outCount = count;\n    return result;\n}\n\n\nobjc_property_t \nprotocol_getProperty(Protocol *p, const char *name, \n                     BOOL isRequiredProperty, BOOL isInstanceProperty)\n{\n    old_protocol *proto = oldprotocol(p);\n    old_protocol_ext *ext;\n    old_protocol_list *proto_list;\n\n    if (!proto  ||  !name) return nil;\n    \n    if (!isRequiredProperty) {\n        // Only required properties are currently supported\n        return nil;\n    }\n\n    if ((ext = ext_for_protocol(proto))) {\n        old_property_list *plist;\n        if (isInstanceProperty) plist = ext->instance_properties;\n        else if (ext->hasClassPropertiesField()) plist = ext->class_properties;\n        else plist = nil;\n\n        if (plist) {\n            uint32_t i;\n            for (i = 0; i < plist->count; i++) {\n                old_property *prop = property_list_nth(plist, i);\n                if (0 == strcmp(name, prop->name)) {\n                    return (objc_property_t)prop;\n                }\n            }\n        }\n    }\n\n    if ((proto_list = proto->protocol_list)) {\n        int i;\n        for (i = 0; i < proto_list->count; i++) {\n            objc_property_t prop = \n                protocol_getProperty((Protocol *)proto_list->list[i], name, \n                                     isRequiredProperty, isInstanceProperty);\n            if (prop) return prop;\n        }\n    }\n    \n    return nil;\n}\n\n\nobjc_property_t *\nprotocol_copyPropertyList2(Protocol *p, unsigned int *outCount,\n                           BOOL isRequiredProperty, BOOL isInstanceProperty)\n{\n    old_property **result = nil;\n    old_protocol_ext *ext;\n    old_property_list *plist;\n    \n    old_protocol *proto = oldprotocol(p);\n    if (! (ext = ext_for_protocol(proto))  ||  !isRequiredProperty) {\n        // Only required properties are currently supported.\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    if (isInstanceProperty) plist = ext->instance_properties;\n    else if (ext->hasClassPropertiesField()) plist = ext->class_properties;\n    else plist = nil;\n\n    result = copyPropertyList(plist, outCount);\n    \n    return (objc_property_t *)result;\n}\n\nobjc_property_t *protocol_copyPropertyList(Protocol *p, unsigned int *outCount)\n{\n    return protocol_copyPropertyList2(p, outCount, YES, YES);\n}\n\n\n/***********************************************************************\n* protocol_copyProtocolList\n* Copies this protocol's incorporated protocols. \n* Does not copy those protocol's incorporated protocols in turn.\n**********************************************************************/\nProtocol * __unsafe_unretained *\nprotocol_copyProtocolList(Protocol *p, unsigned int *outCount)\n{\n    unsigned int count = 0;\n    Protocol **result = nil;\n    old_protocol *proto = oldprotocol(p);\n    \n    if (!proto) {\n        if (outCount) *outCount = 0;\n        return nil;\n    }\n\n    if (proto->protocol_list) {\n        count = (unsigned int)proto->protocol_list->count;\n    }\n    if (count > 0) {\n        unsigned int i;\n        result = (Protocol **)malloc((count+1) * sizeof(Protocol *));\n\n        for (i = 0; i < count; i++) {\n            result[i] = (Protocol *)proto->protocol_list->list[i];\n        }\n        result[i] = nil;\n    }\n\n    if (outCount) *outCount = count;\n    return result;\n}\n\n\nBOOL protocol_conformsToProtocol(Protocol *self_gen, Protocol *other_gen)\n{\n    old_protocol *self = oldprotocol(self_gen);\n    old_protocol *other = oldprotocol(other_gen);\n\n    if (!self  ||  !other) {\n        return NO;\n    }\n\n    if (0 == strcmp(self->protocol_name, other->protocol_name)) {\n        return YES;\n    }\n\n    if (self->protocol_list) {\n        int i;\n        for (i = 0; i < self->protocol_list->count; i++) {\n            old_protocol *proto = self->protocol_list->list[i];\n            if (0 == strcmp(other->protocol_name, proto->protocol_name)) {\n                return YES;\n            }\n            if (protocol_conformsToProtocol((Protocol *)proto, other_gen)) {\n                return YES;\n            }\n        }\n    }\n\n    return NO;\n}\n\n\nBOOL protocol_isEqual(Protocol *self, Protocol *other)\n{\n    if (self == other) return YES;\n    if (!self  ||  !other) return NO;\n\n    if (!protocol_conformsToProtocol(self, other)) return NO;\n    if (!protocol_conformsToProtocol(other, self)) return NO;\n\n    return YES;\n}\n\n\n/***********************************************************************\n* _protocol_getMethodTypeEncoding\n* Return the @encode string for the requested protocol method.\n* Returns nil if the compiler did not emit any extended @encode data.\n* Locking: runtimeLock must not be held by the caller\n**********************************************************************/\nconst char * \n_protocol_getMethodTypeEncoding(Protocol *proto_gen, SEL sel, \n                                BOOL isRequiredMethod, BOOL isInstanceMethod)\n{\n    old_protocol *proto = oldprotocol(proto_gen);\n    if (!proto) return nil;\n    old_protocol_ext *ext = ext_for_protocol(proto);\n    if (!ext) return nil;\n    if (ext->size < offsetof(old_protocol_ext, extendedMethodTypes) + sizeof(ext->extendedMethodTypes)) return nil;\n    if (! ext->extendedMethodTypes) return nil;\n\n    struct objc_method_description *m = \n        lookup_protocol_method(proto, sel, \n                               isRequiredMethod, isInstanceMethod, false);\n    if (!m) {\n        // No method with that name. Search incorporated protocols.\n        if (proto->protocol_list) {\n            for (int i = 0; i < proto->protocol_list->count; i++) {\n                const char *enc = \n                    _protocol_getMethodTypeEncoding((Protocol *)proto->protocol_list->list[i], sel, isRequiredMethod, isInstanceMethod);\n                if (enc) return enc;\n            }\n        }\n        return nil;\n    }\n    \n    int i = 0;\n    if (isRequiredMethod && isInstanceMethod) {\n        i += ((uintptr_t)m - (uintptr_t)proto->instance_methods) / sizeof(proto->instance_methods->list[0]);\n        goto done;\n    } else if (proto->instance_methods) {\n        i += proto->instance_methods->count;\n    }\n\n    if (isRequiredMethod && !isInstanceMethod) {\n        i += ((uintptr_t)m - (uintptr_t)proto->class_methods) / sizeof(proto->class_methods->list[0]);\n        goto done;\n    } else if (proto->class_methods) {\n        i += proto->class_methods->count;\n    }\n\n    if (!isRequiredMethod && isInstanceMethod) {\n        i += ((uintptr_t)m - (uintptr_t)ext->optional_instance_methods) / sizeof(ext->optional_instance_methods->list[0]);\n        goto done;\n    } else if (ext->optional_instance_methods) {\n        i += ext->optional_instance_methods->count;\n    }\n\n    if (!isRequiredMethod && !isInstanceMethod) {\n        i += ((uintptr_t)m - (uintptr_t)ext->optional_class_methods) / sizeof(ext->optional_class_methods->list[0]);\n        goto done;\n    } else if (ext->optional_class_methods) {\n        i += ext->optional_class_methods->count;\n    }\n\n done:\n    return ext->extendedMethodTypes[i];\n}\n\n\n/***********************************************************************\n* objc_allocateProtocol\n* Creates a new protocol. The protocol may not be used until \n* objc_registerProtocol() is called.\n* Returns nil if a protocol with the same name already exists.\n* Locking: acquires classLock\n**********************************************************************/\nProtocol *\nobjc_allocateProtocol(const char *name)\n{\n    Class cls = objc_getClass(\"__IncompleteProtocol\");\n    assert(cls);\n\n    mutex_locker_t lock(classLock);\n\n    if (NXMapGet(protocol_map, name)) return nil;\n\n    old_protocol *result = (old_protocol *)\n        calloc(1, sizeof(old_protocol) \n                         + sizeof(old_protocol_ext));\n    old_protocol_ext *ext = (old_protocol_ext *)(result+1);\n    \n    result->isa = cls;\n    result->protocol_name = strdup(name);\n    ext->size = sizeof(old_protocol_ext);\n\n    // fixme reserve name without installing\n\n    NXMapInsert(protocol_ext_map, result, result+1);\n\n    return (Protocol *)result;\n}\n\n\n/***********************************************************************\n* objc_registerProtocol\n* Registers a newly-constructed protocol. The protocol is now \n* ready for use and immutable.\n* Locking: acquires classLock\n**********************************************************************/\nvoid objc_registerProtocol(Protocol *proto_gen) \n{\n    old_protocol *proto = oldprotocol(proto_gen);\n\n    Class oldcls = objc_getClass(\"__IncompleteProtocol\");\n    Class cls = objc_getClass(\"Protocol\");\n\n    mutex_locker_t lock(classLock);\n\n    if (proto->isa == cls) {\n        _objc_inform(\"objc_registerProtocol: protocol '%s' was already \"\n                     \"registered!\", proto->protocol_name);\n        return;\n    }\n    if (proto->isa != oldcls) {\n        _objc_inform(\"objc_registerProtocol: protocol '%s' was not allocated \"\n                     \"with objc_allocateProtocol!\", proto->protocol_name);\n        return;\n    }\n\n    proto->isa = cls;\n\n    NXMapKeyCopyingInsert(protocol_map, proto->protocol_name, proto);\n}\n\n\n/***********************************************************************\n* protocol_addProtocol\n* Adds an incorporated protocol to another protocol.\n* No method enforcement is performed.\n* `proto` must be under construction. `addition` must not.\n* Locking: acquires classLock\n**********************************************************************/\nvoid \nprotocol_addProtocol(Protocol *proto_gen, Protocol *addition_gen) \n{\n    old_protocol *proto = oldprotocol(proto_gen);\n    old_protocol *addition = oldprotocol(addition_gen);\n\n    Class cls = objc_getClass(\"__IncompleteProtocol\");\n\n    if (!proto_gen) return;\n    if (!addition_gen) return;\n\n    mutex_locker_t lock(classLock);\n\n    if (proto->isa != cls) {\n        _objc_inform(\"protocol_addProtocol: modified protocol '%s' is not \"\n                     \"under construction!\", proto->protocol_name);\n        return;\n    }\n    if (addition->isa == cls) {\n        _objc_inform(\"protocol_addProtocol: added protocol '%s' is still \"\n                     \"under construction!\", addition->protocol_name);\n        return;        \n    }\n    \n    old_protocol_list *protolist = proto->protocol_list;\n    if (protolist) {\n        size_t size = sizeof(old_protocol_list) \n            + protolist->count * sizeof(protolist->list[0]);\n        protolist = (old_protocol_list *)\n            realloc(protolist, size);\n    } else {\n        protolist = (old_protocol_list *)\n            calloc(1, sizeof(old_protocol_list));\n    }\n\n    protolist->list[protolist->count++] = addition;\n    proto->protocol_list = protolist;\n}\n\n\n/***********************************************************************\n* protocol_addMethodDescription\n* Adds a method to a protocol. The protocol must be under construction.\n* Locking: acquires classLock\n**********************************************************************/\nstatic void\n_protocol_addMethod(struct objc_method_description_list **list, SEL name, const char *types)\n{\n    if (!*list) {\n        *list = (struct objc_method_description_list *)\n            calloc(sizeof(struct objc_method_description_list), 1);\n    } else {\n        size_t size = sizeof(struct objc_method_description_list) \n            + (*list)->count * sizeof(struct objc_method_description);\n        *list = (struct objc_method_description_list *)\n            realloc(*list, size);\n    }\n\n    struct objc_method_description *desc = &(*list)->list[(*list)->count++];\n    desc->name = name;\n    desc->types = strdup(types ?: \"\");\n}\n\nvoid \nprotocol_addMethodDescription(Protocol *proto_gen, SEL name, const char *types,\n                              BOOL isRequiredMethod, BOOL isInstanceMethod) \n{\n    old_protocol *proto = oldprotocol(proto_gen);\n\n    Class cls = objc_getClass(\"__IncompleteProtocol\");\n\n    if (!proto_gen) return;\n\n    mutex_locker_t lock(classLock);\n\n    if (proto->isa != cls) {\n        _objc_inform(\"protocol_addMethodDescription: protocol '%s' is not \"\n                     \"under construction!\", proto->protocol_name);\n        return;\n    }\n\n    if (isRequiredMethod  &&  isInstanceMethod) {\n        _protocol_addMethod(&proto->instance_methods, name, types);\n    } else if (isRequiredMethod  &&  !isInstanceMethod) {\n        _protocol_addMethod(&proto->class_methods, name, types);\n    } else if (!isRequiredMethod  &&  isInstanceMethod) {\n        old_protocol_ext *ext = (old_protocol_ext *)(proto+1);\n        _protocol_addMethod(&ext->optional_instance_methods, name, types);\n    } else /*  !isRequiredMethod  &&  !isInstanceMethod) */ {\n        old_protocol_ext *ext = (old_protocol_ext *)(proto+1);\n        _protocol_addMethod(&ext->optional_class_methods, name, types);\n    }\n}\n\n\n/***********************************************************************\n* protocol_addProperty\n* Adds a property to a protocol. The protocol must be under construction.\n* Locking: acquires classLock\n**********************************************************************/\nstatic void \n_protocol_addProperty(old_property_list **plist, const char *name, \n                      const objc_property_attribute_t *attrs, \n                      unsigned int count)\n{\n    if (!*plist) {\n        *plist = (old_property_list *)\n            calloc(sizeof(old_property_list), 1);\n        (*plist)->entsize = sizeof(old_property);\n    } else {\n        *plist = (old_property_list *)\n            realloc(*plist, sizeof(old_property_list) \n                              + (*plist)->count * (*plist)->entsize);\n    }\n\n    old_property *prop = property_list_nth(*plist, (*plist)->count++);\n    prop->name = strdup(name);\n    prop->attributes = copyPropertyAttributeString(attrs, count);\n}\n\nvoid \nprotocol_addProperty(Protocol *proto_gen, const char *name, \n                     const objc_property_attribute_t *attrs, \n                     unsigned int count,\n                     BOOL isRequiredProperty, BOOL isInstanceProperty)\n{\n    old_protocol *proto = oldprotocol(proto_gen);\n\n    Class cls = objc_getClass(\"__IncompleteProtocol\");\n\n    if (!proto) return;\n    if (!name) return;\n\n    mutex_locker_t lock(classLock);\n    \n    if (proto->isa != cls) {\n        _objc_inform(\"protocol_addProperty: protocol '%s' is not \"\n                     \"under construction!\", proto->protocol_name);\n        return;\n    }\n\n    old_protocol_ext *ext = ext_for_protocol(proto);\n\n    if (isRequiredProperty  &&  isInstanceProperty) {\n        _protocol_addProperty(&ext->instance_properties, name, attrs, count);\n    }\n    else if (isRequiredProperty  &&  !isInstanceProperty) {\n        _protocol_addProperty(&ext->class_properties, name, attrs, count);\n    }\n    // else if (!isRequiredProperty  &&  isInstanceProperty) {\n    //    _protocol_addProperty(&ext->optional_instance_properties, name, attrs, count);\n    //} \n    // else /*  !isRequiredProperty  &&  !isInstanceProperty) */ {\n    //    _protocol_addProperty(&ext->optional_class_properties, name, attrs, count);\n    //}\n}\n\n\n/***********************************************************************\n* _objc_fixup_protocol_objects_for_image.  For each protocol in the\n* specified image, selectorize the method names and add to the protocol hash.\n**********************************************************************/\n\nstatic bool versionIsExt(uintptr_t version, const char *names, size_t size)\n{\n    // CodeWarrior used isa field for string \"Protocol\" \n    //   from section __OBJC,__class_names.  rdar://4951638\n    // gcc (10.4 and earlier) used isa field for version number; \n    //   the only version number used on Mac OS X was 2.\n    // gcc (10.5 and later) uses isa field for ext pointer\n\n    if (version < 4096 /* not PAGE_SIZE */) {\n        return NO;\n    }\n\n    if (version >= (uintptr_t)names  &&  version < (uintptr_t)(names + size)) {\n        return NO;\n    }\n\n    return YES;\n}\n\nstatic void fix_protocol(old_protocol *proto, Class protocolClass, \n                         bool isBundle, const char *names, size_t names_size)\n{\n    uintptr_t version;\n    if (!proto) return;\n\n    version = (uintptr_t)proto->isa;\n\n    // Set the protocol's isa\n    proto->isa = protocolClass;\n\n    // Fix up method lists\n    // fixme share across duplicates\n    map_method_descs (proto->instance_methods, isBundle);\n    map_method_descs (proto->class_methods, isBundle);\n\n    // Fix up ext, if any\n    if (versionIsExt(version, names, names_size)) {\n        old_protocol_ext *ext = (old_protocol_ext *)version;\n        NXMapInsert(protocol_ext_map, proto, ext);\n        map_method_descs (ext->optional_instance_methods, isBundle);\n        map_method_descs (ext->optional_class_methods, isBundle);\n    }\n    \n    // Record the protocol it if we don't have one with this name yet\n    // fixme bundles - copy protocol\n    // fixme unloading\n    if (!NXMapGet(protocol_map, proto->protocol_name)) {\n        NXMapKeyCopyingInsert(protocol_map, proto->protocol_name, proto);\n        if (PrintProtocols) {\n            _objc_inform(\"PROTOCOLS: protocol at %p is %s\",\n                         proto, proto->protocol_name);\n        }\n    } else {\n        // duplicate - do nothing\n        if (PrintProtocols) {\n            _objc_inform(\"PROTOCOLS: protocol at %p is %s (duplicate)\",\n                         proto, proto->protocol_name);\n        }\n    }\n}\n\nstatic void _objc_fixup_protocol_objects_for_image (header_info * hi)\n{\n    Class protocolClass = objc_getClass(\"Protocol\");\n    size_t count, i;\n    old_protocol **protos;\n    int isBundle = headerIsBundle(hi);\n    const char *names;\n    size_t names_size;\n\n    mutex_locker_t lock(classLock);\n\n    // Allocate the protocol registry if necessary.\n    if (!protocol_map) {\n        protocol_map = \n            NXCreateMapTable(NXStrValueMapPrototype, 32);\n    }\n    if (!protocol_ext_map) {\n        protocol_ext_map = \n            NXCreateMapTable(NXPtrValueMapPrototype, 32);\n    }\n\n    protos = _getObjcProtocols(hi, &count);\n    names = _getObjcClassNames(hi, &names_size);\n    for (i = 0; i < count; i++) {\n        fix_protocol(protos[i], protocolClass, isBundle, names, names_size);\n    }\n}\n\n\n/***********************************************************************\n* _objc_fixup_selector_refs.  Register all of the selectors in each\n* image, and fix them all up.\n**********************************************************************/\nstatic void _objc_fixup_selector_refs   (const header_info *hi)\n{\n    size_t count;\n    SEL *sels;\n\n    bool preoptimized = hi->isPreoptimized();\n\n    if (PrintPreopt) {\n        if (preoptimized) {\n            _objc_inform(\"PREOPTIMIZATION: honoring preoptimized selectors in %s\", \n                         hi->fname());\n        }\n        else if (hi->info()->optimizedByDyld()) {\n            _objc_inform(\"PREOPTIMIZATION: IGNORING preoptimized selectors in %s\", \n                         hi->fname());\n        }\n    }\n\n    if (preoptimized) return;\n    \n    sels = _getObjcSelectorRefs (hi, &count);\n\n    map_selrefs(sels, count, headerIsBundle(hi));\n}\n\nstatic inline bool _is_threaded() {\n#if TARGET_OS_WIN32\n    return YES;\n#else\n    return pthread_is_threaded_np() != 0;\n#endif\n}\n\n#if !TARGET_OS_WIN32\n/***********************************************************************\n* unmap_image\n* Process the given image which is about to be unmapped by dyld.\n* mh is mach_header instead of headerType because that's what \n*   dyld_priv.h says even for 64-bit.\n**********************************************************************/\nvoid \nunmap_image(const char *path __unused, const struct mach_header *mh)\n{\n    recursive_mutex_locker_t lock(loadMethodLock);\n    unmap_image_nolock(mh);\n}\n\n\n/***********************************************************************\n* map_images\n* Process the given images which are being mapped in by dyld.\n* Calls ABI-agnostic code after taking ABI-specific locks.\n**********************************************************************/\nvoid\nmap_images(unsigned count, const char * const paths[],\n           const struct mach_header * const mhdrs[])\n{\n    recursive_mutex_locker_t lock(loadMethodLock);\n    map_images_nolock(count, paths, mhdrs);\n}\n\n\n/***********************************************************************\n* load_images\n* Process +load in the given images which are being mapped in by dyld.\n*\n* Locking: acquires classLock and loadMethodLock\n**********************************************************************/\nextern void prepare_load_methods(const headerType *mhdr);\n\nvoid\nload_images(const char *path __unused, const struct mach_header *mh)\n{\n    recursive_mutex_locker_t lock(loadMethodLock);\n\n    // Discover +load methods\n    prepare_load_methods((const headerType *)mh);\n\n    // Call +load methods (without classLock - re-entrant)\n    call_load_methods();\n}\n#endif\n\n\n/***********************************************************************\n* _read_images\n* Perform metadata processing for hCount images starting with firstNewHeader\n**********************************************************************/\nvoid _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClass)\n{\n    uint32_t i;\n    bool categoriesLoaded = NO;\n\n    if (!class_hash) _objc_init_class_hash();\n\n    // Parts of this order are important for correctness or performance.\n\n    // Read classes from all images.\n    for (i = 0; i < hCount; i++) {\n        _objc_read_classes_from_image(hList[i]);\n    }\n\n    // Read categories from all images. \n    // But not if any other threads are running - they might\n    // call a category method before the fixups below are complete.\n     if (!_is_threaded()) {\n        bool needFlush = NO;\n        for (i = 0; i < hCount; i++) {\n            needFlush |= _objc_read_categories_from_image(hList[i]);\n        }\n        if (needFlush) flush_marked_caches();\n        categoriesLoaded = YES;\n    }\n\n    // Connect classes from all images.\n    for (i = 0; i < hCount; i++) {\n        _objc_connect_classes_from_image(hList[i]);\n    }\n\n    // Fix up class refs, selector refs, and protocol objects from all images.\n    for (i = 0; i < hCount; i++) {\n        _objc_map_class_refs_for_image(hList[i]);\n        _objc_fixup_selector_refs(hList[i]);\n        _objc_fixup_protocol_objects_for_image(hList[i]);\n    }\n\n    // Read categories from all images. \n    // But not if this is the only thread - it's more \n    // efficient to attach categories earlier if safe.\n    if (!categoriesLoaded) {\n        bool needFlush = NO;\n        for (i = 0; i < hCount; i++) {\n            needFlush |= _objc_read_categories_from_image(hList[i]);\n        }\n        if (needFlush) flush_marked_caches();\n    }\n\n    // Multi-threaded category load MUST BE LAST to avoid a race.\n}\n\n\n/***********************************************************************\n* prepare_load_methods\n* Schedule +load for classes in this image, any un-+load-ed \n* superclasses in other images, and any categories in this image.\n**********************************************************************/\n// Recursively schedule +load for cls and any un-+load-ed superclasses.\n// cls must already be connected.\nstatic void schedule_class_load(Class cls)\n{\n    if (cls->info & CLS_LOADED) return;\n    if (cls->superclass) schedule_class_load(cls->superclass);\n    add_class_to_loadable_list(cls);\n    cls->info |= CLS_LOADED;\n}\n\nvoid prepare_load_methods(const headerType *mhdr)\n{\n    Module mods;\n    unsigned int midx;\n\n    header_info *hi;\n    for (hi = FirstHeader; hi; hi = hi->getNext()) {\n        if (mhdr == hi->mhdr()) break;\n    }\n    if (!hi) return;\n\n    if (hi->info()->isReplacement()) {\n        // Ignore any classes in this image\n        return;\n    }\n\n    // Major loop - process all modules in the image\n    mods = hi->mod_ptr;\n    for (midx = 0; midx < hi->mod_count; midx += 1)\n    {\n        unsigned int index;\n\n        // Skip module containing no classes\n        if (mods[midx].symtab == nil)\n            continue;\n\n        // Minor loop - process all the classes in given module\n        for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)\n        {\n            // Locate the class description pointer\n            Class cls = (Class)mods[midx].symtab->defs[index];\n            if (cls->info & CLS_CONNECTED) {\n                schedule_class_load(cls);\n            }\n        }\n    }\n\n\n    // Major loop - process all modules in the header\n    mods = hi->mod_ptr;\n\n    // NOTE: The module and category lists are traversed backwards \n    // to preserve the pre-10.4 processing order. Changing the order \n    // would have a small chance of introducing binary compatibility bugs.\n    midx = (unsigned int)hi->mod_count;\n    while (midx-- > 0) {\n        unsigned int index;\n        unsigned int total;\n        Symtab symtab = mods[midx].symtab;\n\n        // Nothing to do for a module without a symbol table\n        if (mods[midx].symtab == nil)\n            continue;\n        // Total entries in symbol table (class entries followed\n        // by category entries)\n        total = mods[midx].symtab->cls_def_cnt +\n            mods[midx].symtab->cat_def_cnt;\n        \n        // Minor loop - register all categories from given module\n        index = total;\n        while (index-- > mods[midx].symtab->cls_def_cnt) {\n            old_category *cat = (old_category *)symtab->defs[index];\n            add_category_to_loadable_list((Category)cat);\n        }\n    }\n}\n\n\n#if TARGET_OS_WIN32\n\nvoid unload_class(Class cls)\n{\n}\n\n#else\n\n/***********************************************************************\n* _objc_remove_classes_in_image\n* Remove all classes in the given image from the runtime, because \n* the image is about to be unloaded.\n* Things to clean up:\n*   class_hash\n*   unconnected_class_hash\n*   pending subclasses list (only if class is still unconnected)\n*   loadable class list\n*   class's method caches\n*   class refs in all other images\n**********************************************************************/\n// Re-pend any class references in refs that point into [start..end)\nstatic void rependClassReferences(Class *refs, size_t count, \n                                  uintptr_t start, uintptr_t end)\n{\n    size_t i;\n\n    if (!refs) return;\n\n    // Process each class ref\n    for (i = 0; i < count; i++) {\n        if ((uintptr_t)(refs[i]) >= start  &&  (uintptr_t)(refs[i]) < end) {\n            pendClassReference(&refs[i], refs[i]->name,\n                               refs[i]->info & CLS_META);\n            refs[i] = nil;\n        }\n    }\n}\n\n\nvoid try_free(const void *p)\n{\n    if (p  &&  malloc_size(p)) free((void *)p);\n}\n\n// Deallocate all memory in a method list\nstatic void unload_mlist(old_method_list *mlist) \n{\n    int i;\n    for (i = 0; i < mlist->method_count; i++) {\n        try_free(mlist->method_list[i].method_types);\n    }\n    try_free(mlist);\n}\n\nstatic void unload_property_list(old_property_list *proplist)\n{\n    uint32_t i;\n\n    if (!proplist) return;\n\n    for (i = 0; i < proplist->count; i++) {\n        old_property *prop = property_list_nth(proplist, i);\n        try_free(prop->name);\n        try_free(prop->attributes);\n    }\n    try_free(proplist);\n}\n\n\n// Deallocate all memory in a class. \nvoid unload_class(Class cls)\n{\n    // Free method cache\n    // This dereferences the cache contents; do this before freeing methods\n    if (cls->cache  &&  cls->cache != &_objc_empty_cache) {\n        _cache_free(cls->cache);\n    }\n\n    // Free ivar lists\n    if (cls->ivars) {\n        int i;\n        for (i = 0; i < cls->ivars->ivar_count; i++) {\n            try_free(cls->ivars->ivar_list[i].ivar_name);\n            try_free(cls->ivars->ivar_list[i].ivar_type);\n        }\n        try_free(cls->ivars);\n    }\n\n    // Free fixed-up method lists and method list array\n    if (cls->methodLists) {\n        // more than zero method lists\n        if (cls->info & CLS_NO_METHOD_ARRAY) {\n            // one method list\n            unload_mlist((old_method_list *)cls->methodLists);\n        } \n        else {\n            // more than one method list\n            old_method_list **mlistp;\n            for (mlistp = cls->methodLists; \n                 *mlistp != nil  &&  *mlistp != END_OF_METHODS_LIST; \n                 mlistp++) \n            {\n                unload_mlist(*mlistp);\n            }\n            free(cls->methodLists);\n        }\n    }\n\n    // Free protocol list\n    old_protocol_list *protos = cls->protocols;\n    while (protos) {\n        old_protocol_list *dead = protos;\n        protos = protos->next;\n        try_free(dead);\n    }\n\n    if ((cls->info & CLS_EXT)) {\n        if (cls->ext) {\n            // Free property lists and property list array\n            if (cls->ext->propertyLists) {\n                // more than zero property lists\n                if (cls->info & CLS_NO_PROPERTY_ARRAY) {\n                    // one property list\n                    old_property_list *proplist = \n                        (old_property_list *)cls->ext->propertyLists;\n                    unload_property_list(proplist);\n                } else {\n                    // more than one property list\n                    old_property_list **plistp;\n                    for (plistp = cls->ext->propertyLists; \n                         *plistp != nil; \n                         plistp++) \n                    {\n                        unload_property_list(*plistp);\n                    }\n                    try_free(cls->ext->propertyLists);\n                }\n            }\n\n            // Free weak ivar layout\n            try_free(cls->ext->weak_ivar_layout);\n\n            // Free ext\n            try_free(cls->ext);\n        }\n\n        // Free non-weak ivar layout\n        try_free(cls->ivar_layout);\n    }\n\n    // Free class name\n    try_free(cls->name);\n\n    // Free cls\n    try_free(cls);\n}\n\n\nstatic void _objc_remove_classes_in_image(header_info *hi)\n{\n    unsigned int       index;\n    unsigned int       midx;\n    Module             mods;\n\n    mutex_locker_t lock(classLock);\n    \n    // Major loop - process all modules in the image\n    mods = hi->mod_ptr;\n    for (midx = 0; midx < hi->mod_count; midx += 1)\n    {\n        // Skip module containing no classes\n        if (mods[midx].symtab == nil)\n            continue;\n        \n        // Minor loop - process all the classes in given module\n        for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)\n        {\n            Class cls;\n            \n            // Locate the class description pointer\n            cls = (Class)mods[midx].symtab->defs[index];\n\n            // Remove from loadable class list, if present\n            remove_class_from_loadable_list(cls);\n\n            // Remove from unconnected_class_hash and pending subclasses\n            if (unconnected_class_hash  &&  NXHashMember(unconnected_class_hash, cls)) {\n                NXHashRemove(unconnected_class_hash, cls);\n                if (pendingSubclassesMap) {\n                    // Find this class in its superclass's pending list\n                    char *supercls_name = (char *)cls->superclass;\n                    PendingSubclass *pending = (PendingSubclass *)\n                        NXMapGet(pendingSubclassesMap, supercls_name);\n                    for ( ; pending != nil; pending = pending->next) {\n                        if (pending->subclass == cls) {\n                            pending->subclass = Nil;\n                            break;\n                        }\n                    }\n                }\n            }\n            \n            // Remove from class_hash\n            NXHashRemove(class_hash, cls);\n\n            // Free heap memory pointed to by the class\n            unload_class(cls->ISA());\n            unload_class(cls);\n        }\n    }\n\n\n    // Search all other images for class refs that point back to this range.\n    // Un-fix and re-pend any such class refs.\n\n    // Get the location of the dying image's __OBJC segment\n    uintptr_t seg;\n    unsigned long seg_size;\n    seg = (uintptr_t)getsegmentdata(hi->mhdr(), \"__OBJC\", &seg_size);\n\n    header_info *other_hi;\n    for (other_hi = FirstHeader; other_hi != nil; other_hi = other_hi->getNext()) {\n        Class *other_refs;\n        size_t count;\n        if (other_hi == hi) continue;  // skip the image being unloaded\n\n        // Fix class refs in the other image\n        other_refs = _getObjcClassRefs(other_hi, &count);\n        rependClassReferences(other_refs, count, seg, seg+seg_size);\n    }\n}\n\n\n/***********************************************************************\n* _objc_remove_categories_in_image\n* Remove all categories in the given image from the runtime, because \n* the image is about to be unloaded.\n* Things to clean up:\n*    unresolved category list\n*    loadable category list\n**********************************************************************/\nstatic void _objc_remove_categories_in_image(header_info *hi)\n{\n    Module mods;\n    unsigned int midx;\n    \n    // Major loop - process all modules in the header\n    mods = hi->mod_ptr;\n    \n    for (midx = 0; midx < hi->mod_count; midx++) {\n        unsigned int index;\n        unsigned int total;\n        Symtab symtab = mods[midx].symtab;\n        \n        // Nothing to do for a module without a symbol table\n        if (symtab == nil) continue;\n        \n        // Total entries in symbol table (class entries followed\n        // by category entries)\n        total = symtab->cls_def_cnt + symtab->cat_def_cnt;\n        \n        // Minor loop - check all categories from given module\n        for (index = symtab->cls_def_cnt; index < total; index++) {\n            old_category *cat = (old_category *)symtab->defs[index];\n\n            // Clean up loadable category list\n            remove_category_from_loadable_list((Category)cat);\n\n            // Clean up category_hash\n            if (category_hash) {\n                _objc_unresolved_category *cat_entry = (_objc_unresolved_category *)NXMapGet(category_hash, cat->class_name);\n                for ( ; cat_entry != nil; cat_entry = cat_entry->next) {\n                    if (cat_entry->cat == cat) {\n                        cat_entry->cat = nil;\n                        break;\n                    }\n                }\n            }\n        }\n    }\n}\n\n\n/***********************************************************************\n* unload_paranoia\n* Various paranoid debugging checks that look for poorly-behaving \n* unloadable bundles. \n* Called by _objc_unmap_image when OBJC_UNLOAD_DEBUG is set.\n**********************************************************************/\nstatic void unload_paranoia(header_info *hi) \n{\n    // Get the location of the dying image's __OBJC segment\n    uintptr_t seg;\n    unsigned long seg_size;\n    seg = (uintptr_t)getsegmentdata(hi->mhdr(), \"__OBJC\", &seg_size);\n\n    _objc_inform(\"UNLOAD DEBUG: unloading image '%s' [%p..%p]\", \n                 hi->fname(), (void *)seg, (void*)(seg+seg_size));\n\n    mutex_locker_t lock(classLock);\n\n    // Make sure the image contains no categories on surviving classes.\n    {\n        Module mods;\n        unsigned int midx;\n\n        // Major loop - process all modules in the header\n        mods = hi->mod_ptr;\n        \n        for (midx = 0; midx < hi->mod_count; midx++) {\n            unsigned int index;\n            unsigned int total;\n            Symtab symtab = mods[midx].symtab;\n\n            // Nothing to do for a module without a symbol table\n            if (symtab == nil) continue;\n            \n            // Total entries in symbol table (class entries followed\n            // by category entries)\n            total = symtab->cls_def_cnt + symtab->cat_def_cnt;\n            \n            // Minor loop - check all categories from given module\n            for (index = symtab->cls_def_cnt; index < total; index++) {\n                old_category *cat = (old_category *)symtab->defs[index];\n                struct objc_class query;\n\n                query.name = cat->class_name;\n                if (NXHashMember(class_hash, &query)) {\n                    _objc_inform(\"UNLOAD DEBUG: dying image contains category '%s(%s)' on surviving class '%s'!\", cat->class_name, cat->category_name, cat->class_name);\n                }\n            }\n        }\n    }\n\n    // Make sure no surviving class is in the dying image.\n    // Make sure no surviving class has a superclass in the dying image.\n    // fixme check method implementations too\n    {\n        Class cls;\n        NXHashState state;\n\n        state = NXInitHashState(class_hash);\n        while (NXNextHashState(class_hash, &state, (void **)&cls)) {\n            if ((vm_address_t)cls >= seg  && \n                (vm_address_t)cls < seg+seg_size) \n            {\n                _objc_inform(\"UNLOAD DEBUG: dying image contains surviving class '%s'!\", cls->name);\n            }\n            \n            if ((vm_address_t)cls->superclass >= seg  &&  \n                (vm_address_t)cls->superclass < seg+seg_size)\n            {\n                _objc_inform(\"UNLOAD DEBUG: dying image contains superclass '%s' of surviving class '%s'!\", cls->superclass->name, cls->name);\n            }\n        }\n    }\n}\n\n\n/***********************************************************************\n* _unload_image\n* Only handles MH_BUNDLE for now.\n* Locking: loadMethodLock acquired by unmap_image\n**********************************************************************/\nvoid _unload_image(header_info *hi)\n{\n    loadMethodLock.assertLocked();\n\n    // Cleanup:\n    // Remove image's classes from the class list and free auxiliary data.\n    // Remove image's unresolved or loadable categories and free auxiliary data\n    // Remove image's unresolved class refs.\n    _objc_remove_classes_in_image(hi);\n    _objc_remove_categories_in_image(hi);\n    _objc_remove_pending_class_refs_in_image(hi);\n    if (hi->proto_refs) try_free(hi->proto_refs);\n\n    // Perform various debugging checks if requested.\n    if (DebugUnload) unload_paranoia(hi);\n}\n\n#endif\n\n\n/***********************************************************************\n* objc_addClass.  Add the specified class to the table of known classes,\n* after doing a little verification and fixup.\n**********************************************************************/\nvoid\t\tobjc_addClass\t\t(Class cls)\n{\n    OBJC_WARN_DEPRECATED;\n\n    // Synchronize access to hash table\n    mutex_locker_t lock(classLock);\n\n    // Make sure both the class and the metaclass have caches!\n    // Clear all bits of the info fields except CLS_CLASS and CLS_META.\n    // Normally these bits are already clear but if someone tries to cons\n    // up their own class on the fly they might need to be cleared.\n    if (cls->cache == nil) {\n        cls->cache = (Cache) &_objc_empty_cache;\n        cls->info = CLS_CLASS;\n    }\n\n    if (cls->ISA()->cache == nil) {\n        cls->ISA()->cache = (Cache) &_objc_empty_cache;\n        cls->ISA()->info = CLS_META;\n    }\n\n    // methodLists should be: \n    // 1. nil (Tiger and later only)\n    // 2. A -1 terminated method list array\n    // In either case, CLS_NO_METHOD_ARRAY remains clear.\n    // If the user manipulates the method list directly, \n    // they must use the magic private format.\n\n    // Add the class to the table\n    (void) NXHashInsert (class_hash, cls);\n\n    // Superclass is no longer a leaf for cache flushing\n    if (cls->superclass && (cls->superclass->info & CLS_LEAF)) {\n        cls->superclass->clearInfo(CLS_LEAF);\n        cls->superclass->ISA()->clearInfo(CLS_LEAF);\n    }\n}\n\n/***********************************************************************\n* _objcTweakMethodListPointerForClass.\n* Change the class's method list pointer to a method list array. \n* Does nothing if the method list pointer is already a method list array.\n* If the class is currently in use, methodListLock must be held by the caller.\n**********************************************************************/\nstatic void _objcTweakMethodListPointerForClass(Class cls)\n{\n    old_method_list *\toriginalList;\n    const int\t\t\t\t\tinitialEntries = 4;\n    size_t\t\t\t\t\t\t\tmallocSize;\n    old_method_list **\tptr;\n\n    // Do nothing if methodLists is already an array.\n    if (cls->methodLists  &&  !(cls->info & CLS_NO_METHOD_ARRAY)) return;\n\n    // Remember existing list\n    originalList = (old_method_list *) cls->methodLists;\n\n    // Allocate and zero a method list array\n    mallocSize   = sizeof(old_method_list *) * initialEntries;\n    ptr\t     = (old_method_list **) calloc(1, mallocSize);\n\n    // Insert the existing list into the array\n    ptr[initialEntries - 1] = END_OF_METHODS_LIST;\n    ptr[0] = originalList;\n\n    // Replace existing list with array\n    cls->methodLists = ptr;\n    cls->clearInfo(CLS_NO_METHOD_ARRAY);\n}\n\n\n/***********************************************************************\n* _objc_insertMethods.\n* Adds methods to a class.\n* Does not flush any method caches.\n* Does not take any locks.\n* If the class is already in use, use class_addMethods() instead.\n**********************************************************************/\nvoid _objc_insertMethods(Class cls, old_method_list *mlist, old_category *cat)\n{\n    old_method_list ***list;\n    old_method_list **ptr;\n    ptrdiff_t endIndex;\n    size_t oldSize;\n    size_t newSize;\n\n    if (!cls->methodLists) {\n        // cls has no methods - simply use this method list\n        cls->methodLists = (old_method_list **)mlist;\n        cls->setInfo(CLS_NO_METHOD_ARRAY);\n        return;\n    }\n\n    // Log any existing methods being replaced\n    if (PrintReplacedMethods) {\n        int i;\n        for (i = 0; i < mlist->method_count; i++) {\n            extern IMP findIMPInClass(Class cls, SEL sel);\n            SEL sel = sel_registerName((char *)mlist->method_list[i].method_name);\n            IMP newImp = mlist->method_list[i].method_imp;\n            IMP oldImp;\n\n            if ((oldImp = findIMPInClass(cls, sel))) {\n                logReplacedMethod(cls->name, sel, ISMETA(cls), \n                                  cat ? cat->category_name : nil, \n                                  oldImp, newImp);\n            }\n        }\n    }\n\n    // Create method list array if necessary\n    _objcTweakMethodListPointerForClass(cls);\n    \n    list = &cls->methodLists;\n\n    // Locate unused entry for insertion point\n    ptr = *list;\n    while ((*ptr != 0) && (*ptr != END_OF_METHODS_LIST))\n        ptr += 1;\n\n    // If array is full, add to it\n    if (*ptr == END_OF_METHODS_LIST)\n    {\n        // Calculate old and new dimensions\n        endIndex = ptr - *list;\n        oldSize  = (endIndex + 1) * sizeof(void *);\n        newSize  = oldSize + sizeof(old_method_list *); // only increase by 1\n\n        // Grow the method list array by one.\n        *list = (old_method_list **)realloc(*list, newSize);\n\n        // Zero out addition part of new array\n        bzero (&((*list)[endIndex]), newSize - oldSize);\n\n        // Place new end marker\n        (*list)[(newSize/sizeof(void *)) - 1] = END_OF_METHODS_LIST;\n\n        // Insertion point corresponds to old array end\n        ptr = &((*list)[endIndex]);\n    }\n\n    // Right shift existing entries by one\n    bcopy (*list, (*list) + 1, (uint8_t *)ptr - (uint8_t *)*list);\n\n    // Insert at method list at beginning of array\n    **list = mlist;\n}\n\n/***********************************************************************\n* _objc_removeMethods.\n* Remove methods from a class.\n* Does not take any locks.\n* Does not flush any method caches.\n* If the class is currently in use, use class_removeMethods() instead.\n**********************************************************************/\nvoid _objc_removeMethods(Class cls, old_method_list *mlist)\n{\n    old_method_list ***list;\n    old_method_list **ptr;\n\n    if (cls->methodLists == nil) {\n        // cls has no methods\n        return;\n    }\n    if (cls->methodLists == (old_method_list **)mlist) {\n        // mlist is the class's only method list - erase it\n        cls->methodLists = nil;\n        return;\n    }\n    if (cls->info & CLS_NO_METHOD_ARRAY) {\n        // cls has only one method list, and this isn't it - do nothing\n        return;\n    }\n\n    // cls has a method list array - search it\n\n    list = &cls->methodLists;\n\n    // Locate list in the array\n    ptr = *list;\n    while (*ptr != mlist) {\n        // fix for radar # 2538790\n        if ( *ptr == END_OF_METHODS_LIST ) return;\n        ptr += 1;\n    }\n\n    // Remove this entry\n    *ptr = 0;\n\n    // Left shift the following entries\n    while (*(++ptr) != END_OF_METHODS_LIST)\n        *(ptr-1) = *ptr;\n    *(ptr-1) = 0;\n}\n\n/***********************************************************************\n* _objc_add_category.  Install the specified category's methods and\n* protocols into the class it augments.\n* The class is assumed not to be in use yet: no locks are taken and \n* no method caches are flushed.\n**********************************************************************/\nstatic inline void _objc_add_category(Class cls, old_category *category, int version)\n{\n    if (PrintConnecting) {\n        _objc_inform(\"CONNECT: attaching category '%s (%s)'\", cls->name, category->category_name);\n    }\n\n    // Augment instance methods\n    if (category->instance_methods)\n        _objc_insertMethods (cls, category->instance_methods, category);\n\n    // Augment class methods\n    if (category->class_methods)\n        _objc_insertMethods (cls->ISA(), category->class_methods, category);\n\n    // Augment protocols\n    if ((version >= 5) && category->protocols)\n    {\n        if (cls->ISA()->version >= 5)\n        {\n            category->protocols->next = cls->protocols;\n            cls->protocols\t          = category->protocols;\n            cls->ISA()->protocols       = category->protocols;\n        }\n        else\n        {\n            _objc_inform (\"unable to add protocols from category %s...\\n\", category->category_name);\n            _objc_inform (\"class `%s' must be recompiled\\n\", category->class_name);\n        }\n    }\n\n    // Augment instance properties\n    if (version >= 7  &&  category->instance_properties) {\n        if (cls->ISA()->version >= 6) {\n            _class_addProperties(cls, category->instance_properties);\n        } else {\n            _objc_inform (\"unable to add instance properties from category %s...\\n\", category->category_name);\n            _objc_inform (\"class `%s' must be recompiled\\n\", category->class_name);\n        }\n    }\n\n    // Augment class properties\n    if (version >= 7  &&  category->hasClassPropertiesField()  &&  \n        category->class_properties) \n    {\n        if (cls->ISA()->version >= 6) {\n            _class_addProperties(cls->ISA(), category->class_properties);\n        } else {\n            _objc_inform (\"unable to add class properties from category %s...\\n\", category->category_name);\n            _objc_inform (\"class `%s' must be recompiled\\n\", category->class_name);\n        }\n    }\n}\n\n/***********************************************************************\n* _objc_add_category_flush_caches.  Install the specified category's \n* methods into the class it augments, and flush the class' method cache.\n* Return YES if some method caches now need to be flushed.\n**********************************************************************/\nstatic bool _objc_add_category_flush_caches(Class cls, old_category *category, int version)\n{\n    bool needFlush = NO;\n\n    // Install the category's methods into its intended class\n    {\n        mutex_locker_t lock(methodListLock);\n        _objc_add_category (cls, category, version);\n    }\n\n    // Queue for cache flushing so category's methods can get called\n    if (category->instance_methods) {\n        cls->setInfo(CLS_FLUSH_CACHE);\n        needFlush = YES;\n    }\n    if (category->class_methods) {\n        cls->ISA()->setInfo(CLS_FLUSH_CACHE);\n        needFlush = YES;\n    }\n    \n    return needFlush;\n}\n\n\n/***********************************************************************\n* reverse_cat\n* Reverse the given linked list of pending categories. \n* The pending category list is built backwards, and needs to be \n* reversed before actually attaching the categories to a class.\n* Returns the head of the new linked list.\n**********************************************************************/\nstatic _objc_unresolved_category *reverse_cat(_objc_unresolved_category *cat)\n{\n    _objc_unresolved_category *prev;\n    _objc_unresolved_category *cur;\n    _objc_unresolved_category *ahead;\n\n    if (!cat) return nil;\n\n    prev = nil;\n    cur = cat;\n    ahead = cat->next;\n    \n    while (cur) {\n        ahead = cur->next;\n        cur->next = prev;\n        prev = cur;\n        cur = ahead;\n    }\n\n    return prev;\n}\n\n\n/***********************************************************************\n* resolve_categories_for_class.  \n* Install all existing categories intended for the specified class.\n* cls must be a true class and not a metaclass.\n**********************************************************************/\nstatic void resolve_categories_for_class(Class cls)\n{\n    _objc_unresolved_category *\tpending;\n    _objc_unresolved_category *\tnext;\n\n    // Nothing to do if there are no categories at all\n    if (!category_hash) return;\n\n    // Locate and remove first element in category list\n    // associated with this class\n    pending = (_objc_unresolved_category *)\n        NXMapKeyFreeingRemove (category_hash, cls->name);\n\n    // Traverse the list of categories, if any, registered for this class\n\n    // The pending list is built backwards. Reverse it and walk forwards.\n    pending = reverse_cat(pending);\n\n    while (pending) {\n        if (pending->cat) {\n            // Install the category\n            // use the non-flush-cache version since we are only\n            // called from the class intialization code\n            _objc_add_category(cls, pending->cat, (int)pending->version);\n        }\n\n        // Delink and reclaim this registration\n        next = pending->next;\n        free(pending);\n        pending = next;\n    }\n}\n\n\n/***********************************************************************\n* _objc_resolve_categories_for_class.  \n* Public version of resolve_categories_for_class. This was \n* exported pre-10.4 for Omni et al. to workaround a problem \n* with too-lazy category attachment.\n* cls should be a class, but this function can also cope with metaclasses.\n**********************************************************************/\nvoid _objc_resolve_categories_for_class(Class cls)\n{\n    // If cls is a metaclass, get the class. \n    // resolve_categories_for_class() requires a real class to work correctly.\n    if (ISMETA(cls)) {\n        if (strncmp(cls->name, \"_%\", 2) == 0) {\n            // Posee's meta's name is smashed and isn't in the class_hash, \n            // so objc_getClass doesn't work.\n            const char *baseName = strchr(cls->name, '%'); // get posee's real name\n            cls = objc_getClass(baseName);\n        } else {\n            cls = objc_getClass(cls->name);\n        }\n    }\n\n    resolve_categories_for_class(cls);\n}\n\n\n/***********************************************************************\n* _objc_register_category.\n* Process a category read from an image. \n* If the category's class exists, attach the category immediately. \n*   Classes that need cache flushing are marked but not flushed.\n* If the category's class does not exist yet, pend the category for \n*   later attachment. Pending categories are attached in the order \n*   they were discovered.\n* Returns YES if some method caches now need to be flushed.\n**********************************************************************/\nstatic bool _objc_register_category(old_category *cat, int version)\n{\n    _objc_unresolved_category *\tnew_cat;\n    _objc_unresolved_category *\told;\n    Class theClass;\n\n    // If the category's class exists, attach the category.\n    if ((theClass = objc_lookUpClass(cat->class_name))) {\n        return _objc_add_category_flush_caches(theClass, cat, version);\n    }\n    \n    // If the category's class exists but is unconnected, \n    // then attach the category to the class but don't bother \n    // flushing any method caches (because they must be empty).\n    // YES unconnected, NO class_handler\n    if ((theClass = look_up_class(cat->class_name, YES, NO))) {\n        _objc_add_category(theClass, cat, version);\n        return NO;\n    }\n\n\n    // Category's class does not exist yet. \n    // Save the category for later attachment.\n\n    if (PrintConnecting) {\n        _objc_inform(\"CONNECT: pending category '%s (%s)'\", cat->class_name, cat->category_name);\n    }\n\n    // Create category lookup table if needed\n    if (!category_hash)\n        category_hash = NXCreateMapTable(NXStrValueMapPrototype, 128);\n\n    // Locate an existing list of categories, if any, for the class.\n    old = (_objc_unresolved_category *)\n        NXMapGet (category_hash, cat->class_name);\n\n    // Register the category to be fixed up later.\n    // The category list is built backwards, and is reversed again \n    // by resolve_categories_for_class().\n    new_cat = (_objc_unresolved_category *)\n        malloc(sizeof(_objc_unresolved_category));\n    new_cat->next    = old;\n    new_cat->cat     = cat;\n    new_cat->version = version;\n    (void) NXMapKeyCopyingInsert (category_hash, cat->class_name, new_cat);\n\n    return NO;\n}\n\n\nconst char **objc_copyImageNames(unsigned int *outCount)\n{\n    header_info *hi;\n    int count = 0;\n    int max = HeaderCount;\n#if TARGET_OS_WIN32\n    const TCHAR **names = (const TCHAR **)calloc(max+1, sizeof(TCHAR *));\n#else\n    const char **names = (const char **)calloc(max+1, sizeof(char *));\n#endif\n\n    for (hi = FirstHeader; hi != NULL && count < max; hi = hi->getNext()) {\n#if TARGET_OS_WIN32\n        if (hi->moduleName) {\n            names[count++] = hi->moduleName;\n        }\n#else\n        const char *fname = hi->fname();\n        if (fname) {\n            names[count++] = fname;\n        }\n#endif\n    }\n    names[count] = NULL;\n\n    if (count == 0) {\n        // Return NULL instead of empty list if there are no images\n        free((void *)names);\n        names = NULL;\n    }\n\n    if (outCount) *outCount = count;\n    return names;\n}\n\n\nstatic const char **\n_objc_copyClassNamesForImage(header_info *hi, unsigned int *outCount)\n{\n    Module mods;\n    unsigned int m;\n    const char **list;\n    int count;\n    int allocated;\n\n    list = nil;\n    count = 0;\n    allocated = 0;\n    \n    mods = hi->mod_ptr;\n    for (m = 0; m < hi->mod_count; m++) {\n        int d;\n\n        if (!mods[m].symtab) continue;\n        \n        for (d = 0; d < mods[m].symtab->cls_def_cnt; d++) {\n            Class cls = (Class)mods[m].symtab->defs[d];\n            // fixme what about future-ified classes?\n            if (cls->isConnected()) {\n                if (count == allocated) {\n                    allocated = allocated*2 + 16;\n                    list = (const char **)\n                        realloc((void *)list, allocated * sizeof(char *));\n                }\n                list[count++] = cls->name;\n            }\n        }\n    }\n\n    if (count > 0) {\n        // nil-terminate non-empty list\n        if (count == allocated) {\n            allocated = allocated+1;\n            list = (const char **)\n                realloc((void *)list, allocated * sizeof(char *));\n        }\n        list[count] = nil;\n    }\n\n    if (outCount) *outCount = count;\n    return list;\n}\n\n\n/**********************************************************************\n*\n**********************************************************************/\nconst char **\nobjc_copyClassNamesForImage(const char *image, unsigned int *outCount)\n{\n    header_info *hi;\n\n    if (!image) {\n        if (outCount) *outCount = 0;\n        return NULL;\n    }\n\n    // Find the image.\n    for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) {\n#if TARGET_OS_WIN32\n        if (0 == wcscmp((TCHAR *)image, hi->moduleName)) break;\n#else\n        if (0 == strcmp(image, hi->fname())) break;\n#endif\n    }\n\n    if (!hi) {\n        if (outCount) *outCount = 0;\n        return NULL;\n    }\n\n    return _objc_copyClassNamesForImage(hi, outCount);\n}\n\n\n\n/**********************************************************************\n*\n**********************************************************************/\nconst char **\nobjc_copyClassNamesForImageHeader(const struct mach_header *mh, unsigned int *outCount)\n{\n    header_info *hi;\n\n    if (!mh) {\n        if (outCount) *outCount = 0;\n        return NULL;\n    }\n\n    // Find the image.\n    for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) {\n        if (hi->mhdr() == (const headerType *)mh) break;\n    }\n\n    if (!hi) {\n        if (outCount) *outCount = 0;\n        return NULL;\n    }\n\n    return _objc_copyClassNamesForImage(hi, outCount);\n}\n\n\nClass gdb_class_getClass(Class cls)\n{\n    const char *className = cls->name;\n    if(!className || !strlen(className)) return Nil;\n    Class rCls = look_up_class(className, NO, NO);\n    return rCls;\n\n}\n\nClass gdb_object_getClass(id obj)\n{\n    if (!obj) return nil;\n    return gdb_class_getClass(obj->getIsa());\n}\n\n\n/***********************************************************************\n* objc_setMultithreaded.\n**********************************************************************/\nvoid objc_setMultithreaded (BOOL flag)\n{\n    OBJC_WARN_DEPRECATED;\n\n    // Nothing here. Thread synchronization in the runtime is always active.\n}\n\n\n/***********************************************************************\n* Lock management\n**********************************************************************/\nmutex_t selLock;\nmutex_t classLock;\nmutex_t methodListLock;\nmutex_t cacheUpdateLock;\nrecursive_mutex_t loadMethodLock;\n\nvoid lock_init(void)\n{\n}\n\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-runtime.h",
    "content": "#include <objc/runtime.h>\n#include <objc/message.h>\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-runtime.mm",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/***********************************************************************\n* objc-runtime.m\n* Copyright 1988-1996, NeXT Software, Inc.\n* Author:\ts. naroff\n*\n**********************************************************************/\n\n\n\n/***********************************************************************\n* Imports.\n**********************************************************************/\n\n#include \"objc-private.h\"\n#include \"objc-loadmethod.h\"\n#include \"message.h\"\n\n/***********************************************************************\n* Exports.\n**********************************************************************/\n\n/* Linker metadata symbols */\n\n// NSObject was in Foundation/CF on macOS < 10.8.\n#if TARGET_OS_OSX\n#if __OBJC2__\n\nconst char __objc_nsobject_class_10_5 = 0;\nconst char __objc_nsobject_class_10_6 = 0;\nconst char __objc_nsobject_class_10_7 = 0;\n\nconst char __objc_nsobject_metaclass_10_5 = 0;\nconst char __objc_nsobject_metaclass_10_6 = 0;\nconst char __objc_nsobject_metaclass_10_7 = 0;\n\nconst char __objc_nsobject_isa_10_5 = 0;\nconst char __objc_nsobject_isa_10_6 = 0;\nconst char __objc_nsobject_isa_10_7 = 0;\n\n#else\n\nconst char __objc_nsobject_class_10_5 = 0;\nconst char __objc_nsobject_class_10_6 = 0;\nconst char __objc_nsobject_class_10_7 = 0;\n\n#endif\n#endif\n\n// Settings from environment variables\n#define OPTION(var, env, help) bool var = false;\n#include \"objc-env.h\"\n#undef OPTION\n\nstruct option_t {\n    bool* var;\n    const char *env;\n    const char *help;\n    size_t envlen;\n};\n\nconst option_t Settings[] = {\n#define OPTION(var, env, help) option_t{&var, #env, help, strlen(#env)}, \n#include \"objc-env.h\"\n#undef OPTION\n};\n\n\n// objc's key for pthread_getspecific\nstatic tls_key_t _objc_pthread_key;\n\n// Selectors\nSEL SEL_load = NULL;\nSEL SEL_initialize = NULL;\nSEL SEL_resolveInstanceMethod = NULL;\nSEL SEL_resolveClassMethod = NULL;\nSEL SEL_cxx_construct = NULL;\nSEL SEL_cxx_destruct = NULL;\nSEL SEL_retain = NULL;\nSEL SEL_release = NULL;\nSEL SEL_autorelease = NULL;\nSEL SEL_retainCount = NULL;\nSEL SEL_alloc = NULL;\nSEL SEL_allocWithZone = NULL;\nSEL SEL_dealloc = NULL;\nSEL SEL_copy = NULL;\nSEL SEL_new = NULL;\nSEL SEL_forwardInvocation = NULL;\nSEL SEL_tryRetain = NULL;\nSEL SEL_isDeallocating = NULL;\nSEL SEL_retainWeakReference = NULL;\nSEL SEL_allowsWeakReference = NULL;\n\n\nheader_info *FirstHeader = 0;  // NULL means empty list\nheader_info *LastHeader  = 0;  // NULL means invalid; recompute it\nint HeaderCount = 0;\n\n\n// Set to true on the child side of fork() \n// if the parent process was multithreaded when fork() was called.\nbool MultithreadedForkChild = false;\n\n\n/***********************************************************************\n* objc_noop_imp. Used when we need to install a do-nothing method somewhere.\n**********************************************************************/\nid objc_noop_imp(id self, SEL _cmd __unused) {\n    return self;\n}\n\n\n/***********************************************************************\n* objc_getClass.  Return the id of the named class.  If the class does\n* not exist, call _objc_classLoader and then objc_classHandler, either of \n* which may create a new class.\n* Warning: doesn't work if aClassName is the name of a posed-for class's isa!\n**********************************************************************/\nClass objc_getClass(const char *aClassName)\n{\n    if (!aClassName) return Nil;\n\n    // NO unconnected, YES class handler\n    return look_up_class(aClassName, NO, YES);\n}\n\n\n/***********************************************************************\n* objc_getRequiredClass.  \n* Same as objc_getClass, but kills the process if the class is not found. \n* This is used by ZeroLink, where failing to find a class would be a \n* compile-time link error without ZeroLink.\n**********************************************************************/\nClass objc_getRequiredClass(const char *aClassName)\n{\n    Class cls = objc_getClass(aClassName);\n    if (!cls) _objc_fatal(\"link error: class '%s' not found.\", aClassName);\n    return cls;\n}\n\n\n/***********************************************************************\n* objc_lookUpClass.  Return the id of the named class.\n* If the class does not exist, call _objc_classLoader, which may create \n* a new class.\n*\n* Formerly objc_getClassWithoutWarning ()\n**********************************************************************/\nClass objc_lookUpClass(const char *aClassName)\n{\n    if (!aClassName) return Nil;\n\n    // NO unconnected, NO class handler\n    return look_up_class(aClassName, NO, NO);\n}\n\n\n/***********************************************************************\n* objc_getMetaClass.  Return the id of the meta class the named class.\n* Warning: doesn't work if aClassName is the name of a posed-for class's isa!\n**********************************************************************/\nClass objc_getMetaClass(const char *aClassName)\n{\n    Class cls;\n\n    if (!aClassName) return Nil;\n\n    cls = objc_getClass (aClassName);\n    if (!cls)\n    {\n        _objc_inform (\"class `%s' not linked into application\", aClassName);\n        return Nil;\n    }\n\n    return cls->ISA();\n}\n\n\n/***********************************************************************\n* appendHeader.  Add a newly-constructed header_info to the list. \n**********************************************************************/\nvoid appendHeader(header_info *hi)\n{\n    // Add the header to the header list. \n    // The header is appended to the list, to preserve the bottom-up order.\n    HeaderCount++;\n    hi->setNext(NULL);\n    if (!FirstHeader) {\n        // list is empty\n        FirstHeader = LastHeader = hi;\n    } else {\n        if (!LastHeader) {\n            // list is not empty, but LastHeader is invalid - recompute it\n            LastHeader = FirstHeader;\n            while (LastHeader->getNext()) LastHeader = LastHeader->getNext();\n        }\n        // LastHeader is now valid\n        LastHeader->setNext(hi);\n        LastHeader = hi;\n    }\n}\n\n\n/***********************************************************************\n* removeHeader\n* Remove the given header from the header list.\n* FirstHeader is updated. \n* LastHeader is set to NULL. Any code that uses LastHeader must \n* detect this NULL and recompute LastHeader by traversing the list.\n**********************************************************************/\nvoid removeHeader(header_info *hi)\n{\n    header_info *prev = NULL;\n    header_info *current = NULL;\n\n    for (current = FirstHeader; current != NULL; current = current->getNext()) {\n        if (current == hi) {\n            header_info *deadHead = current;\n\n            // Remove from the linked list.\n            if (prev)\n                prev->setNext(current->getNext());\n            else\n                FirstHeader = current->getNext(); // no prev so removing head\n            \n            // Update LastHeader if necessary.\n            if (LastHeader == deadHead) {\n                LastHeader = NULL;  // will be recomputed next time it's used\n            }\n\n            HeaderCount--;\n            break;\n        }\n        prev = current;\n    }\n}\n\n\n/***********************************************************************\n* environ_init\n* Read environment variables that affect the runtime.\n* Also print environment variable help, if requested.\n**********************************************************************/\nvoid environ_init(void) \n{\n    if (issetugid()) {\n        // All environment variables are silently ignored when setuid or setgid\n        // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.\n        return;\n    } \n\n    bool PrintHelp = false;\n    bool PrintOptions = false;\n    bool maybeMallocDebugging = false;\n\n    // Scan environ[] directly instead of calling getenv() a lot.\n    // This optimizes the case where none are set.\n    for (char **p = *_NSGetEnviron(); *p != nil; p++) {\n        if (0 == strncmp(*p, \"Malloc\", 6)  ||  0 == strncmp(*p, \"DYLD\", 4)  ||  \n            0 == strncmp(*p, \"NSZombiesEnabled\", 16))\n        {\n            maybeMallocDebugging = true;\n        }\n\n        if (0 != strncmp(*p, \"OBJC_\", 5)) continue;\n        \n        if (0 == strncmp(*p, \"OBJC_HELP=\", 10)) {\n            PrintHelp = true;\n            continue;\n        }\n        if (0 == strncmp(*p, \"OBJC_PRINT_OPTIONS=\", 19)) {\n            PrintOptions = true;\n            continue;\n        }\n        \n        const char *value = strchr(*p, '=');\n        if (!*value) continue;\n        value++;\n        \n        for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {\n            const option_t *opt = &Settings[i];\n            if ((size_t)(value - *p) == 1+opt->envlen  &&  \n                0 == strncmp(*p, opt->env, opt->envlen))\n            {\n                *opt->var = (0 == strcmp(value, \"YES\"));\n                break;\n            }\n        }            \n    }\n\n    // Special case: enable some autorelease pool debugging \n    // when some malloc debugging is enabled \n    // and OBJC_DEBUG_POOL_ALLOCATION is not set to something other than NO.\n    if (maybeMallocDebugging) {\n        const char *insert = getenv(\"DYLD_INSERT_LIBRARIES\");\n        const char *zombie = getenv(\"NSZombiesEnabled\");\n        const char *pooldebug = getenv(\"OBJC_DEBUG_POOL_ALLOCATION\");\n        if ((getenv(\"MallocStackLogging\")\n             || getenv(\"MallocStackLoggingNoCompact\")\n             || (zombie && (*zombie == 'Y' || *zombie == 'y'))\n             || (insert && strstr(insert, \"libgmalloc\")))\n            &&\n            (!pooldebug || 0 == strcmp(pooldebug, \"YES\")))\n        {\n            DebugPoolAllocation = true;\n        }\n    }\n\n    // Print OBJC_HELP and OBJC_PRINT_OPTIONS output.\n    if (PrintHelp  ||  PrintOptions) {\n        if (PrintHelp) {\n            _objc_inform(\"Objective-C runtime debugging. Set variable=YES to enable.\");\n            _objc_inform(\"OBJC_HELP: describe available environment variables\");\n            if (PrintOptions) {\n                _objc_inform(\"OBJC_HELP is set\");\n            }\n            _objc_inform(\"OBJC_PRINT_OPTIONS: list which options are set\");\n        }\n        if (PrintOptions) {\n            _objc_inform(\"OBJC_PRINT_OPTIONS is set\");\n        }\n\n        for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {\n            const option_t *opt = &Settings[i];            \n            if (PrintHelp) _objc_inform(\"%s: %s\", opt->env, opt->help);\n            if (PrintOptions && *opt->var) _objc_inform(\"%s is set\", opt->env);\n        }\n    }\n}\n\n\n/***********************************************************************\n* logReplacedMethod\n* OBJC_PRINT_REPLACED_METHODS implementation\n**********************************************************************/\nvoid \nlogReplacedMethod(const char *className, SEL s, \n                  bool isMeta, const char *catName, \n                  IMP oldImp, IMP newImp)\n{\n    const char *oldImage = \"??\";\n    const char *newImage = \"??\";\n\n    // Silently ignore +load replacement because category +load is special\n    if (s == SEL_load) return;\n\n#if TARGET_OS_WIN32\n    // don't know dladdr()/dli_fname equivalent\n#else\n    Dl_info dl;\n\n    if (dladdr((void*)oldImp, &dl)  &&  dl.dli_fname) oldImage = dl.dli_fname;\n    if (dladdr((void*)newImp, &dl)  &&  dl.dli_fname) newImage = dl.dli_fname;\n#endif\n    \n    _objc_inform(\"REPLACED: %c[%s %s]  %s%s  (IMP was %p (%s), now %p (%s))\",\n                 isMeta ? '+' : '-', className, sel_getName(s), \n                 catName ? \"by category \" : \"\", catName ? catName : \"\", \n                 oldImp, oldImage, newImp, newImage);\n}\n\n\n/***********************************************************************\n* _objc_fetch_pthread_data\n* Fetch objc's pthread data for this thread.\n* If the data doesn't exist yet and create is NO, return NULL.\n* If the data doesn't exist yet and create is YES, allocate and return it.\n**********************************************************************/\n_objc_pthread_data *_objc_fetch_pthread_data(bool create)\n{\n    _objc_pthread_data *data;\n\n    data = (_objc_pthread_data *)tls_get(_objc_pthread_key);\n    if (!data  &&  create) {\n        data = (_objc_pthread_data *)\n            calloc(1, sizeof(_objc_pthread_data));\n        tls_set(_objc_pthread_key, data);\n    }\n\n    return data;\n}\n\n\n/***********************************************************************\n* _objc_pthread_destroyspecific\n* Destructor for objc's per-thread data.\n* arg shouldn't be NULL, but we check anyway.\n**********************************************************************/\nextern void _destroyInitializingClassList(struct _objc_initializing_classes *list);\nvoid _objc_pthread_destroyspecific(void *arg)\n{\n    _objc_pthread_data *data = (_objc_pthread_data *)arg;\n    if (data != NULL) {\n        _destroyInitializingClassList(data->initializingClasses);\n        _destroySyncCache(data->syncCache);\n        _destroyAltHandlerList(data->handlerList);\n        for (int i = 0; i < (int)countof(data->printableNames); i++) {\n            if (data->printableNames[i]) {\n                free(data->printableNames[i]);  \n            }\n        }\n\n        // add further cleanup here...\n\n        free(data);\n    }\n}\n\n\nvoid tls_init(void)\n{\n#if SUPPORT_DIRECT_THREAD_KEYS\n    _objc_pthread_key = TLS_DIRECT_KEY;\n    pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);\n#else\n    _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);\n#endif\n}\n\n\n/***********************************************************************\n* _objcInit\n* Former library initializer. This function is now merely a placeholder \n* for external callers. All runtime initialization has now been moved \n* to map_images() and _objc_init.\n**********************************************************************/\nvoid _objcInit(void)\n{\n    // do nothing\n}\n\n\n/***********************************************************************\n* objc_setForwardHandler\n**********************************************************************/\n\n#if !__OBJC2__\n\n// Default forward handler (nil) goes to forward:: dispatch.\nvoid *_objc_forward_handler = nil;\nvoid *_objc_forward_stret_handler = nil;\n\n#else\n\n// Default forward handler halts the process.\n__attribute__((noreturn)) void \nobjc_defaultForwardHandler(id self, SEL sel)\n{\n    _objc_fatal(\"%c[%s %s]: unrecognized selector sent to instance %p \"\n                \"(no message forward handler is installed)\", \n                class_isMetaClass(object_getClass(self)) ? '+' : '-', \n                object_getClassName(self), sel_getName(sel), self);\n}\nvoid *_objc_forward_handler = (void*)objc_defaultForwardHandler;\n\n#if SUPPORT_STRET\nstruct stret { int i[100]; };\n__attribute__((noreturn)) struct stret \nobjc_defaultForwardStretHandler(id self, SEL sel)\n{\n    objc_defaultForwardHandler(self, sel);\n}\nvoid *_objc_forward_stret_handler = (void*)objc_defaultForwardStretHandler;\n#endif\n\n#endif\n\nvoid objc_setForwardHandler(void *fwd, void *fwd_stret)\n{\n    _objc_forward_handler = fwd;\n#if SUPPORT_STRET\n    _objc_forward_stret_handler = fwd_stret;\n#endif\n}\n\n\n#if !__OBJC2__\n// GrP fixme\nextern \"C\" Class _objc_getOrigClass(const char *name);\n#endif\n\nstatic BOOL internal_class_getImageName(Class cls, const char **outName)\n{\n#if !__OBJC2__\n    cls = _objc_getOrigClass(cls->demangledName());\n#endif\n    auto result = dyld_image_path_containing_address(cls);\n    *outName = result;\n    return (result != nil);\n}\n\n\nstatic ChainedHookFunction<objc_hook_getImageName>\nGetImageNameHook{internal_class_getImageName};\n\nvoid objc_setHook_getImageName(objc_hook_getImageName newValue,\n                               objc_hook_getImageName *outOldValue)\n{\n    GetImageNameHook.set(newValue, outOldValue);\n}\n\nconst char *class_getImageName(Class cls)\n{\n    if (!cls) return nil;\n\n    const char *name;\n    if (GetImageNameHook.get()(cls, &name)) return name;\n    else return nil;\n}\n\n\n/**********************************************************************\n* Fast Enumeration Support\n**********************************************************************/\n\nstatic void (*enumerationMutationHandler)(id);\n\n/**********************************************************************\n* objc_enumerationMutation\n* called by compiler when a mutation is detected during foreach iteration\n**********************************************************************/\nvoid objc_enumerationMutation(id object) {\n    if (enumerationMutationHandler == nil) {\n        _objc_fatal(\"mutation detected during 'for(... in ...)'  enumeration of object %p.\", (void*)object);\n    }\n    (*enumerationMutationHandler)(object);\n}\n\n\n/**********************************************************************\n* objc_setEnumerationMutationHandler\n* an entry point to customize mutation error handing\n**********************************************************************/\nvoid objc_setEnumerationMutationHandler(void (*handler)(id)) {\n    enumerationMutationHandler = handler;\n}\n\n\n/**********************************************************************\n* Associative Reference Support\n**********************************************************************/\n\nid objc_getAssociatedObject(id object, const void *key) {\n    return _object_get_associative_reference(object, (void *)key);\n}\n\n\nvoid objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {\n    _object_set_associative_reference(object, (void *)key, value, policy);\n}\n\n\nvoid objc_removeAssociatedObjects(id object) \n{\n    if (object && object->hasAssociatedObjects()) {\n        _object_remove_assocations(object);\n    }\n}\n\n\n\n#if SUPPORT_GC_COMPAT\n\n#include <mach-o/fat.h>\n\n// GC preflight for an app executable.\n\nenum GCness {\n    WithGC = 1, \n    WithoutGC = 0, \n    Error = -1\n};\n\n// Overloaded template wrappers around clang's overflow-checked arithmetic.\n\ntemplate <typename T> bool uadd_overflow(T x, T y, T* sum);\ntemplate <typename T> bool usub_overflow(T x, T y, T* diff);\ntemplate <typename T> bool umul_overflow(T x, T y, T* prod);\n\ntemplate <typename T> bool sadd_overflow(T x, T y, T* sum);\ntemplate <typename T> bool ssub_overflow(T x, T y, T* diff);\ntemplate <typename T> bool smul_overflow(T x, T y, T* prod);\n\ntemplate <> bool uadd_overflow(unsigned x, unsigned y, unsigned* sum) { return __builtin_uadd_overflow(x, y, sum); }\ntemplate <> bool uadd_overflow(unsigned long x, unsigned long y, unsigned long* sum) { return __builtin_uaddl_overflow(x, y, sum); }\ntemplate <> bool uadd_overflow(unsigned long long x, unsigned long long y, unsigned long long* sum) { return __builtin_uaddll_overflow(x, y, sum); }\n\ntemplate <> bool usub_overflow(unsigned x, unsigned y, unsigned* diff) { return __builtin_usub_overflow(x, y, diff); }\ntemplate <> bool usub_overflow(unsigned long x, unsigned long y, unsigned long* diff) { return __builtin_usubl_overflow(x, y, diff); }\ntemplate <> bool usub_overflow(unsigned long long x, unsigned long long y, unsigned long long* diff) { return __builtin_usubll_overflow(x, y, diff); }\n\ntemplate <> bool umul_overflow(unsigned x, unsigned y, unsigned* prod) { return __builtin_umul_overflow(x, y, prod); }\ntemplate <> bool umul_overflow(unsigned long x, unsigned long y, unsigned long* prod) { return __builtin_umull_overflow(x, y, prod); }\ntemplate <> bool umul_overflow(unsigned long long x, unsigned long long y, unsigned long long* prod) { return __builtin_umulll_overflow(x, y, prod); }\n\ntemplate <> bool sadd_overflow(signed x, signed y, signed* sum) { return __builtin_sadd_overflow(x, y, sum); }\ntemplate <> bool sadd_overflow(signed long x, signed long y, signed long* sum) { return __builtin_saddl_overflow(x, y, sum); }\ntemplate <> bool sadd_overflow(signed long long x, signed long long y, signed long long* sum) { return __builtin_saddll_overflow(x, y, sum); }\n\ntemplate <> bool ssub_overflow(signed x, signed y, signed* diff) { return __builtin_ssub_overflow(x, y, diff); }\ntemplate <> bool ssub_overflow(signed long x, signed long y, signed long* diff) { return __builtin_ssubl_overflow(x, y, diff); }\ntemplate <> bool ssub_overflow(signed long long x, signed long long y, signed long long* diff) { return __builtin_ssubll_overflow(x, y, diff); }\n\ntemplate <> bool smul_overflow(signed x, signed y, signed* prod) { return __builtin_smul_overflow(x, y, prod); }\ntemplate <> bool smul_overflow(signed long x, signed long y, signed long* prod) { return __builtin_smull_overflow(x, y, prod); }\ntemplate <> bool smul_overflow(signed long long x, signed long long y, signed long long* prod) { return __builtin_smulll_overflow(x, y, prod); }\n\n\n// Range-checking subview of a file.\nclass FileSlice {\n    int fd;\n    uint64_t sliceOffset;\n    uint64_t sliceSize;\n\npublic:\n    FileSlice() : fd(-1), sliceOffset(0), sliceSize(0) { }\n\n    FileSlice(int newfd, uint64_t newOffset, uint64_t newSize) \n        : fd(newfd) , sliceOffset(newOffset) , sliceSize(newSize) { }\n\n    // Read bytes from this slice. \n    // Returns YES if all bytes were read successfully.\n    bool pread(void *buf, uint64_t readSize, uint64_t readOffset = 0) {\n        uint64_t readEnd;\n        if (uadd_overflow(readOffset, readSize, &readEnd)) return NO;\n        if (readEnd > sliceSize) return NO;\n\n        uint64_t preadOffset;\n        if (uadd_overflow(sliceOffset, readOffset, &preadOffset)) return NO;\n\n        int64_t readed = ::pread(fd, buf, (size_t)readSize, preadOffset);\n        if (readed < 0  ||  (uint64_t)readed != readSize) return NO;\n        return YES;\n    }\n\n    // Create a new slice that is a subset of this slice.\n    // Returnes YES if successful.\n    bool slice(uint64_t newOffset, uint64_t newSize, FileSlice& result) {\n        // fixme arithmetic overflow\n        uint64_t newEnd;\n        if (uadd_overflow(newOffset, newSize, &newEnd)) return NO;\n        if (newEnd > sliceSize) return NO;\n\n        if (uadd_overflow(sliceOffset, newOffset, &result.sliceOffset)) {\n            return NO;\n        }\n        result.sliceSize = newSize;\n        result.fd = fd;\n        return YES;\n    }\n\n    // Shorten this slice in place by removing a range from the start.\n    bool advance(uint64_t distance) {\n        if (distance > sliceSize) return NO;\n        if (uadd_overflow(sliceOffset, distance, &sliceOffset)) return NO;\n        if (usub_overflow(sliceSize, distance, &sliceSize)) return NO;\n        return YES;\n    }\n};\n\n\n// Arch32 and Arch64 are used to specialize sliceRequiresGC()\n// to interrogate old-ABI i386 and new-ABI x86_64 files.\n\nstruct Arch32 {\n    using mh_t = struct mach_header;\n    using segment_command_t = struct segment_command;\n    using section_t = struct section;\n\n    enum : cpu_type_t { cputype = CPU_TYPE_X86 };\n    enum : int { segment_cmd = LC_SEGMENT };\n\n    static bool isObjCSegment(const char *segname) {\n        return segnameEquals(segname, \"__OBJC\");\n    }\n\n    static bool isImageInfoSection(const char *sectname) {\n        return sectnameEquals(sectname, \"__image_info\");\n    }\n\n    static bool countClasses(FileSlice file, section_t& sect, \n                             int& classCount, int& classrefCount)\n    {\n        if (sectnameEquals(sect.sectname, \"__cls_refs\")) {\n            classrefCount += sect.size / 4;\n        }\n        else if (sectnameEquals(sect.sectname, \"__module_info\")) {\n            struct module_t {\n                uint32_t version;\n                uint32_t size;\n                uint32_t name;    // not bound\n                uint32_t symtab;  // not bound\n            };\n            size_t mod_count = sect.size / sizeof(module_t);\n            if (mod_count == 0) {\n                // no classes defined\n            } else if (mod_count > 1) {\n                // AppleScriptObjC apps only have one module.\n                // Disqualify this app by setting classCount to non-zero.\n                // We don't actually need an accurate count.\n                classCount = 1;\n            } else if (mod_count == 1) {\n                FileSlice moduleSlice;\n                if (!file.slice(sect.offset, sect.size, moduleSlice)) return NO;\n                module_t module;\n                if (!moduleSlice.pread(&module, sizeof(module))) return NO;\n                if (module.symtab) {\n                    // AppleScriptObjC apps only have a module with no symtab.\n                    // Disqualify this app by setting classCount to non-zero.\n                    // We don't actually need an accurate count.\n                    classCount = 1;\n                }\n            }\n            \n        }\n        return YES;\n    }\n\n};\n\nstruct Arch64 {\n    using mh_t = struct mach_header_64;\n    using segment_command_t = struct segment_command_64;\n    using section_t = struct section_64;\n\n    enum : cpu_type_t { cputype = CPU_TYPE_X86_64 };\n    enum : int { segment_cmd = LC_SEGMENT_64 };\n\n    static bool isObjCSegment(const char *segname) {\n        return \n            segnameEquals(segname, \"__DATA\")  ||  \n            segnameEquals(segname, \"__DATA_CONST\")  ||  \n            segnameEquals(segname, \"__DATA_DIRTY\");\n    }\n\n    static bool isImageInfoSection(const char *sectname) {\n        return sectnameEquals(sectname, \"__objc_imageinfo\");\n    }\n\n    static bool countClasses(FileSlice, section_t& sect, \n                             int& classCount, int& classrefCount)\n    {\n        if (sectnameEquals(sect.sectname, \"__objc_classlist\")) {\n            classCount += sect.size / 8;\n        }\n        else if (sectnameEquals(sect.sectname, \"__objc_classrefs\")) {\n            classrefCount += sect.size / 8;\n        }\n        return YES;\n    }\n};\n\n\n#define SANE_HEADER_SIZE (32*1024)\n\ntemplate <typename Arch>\nstatic int sliceRequiresGC(typename Arch::mh_t mh, FileSlice file)\n{\n    // We assume there is only one arch per pointer size that can support GC.\n    // (i386 and x86_64)\n    if (mh.cputype != Arch::cputype) return 0;\n\n    // We only check the main executable.\n    if (mh.filetype != MH_EXECUTE) return 0;\n\n    // Look for ObjC segment.\n    // Look for AppleScriptObjC linkage.\n    FileSlice cmds;\n    if (!file.slice(sizeof(mh), mh.sizeofcmds, cmds)) return Error;\n\n    // Exception: Some AppleScriptObjC apps built for GC can run without GC.\n    // 1. executable defines no classes\n    // 2. executable references NSBundle only\n    // 3. executable links to AppleScriptObjC.framework\n    // Note that shouldRejectGCApp() also knows about this.\n    bool wantsGC = NO;\n    bool linksToAppleScriptObjC = NO;\n    int classCount = 0;\n    int classrefCount = 0;\n\n    // Disallow abusively-large executables that could hang this checker.\n    // dyld performs similar checks (MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE)\n    if (mh.sizeofcmds > SANE_HEADER_SIZE) return Error;\n    if (mh.ncmds > mh.sizeofcmds / sizeof(struct load_command)) return Error;\n\n    for (uint32_t cmdindex = 0; cmdindex < mh.ncmds; cmdindex++) {\n        struct load_command lc;\n        if (!cmds.pread(&lc, sizeof(lc))) return Error;\n\n        // Disallow abusively-small load commands that could hang this checker.\n        // dyld performs a similar check.\n        if (lc.cmdsize < sizeof(lc)) return Error;\n\n        if (lc.cmd == LC_LOAD_DYLIB  ||  lc.cmd == LC_LOAD_UPWARD_DYLIB  ||  \n            lc.cmd == LC_LOAD_WEAK_DYLIB  ||  lc.cmd == LC_REEXPORT_DYLIB) \n        {\n            // Look for AppleScriptObjC linkage.\n            FileSlice dylibSlice;\n            if (!cmds.slice(0, lc.cmdsize, dylibSlice)) return Error;\n            struct dylib_command dylib;\n            if (!dylibSlice.pread(&dylib, sizeof(dylib))) return Error;\n\n            const char *asoFramework = \n                \"/System/Library/Frameworks/AppleScriptObjC.framework\"\n                \"/Versions/A/AppleScriptObjC\";\n            size_t asoLen = strlen(asoFramework);\n\n            FileSlice nameSlice;\n            if (dylibSlice.slice(dylib.dylib.name.offset, asoLen, nameSlice)) {\n                char name[asoLen];\n                if (!nameSlice.pread(name, asoLen)) return Error;\n                if (0 == memcmp(name, asoFramework, asoLen)) {\n                    linksToAppleScriptObjC = YES;\n                }\n            }\n        }\n        else if (lc.cmd == Arch::segment_cmd) {\n            typename Arch::segment_command_t seg;\n            if (!cmds.pread(&seg, sizeof(seg))) return Error;\n\n            if (Arch::isObjCSegment(seg.segname)) {\n                // ObjC segment. \n                // Look for image info section.\n                // Look for class implementations and class references.\n                FileSlice sections;\n                if (!cmds.slice(0, seg.cmdsize, sections)) return Error;\n                if (!sections.advance(sizeof(seg))) return Error;\n                \n                for (uint32_t segindex = 0; segindex < seg.nsects; segindex++) {\n                    typename Arch::section_t sect;\n                    if (!sections.pread(&sect, sizeof(sect))) return Error;\n                    if (!Arch::isObjCSegment(sect.segname)) return Error;\n\n                    if (!Arch::countClasses(file, sect, \n                                            classCount, classrefCount)) \n                    {\n                        return Error;\n                    }\n\n                    if ((sect.flags & SECTION_TYPE) == S_REGULAR  &&  \n                        Arch::isImageInfoSection(sect.sectname))\n                    {\n                        // ObjC image info section.\n                        // Check its contents.\n                        FileSlice section;\n                        if (!file.slice(sect.offset, sect.size, section)) {\n                            return Error;\n                        }\n                        // The subset of objc_image_info that was in use for GC.\n                        struct {\n                            uint32_t version;\n                            uint32_t flags;\n                        } ii;\n                        if (!section.pread(&ii, sizeof(ii))) return Error;\n                        if (ii.flags & (1<<1)) {\n                            // App wants GC. \n                            // Don't return yet because we need to \n                            // check the AppleScriptObjC exception.\n                            wantsGC = YES;\n                        }\n                    }\n\n                    if (!sections.advance(sizeof(sect))) return Error;\n                }\n            }\n        }\n\n        if (!cmds.advance(lc.cmdsize)) return Error;\n    }\n\n    if (!wantsGC) {\n        // No GC bit set.\n        return WithoutGC;\n    }\n    else if (linksToAppleScriptObjC && classCount == 0 && classrefCount == 1) {\n        // Has GC bit but falls under the AppleScriptObjC exception.\n        return WithoutGC;\n    }\n    else {\n        // Has GC bit and is not AppleScriptObjC.\n        return WithGC;\n    }\n}\n\n\nstatic int sliceRequiresGC(FileSlice file)\n{\n    // Read mach-o header.\n    struct mach_header_64 mh;\n    if (!file.pread(&mh, sizeof(mh))) return Error;\n\n    // Check header magic. We assume only host-endian slices can support GC.\n    switch (mh.magic) {\n    case MH_MAGIC:\n        return sliceRequiresGC<Arch32>(*(struct mach_header *)&mh, file);\n    case MH_MAGIC_64:\n        return sliceRequiresGC<Arch64>(mh, file);\n    default:\n        return WithoutGC;\n    }\n}\n\n\n// Returns 1 if any slice requires GC.\n// Returns 0 if no slice requires GC.\n// Returns -1 on any I/O or file format error.\nint objc_appRequiresGC(int fd)\n{\n    struct stat st;\n    if (fstat(fd, &st) < 0) return Error;\n\n    FileSlice file(fd, 0, st.st_size);\n\n    // Read fat header, if any.\n    struct fat_header fh;\n\n    if (! file.pread(&fh, sizeof(fh))) return Error;\n\n    int result;\n\n    if (OSSwapBigToHostInt32(fh.magic) == FAT_MAGIC) {\n        // Fat header.\n\n        size_t nfat_arch = OSSwapBigToHostInt32(fh.nfat_arch);\n        // Disallow abusively-large files that could hang this checker.\n        if (nfat_arch > SANE_HEADER_SIZE/sizeof(struct fat_arch)) return Error;\n\n        size_t fat_size;\n        if (umul_overflow(nfat_arch, sizeof(struct fat_arch), &fat_size)) {\n            return Error;\n        }\n\n        FileSlice archlist;\n        if (!file.slice(sizeof(fh), fat_size, archlist)) return Error;\n\n        result = WithoutGC;\n        for (size_t i = 0; i < nfat_arch; i++) {\n            struct fat_arch fa;\n            if (!archlist.pread(&fa, sizeof(fa))) return Error;\n            if (!archlist.advance(sizeof(fa))) return Error;\n\n            FileSlice thin;\n            if (!file.slice(OSSwapBigToHostInt32(fa.offset), \n                            OSSwapBigToHostInt32(fa.size), thin)) \n            {\n                return Error;\n            }\n            switch (sliceRequiresGC(thin)) {\n            case WithoutGC: break; // no change\n            case WithGC: if (result != Error) result = WithGC; break;\n            case Error: result = Error; break;\n            }\n        }\n    }\n    else {\n        // Thin header or not a header.\n        result = sliceRequiresGC(file);\n    }\n    \n    return result;\n}\n\n// SUPPORT_GC_COMPAT\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-sel-old.mm",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/*\n *\tUtilities for registering and looking up selectors.  The sole\n *\tpurpose of the selector tables is a registry whereby there is\n *\texactly one address (selector) associated with a given string\n *\t(method name).\n */\n\n#if !__OBJC2__\n\n#include \"objc-private.h\"\n#include \"objc-sel-set.h\"\n\n#if SUPPORT_PREOPT\n#include <objc-shared-cache.h>\nstatic const objc_selopt_t *builtins = NULL;\n#endif\n\n__BEGIN_DECLS\n\nstatic size_t SelrefCount = 0;\n\nstatic const char *_objc_empty_selector = \"\";\nstatic struct __objc_sel_set *_objc_selectors = NULL;\n\n\nstatic SEL _objc_search_builtins(const char *key) \n{\n#if defined(DUMP_SELECTORS)\n    if (NULL != key) printf(\"\\t\\\"%s\\\",\\n\", key);\n#endif\n\n    if (!key) return (SEL)0;\n    if ('\\0' == *key) return (SEL)_objc_empty_selector;\n\n#if SUPPORT_PREOPT\n    if (builtins) return (SEL)builtins->get(key);\n#endif\n\n    return (SEL)0;\n}\n\n\nconst char *sel_getName(SEL sel) {\n    return sel ? (const char *)sel : \"<null selector>\";\n}\n\n\nBOOL sel_isMapped(SEL name) \n{\n    SEL sel;\n    \n    if (!name) return NO;\n\n    sel = _objc_search_builtins((const char *)name);\n    if (sel) return YES;\n\n    mutex_locker_t lock(selLock);\n    if (_objc_selectors) {\n        sel = __objc_sel_set_get(_objc_selectors, name);\n    }\n    return bool(sel);\n}\n\nstatic SEL __sel_registerName(const char *name, bool shouldLock, bool copy) \n{\n    SEL result = 0;\n\n    if (shouldLock) selLock.assertUnlocked();\n    else selLock.assertLocked();\n\n    if (!name) return (SEL)0;\n    result = _objc_search_builtins(name);\n    if (result) return result;\n\n    conditional_mutex_locker_t lock(selLock, shouldLock);\n    if (_objc_selectors) {\n        result = __objc_sel_set_get(_objc_selectors, (SEL)name);\n    }\n    if (result) return result;\n\n    // No match. Insert.\n\n    if (!_objc_selectors) {\n        _objc_selectors = __objc_sel_set_create(SelrefCount);\n    }\n    if (!result) {\n        result = (SEL)(copy ? strdup(name) : name);\n        __objc_sel_set_add(_objc_selectors, result);\n#if defined(DUMP_UNKNOWN_SELECTORS)\n        printf(\"\\t\\\"%s\\\",\\n\", name);\n#endif\n    }\n\n    return result;\n}\n\n\nSEL sel_registerName(const char *name) {\n    return __sel_registerName(name, 1, 1);     // YES lock, YES copy\n}\n\nSEL sel_registerNameNoLock(const char *name, bool copy) {\n    return __sel_registerName(name, 0, copy);  // NO lock, maybe copy\n}\n\n\n// 2001/1/24\n// the majority of uses of this function (which used to return NULL if not found)\n// did not check for NULL, so, in fact, never return NULL\n//\nSEL sel_getUid(const char *name) {\n    return __sel_registerName(name, 2, 1);  // YES lock, YES copy\n}\n\n\nBOOL sel_isEqual(SEL lhs, SEL rhs)\n{\n    return bool(lhs == rhs);\n}\n\n\n/***********************************************************************\n* sel_init\n* Initialize selector tables and register selectors used internally.\n**********************************************************************/\nvoid sel_init(size_t selrefCount)\n{\n    // save this value for later\n    SelrefCount = selrefCount;\n\n#if SUPPORT_PREOPT\n    builtins = preoptimizedSelectors();\n#endif\n\n    // Register selectors used by libobjc\n\n#define s(x) SEL_##x = sel_registerNameNoLock(#x, NO)\n#define t(x,y) SEL_##y = sel_registerNameNoLock(#x, NO)\n\n    mutex_locker_t lock(selLock);\n\n    s(load);\n    s(initialize);\n    t(resolveInstanceMethod:, resolveInstanceMethod);\n    t(resolveClassMethod:, resolveClassMethod);\n    t(.cxx_construct, cxx_construct);\n    t(.cxx_destruct, cxx_destruct);\n    s(retain);\n    s(release);\n    s(autorelease);\n    s(retainCount);\n    s(alloc);\n    t(allocWithZone:, allocWithZone);\n    s(dealloc);\n    s(copy);\n    s(new);\n    t(forwardInvocation:, forwardInvocation);\n    t(_tryRetain, tryRetain);\n    t(_isDeallocating, isDeallocating);\n    s(retainWeakReference);\n    s(allowsWeakReference);\n\n    extern SEL FwdSel;\n    FwdSel = sel_registerNameNoLock(\"forward::\", NO);\n\n#undef s\n#undef t\n}\n\n__END_DECLS\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-sel-set.h",
    "content": "/*\n * Copyright (c) 2004 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/*\n * objc-sel-set.h\n * A set of SELs used for SEL uniquing.\n */\n\n#ifndef _OBJC_SEL_SET_H_\n#define _OBJC_SEL_SET_H_\n\n#if !__OBJC2__\n\n#include <stdint.h>\n#include \"objc-os.h\"\n\n__BEGIN_DECLS\n\nstruct __objc_sel_set;\n\nextern struct __objc_sel_set *__objc_sel_set_create(size_t selrefCount);\nextern SEL __objc_sel_set_get(struct __objc_sel_set *sset, SEL candidate);\nextern void __objc_sel_set_add(struct __objc_sel_set *sset, SEL value);\n            \n__END_DECLS\n\n#endif\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-sel-set.mm",
    "content": "/*\n * Copyright (c) 1999-2004,2008 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/*\n * objc-sel-set.h\n * A cut-down copy of CFSet used for SEL uniquing.\n */\n\n\n// NOTE: even on a 64-bit system, the implementation is still limited\n// to 32-bit integers (like, the count), but SEL can be any size.\n\n#include <stdint.h>\n#include \"objc-private.h\"\n#include \"objc-sel-set.h\"\n\n#if !__OBJC2__\n\n\n#if !SUPPORT_MOD\n// mod-free power of 2 version\n\n#define CONSTRAIN(val, range) ((val) & ((range)-1))\n#define SIZE 27\n\nstatic const uint32_t __objc_sel_set_capacities[SIZE+1] = {\n    3, 6, 12, 24, 48,  96, 192, 384,  768, 1536, 3072, 6144, 12288, 24576, \n    49152,  98304, 196608, 393216,  786432, 1572864, 3145728, 6291456, \n    12582912, 25165824, 50331648, 100663296, 201326592, UINT32_MAX\n};\n\nstatic const uint32_t __objc_sel_set_buckets[SIZE] = {    // powers of 2\n    4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, \n    65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, \n    16777216, 33554432, 67108864, 134217728, 268435456\n};\n\n#else\n// prime version\n\n#define CONSTRAIN(val, range) ((val) % (range))\n#define SIZE 42\n\nstatic const uint32_t __objc_sel_set_capacities[SIZE+1] = {\n    4,  8, 17, 29, 47,  76, 123, 199, 322, 521,  843, 1364, 2207, 3571, \n    5778,  9349, 15127, 24476, 39603,  64079, 103682, 167761, 271443, \n    439204,  710647, 1149851, 1860498, 3010349, 4870847,  7881196, 12752043, \n    20633239, 33385282, 54018521,  87403803, 141422324, 228826127, 370248451, \n    599074578,  969323029, 1568397607, 2537720636U, UINT32_MAX\n};\n\nstatic const uint32_t __objc_sel_set_buckets[SIZE] = {    // primes\n    5, 11, 23, 41, 67, 113, 199, 317, 521, 839, 1361, 2207, 3571, 5779, \n    9349, 15121, 24473, 39607, 64081, 103681, 167759, 271429, 439199, \n    710641, 1149857, 1860503, 3010349, 4870843, 7881193, 12752029, 20633237, \n    33385273, 54018521, 87403763, 141422317, 228826121, 370248451, 599074561, \n    969323023, 1568397599, 2537720629U, 4106118251U\n};\n\n#endif\n\nstruct __objc_sel_set {\n    uint32_t _count;            /* number of slots used */\n    uint32_t _capacity;         /* maximum number of used slots */\n    uint32_t _bucketsNum;       /* number of slots */\n    SEL *_buckets;              /* can be NULL if not allocated yet */\n};\n\nstruct __objc_sel_set_finds {\n    SEL match;\n    uint32_t nomatch;\n};\n\n// candidate may not be 0; match is 0 if not present\nstatic struct __objc_sel_set_finds __objc_sel_set_findBuckets(struct __objc_sel_set *sset, SEL candidate) {\n    struct __objc_sel_set_finds ret = {0, 0xffffffff};\n    uint32_t probe = CONSTRAIN((uint32_t)_objc_strhash((const char *)candidate), sset->_bucketsNum);\n    for (;;) {\n        SEL currentSel = sset->_buckets[probe];\n        if (!currentSel) {\n            ret.nomatch = probe;\n            return ret;\n        } else if (!ret.match && 0 == strcmp((const char *)currentSel, (const char *)candidate)) {\n            ret.match = currentSel;\n        }\n        probe++;\n        if (sset->_bucketsNum <= probe) {\n            probe -= sset->_bucketsNum;\n        }\n    }\n}\n\n// create a set with given starting capacity, will resize as needed\nstruct __objc_sel_set *__objc_sel_set_create(size_t selrefs) {\n    uint32_t idx;\n\n    struct __objc_sel_set *sset = (struct __objc_sel_set *)\n        malloc(sizeof(struct __objc_sel_set));\n    if (!sset) _objc_fatal(\"objc_sel_set failure\");\n    sset->_count = 0;\n\n    // heuristic to convert executable's selrefs count to table size\n#if TARGET_OS_IPHONE && !TARGET_OS_IOSMAC\n    for (idx = 0; __objc_sel_set_capacities[idx] < selrefs; idx++);\n    if (idx > 0 && selrefs < 1536) idx--;\n#else\n    if (selrefs < 1024) selrefs = 1024;\n    for (idx = 0; __objc_sel_set_capacities[idx] < selrefs; idx++);\n    idx++;\n#endif\n\n    if (SIZE <= idx) _objc_fatal(\"objc_sel_set failure\");\n    sset->_capacity = __objc_sel_set_capacities[idx];\n    sset->_bucketsNum = __objc_sel_set_buckets[idx];\n    sset->_buckets = (SEL *)calloc(sset->_bucketsNum, sizeof(SEL));\n    if (!sset->_buckets) _objc_fatal(\"objc_sel_set failure\");\n    return sset;\n}\n\n// returns 0 on failure; candidate may not be 0\nSEL __objc_sel_set_get(struct __objc_sel_set *sset, SEL candidate) {\n    return __objc_sel_set_findBuckets(sset, candidate).match;\n}\n\n// value may not be 0; should not be called unless it is known the value is not in the set\nvoid __objc_sel_set_add(struct __objc_sel_set *sset, SEL value) {\n    if (sset->_count == sset->_capacity) {\n        SEL *oldbuckets = sset->_buckets;\n        uint32_t oldnbuckets = sset->_bucketsNum;\n        uint32_t idx, capacity = sset->_count + 1;\n        for (idx = 0; __objc_sel_set_capacities[idx] < capacity; idx++);\n        if (SIZE <= idx) _objc_fatal(\"objc_sel_set failure\");\n        sset->_capacity = __objc_sel_set_capacities[idx];\n        sset->_bucketsNum = __objc_sel_set_buckets[idx];\n        sset->_buckets = (SEL *)\n            calloc(sset->_bucketsNum, sizeof(SEL));\n        if (!sset->_buckets) _objc_fatal(\"objc_sel_set failure\");\n        for (idx = 0; idx < oldnbuckets; idx++) {\n            SEL currentSel = oldbuckets[idx];\n            if (currentSel) {\n                uint32_t nomatch = __objc_sel_set_findBuckets(sset, currentSel).nomatch;\n                sset->_buckets[nomatch] = currentSel;\n            }\n        }\n        free(oldbuckets);\n    }\n    {\n        uint32_t nomatch = __objc_sel_set_findBuckets(sset, value).nomatch;\n        sset->_buckets[nomatch] = value;\n        sset->_count++;\n    }\n}\n\n\n// !__OBJC2__\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-sel-table.s",
    "content": "#include <TargetConditionals.h>\n#include <mach/vm_param.h>\n\n#if __LP64__\n# define PTR(x) .quad x\n#else\n# define PTR(x) .long x\n#endif\n\n.section __TEXT,__objc_opt_ro\n.align 3\n.private_extern __objc_opt_data\n__objc_opt_data:\n.long 15 /* table.version */\n.long 0 /* table.flags */\n.long 0 /* table.selopt_offset */\n.long 0 /* table.headeropt_ro_offset */\n.long 0 /* table.clsopt_offset */\t\n.long 0 /* table.protocolopt_offset */\n.long 0 /* table.headeropt_rw_offset */\n.space PAGE_MAX_SIZE-28\n\n/* space for selopt, smax/capacity=1048576, blen/mask=524287+1 */\n.space 4*(8+256)  /* header and scramble */\n.space 524288     /* mask tab */\n.space 1048576     /* checkbytes */\n.space 1048576*4   /* offsets */\n\n/* space for clsopt, smax/capacity=131072, blen/mask=32767+1 */\n.space 4*(8+256)        /* header and scramble */\n.space 32768            /* mask tab */\n.space 131072           /* checkbytes */\n.space 131072*12        /* offsets to name and class and header_info */\n.space 512*8            /* some duplicate classes */\n\n/* space for some demangled protocol names */\n.space 1024\n\n/* space for protocolopt, smax/capacity=16384, blen/mask=8191+1 */\n.space 4*(8+256)        /* header and scramble */\n.space 8192             /* mask tab */\n.space 16384             /* checkbytes */\n.space 16384*8           /* offsets */\n\n/* space for 2048 header_info (RO) structures */\n.space 8 + (2048*16)\n\n\n.section __DATA,__objc_opt_rw\n.align 3\n.private_extern __objc_opt_rw_data\n__objc_opt_rw_data:\n\n/* space for 2048 header_info (RW) structures */\n.space 8 + (2048*8)\n\n/* space for 16384 protocols */\n#if __LP64__\n.space 16384 * 12 * 8\n#else\n.space 16384 * 12 * 4\n#endif\n\n\n/* section of pointers that the shared cache optimizer wants to know about */\n.section __DATA,__objc_opt_ptrs\n.align 3\n\n#if TARGET_OS_OSX  &&  __i386__\n// old ABI\n.globl .objc_class_name_Protocol\nPTR(.objc_class_name_Protocol)\n#else\n// new ABI\n.globl _OBJC_CLASS_$_Protocol\nPTR(_OBJC_CLASS_$_Protocol)\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-sel.mm",
    "content": "/*\n * Copyright (c) 2012 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#if __OBJC2__\n\n#include \"objc-private.h\"\n#include \"objc-cache.h\"\n\n#if SUPPORT_PREOPT\nstatic const objc_selopt_t *builtins = NULL;\n#endif\n\n\nstatic size_t SelrefCount = 0;\n\nstatic NXMapTable *namedSelectors;\n\nstatic SEL search_builtins(const char *key);\n\n\n/***********************************************************************\n* sel_init\n* Initialize selector tables and register selectors used internally.\n**********************************************************************/\nvoid sel_init(size_t selrefCount)\n{\n    // save this value for later\n    SelrefCount = selrefCount;\n\n#if SUPPORT_PREOPT\n    builtins = preoptimizedSelectors();\n\n    if (PrintPreopt  &&  builtins) {\n        uint32_t occupied = builtins->occupied;\n        uint32_t capacity = builtins->capacity;\n        \n        _objc_inform(\"PREOPTIMIZATION: using selopt at %p\", builtins);\n        _objc_inform(\"PREOPTIMIZATION: %u selectors\", occupied);\n        _objc_inform(\"PREOPTIMIZATION: %u/%u (%u%%) hash table occupancy\",\n                     occupied, capacity,\n                     (unsigned)(occupied/(double)capacity*100));\n        }\n#endif\n\n    // Register selectors used by libobjc\n\n#define s(x) SEL_##x = sel_registerNameNoLock(#x, NO)\n#define t(x,y) SEL_##y = sel_registerNameNoLock(#x, NO)\n\n    mutex_locker_t lock(selLock);\n\n    s(load);\n    s(initialize);\n    t(resolveInstanceMethod:, resolveInstanceMethod);\n    t(resolveClassMethod:, resolveClassMethod);\n    t(.cxx_construct, cxx_construct);\n    t(.cxx_destruct, cxx_destruct);\n    s(retain);\n    s(release);\n    s(autorelease);\n    s(retainCount);\n    s(alloc);\n    t(allocWithZone:, allocWithZone);\n    s(dealloc);\n    s(copy);\n    s(new);\n    t(forwardInvocation:, forwardInvocation);\n    t(_tryRetain, tryRetain);\n    t(_isDeallocating, isDeallocating);\n    s(retainWeakReference);\n    s(allowsWeakReference);\n\n#undef s\n#undef t\n}\n\n\nstatic SEL sel_alloc(const char *name, bool copy)\n{\n    selLock.assertLocked();\n    return (SEL)(copy ? strdupIfMutable(name) : name);    \n}\n\n\nconst char *sel_getName(SEL sel) \n{\n    if (!sel) return \"<null selector>\";\n    return (const char *)(const void*)sel;\n}\n\n\nBOOL sel_isMapped(SEL sel) \n{\n    if (!sel) return NO;\n\n    const char *name = (const char *)(void *)sel;\n\n    if (sel == search_builtins(name)) return YES;\n\n    mutex_locker_t lock(selLock);\n    if (namedSelectors) {\n        return (sel == (SEL)NXMapGet(namedSelectors, name));\n    }\n    return false;\n}\n\n\nstatic SEL search_builtins(const char *name) \n{\n#if SUPPORT_PREOPT\n    if (builtins) return (SEL)builtins->get(name);\n#endif\n    return nil;\n}\n\n\nstatic SEL __sel_registerName(const char *name, bool shouldLock, bool copy) \n{\n    SEL result = 0;\n\n    if (shouldLock) selLock.assertUnlocked();\n    else selLock.assertLocked();\n\n    if (!name) return (SEL)0;\n\n    result = search_builtins(name);\n    if (result) return result;\n    \n    conditional_mutex_locker_t lock(selLock, shouldLock);\n    if (namedSelectors) {\n        result = (SEL)NXMapGet(namedSelectors, name);\n    }\n    if (result) return result;\n\n    // No match. Insert.\n\n    if (!namedSelectors) {\n        namedSelectors = NXCreateMapTable(NXStrValueMapPrototype, \n                                          (unsigned)SelrefCount);\n    }\n    if (!result) {\n        result = sel_alloc(name, copy);\n        // fixme choose a better container (hash not map for starters)\n        NXMapInsert(namedSelectors, sel_getName(result), result);\n    }\n\n    return result;\n}\n\n\nSEL sel_registerName(const char *name) {\n    return __sel_registerName(name, 1, 1);     // YES lock, YES copy\n}\n\nSEL sel_registerNameNoLock(const char *name, bool copy) {\n    return __sel_registerName(name, 0, copy);  // NO lock, maybe copy\n}\n\n\n// 2001/1/24\n// the majority of uses of this function (which used to return NULL if not found)\n// did not check for NULL, so, in fact, never return NULL\n//\nSEL sel_getUid(const char *name) {\n    return __sel_registerName(name, 2, 1);  // YES lock, YES copy\n}\n\n\nBOOL sel_isEqual(SEL lhs, SEL rhs)\n{\n    return bool(lhs == rhs);\n}\n\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-sync.h",
    "content": "/*\n * Copyright (c) 2002, 2006 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef __OBJC_SNYC_H_\n#define __OBJC_SNYC_H_\n\n#include <objc/objc.h>\n\n\n/** \n * Begin synchronizing on 'obj'.  \n * Allocates recursive pthread_mutex associated with 'obj' if needed.\n * \n * @param obj The object to begin synchronizing on.\n * \n * @return OBJC_SYNC_SUCCESS once lock is acquired.  \n */\nOBJC_EXPORT int\nobjc_sync_enter(id _Nonnull obj)\n    OBJC_AVAILABLE(10.3, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * End synchronizing on 'obj'. \n * \n * @param obj The object to end synchronizing on.\n * \n * @return OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR\n */\nOBJC_EXPORT int\nobjc_sync_exit(id _Nonnull obj)\n    OBJC_AVAILABLE(10.3, 2.0, 9.0, 1.0, 2.0);\n\nenum {\n    OBJC_SYNC_SUCCESS                 = 0,\n    OBJC_SYNC_NOT_OWNING_THREAD_ERROR = -1\n};\n\n\n#endif // __OBJC_SYNC_H_\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-sync.mm",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"objc-private.h\"\n#include \"objc-sync.h\"\n\n//\n// Allocate a lock only when needed.  Since few locks are needed at any point\n// in time, keep them on a single list.\n//\n\n\ntypedef struct alignas(CacheLineSize) SyncData {\n    struct SyncData* nextData;\n    DisguisedPtr<objc_object> object;\n    int32_t threadCount;  // number of THREADS using this block\n    recursive_mutex_t mutex;\n} SyncData;\n\ntypedef struct {\n    SyncData *data;\n    unsigned int lockCount;  // number of times THIS THREAD locked this block\n} SyncCacheItem;\n\ntypedef struct SyncCache {\n    unsigned int allocated;\n    unsigned int used;\n    SyncCacheItem list[0];\n} SyncCache;\n\n/*\n  Fast cache: two fixed pthread keys store a single SyncCacheItem. \n  This avoids malloc of the SyncCache for threads that only synchronize \n  a single object at a time.\n  SYNC_DATA_DIRECT_KEY  == SyncCacheItem.data\n  SYNC_COUNT_DIRECT_KEY == SyncCacheItem.lockCount\n */\n\nstruct SyncList {\n    SyncData *data;\n    spinlock_t lock;\n\n    constexpr SyncList() : data(nil), lock(fork_unsafe_lock) { }\n};\n\n// Use multiple parallel lists to decrease contention among unrelated objects.\n#define LOCK_FOR_OBJ(obj) sDataLists[obj].lock\n#define LIST_FOR_OBJ(obj) sDataLists[obj].data\nstatic StripedMap<SyncList> sDataLists;\n\n\nenum usage { ACQUIRE, RELEASE, CHECK };\n\nstatic SyncCache *fetch_cache(bool create)\n{\n    _objc_pthread_data *data;\n    \n    data = _objc_fetch_pthread_data(create);\n    if (!data) return NULL;\n\n    if (!data->syncCache) {\n        if (!create) {\n            return NULL;\n        } else {\n            int count = 4;\n            data->syncCache = (SyncCache *)\n                calloc(1, sizeof(SyncCache) + count*sizeof(SyncCacheItem));\n            data->syncCache->allocated = count;\n        }\n    }\n\n    // Make sure there's at least one open slot in the list.\n    if (data->syncCache->allocated == data->syncCache->used) {\n        data->syncCache->allocated *= 2;\n        data->syncCache = (SyncCache *)\n            realloc(data->syncCache, sizeof(SyncCache) \n                    + data->syncCache->allocated * sizeof(SyncCacheItem));\n    }\n\n    return data->syncCache;\n}\n\n\nvoid _destroySyncCache(struct SyncCache *cache)\n{\n    if (cache) free(cache);\n}\n\n\nstatic SyncData* id2data(id object, enum usage why)\n{\n    spinlock_t *lockp = &LOCK_FOR_OBJ(object);\n    SyncData **listp = &LIST_FOR_OBJ(object);\n    SyncData* result = NULL;\n\n#if SUPPORT_DIRECT_THREAD_KEYS\n    // Check per-thread single-entry fast cache for matching object\n    bool fastCacheOccupied = NO;\n    SyncData *data = (SyncData *)tls_get_direct(SYNC_DATA_DIRECT_KEY);\n    if (data) {\n        fastCacheOccupied = YES;\n\n        if (data->object == object) {\n            // Found a match in fast cache.\n            uintptr_t lockCount;\n\n            result = data;\n            lockCount = (uintptr_t)tls_get_direct(SYNC_COUNT_DIRECT_KEY);\n            if (result->threadCount <= 0  ||  lockCount <= 0) {\n                _objc_fatal(\"id2data fastcache is buggy\");\n            }\n\n            switch(why) {\n            case ACQUIRE: {\n                lockCount++;\n                tls_set_direct(SYNC_COUNT_DIRECT_KEY, (void*)lockCount);\n                break;\n            }\n            case RELEASE:\n                lockCount--;\n                tls_set_direct(SYNC_COUNT_DIRECT_KEY, (void*)lockCount);\n                if (lockCount == 0) {\n                    // remove from fast cache\n                    tls_set_direct(SYNC_DATA_DIRECT_KEY, NULL);\n                    // atomic because may collide with concurrent ACQUIRE\n                    OSAtomicDecrement32Barrier(&result->threadCount);\n                }\n                break;\n            case CHECK:\n                // do nothing\n                break;\n            }\n\n            return result;\n        }\n    }\n#endif\n\n    // Check per-thread cache of already-owned locks for matching object\n    SyncCache *cache = fetch_cache(NO);\n    if (cache) {\n        unsigned int i;\n        for (i = 0; i < cache->used; i++) {\n            SyncCacheItem *item = &cache->list[i];\n            if (item->data->object != object) continue;\n\n            // Found a match.\n            result = item->data;\n            if (result->threadCount <= 0  ||  item->lockCount <= 0) {\n                _objc_fatal(\"id2data cache is buggy\");\n            }\n                \n            switch(why) {\n            case ACQUIRE:\n                item->lockCount++;\n                break;\n            case RELEASE:\n                item->lockCount--;\n                if (item->lockCount == 0) {\n                    // remove from per-thread cache\n                    cache->list[i] = cache->list[--cache->used];\n                    // atomic because may collide with concurrent ACQUIRE\n                    OSAtomicDecrement32Barrier(&result->threadCount);\n                }\n                break;\n            case CHECK:\n                // do nothing\n                break;\n            }\n\n            return result;\n        }\n    }\n\n    // Thread cache didn't find anything.\n    // Walk in-use list looking for matching object\n    // Spinlock prevents multiple threads from creating multiple \n    // locks for the same new object.\n    // We could keep the nodes in some hash table if we find that there are\n    // more than 20 or so distinct locks active, but we don't do that now.\n    \n    lockp->lock();\n\n    {\n        SyncData* p;\n        SyncData* firstUnused = NULL;\n        for (p = *listp; p != NULL; p = p->nextData) {\n            if ( p->object == object ) {\n                result = p;\n                // atomic because may collide with concurrent RELEASE\n                OSAtomicIncrement32Barrier(&result->threadCount);\n                goto done;\n            }\n            if ( (firstUnused == NULL) && (p->threadCount == 0) )\n                firstUnused = p;\n        }\n    \n        // no SyncData currently associated with object\n        if ( (why == RELEASE) || (why == CHECK) )\n            goto done;\n    \n        // an unused one was found, use it\n        if ( firstUnused != NULL ) {\n            result = firstUnused;\n            result->object = (objc_object *)object;\n            result->threadCount = 1;\n            goto done;\n        }\n    }\n\n    // Allocate a new SyncData and add to list.\n    // XXX allocating memory with a global lock held is bad practice,\n    // might be worth releasing the lock, allocating, and searching again.\n    // But since we never free these guys we won't be stuck in allocation very often.\n    posix_memalign((void **)&result, alignof(SyncData), sizeof(SyncData));\n    result->object = (objc_object *)object;\n    result->threadCount = 1;\n    new (&result->mutex) recursive_mutex_t(fork_unsafe_lock);\n    result->nextData = *listp;\n    *listp = result;\n    \n done:\n    lockp->unlock();\n    if (result) {\n        // Only new ACQUIRE should get here.\n        // All RELEASE and CHECK and recursive ACQUIRE are \n        // handled by the per-thread caches above.\n        if (why == RELEASE) {\n            // Probably some thread is incorrectly exiting \n            // while the object is held by another thread.\n            return nil;\n        }\n        if (why != ACQUIRE) _objc_fatal(\"id2data is buggy\");\n        if (result->object != object) _objc_fatal(\"id2data is buggy\");\n\n#if SUPPORT_DIRECT_THREAD_KEYS\n        if (!fastCacheOccupied) {\n            // Save in fast thread cache\n            tls_set_direct(SYNC_DATA_DIRECT_KEY, result);\n            tls_set_direct(SYNC_COUNT_DIRECT_KEY, (void*)1);\n        } else \n#endif\n        {\n            // Save in thread cache\n            if (!cache) cache = fetch_cache(YES);\n            cache->list[cache->used].data = result;\n            cache->list[cache->used].lockCount = 1;\n            cache->used++;\n        }\n    }\n\n    return result;\n}\n\n\nBREAKPOINT_FUNCTION(\n    void objc_sync_nil(void)\n);\n\n\n// Begin synchronizing on 'obj'. \n// Allocates recursive mutex associated with 'obj' if needed.\n// Returns OBJC_SYNC_SUCCESS once lock is acquired.  \nint objc_sync_enter(id obj)\n{\n    int result = OBJC_SYNC_SUCCESS;\n\n    if (obj) {\n        SyncData* data = id2data(obj, ACQUIRE);\n        assert(data);\n        data->mutex.lock();\n    } else {\n        // @synchronized(nil) does nothing\n        if (DebugNilSync) {\n            _objc_inform(\"NIL SYNC DEBUG: @synchronized(nil); set a breakpoint on objc_sync_nil to debug\");\n        }\n        objc_sync_nil();\n    }\n\n    return result;\n}\n\n\n// End synchronizing on 'obj'. \n// Returns OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR\nint objc_sync_exit(id obj)\n{\n    int result = OBJC_SYNC_SUCCESS;\n    \n    if (obj) {\n        SyncData* data = id2data(obj, RELEASE); \n        if (!data) {\n            result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;\n        } else {\n            bool okay = data->mutex.tryUnlock();\n            if (!okay) {\n                result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;\n            }\n        }\n    } else {\n        // @synchronized(nil) does nothing\n    }\n\t\n\n    return result;\n}\n\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-typeencoding.mm",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n/***********************************************************************\n* objc-typeencoding.m\n* Parsing of old-style type strings.\n**********************************************************************/\n\n#include \"objc-private.h\"\n\n/***********************************************************************\n* SubtypeUntil.\n*\n* Delegation.\n**********************************************************************/\nstatic int\tSubtypeUntil\t       (const char *\ttype,\n                                char\t\tend)\n{\n    int\t\tlevel = 0;\n    const char *\thead = type;\n\n    //\n    while (*type)\n    {\n        if (!*type || (!level && (*type == end)))\n            return (int)(type - head);\n\n        switch (*type)\n        {\n            case ']': case '}': case ')': level--; break;\n            case '[': case '{': case '(': level += 1; break;\n        }\n\n        type += 1;\n    }\n\n    _objc_fatal (\"Object: SubtypeUntil: end of type encountered prematurely\\n\");\n    return 0;\n}\n\n\n/***********************************************************************\n* SkipFirstType.\n**********************************************************************/\nstatic const char *\tSkipFirstType\t   (const char *\ttype)\n{\n    while (1)\n    {\n        switch (*type++)\n        {\n            case 'O':\t/* bycopy */\n            case 'n':\t/* in */\n            case 'o':\t/* out */\n            case 'N':\t/* inout */\n            case 'r':\t/* const */\n            case 'V':\t/* oneway */\n            case '^':\t/* pointers */\n                break;\n\n            case '@':   /* objects */\n                if (type[0] == '?') type++;  /* Blocks */\n                return type;\n\n                /* arrays */\n            case '[':\n                while ((*type >= '0') && (*type <= '9'))\n                    type += 1;\n                return type + SubtypeUntil (type, ']') + 1;\n\n                /* structures */\n            case '{':\n                return type + SubtypeUntil (type, '}') + 1;\n\n                /* unions */\n            case '(':\n                return type + SubtypeUntil (type, ')') + 1;\n\n                /* basic types */\n            default:\n                return type;\n        }\n    }\n}\n\n\n/***********************************************************************\n* encoding_getNumberOfArguments.\n**********************************************************************/\nunsigned int \nencoding_getNumberOfArguments(const char *typedesc)\n{\n    unsigned nargs;\n\n    // First, skip the return type\n    typedesc = SkipFirstType (typedesc);\n\n    // Next, skip stack size\n    while ((*typedesc >= '0') && (*typedesc <= '9'))\n        typedesc += 1;\n\n    // Now, we have the arguments - count how many\n    nargs = 0;\n    while (*typedesc)\n    {\n        // Traverse argument type\n        typedesc = SkipFirstType (typedesc);\n\n        // Skip GNU runtime's register parameter hint\n        if (*typedesc == '+') typedesc++;\n\n        // Traverse (possibly negative) argument offset\n        if (*typedesc == '-')\n            typedesc += 1;\n        while ((*typedesc >= '0') && (*typedesc <= '9'))\n            typedesc += 1;\n\n        // Made it past an argument\n        nargs += 1;\n    }\n\n    return nargs;\n}\n\n/***********************************************************************\n* encoding_getSizeOfArguments.\n**********************************************************************/\nunsigned \nencoding_getSizeOfArguments(const char *typedesc)\n{\n    unsigned\t\tstack_size;\n\n    // Get our starting points\n    stack_size = 0;\n\n    // Skip the return type\n    typedesc = SkipFirstType (typedesc);\n\n    // Convert ASCII number string to integer\n    while ((*typedesc >= '0') && (*typedesc <= '9'))\n        stack_size = (stack_size * 10) + (*typedesc++ - '0');\n\n    return stack_size;\n}\n\n\n/***********************************************************************\n* encoding_getArgumentInfo.\n**********************************************************************/\nunsigned int \nencoding_getArgumentInfo(const char *typedesc, unsigned int arg,\n                         const char **type, int *offset)\n{\n    unsigned nargs = 0;\n    int self_offset = 0;\n    bool offset_is_negative = NO;\n\n    // First, skip the return type\n    typedesc = SkipFirstType (typedesc);\n\n    // Next, skip stack size\n    while ((*typedesc >= '0') && (*typedesc <= '9'))\n        typedesc += 1;\n\n    // Now, we have the arguments - position typedesc to the appropriate argument\n    while (*typedesc && nargs != arg)\n    {\n\n        // Skip argument type\n        typedesc = SkipFirstType (typedesc);\n\n        if (nargs == 0)\n        {\n            // Skip GNU runtime's register parameter hint\n            if (*typedesc == '+') typedesc++;\n\n            // Skip negative sign in offset\n            if (*typedesc == '-')\n            {\n                offset_is_negative = YES;\n                typedesc += 1;\n            }\n            else\n                offset_is_negative = NO;\n\n            while ((*typedesc >= '0') && (*typedesc <= '9'))\n                self_offset = self_offset * 10 + (*typedesc++ - '0');\n            if (offset_is_negative)\n                self_offset = -(self_offset);\n\n        }\n\n        else\n        {\n            // Skip GNU runtime's register parameter hint\n            if (*typedesc == '+') typedesc++;\n\n            // Skip (possibly negative) argument offset\n            if (*typedesc == '-')\n                typedesc += 1;\n            while ((*typedesc >= '0') && (*typedesc <= '9'))\n                typedesc += 1;\n        }\n\n        nargs += 1;\n    }\n\n    if (*typedesc)\n    {\n        int arg_offset = 0;\n\n        *type\t = typedesc;\n        typedesc = SkipFirstType (typedesc);\n\n        if (arg == 0)\n        {\n            *offset = 0;\n        }\n\n        else\n        {\n            // Skip GNU register parameter hint\n            if (*typedesc == '+') typedesc++;\n\n            // Pick up (possibly negative) argument offset\n            if (*typedesc == '-')\n            {\n                offset_is_negative = YES;\n                typedesc += 1;\n            }\n            else\n                offset_is_negative = NO;\n\n            while ((*typedesc >= '0') && (*typedesc <= '9'))\n                arg_offset = arg_offset * 10 + (*typedesc++ - '0');\n            if (offset_is_negative)\n                arg_offset = - arg_offset;\n\n            *offset = arg_offset - self_offset;\n        }\n\n    }\n\n    else\n    {\n        *type\t= 0;\n        *offset\t= 0;\n    }\n\n    return nargs;\n}\n\n\nvoid \nencoding_getReturnType(const char *t, char *dst, size_t dst_len)\n{\n    size_t len;\n    const char *end;\n\n    if (!dst) return;\n    if (!t) {\n        strncpy(dst, \"\", dst_len);\n        return;\n    }\n\n    end = SkipFirstType(t);\n    len = end - t;\n    strncpy(dst, t, MIN(len, dst_len));\n    if (len < dst_len) memset(dst+len, 0, dst_len - len);\n}\n\n/***********************************************************************\n* encoding_copyReturnType.  Returns the method's return type string \n* on the heap. \n**********************************************************************/\nchar *\nencoding_copyReturnType(const char *t)\n{\n    size_t len;\n    const char *end;\n    char *result;\n\n    if (!t) return NULL;\n\n    end = SkipFirstType(t);\n    len = end - t;\n    result = (char *)malloc(len + 1);\n    strncpy(result, t, len);\n    result[len] = '\\0';\n    return result;\n}\n\n\nvoid \nencoding_getArgumentType(const char *t, unsigned int index, \n                         char *dst, size_t dst_len)\n{\n    size_t len;\n    const char *end;\n    int offset;\n\n    if (!dst) return;\n    if (!t) {\n        strncpy(dst, \"\", dst_len);\n        return;\n    }\n\n    encoding_getArgumentInfo(t, index, &t, &offset);\n\n    if (!t) {\n        strncpy(dst, \"\", dst_len);\n        return;\n    }\n\n    end = SkipFirstType(t);\n    len = end - t;\n    strncpy(dst, t, MIN(len, dst_len));\n    if (len < dst_len) memset(dst+len, 0, dst_len - len);\n}\n\n\n/***********************************************************************\n* encoding_copyArgumentType.  Returns a single argument's type string \n* on the heap. Argument 0 is `self`; argument 1 is `_cmd`. \n**********************************************************************/\nchar *\nencoding_copyArgumentType(const char *t, unsigned int index)\n{\n    size_t len;\n    const char *end;\n    char *result;\n    int offset;\n\n    if (!t) return NULL;\n\n    encoding_getArgumentInfo(t, index, &t, &offset);\n\n    if (!t) return NULL;\n\n    end = SkipFirstType(t);\n    len = end - t;\n    result = (char *)malloc(len + 1);\n    strncpy(result, t, len);\n    result[len] = '\\0';\n    return result;\n}\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-weak.h",
    "content": "/*\n * Copyright (c) 2010-2011 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _OBJC_WEAK_H_\n#define _OBJC_WEAK_H_\n\n#include <objc/objc.h>\n#include \"objc-config.h\"\n\n__BEGIN_DECLS\n\n/*\nThe weak table is a hash table governed by a single spin lock.\nAn allocated blob of memory, most often an object, but under GC any such \nallocation, may have its address stored in a __weak marked storage location \nthrough use of compiler generated write-barriers or hand coded uses of the \nregister weak primitive. Associated with the registration can be a callback \nblock for the case when one of the allocated chunks of memory is reclaimed. \nThe table is hashed on the address of the allocated memory.  When __weak \nmarked memory changes its reference, we count on the fact that we can still \nsee its previous reference.\n\nSo, in the hash table, indexed by the weakly referenced item, is a list of \nall locations where this address is currently being stored.\n \nFor ARC, we also keep track of whether an arbitrary object is being \ndeallocated by briefly placing it in the table just prior to invoking \ndealloc, and removing it via objc_clear_deallocating just prior to memory \nreclamation.\n\n*/\n\n// The address of a __weak variable.\n// These pointers are stored disguised so memory analysis tools\n// don't see lots of interior pointers from the weak table into objects.\ntypedef DisguisedPtr<objc_object *> weak_referrer_t;\n\n#if __LP64__\n#define PTR_MINUS_2 62\n#else\n#define PTR_MINUS_2 30\n#endif\n\n/**\n * The internal structure stored in the weak references table. \n * It maintains and stores\n * a hash set of weak references pointing to an object.\n * If out_of_line_ness != REFERRERS_OUT_OF_LINE then the set\n * is instead a small inline array.\n */\n#define WEAK_INLINE_COUNT 4\n\n// out_of_line_ness field overlaps with the low two bits of inline_referrers[1].\n// inline_referrers[1] is a DisguisedPtr of a pointer-aligned address.\n// The low two bits of a pointer-aligned DisguisedPtr will always be 0b00\n// (disguised nil or 0x80..00) or 0b11 (any other address).\n// Therefore out_of_line_ness == 0b10 is used to mark the out-of-line state.\n#define REFERRERS_OUT_OF_LINE 2\n\nstruct weak_entry_t {\n    DisguisedPtr<objc_object> referent;\n    union {\n        struct {\n            weak_referrer_t *referrers;\n            uintptr_t        out_of_line_ness : 2;\n            uintptr_t        num_refs : PTR_MINUS_2;\n            uintptr_t        mask;\n            uintptr_t        max_hash_displacement;\n        };\n        struct {\n            // out_of_line_ness field is low bits of inline_referrers[1]\n            weak_referrer_t  inline_referrers[WEAK_INLINE_COUNT];\n        };\n    };\n\n    bool out_of_line() {\n        return (out_of_line_ness == REFERRERS_OUT_OF_LINE);\n    }\n\n    weak_entry_t& operator=(const weak_entry_t& other) {\n        memcpy(this, &other, sizeof(other));\n        return *this;\n    }\n\n    weak_entry_t(objc_object *newReferent, objc_object **newReferrer)\n        : referent(newReferent)\n    {\n        inline_referrers[0] = newReferrer;\n        for (int i = 1; i < WEAK_INLINE_COUNT; i++) {\n            inline_referrers[i] = nil;\n        }\n    }\n};\n\n/**\n * The global weak references table. Stores object ids as keys,\n * and weak_entry_t structs as their values.\n */\nstruct weak_table_t {\n    weak_entry_t *weak_entries;\n    size_t    num_entries;\n    uintptr_t mask;\n    uintptr_t max_hash_displacement;\n};\n\n/// Adds an (object, weak pointer) pair to the weak table.\nid weak_register_no_lock(weak_table_t *weak_table, id referent, \n                         id *referrer, bool crashIfDeallocating);\n\n/// Removes an (object, weak pointer) pair from the weak table.\nvoid weak_unregister_no_lock(weak_table_t *weak_table, id referent, id *referrer);\n\n#if DEBUG\n/// Returns true if an object is weakly referenced somewhere.\nbool weak_is_registered_no_lock(weak_table_t *weak_table, id referent);\n#endif\n\n/// Called on object destruction. Sets all remaining weak pointers to nil.\nvoid weak_clear_no_lock(weak_table_t *weak_table, id referent);\n\n__END_DECLS\n\n#endif /* _OBJC_WEAK_H_ */\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc-weak.mm",
    "content": "/*\n * Copyright (c) 2010-2011 Apple Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#include \"objc-private.h\"\n\n#include \"objc-weak.h\"\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <sys/types.h>\n#include <libkern/OSAtomic.h>\n\n#define TABLE_SIZE(entry) (entry->mask ? entry->mask + 1 : 0)\n\nstatic void append_referrer(weak_entry_t *entry, objc_object **new_referrer);\n\nBREAKPOINT_FUNCTION(\n    void objc_weak_error(void)\n);\n\nstatic void bad_weak_table(weak_entry_t *entries)\n{\n    _objc_fatal(\"bad weak table at %p. This may be a runtime bug or a \"\n                \"memory error somewhere else.\", entries);\n}\n\n/** \n * Unique hash function for object pointers only.\n * \n * @param key The object pointer\n * \n * @return Size unrestricted hash of pointer.\n */\nstatic inline uintptr_t hash_pointer(objc_object *key) {\n    return ptr_hash((uintptr_t)key);\n}\n\n/** \n * Unique hash function for weak object pointers only.\n * \n * @param key The weak object pointer. \n * \n * @return Size unrestricted hash of pointer.\n */\nstatic inline uintptr_t w_hash_pointer(objc_object **key) {\n    return ptr_hash((uintptr_t)key);\n}\n\n/** \n * Grow the entry's hash table of referrers. Rehashes each\n * of the referrers.\n * \n * @param entry Weak pointer hash set for a particular object.\n */\n__attribute__((noinline, used))\nstatic void grow_refs_and_insert(weak_entry_t *entry, \n                                 objc_object **new_referrer)\n{\n    assert(entry->out_of_line());\n\n    size_t old_size = TABLE_SIZE(entry);\n    size_t new_size = old_size ? old_size * 2 : 8;\n\n    size_t num_refs = entry->num_refs;\n    weak_referrer_t *old_refs = entry->referrers;\n    entry->mask = new_size - 1;\n    \n    entry->referrers = (weak_referrer_t *)\n        calloc(TABLE_SIZE(entry), sizeof(weak_referrer_t));\n    entry->num_refs = 0;\n    entry->max_hash_displacement = 0;\n    \n    for (size_t i = 0; i < old_size && num_refs > 0; i++) {\n        if (old_refs[i] != nil) {\n            append_referrer(entry, old_refs[i]);\n            num_refs--;\n        }\n    }\n    // Insert\n    append_referrer(entry, new_referrer);\n    if (old_refs) free(old_refs);\n}\n\n/** \n * Add the given referrer to set of weak pointers in this entry.\n * Does not perform duplicate checking (b/c weak pointers are never\n * added to a set twice). \n *\n * @param entry The entry holding the set of weak pointers. \n * @param new_referrer The new weak pointer to be added.\n */\nstatic void append_referrer(weak_entry_t *entry, objc_object **new_referrer)\n{\n    if (! entry->out_of_line()) {\n        // Try to insert inline.\n        for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {\n            if (entry->inline_referrers[i] == nil) {\n                entry->inline_referrers[i] = new_referrer;\n                return;\n            }\n        }\n\n        // Couldn't insert inline. Allocate out of line.\n        weak_referrer_t *new_referrers = (weak_referrer_t *)\n            calloc(WEAK_INLINE_COUNT, sizeof(weak_referrer_t));\n        // This constructed table is invalid, but grow_refs_and_insert\n        // will fix it and rehash it.\n        for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {\n            new_referrers[i] = entry->inline_referrers[i];\n        }\n        entry->referrers = new_referrers;\n        entry->num_refs = WEAK_INLINE_COUNT;\n        entry->out_of_line_ness = REFERRERS_OUT_OF_LINE;\n        entry->mask = WEAK_INLINE_COUNT-1;\n        entry->max_hash_displacement = 0;\n    }\n\n    assert(entry->out_of_line());\n\n    if (entry->num_refs >= TABLE_SIZE(entry) * 3/4) {\n        return grow_refs_and_insert(entry, new_referrer);\n    }\n    size_t begin = w_hash_pointer(new_referrer) & (entry->mask);\n    size_t index = begin;\n    size_t hash_displacement = 0;\n    while (entry->referrers[index] != nil) {\n        hash_displacement++;\n        index = (index+1) & entry->mask;\n        if (index == begin) bad_weak_table(entry);\n    }\n    if (hash_displacement > entry->max_hash_displacement) {\n        entry->max_hash_displacement = hash_displacement;\n    }\n    weak_referrer_t &ref = entry->referrers[index];\n    ref = new_referrer;\n    entry->num_refs++;\n}\n\n/** \n * Remove old_referrer from set of referrers, if it's present.\n * Does not remove duplicates, because duplicates should not exist. \n * \n * @todo this is slow if old_referrer is not present. Is this ever the case? \n *\n * @param entry The entry holding the referrers.\n * @param old_referrer The referrer to remove. \n */\nstatic void remove_referrer(weak_entry_t *entry, objc_object **old_referrer)\n{\n    if (! entry->out_of_line()) {\n        for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {\n            if (entry->inline_referrers[i] == old_referrer) {\n                entry->inline_referrers[i] = nil;\n                return;\n            }\n        }\n        _objc_inform(\"Attempted to unregister unknown __weak variable \"\n                     \"at %p. This is probably incorrect use of \"\n                     \"objc_storeWeak() and objc_loadWeak(). \"\n                     \"Break on objc_weak_error to debug.\\n\", \n                     old_referrer);\n        objc_weak_error();\n        return;\n    }\n\n    size_t begin = w_hash_pointer(old_referrer) & (entry->mask);\n    size_t index = begin;\n    size_t hash_displacement = 0;\n    while (entry->referrers[index] != old_referrer) {\n        index = (index+1) & entry->mask;\n        if (index == begin) bad_weak_table(entry);\n        hash_displacement++;\n        if (hash_displacement > entry->max_hash_displacement) {\n            _objc_inform(\"Attempted to unregister unknown __weak variable \"\n                         \"at %p. This is probably incorrect use of \"\n                         \"objc_storeWeak() and objc_loadWeak(). \"\n                         \"Break on objc_weak_error to debug.\\n\", \n                         old_referrer);\n            objc_weak_error();\n            return;\n        }\n    }\n    entry->referrers[index] = nil;\n    entry->num_refs--;\n}\n\n/** \n * Add new_entry to the object's table of weak references.\n * Does not check whether the referent is already in the table.\n */\nstatic void weak_entry_insert(weak_table_t *weak_table, weak_entry_t *new_entry)\n{\n    weak_entry_t *weak_entries = weak_table->weak_entries;\n    assert(weak_entries != nil);\n\n    size_t begin = hash_pointer(new_entry->referent) & (weak_table->mask);\n    size_t index = begin;\n    size_t hash_displacement = 0;\n    while (weak_entries[index].referent != nil) {\n        index = (index+1) & weak_table->mask;\n        if (index == begin) bad_weak_table(weak_entries);\n        hash_displacement++;\n    }\n\n    weak_entries[index] = *new_entry;\n    weak_table->num_entries++;\n\n    if (hash_displacement > weak_table->max_hash_displacement) {\n        weak_table->max_hash_displacement = hash_displacement;\n    }\n}\n\n\nstatic void weak_resize(weak_table_t *weak_table, size_t new_size)\n{\n    size_t old_size = TABLE_SIZE(weak_table);\n\n    weak_entry_t *old_entries = weak_table->weak_entries;\n    weak_entry_t *new_entries = (weak_entry_t *)\n        calloc(new_size, sizeof(weak_entry_t));\n\n    weak_table->mask = new_size - 1;\n    weak_table->weak_entries = new_entries;\n    weak_table->max_hash_displacement = 0;\n    weak_table->num_entries = 0;  // restored by weak_entry_insert below\n    \n    if (old_entries) {\n        weak_entry_t *entry;\n        weak_entry_t *end = old_entries + old_size;\n        for (entry = old_entries; entry < end; entry++) {\n            if (entry->referent) {\n                weak_entry_insert(weak_table, entry);\n            }\n        }\n        free(old_entries);\n    }\n}\n\n// Grow the given zone's table of weak references if it is full.\nstatic void weak_grow_maybe(weak_table_t *weak_table)\n{\n    size_t old_size = TABLE_SIZE(weak_table);\n\n    // Grow if at least 3/4 full.\n    if (weak_table->num_entries >= old_size * 3 / 4) {\n        weak_resize(weak_table, old_size ? old_size*2 : 64);\n    }\n}\n\n// Shrink the table if it is mostly empty.\nstatic void weak_compact_maybe(weak_table_t *weak_table)\n{\n    size_t old_size = TABLE_SIZE(weak_table);\n\n    // Shrink if larger than 1024 buckets and at most 1/16 full.\n    if (old_size >= 1024  && old_size / 16 >= weak_table->num_entries) {\n        weak_resize(weak_table, old_size / 8);\n        // leaves new table no more than 1/2 full\n    }\n}\n\n\n/**\n * Remove entry from the zone's table of weak references.\n */\nstatic void weak_entry_remove(weak_table_t *weak_table, weak_entry_t *entry)\n{\n    // remove entry\n    if (entry->out_of_line()) free(entry->referrers);\n    bzero(entry, sizeof(*entry));\n\n    weak_table->num_entries--;\n\n    weak_compact_maybe(weak_table);\n}\n\n\n/** \n * Return the weak reference table entry for the given referent. \n * If there is no entry for referent, return NULL. \n * Performs a lookup.\n *\n * @param weak_table \n * @param referent The object. Must not be nil.\n * \n * @return The table of weak referrers to this object. \n */\nstatic weak_entry_t *\nweak_entry_for_referent(weak_table_t *weak_table, objc_object *referent)\n{\n    assert(referent);\n\n    weak_entry_t *weak_entries = weak_table->weak_entries;\n\n    if (!weak_entries) return nil;\n\n    size_t begin = hash_pointer(referent) & weak_table->mask;\n    size_t index = begin;\n    size_t hash_displacement = 0;\n    while (weak_table->weak_entries[index].referent != referent) {\n        index = (index+1) & weak_table->mask;\n        if (index == begin) bad_weak_table(weak_table->weak_entries);\n        hash_displacement++;\n        if (hash_displacement > weak_table->max_hash_displacement) {\n            return nil;\n        }\n    }\n    \n    return &weak_table->weak_entries[index];\n}\n\n/** \n * Unregister an already-registered weak reference.\n * This is used when referrer's storage is about to go away, but referent\n * isn't dead yet. (Otherwise, zeroing referrer later would be a\n * bad memory access.)\n * Does nothing if referent/referrer is not a currently active weak reference.\n * Does not zero referrer.\n * \n * FIXME currently requires old referent value to be passed in (lame)\n * FIXME unregistration should be automatic if referrer is collected\n * \n * @param weak_table The global weak table.\n * @param referent The object.\n * @param referrer The weak reference.\n */\nvoid\nweak_unregister_no_lock(weak_table_t *weak_table, id referent_id, \n                        id *referrer_id)\n{\n    objc_object *referent = (objc_object *)referent_id;\n    objc_object **referrer = (objc_object **)referrer_id;\n\n    weak_entry_t *entry;\n\n    if (!referent) return;\n\n    if ((entry = weak_entry_for_referent(weak_table, referent))) {\n        remove_referrer(entry, referrer);\n        bool empty = true;\n        if (entry->out_of_line()  &&  entry->num_refs != 0) {\n            empty = false;\n        }\n        else {\n            for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {\n                if (entry->inline_referrers[i]) {\n                    empty = false; \n                    break;\n                }\n            }\n        }\n\n        if (empty) {\n            weak_entry_remove(weak_table, entry);\n        }\n    }\n\n    // Do not set *referrer = nil. objc_storeWeak() requires that the \n    // value not change.\n}\n\n/** \n * Registers a new (object, weak pointer) pair. Creates a new weak\n * object entry if it does not exist.\n * \n * @param weak_table The global weak table.\n * @param referent The object pointed to by the weak reference.\n * @param referrer The weak pointer address.\n */\nid \nweak_register_no_lock(weak_table_t *weak_table, id referent_id, \n                      id *referrer_id, bool crashIfDeallocating)\n{\n    objc_object *referent = (objc_object *)referent_id;\n    objc_object **referrer = (objc_object **)referrer_id;\n\n    if (!referent  ||  referent->isTaggedPointer()) return referent_id;\n\n    // ensure that the referenced object is viable\n    bool deallocating;\n    if (!referent->ISA()->hasCustomRR()) {\n        deallocating = referent->rootIsDeallocating();\n    }\n    else {\n        BOOL (*allowsWeakReference)(objc_object *, SEL) = \n            (BOOL(*)(objc_object *, SEL))\n            object_getMethodImplementation((id)referent, \n                                           SEL_allowsWeakReference);\n        if ((IMP)allowsWeakReference == _objc_msgForward) {\n            return nil;\n        }\n        deallocating =\n            ! (*allowsWeakReference)(referent, SEL_allowsWeakReference);\n    }\n\n    if (deallocating) {\n        if (crashIfDeallocating) {\n            _objc_fatal(\"Cannot form weak reference to instance (%p) of \"\n                        \"class %s. It is possible that this object was \"\n                        \"over-released, or is in the process of deallocation.\",\n                        (void*)referent, object_getClassName((id)referent));\n        } else {\n            return nil;\n        }\n    }\n\n    // now remember it and where it is being stored\n    weak_entry_t *entry;\n    if ((entry = weak_entry_for_referent(weak_table, referent))) {\n        append_referrer(entry, referrer);\n    } \n    else {\n        weak_entry_t new_entry(referent, referrer);\n        weak_grow_maybe(weak_table);\n        weak_entry_insert(weak_table, &new_entry);\n    }\n\n    // Do not set *referrer. objc_storeWeak() requires that the \n    // value not change.\n\n    return referent_id;\n}\n\n\n#if DEBUG\nbool\nweak_is_registered_no_lock(weak_table_t *weak_table, id referent_id) \n{\n    return weak_entry_for_referent(weak_table, (objc_object *)referent_id);\n}\n#endif\n\n\n/** \n * Called by dealloc; nils out all weak pointers that point to the \n * provided object so that they can no longer be used.\n * \n * @param weak_table \n * @param referent The object being deallocated. \n */\nvoid \nweak_clear_no_lock(weak_table_t *weak_table, id referent_id) \n{\n    objc_object *referent = (objc_object *)referent_id;\n\n    weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);\n    if (entry == nil) {\n        /// XXX shouldn't happen, but does with mismatched CF/objc\n        //printf(\"XXX no entry for clear deallocating %p\\n\", referent);\n        return;\n    }\n\n    // zero out references\n    weak_referrer_t *referrers;\n    size_t count;\n    \n    if (entry->out_of_line()) {\n        referrers = entry->referrers;\n        count = TABLE_SIZE(entry);\n    } \n    else {\n        referrers = entry->inline_referrers;\n        count = WEAK_INLINE_COUNT;\n    }\n    \n    for (size_t i = 0; i < count; ++i) {\n        objc_object **referrer = referrers[i];\n        if (referrer) {\n            if (*referrer == referent) {\n                *referrer = nil;\n            }\n            else if (*referrer) {\n                _objc_inform(\"__weak variable at %p holds %p instead of %p. \"\n                             \"This is probably incorrect use of \"\n                             \"objc_storeWeak() and objc_loadWeak(). \"\n                             \"Break on objc_weak_error to debug.\\n\", \n                             referrer, (void*)*referrer, (void*)referent);\n                objc_weak_error();\n            }\n        }\n    }\n    \n    weak_entry_remove(weak_table, entry);\n}\n\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objc.h",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/*\n *\tobjc.h\n *\tCopyright 1988-1996, NeXT Software, Inc.\n */\n\n#ifndef _OBJC_OBJC_H_\n#define _OBJC_OBJC_H_\n\n#include <sys/types.h>      // for __DARWIN_NULL\n#include <Availability.h>\n#include <objc/objc-api.h>\n#include <stdbool.h>\n\n#if !OBJC_TYPES_DEFINED\n/// An opaque type that represents an Objective-C class.\ntypedef struct objc_class *Class;\n\n/// Represents an instance of a class.\nstruct objc_object {\n    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;\n};\n\n/// A pointer to an instance of a class.\ntypedef struct objc_object *id;\n#endif\n\n/// An opaque type that represents a method selector.\ntypedef struct objc_selector *SEL;\n\n/// A pointer to the function of a method implementation. \n#if !OBJC_OLD_DISPATCH_PROTOTYPES\ntypedef void (*IMP)(void /* id, SEL, ... */ ); \n#else\ntypedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...); \n#endif\n\n/// Type to represent a boolean value.\n\n#if defined(__OBJC_BOOL_IS_BOOL)\n    // Honor __OBJC_BOOL_IS_BOOL when available.\n#   if __OBJC_BOOL_IS_BOOL\n#       define OBJC_BOOL_IS_BOOL 1\n#   else\n#       define OBJC_BOOL_IS_BOOL 0\n#   endif\n#else\n    // __OBJC_BOOL_IS_BOOL not set.\n#   if TARGET_OS_OSX || TARGET_OS_IOSMAC || (TARGET_OS_IOS && !__LP64__ && !__ARM_ARCH_7K)\n#      define OBJC_BOOL_IS_BOOL 0\n#   else\n#      define OBJC_BOOL_IS_BOOL 1\n#   endif\n#endif\n\n#if OBJC_BOOL_IS_BOOL\n    typedef bool BOOL;\n#else\n#   define OBJC_BOOL_IS_CHAR 1\n    typedef signed char BOOL; \n    // BOOL is explicitly signed so @encode(BOOL) == \"c\" rather than \"C\" \n    // even if -funsigned-char is used.\n#endif\n\n#define OBJC_BOOL_DEFINED\n\n#if __has_feature(objc_bool)\n#define YES __objc_yes\n#define NO  __objc_no\n#else\n#define YES ((BOOL)1)\n#define NO  ((BOOL)0)\n#endif\n\n#ifndef Nil\n# if __has_feature(cxx_nullptr)\n#   define Nil nullptr\n# else\n#   define Nil __DARWIN_NULL\n# endif\n#endif\n\n#ifndef nil\n# if __has_feature(cxx_nullptr)\n#   define nil nullptr\n# else\n#   define nil __DARWIN_NULL\n# endif\n#endif\n\n#ifndef __strong\n# if !__has_feature(objc_arc)\n#   define __strong /* empty */\n# endif\n#endif\n\n#ifndef __unsafe_unretained\n# if !__has_feature(objc_arc)\n#   define __unsafe_unretained /* empty */\n# endif\n#endif\n\n#ifndef __autoreleasing\n# if !__has_feature(objc_arc)\n#   define __autoreleasing /* empty */\n# endif\n#endif\n\n\n/** \n * Returns the name of the method specified by a given selector.\n * \n * @param sel A pointer of type \\c SEL. Pass the selector whose name you wish to determine.\n * \n * @return A C string indicating the name of the selector.\n */\nOBJC_EXPORT const char * _Nonnull sel_getName(SEL _Nonnull sel)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Registers a method with the Objective-C runtime system, maps the method \n * name to a selector, and returns the selector value.\n * \n * @param str A pointer to a C string. Pass the name of the method you wish to register.\n * \n * @return A pointer of type SEL specifying the selector for the named method.\n * \n * @note You must register a method name with the Objective-C runtime system to obtain the\n *  method’s selector before you can add the method to a class definition. If the method name\n *  has already been registered, this function simply returns the selector.\n */\nOBJC_EXPORT SEL _Nonnull sel_registerName(const char * _Nonnull str)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the class name of a given object.\n * \n * @param obj An Objective-C object.\n * \n * @return The name of the class of which \\e obj is an instance.\n */\nOBJC_EXPORT const char * _Nonnull object_getClassName(id _Nullable obj)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a pointer to any extra bytes allocated with an instance given object.\n * \n * @param obj An Objective-C object.\n * \n * @return A pointer to any extra bytes allocated with \\e obj. If \\e obj was\n *   not allocated with any extra bytes, then dereferencing the returned pointer is undefined.\n * \n * @note This function returns a pointer to any extra bytes allocated with the instance\n *  (as specified by \\c class_createInstance with extraBytes>0). This memory follows the\n *  object's ordinary ivars, but may not be adjacent to the last ivar.\n * @note The returned pointer is guaranteed to be pointer-size aligned, even if the area following\n *  the object's last ivar is less aligned than that. Alignment greater than pointer-size is never\n *  guaranteed, even if the area following the object's last ivar is more aligned than that.\n * @note In a garbage-collected environment, the memory is scanned conservatively.\n */\nOBJC_EXPORT void * _Nullable object_getIndexedIvars(id _Nullable obj)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)\n    OBJC_ARC_UNAVAILABLE;\n\n/** \n * Identifies a selector as being valid or invalid.\n * \n * @param sel The selector you want to identify.\n * \n * @return YES if selector is valid and has a function implementation, NO otherwise. \n * \n * @warning On some platforms, an invalid reference (to invalid memory addresses) can cause\n *  a crash. \n */\nOBJC_EXPORT BOOL sel_isMapped(SEL _Nonnull sel)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Registers a method name with the Objective-C runtime system.\n * \n * @param str A pointer to a C string. Pass the name of the method you wish to register.\n * \n * @return A pointer of type SEL specifying the selector for the named method.\n * \n * @note The implementation of this method is identical to the implementation of \\c sel_registerName.\n * @note Prior to OS X version 10.0, this method tried to find the selector mapped to the given name\n *  and returned \\c NULL if the selector was not found. This was changed for safety, because it was\n *  observed that many of the callers of this function did not check the return value for \\c NULL.\n */\nOBJC_EXPORT SEL _Nonnull sel_getUid(const char * _Nonnull str)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\ntypedef const void* objc_objectptr_t;\n\n\n// Obsolete ARC conversions.\n\nOBJC_EXPORT id _Nullable objc_retainedObject(objc_objectptr_t _Nullable obj)\n#if !OBJC_DECLARE_SYMBOLS\n    OBJC_UNAVAILABLE(\"use CFBridgingRelease() or a (__bridge_transfer id) cast instead\")\n#endif\n    ;\nOBJC_EXPORT id _Nullable objc_unretainedObject(objc_objectptr_t _Nullable obj)\n#if !OBJC_DECLARE_SYMBOLS\n    OBJC_UNAVAILABLE(\"use a (__bridge id) cast instead\")\n#endif\n    ;\nOBJC_EXPORT objc_objectptr_t _Nullable objc_unretainedPointer(id _Nullable obj)\n#if !OBJC_DECLARE_SYMBOLS\n    OBJC_UNAVAILABLE(\"use a __bridge cast instead\")\n#endif\n    ;\n\n\n#if !__OBJC2__\n\n// The following declarations are provided here for source compatibility.\n\n#if defined(__LP64__)\n    typedef long arith_t;\n    typedef unsigned long uarith_t;\n#   define ARITH_SHIFT 32\n#else\n    typedef int arith_t;\n    typedef unsigned uarith_t;\n#   define ARITH_SHIFT 16\n#endif\n\ntypedef char *STR;\n\n#define ISSELECTOR(sel) sel_isMapped(sel)\n#define SELNAME(sel)\tsel_getName(sel)\n#define SELUID(str)\tsel_getUid(str)\n#define NAMEOF(obj)     object_getClassName(obj)\n#define IV(obj)         object_getIndexedIvars(obj)\n\n#endif\n\n#endif  /* _OBJC_OBJC_H_ */\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objcrt.c",
    "content": "#define WIN32_LEAN_AND_MEAN\r\n#include <stdio.h>\r\n#include <windows.h>\r\n#include <stdlib.h>\r\n#include \"objcrt.h\"\r\n\r\n// Boundary symbols for metadata sections\r\n\r\n#pragma section(\".objc_module_info$A\",long,read,write)\r\n#pragma data_seg(\".objc_module_info$A\")\r\nstatic uintptr_t __objc_modStart = 0;\r\n#pragma section(\".objc_module_info$C\",long,read,write)\r\n#pragma data_seg(\".objc_module_info$C\")\r\nstatic uintptr_t __objc_modEnd = 0;\r\n\r\n#pragma section(\".objc_protocol$A\",long,read,write)\r\n#pragma data_seg(\".objc_protocol$A\")\r\nstatic uintptr_t __objc_protoStart = 0;\r\n#pragma section(\".objc_protocol$C\",long,read,write)\r\n#pragma data_seg(\".objc_protocol$C\")\r\nstatic uintptr_t __objc_protoEnd = 0;\r\n\r\n#pragma section(\".objc_image_info$A\",long,read,write)\r\n#pragma data_seg(\".objc_image_info$A\")\r\nstatic uintptr_t __objc_iiStart = 0;\r\n#pragma section(\".objc_image_info$C\",long,read,write)\r\n#pragma data_seg(\".objc_image_info$C\")\r\nstatic uintptr_t __objc_iiEnd = 0;\r\n\r\n#pragma section(\".objc_message_refs$A\",long,read,write)\r\n#pragma data_seg(\".objc_message_refs$A\")\r\nstatic uintptr_t __objc_selrefsStart = 0;\r\n#pragma section(\".objc_message_refs$C\",long,read,write)\r\n#pragma data_seg(\".objc_message_refs$C\")\r\nstatic uintptr_t __objc_selrefsEnd = 0;\r\n\r\n#pragma section(\".objc_class_refs$A\",long,read,write)\r\n#pragma data_seg(\".objc_class_refs$A\")\r\nstatic uintptr_t __objc_clsrefsStart = 0;\r\n#pragma section(\".objc_class_refs$C\",long,read,write)\r\n#pragma data_seg(\".objc_class_refs$C\")\r\nstatic uintptr_t __objc_clsrefsEnd = 0;\r\n\r\n#pragma data_seg()\r\n\r\n// Merge all metadata into .data\r\n// fixme order these by usage?\r\n#pragma comment(linker, \"/MERGE:.objc_module_info=.data\")\r\n#pragma comment(linker, \"/MERGE:.objc_protocol=.data\")\r\n#pragma comment(linker, \"/MERGE:.objc_image_info=.data\")\r\n#pragma comment(linker, \"/MERGE:.objc_message_refs=.data\")\r\n#pragma comment(linker, \"/MERGE:.objc_class_refs=.data\")\r\n\r\n\r\n// Image initializers\r\n\r\nstatic void *__hinfo = NULL;  // cookie from runtime\r\nextern IMAGE_DOS_HEADER __ImageBase;  // this image's header\r\n\r\nstatic int __objc_init(void)\r\n{\r\n    objc_sections sections = {\r\n        5, \r\n        &__objc_modStart, &__objc_modEnd, \r\n        &__objc_protoStart, &__objc_protoEnd, \r\n        &__objc_iiStart, &__objc_iiEnd, \r\n        &__objc_selrefsStart, &__objc_selrefsEnd, \r\n        &__objc_clsrefsStart, &__objc_clsrefsEnd, \r\n    };\r\n    __hinfo = _objc_init_image((HMODULE)&__ImageBase, &sections);\r\n    return 0;\r\n}\r\n\r\nstatic void __objc_unload(void)\r\n{\r\n    _objc_unload_image((HMODULE)&__ImageBase, __hinfo);\r\n}\r\n\r\nstatic int __objc_load(void)\r\n{\r\n    _objc_load_image((HMODULE)&__ImageBase, __hinfo);\r\n    return 0;\r\n}\r\n\r\n// run _objc_init_image ASAP\r\n#pragma section(\".CRT$XIAA\",long,read,write)\r\n#pragma data_seg(\".CRT$XIAA\")\r\nstatic void *__objc_init_fn = &__objc_init;\r\n\r\n// run _objc_load_image (+load methods) after all other initializers; \r\n// otherwise constant NSStrings are not initialized yet\r\n#pragma section(\".CRT$XCUO\",long,read,write)\r\n#pragma data_seg(\".CRT$XCUO\")\r\nstatic void *__objc_load_fn = &__objc_load;\r\n\r\n// _objc_unload_image is called by atexit(), not by an image terminator\r\n\r\n#pragma data_seg()\r\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/objcrt.h",
    "content": "#ifndef _OBJC_RT_H_\r\n#define _OBJC_RT_H_\r\n\r\n#include <objc/objc-api.h>\r\n\r\n\r\ntypedef struct {\r\n    int count;  // number of pointer pairs that follow\r\n    void *modStart;\r\n    void *modEnd;\r\n    void *protoStart;\r\n    void *protoEnd;\r\n    void *iiStart;\r\n    void *iiEnd;\r\n    void *selrefsStart;\r\n    void *selrefsEnd;\r\n    void *clsrefsStart;\r\n    void *clsrefsEnd;\r\n} objc_sections;\r\n\r\nOBJC_EXPORT void *_objc_init_image(HMODULE image, const objc_sections *sects);\r\nOBJC_EXPORT void _objc_load_image(HMODULE image, void *hinfo);\r\nOBJC_EXPORT void _objc_unload_image(HMODULE image, void *hinfo);\r\n\r\n#endif\r\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/runtime/runtime.h",
    "content": "/*\n * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.\n * \n * @APPLE_LICENSE_HEADER_START@\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n\n#ifndef _OBJC_RUNTIME_H\n#define _OBJC_RUNTIME_H\n\n#include <objc/objc.h>\n#include <stdarg.h>\n#include <stdint.h>\n#include <stddef.h>\n#include <Availability.h>\n#include <TargetConditionals.h>\n\n#if TARGET_OS_MAC\n#include <sys/types.h>\n#endif\n\n\n/* Types */\n\n#if !OBJC_TYPES_DEFINED\n\n/// An opaque type that represents a method in a class definition.\ntypedef struct objc_method *Method;\n\n/// An opaque type that represents an instance variable.\ntypedef struct objc_ivar *Ivar;\n\n/// An opaque type that represents a category.\ntypedef struct objc_category *Category;\n\n/// An opaque type that represents an Objective-C declared property.\ntypedef struct objc_property *objc_property_t;\n\nstruct objc_class {\n    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;\n\n#if !__OBJC2__\n    Class _Nullable super_class                              OBJC2_UNAVAILABLE;\n    const char * _Nonnull name                               OBJC2_UNAVAILABLE;\n    long version                                             OBJC2_UNAVAILABLE;\n    long info                                                OBJC2_UNAVAILABLE;\n    long instance_size                                       OBJC2_UNAVAILABLE;\n    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;\n    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;\n    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;\n    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;\n#endif\n\n} OBJC2_UNAVAILABLE;\n/* Use `Class` instead of `struct objc_class *` */\n\n#endif\n\n#ifdef __OBJC__\n@class Protocol;\n#else\ntypedef struct objc_object Protocol;\n#endif\n\n/// Defines a method\nstruct objc_method_description {\n    SEL _Nullable name;               /**< The name of the method */\n    char * _Nullable types;           /**< The types of the method arguments */\n};\n\n/// Defines a property attribute\ntypedef struct {\n    const char * _Nonnull name;           /**< The name of the attribute */\n    const char * _Nonnull value;          /**< The value of the attribute (usually empty) */\n} objc_property_attribute_t;\n\n\n/* Functions */\n\n/* Working with Instances */\n\n/** \n * Returns a copy of a given object.\n * \n * @param obj An Objective-C object.\n * @param size The size of the object \\e obj.\n * \n * @return A copy of \\e obj.\n */\nOBJC_EXPORT id _Nullable object_copy(id _Nullable obj, size_t size)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)\n    OBJC_ARC_UNAVAILABLE;\n\n/** \n * Frees the memory occupied by a given object.\n * \n * @param obj An Objective-C object.\n * \n * @return nil\n */\nOBJC_EXPORT id _Nullable\nobject_dispose(id _Nullable obj)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)\n    OBJC_ARC_UNAVAILABLE;\n\n/** \n * Returns the class of an object.\n * \n * @param obj The object you want to inspect.\n * \n * @return The class object of which \\e object is an instance, \n *  or \\c Nil if \\e object is \\c nil.\n */\nOBJC_EXPORT Class _Nullable\nobject_getClass(id _Nullable obj) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Sets the class of an object.\n * \n * @param obj The object to modify.\n * @param cls A class object.\n * \n * @return The previous value of \\e object's class, or \\c Nil if \\e object is \\c nil.\n */\nOBJC_EXPORT Class _Nullable\nobject_setClass(id _Nullable obj, Class _Nonnull cls) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n\n/** \n * Returns whether an object is a class object.\n * \n * @param obj An Objective-C object.\n * \n * @return true if the object is a class or metaclass, false otherwise.\n */\nOBJC_EXPORT BOOL\nobject_isClass(id _Nullable obj)\n    OBJC_AVAILABLE(10.10, 8.0, 9.0, 1.0, 2.0);\n\n\n/** \n * Reads the value of an instance variable in an object.\n * \n * @param obj The object containing the instance variable whose value you want to read.\n * @param ivar The Ivar describing the instance variable whose value you want to read.\n * \n * @return The value of the instance variable specified by \\e ivar, or \\c nil if \\e object is \\c nil.\n * \n * @note \\c object_getIvar is faster than \\c object_getInstanceVariable if the Ivar\n *  for the instance variable is already known.\n */\nOBJC_EXPORT id _Nullable\nobject_getIvar(id _Nullable obj, Ivar _Nonnull ivar) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Sets the value of an instance variable in an object.\n * \n * @param obj The object containing the instance variable whose value you want to set.\n * @param ivar The Ivar describing the instance variable whose value you want to set.\n * @param value The new value for the instance variable.\n * \n * @note Instance variables with known memory management (such as ARC strong and weak)\n *  use that memory management. Instance variables with unknown memory management \n *  are assigned as if they were unsafe_unretained.\n * @note \\c object_setIvar is faster than \\c object_setInstanceVariable if the Ivar\n *  for the instance variable is already known.\n */\nOBJC_EXPORT void\nobject_setIvar(id _Nullable obj, Ivar _Nonnull ivar, id _Nullable value) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Sets the value of an instance variable in an object.\n * \n * @param obj The object containing the instance variable whose value you want to set.\n * @param ivar The Ivar describing the instance variable whose value you want to set.\n * @param value The new value for the instance variable.\n * \n * @note Instance variables with known memory management (such as ARC strong and weak)\n *  use that memory management. Instance variables with unknown memory management \n *  are assigned as if they were strong.\n * @note \\c object_setIvar is faster than \\c object_setInstanceVariable if the Ivar\n *  for the instance variable is already known.\n */\nOBJC_EXPORT void\nobject_setIvarWithStrongDefault(id _Nullable obj, Ivar _Nonnull ivar,\n                                id _Nullable value) \n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\n/** \n * Changes the value of an instance variable of a class instance.\n * \n * @param obj A pointer to an instance of a class. Pass the object containing\n *  the instance variable whose value you wish to modify.\n * @param name A C string. Pass the name of the instance variable whose value you wish to modify.\n * @param value The new value for the instance variable.\n * \n * @return A pointer to the \\c Ivar data structure that defines the type and \n *  name of the instance variable specified by \\e name.\n *\n * @note Instance variables with known memory management (such as ARC strong and weak)\n *  use that memory management. Instance variables with unknown memory management \n *  are assigned as if they were unsafe_unretained.\n */\nOBJC_EXPORT Ivar _Nullable\nobject_setInstanceVariable(id _Nullable obj, const char * _Nonnull name,\n                           void * _Nullable value)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)\n    OBJC_ARC_UNAVAILABLE;\n\n/** \n * Changes the value of an instance variable of a class instance.\n * \n * @param obj A pointer to an instance of a class. Pass the object containing\n *  the instance variable whose value you wish to modify.\n * @param name A C string. Pass the name of the instance variable whose value you wish to modify.\n * @param value The new value for the instance variable.\n * \n * @return A pointer to the \\c Ivar data structure that defines the type and \n *  name of the instance variable specified by \\e name.\n *\n * @note Instance variables with known memory management (such as ARC strong and weak)\n *  use that memory management. Instance variables with unknown memory management \n *  are assigned as if they were strong.\n */\nOBJC_EXPORT Ivar _Nullable\nobject_setInstanceVariableWithStrongDefault(id _Nullable obj,\n                                            const char * _Nonnull name,\n                                            void * _Nullable value)\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0)\n    OBJC_ARC_UNAVAILABLE;\n\n/** \n * Obtains the value of an instance variable of a class instance.\n * \n * @param obj A pointer to an instance of a class. Pass the object containing\n *  the instance variable whose value you wish to obtain.\n * @param name A C string. Pass the name of the instance variable whose value you wish to obtain.\n * @param outValue On return, contains a pointer to the value of the instance variable.\n * \n * @return A pointer to the \\c Ivar data structure that defines the type and name of\n *  the instance variable specified by \\e name.\n */\nOBJC_EXPORT Ivar _Nullable\nobject_getInstanceVariable(id _Nullable obj, const char * _Nonnull name,\n                           void * _Nullable * _Nullable outValue)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)\n    OBJC_ARC_UNAVAILABLE;\n\n\n/* Obtaining Class Definitions */\n\n/** \n * Returns the class definition of a specified class.\n * \n * @param name The name of the class to look up.\n * \n * @return The Class object for the named class, or \\c nil\n *  if the class is not registered with the Objective-C runtime.\n * \n * @note \\c objc_getClass is different from \\c objc_lookUpClass in that if the class\n *  is not registered, \\c objc_getClass calls the class handler callback and then checks\n *  a second time to see whether the class is registered. \\c objc_lookUpClass does \n *  not call the class handler callback.\n * \n * @warning Earlier implementations of this function (prior to OS X v10.0)\n *  terminate the program if the class does not exist.\n */\nOBJC_EXPORT Class _Nullable\nobjc_getClass(const char * _Nonnull name)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the metaclass definition of a specified class.\n * \n * @param name The name of the class to look up.\n * \n * @return The \\c Class object for the metaclass of the named class, or \\c nil if the class\n *  is not registered with the Objective-C runtime.\n * \n * @note If the definition for the named class is not registered, this function calls the class handler\n *  callback and then checks a second time to see if the class is registered. However, every class\n *  definition must have a valid metaclass definition, and so the metaclass definition is always returned,\n *  whether it’s valid or not.\n */\nOBJC_EXPORT Class _Nullable\nobjc_getMetaClass(const char * _Nonnull name)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the class definition of a specified class.\n * \n * @param name The name of the class to look up.\n * \n * @return The Class object for the named class, or \\c nil if the class\n *  is not registered with the Objective-C runtime.\n * \n * @note \\c objc_getClass is different from this function in that if the class is not\n *  registered, \\c objc_getClass calls the class handler callback and then checks a second\n *  time to see whether the class is registered. This function does not call the class handler callback.\n */\nOBJC_EXPORT Class _Nullable\nobjc_lookUpClass(const char * _Nonnull name)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the class definition of a specified class.\n * \n * @param name The name of the class to look up.\n * \n * @return The Class object for the named class.\n * \n * @note This function is the same as \\c objc_getClass, but kills the process if the class is not found.\n * @note This function is used by ZeroLink, where failing to find a class would be a compile-time link error without ZeroLink.\n */\nOBJC_EXPORT Class _Nonnull\nobjc_getRequiredClass(const char * _Nonnull name)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Obtains the list of registered class definitions.\n * \n * @param buffer An array of \\c Class values. On output, each \\c Class value points to\n *  one class definition, up to either \\e bufferCount or the total number of registered classes,\n *  whichever is less. You can pass \\c NULL to obtain the total number of registered class\n *  definitions without actually retrieving any class definitions.\n * @param bufferCount An integer value. Pass the number of pointers for which you have allocated space\n *  in \\e buffer. On return, this function fills in only this number of elements. If this number is less\n *  than the number of registered classes, this function returns an arbitrary subset of the registered classes.\n * \n * @return An integer value indicating the total number of registered classes.\n * \n * @note The Objective-C runtime library automatically registers all the classes defined in your source code.\n *  You can create class definitions at runtime and register them with the \\c objc_addClass function.\n * \n * @warning You cannot assume that class objects you get from this function are classes that inherit from \\c NSObject,\n *  so you cannot safely call any methods on such classes without detecting that the method is implemented first.\n */\nOBJC_EXPORT int\nobjc_getClassList(Class _Nonnull * _Nullable buffer, int bufferCount)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Creates and returns a list of pointers to all registered class definitions.\n * \n * @param outCount An integer pointer used to store the number of classes returned by\n *  this function in the list. It can be \\c nil.\n * \n * @return A nil terminated array of classes. It must be freed with \\c free().\n * \n * @see objc_getClassList\n */\nOBJC_EXPORT Class _Nonnull * _Nullable\nobjc_copyClassList(unsigned int * _Nullable outCount)\n    OBJC_AVAILABLE(10.7, 3.1, 9.0, 1.0, 2.0);\n\n\n/* Working with Classes */\n\n/** \n * Returns the name of a class.\n * \n * @param cls A class object.\n * \n * @return The name of the class, or the empty string if \\e cls is \\c Nil.\n */\nOBJC_EXPORT const char * _Nonnull\nclass_getName(Class _Nullable cls) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a Boolean value that indicates whether a class object is a metaclass.\n * \n * @param cls A class object.\n * \n * @return \\c YES if \\e cls is a metaclass, \\c NO if \\e cls is a non-meta class, \n *  \\c NO if \\e cls is \\c Nil.\n */\nOBJC_EXPORT BOOL\nclass_isMetaClass(Class _Nullable cls) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the superclass of a class.\n * \n * @param cls A class object.\n * \n * @return The superclass of the class, or \\c Nil if\n *  \\e cls is a root class, or \\c Nil if \\e cls is \\c Nil.\n *\n * @note You should usually use \\c NSObject's \\c superclass method instead of this function.\n */\nOBJC_EXPORT Class _Nullable\nclass_getSuperclass(Class _Nullable cls) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Sets the superclass of a given class.\n * \n * @param cls The class whose superclass you want to set.\n * @param newSuper The new superclass for cls.\n * \n * @return The old superclass for cls.\n * \n * @warning You should not use this function.\n */\nOBJC_EXPORT Class _Nonnull\nclass_setSuperclass(Class _Nonnull cls, Class _Nonnull newSuper) \n    __OSX_DEPRECATED(10.5, 10.5, \"not recommended\") \n    __IOS_DEPRECATED(2.0, 2.0, \"not recommended\") \n    __TVOS_DEPRECATED(9.0, 9.0, \"not recommended\") \n    __WATCHOS_DEPRECATED(1.0, 1.0, \"not recommended\")\n    __BRIDGEOS_DEPRECATED(2.0, 2.0, \"not recommended\");\n\n/** \n * Returns the version number of a class definition.\n * \n * @param cls A pointer to a \\c Class data structure. Pass\n *  the class definition for which you wish to obtain the version.\n * \n * @return An integer indicating the version number of the class definition.\n *\n * @see class_setVersion\n */\nOBJC_EXPORT int\nclass_getVersion(Class _Nullable cls)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Sets the version number of a class definition.\n * \n * @param cls A pointer to an Class data structure. \n *  Pass the class definition for which you wish to set the version.\n * @param version An integer. Pass the new version number of the class definition.\n *\n * @note You can use the version number of the class definition to provide versioning of the\n *  interface that your class represents to other classes. This is especially useful for object\n *  serialization (that is, archiving of the object in a flattened form), where it is important to\n *  recognize changes to the layout of the instance variables in different class-definition versions.\n * @note Classes derived from the Foundation framework \\c NSObject class can set the class-definition\n *  version number using the \\c setVersion: class method, which is implemented using the \\c class_setVersion function.\n */\nOBJC_EXPORT void\nclass_setVersion(Class _Nullable cls, int version)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the size of instances of a class.\n * \n * @param cls A class object.\n * \n * @return The size in bytes of instances of the class \\e cls, or \\c 0 if \\e cls is \\c Nil.\n */\nOBJC_EXPORT size_t\nclass_getInstanceSize(Class _Nullable cls) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the \\c Ivar for a specified instance variable of a given class.\n * \n * @param cls The class whose instance variable you wish to obtain.\n * @param name The name of the instance variable definition to obtain.\n * \n * @return A pointer to an \\c Ivar data structure containing information about \n *  the instance variable specified by \\e name.\n */\nOBJC_EXPORT Ivar _Nullable\nclass_getInstanceVariable(Class _Nullable cls, const char * _Nonnull name)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the Ivar for a specified class variable of a given class.\n * \n * @param cls The class definition whose class variable you wish to obtain.\n * @param name The name of the class variable definition to obtain.\n * \n * @return A pointer to an \\c Ivar data structure containing information about the class variable specified by \\e name.\n */\nOBJC_EXPORT Ivar _Nullable\nclass_getClassVariable(Class _Nullable cls, const char * _Nonnull name) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Describes the instance variables declared by a class.\n * \n * @param cls The class to inspect.\n * @param outCount On return, contains the length of the returned array. \n *  If outCount is NULL, the length is not returned.\n * \n * @return An array of pointers of type Ivar describing the instance variables declared by the class. \n *  Any instance variables declared by superclasses are not included. The array contains *outCount \n *  pointers followed by a NULL terminator. You must free the array with free().\n * \n *  If the class declares no instance variables, or cls is Nil, NULL is returned and *outCount is 0.\n */\nOBJC_EXPORT Ivar _Nonnull * _Nullable\nclass_copyIvarList(Class _Nullable cls, unsigned int * _Nullable outCount) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a specified instance method for a given class.\n * \n * @param cls The class you want to inspect.\n * @param name The selector of the method you want to retrieve.\n * \n * @return The method that corresponds to the implementation of the selector specified by \n *  \\e name for the class specified by \\e cls, or \\c NULL if the specified class or its \n *  superclasses do not contain an instance method with the specified selector.\n *\n * @note This function searches superclasses for implementations, whereas \\c class_copyMethodList does not.\n */\nOBJC_EXPORT Method _Nullable\nclass_getInstanceMethod(Class _Nullable cls, SEL _Nonnull name)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a pointer to the data structure describing a given class method for a given class.\n * \n * @param cls A pointer to a class definition. Pass the class that contains the method you want to retrieve.\n * @param name A pointer of type \\c SEL. Pass the selector of the method you want to retrieve.\n * \n * @return A pointer to the \\c Method data structure that corresponds to the implementation of the \n *  selector specified by aSelector for the class specified by aClass, or NULL if the specified \n *  class or its superclasses do not contain an instance method with the specified selector.\n *\n * @note Note that this function searches superclasses for implementations, \n *  whereas \\c class_copyMethodList does not.\n */\nOBJC_EXPORT Method _Nullable\nclass_getClassMethod(Class _Nullable cls, SEL _Nonnull name)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the function pointer that would be called if a \n * particular message were sent to an instance of a class.\n * \n * @param cls The class you want to inspect.\n * @param name A selector.\n * \n * @return The function pointer that would be called if \\c [object name] were called\n *  with an instance of the class, or \\c NULL if \\e cls is \\c Nil.\n *\n * @note \\c class_getMethodImplementation may be faster than \\c method_getImplementation(class_getInstanceMethod(cls, name)).\n * @note The function pointer returned may be a function internal to the runtime instead of\n *  an actual method implementation. For example, if instances of the class do not respond to\n *  the selector, the function pointer returned will be part of the runtime's message forwarding machinery.\n */\nOBJC_EXPORT IMP _Nullable\nclass_getMethodImplementation(Class _Nullable cls, SEL _Nonnull name) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the function pointer that would be called if a particular \n * message were sent to an instance of a class.\n * \n * @param cls The class you want to inspect.\n * @param name A selector.\n * \n * @return The function pointer that would be called if \\c [object name] were called\n *  with an instance of the class, or \\c NULL if \\e cls is \\c Nil.\n */\nOBJC_EXPORT IMP _Nullable\nclass_getMethodImplementation_stret(Class _Nullable cls, SEL _Nonnull name) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0)\n    OBJC_ARM64_UNAVAILABLE;\n\n/** \n * Returns a Boolean value that indicates whether instances of a class respond to a particular selector.\n * \n * @param cls The class you want to inspect.\n * @param sel A selector.\n * \n * @return \\c YES if instances of the class respond to the selector, otherwise \\c NO.\n * \n * @note You should usually use \\c NSObject's \\c respondsToSelector: or \\c instancesRespondToSelector: \n *  methods instead of this function.\n */\nOBJC_EXPORT BOOL\nclass_respondsToSelector(Class _Nullable cls, SEL _Nonnull sel) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Describes the instance methods implemented by a class.\n * \n * @param cls The class you want to inspect.\n * @param outCount On return, contains the length of the returned array. \n *  If outCount is NULL, the length is not returned.\n * \n * @return An array of pointers of type Method describing the instance methods \n *  implemented by the class—any instance methods implemented by superclasses are not included. \n *  The array contains *outCount pointers followed by a NULL terminator. You must free the array with free().\n * \n *  If cls implements no instance methods, or cls is Nil, returns NULL and *outCount is 0.\n * \n * @note To get the class methods of a class, use \\c class_copyMethodList(object_getClass(cls), &count).\n * @note To get the implementations of methods that may be implemented by superclasses, \n *  use \\c class_getInstanceMethod or \\c class_getClassMethod.\n */\nOBJC_EXPORT Method _Nonnull * _Nullable\nclass_copyMethodList(Class _Nullable cls, unsigned int * _Nullable outCount) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a Boolean value that indicates whether a class conforms to a given protocol.\n * \n * @param cls The class you want to inspect.\n * @param protocol A protocol.\n *\n * @return YES if cls conforms to protocol, otherwise NO.\n *\n * @note You should usually use NSObject's conformsToProtocol: method instead of this function.\n */\nOBJC_EXPORT BOOL\nclass_conformsToProtocol(Class _Nullable cls, Protocol * _Nullable protocol) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Describes the protocols adopted by a class.\n * \n * @param cls The class you want to inspect.\n * @param outCount On return, contains the length of the returned array. \n *  If outCount is NULL, the length is not returned.\n * \n * @return An array of pointers of type Protocol* describing the protocols adopted \n *  by the class. Any protocols adopted by superclasses or other protocols are not included. \n *  The array contains *outCount pointers followed by a NULL terminator. You must free the array with free().\n * \n *  If cls adopts no protocols, or cls is Nil, returns NULL and *outCount is 0.\n */\nOBJC_EXPORT Protocol * __unsafe_unretained _Nonnull * _Nullable \nclass_copyProtocolList(Class _Nullable cls, unsigned int * _Nullable outCount)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a property with a given name of a given class.\n * \n * @param cls The class you want to inspect.\n * @param name The name of the property you want to inspect.\n * \n * @return A pointer of type \\c objc_property_t describing the property, or\n *  \\c NULL if the class does not declare a property with that name, \n *  or \\c NULL if \\e cls is \\c Nil.\n */\nOBJC_EXPORT objc_property_t _Nullable\nclass_getProperty(Class _Nullable cls, const char * _Nonnull name)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Describes the properties declared by a class.\n * \n * @param cls The class you want to inspect.\n * @param outCount On return, contains the length of the returned array. \n *  If \\e outCount is \\c NULL, the length is not returned.        \n * \n * @return An array of pointers of type \\c objc_property_t describing the properties \n *  declared by the class. Any properties declared by superclasses are not included. \n *  The array contains \\c *outCount pointers followed by a \\c NULL terminator. You must free the array with \\c free().\n * \n *  If \\e cls declares no properties, or \\e cls is \\c Nil, returns \\c NULL and \\c *outCount is \\c 0.\n */\nOBJC_EXPORT objc_property_t _Nonnull * _Nullable\nclass_copyPropertyList(Class _Nullable cls, unsigned int * _Nullable outCount)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a description of the \\c Ivar layout for a given class.\n * \n * @param cls The class to inspect.\n * \n * @return A description of the \\c Ivar layout for \\e cls.\n */\nOBJC_EXPORT const uint8_t * _Nullable\nclass_getIvarLayout(Class _Nullable cls)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a description of the layout of weak Ivars for a given class.\n * \n * @param cls The class to inspect.\n * \n * @return A description of the layout of the weak \\c Ivars for \\e cls.\n */\nOBJC_EXPORT const uint8_t * _Nullable\nclass_getWeakIvarLayout(Class _Nullable cls)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Adds a new method to a class with a given name and implementation.\n * \n * @param cls The class to which to add a method.\n * @param name A selector that specifies the name of the method being added.\n * @param imp A function which is the implementation of the new method. The function must take at least two arguments—self and _cmd.\n * @param types An array of characters that describe the types of the arguments to the method. \n * \n * @return YES if the method was added successfully, otherwise NO \n *  (for example, the class already contains a method implementation with that name).\n *\n * @note class_addMethod will add an override of a superclass's implementation, \n *  but will not replace an existing implementation in this class. \n *  To change an existing implementation, use method_setImplementation.\n */\nOBJC_EXPORT BOOL\nclass_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, \n                const char * _Nullable types) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Replaces the implementation of a method for a given class.\n * \n * @param cls The class you want to modify.\n * @param name A selector that identifies the method whose implementation you want to replace.\n * @param imp The new implementation for the method identified by name for the class identified by cls.\n * @param types An array of characters that describe the types of the arguments to the method. \n *  Since the function must take at least two arguments—self and _cmd, the second and third characters\n *  must be “@:” (the first character is the return type).\n * \n * @return The previous implementation of the method identified by \\e name for the class identified by \\e cls.\n * \n * @note This function behaves in two different ways:\n *  - If the method identified by \\e name does not yet exist, it is added as if \\c class_addMethod were called. \n *    The type encoding specified by \\e types is used as given.\n *  - If the method identified by \\e name does exist, its \\c IMP is replaced as if \\c method_setImplementation were called.\n *    The type encoding specified by \\e types is ignored.\n */\nOBJC_EXPORT IMP _Nullable\nclass_replaceMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, \n                    const char * _Nullable types) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Adds a new instance variable to a class.\n * \n * @return YES if the instance variable was added successfully, otherwise NO \n *         (for example, the class already contains an instance variable with that name).\n *\n * @note This function may only be called after objc_allocateClassPair and before objc_registerClassPair. \n *       Adding an instance variable to an existing class is not supported.\n * @note The class must not be a metaclass. Adding an instance variable to a metaclass is not supported.\n * @note The instance variable's minimum alignment in bytes is 1<<align. The minimum alignment of an instance \n *       variable depends on the ivar's type and the machine architecture. \n *       For variables of any pointer type, pass log2(sizeof(pointer_type)).\n */\nOBJC_EXPORT BOOL\nclass_addIvar(Class _Nullable cls, const char * _Nonnull name, size_t size, \n              uint8_t alignment, const char * _Nullable types) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Adds a protocol to a class.\n * \n * @param cls The class to modify.\n * @param protocol The protocol to add to \\e cls.\n * \n * @return \\c YES if the method was added successfully, otherwise \\c NO \n *  (for example, the class already conforms to that protocol).\n */\nOBJC_EXPORT BOOL\nclass_addProtocol(Class _Nullable cls, Protocol * _Nonnull protocol) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Adds a property to a class.\n * \n * @param cls The class to modify.\n * @param name The name of the property.\n * @param attributes An array of property attributes.\n * @param attributeCount The number of attributes in \\e attributes.\n * \n * @return \\c YES if the property was added successfully, otherwise \\c NO\n *  (for example, the class already has that property).\n */\nOBJC_EXPORT BOOL\nclass_addProperty(Class _Nullable cls, const char * _Nonnull name,\n                  const objc_property_attribute_t * _Nullable attributes,\n                  unsigned int attributeCount)\n    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);\n\n/** \n * Replace a property of a class. \n * \n * @param cls The class to modify.\n * @param name The name of the property.\n * @param attributes An array of property attributes.\n * @param attributeCount The number of attributes in \\e attributes. \n */\nOBJC_EXPORT void\nclass_replaceProperty(Class _Nullable cls, const char * _Nonnull name,\n                      const objc_property_attribute_t * _Nullable attributes,\n                      unsigned int attributeCount)\n    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);\n\n/** \n * Sets the Ivar layout for a given class.\n * \n * @param cls The class to modify.\n * @param layout The layout of the \\c Ivars for \\e cls.\n */\nOBJC_EXPORT void\nclass_setIvarLayout(Class _Nullable cls, const uint8_t * _Nullable layout)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Sets the layout for weak Ivars for a given class.\n * \n * @param cls The class to modify.\n * @param layout The layout of the weak Ivars for \\e cls.\n */\nOBJC_EXPORT void\nclass_setWeakIvarLayout(Class _Nullable cls, const uint8_t * _Nullable layout)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Used by CoreFoundation's toll-free bridging.\n * Return the id of the named class.\n * \n * @return The id of the named class, or an uninitialized class\n *  structure that will be used for the class when and if it does \n *  get loaded.\n * \n * @warning Do not call this function yourself.\n */\nOBJC_EXPORT Class _Nonnull\nobjc_getFutureClass(const char * _Nonnull name) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0)\n    OBJC_ARC_UNAVAILABLE;\n\n\n/* Instantiating Classes */\n\n/** \n * Creates an instance of a class, allocating memory for the class in the \n * default malloc memory zone.\n * \n * @param cls The class that you wish to allocate an instance of.\n * @param extraBytes An integer indicating the number of extra bytes to allocate. \n *  The additional bytes can be used to store additional instance variables beyond \n *  those defined in the class definition.\n * \n * @return An instance of the class \\e cls.\n */\nOBJC_EXPORT id _Nullable\nclass_createInstance(Class _Nullable cls, size_t extraBytes)\n    OBJC_RETURNS_RETAINED\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Creates an instance of a class at the specific location provided.\n * \n * @param cls The class that you wish to allocate an instance of.\n * @param bytes The location at which to allocate an instance of \\e cls.\n *  Must point to at least \\c class_getInstanceSize(cls) bytes of well-aligned,\n *  zero-filled memory.\n *\n * @return \\e bytes on success, \\c nil otherwise. (For example, \\e cls or \\e bytes\n *  might be \\c nil)\n *\n * @see class_createInstance\n */\nOBJC_EXPORT id _Nullable\nobjc_constructInstance(Class _Nullable cls, void * _Nullable bytes) \n    OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0, 2.0)\n    OBJC_ARC_UNAVAILABLE;\n\n/** \n * Destroys an instance of a class without freeing memory and removes any\n * associated references this instance might have had.\n * \n * @param obj The class instance to destroy.\n * \n * @return \\e obj. Does nothing if \\e obj is nil.\n * \n * @note CF and other clients do call this under GC.\n */\nOBJC_EXPORT void * _Nullable objc_destructInstance(id _Nullable obj) \n    OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0, 2.0)\n    OBJC_ARC_UNAVAILABLE;\n\n\n/* Adding Classes */\n\n/** \n * Creates a new class and metaclass.\n * \n * @param superclass The class to use as the new class's superclass, or \\c Nil to create a new root class.\n * @param name The string to use as the new class's name. The string will be copied.\n * @param extraBytes The number of bytes to allocate for indexed ivars at the end of \n *  the class and metaclass objects. This should usually be \\c 0.\n * \n * @return The new class, or Nil if the class could not be created (for example, the desired name is already in use).\n * \n * @note You can get a pointer to the new metaclass by calling \\c object_getClass(newClass).\n * @note To create a new class, start by calling \\c objc_allocateClassPair. \n *  Then set the class's attributes with functions like \\c class_addMethod and \\c class_addIvar.\n *  When you are done building the class, call \\c objc_registerClassPair. The new class is now ready for use.\n * @note Instance methods and instance variables should be added to the class itself. \n *  Class methods should be added to the metaclass.\n */\nOBJC_EXPORT Class _Nullable\nobjc_allocateClassPair(Class _Nullable superclass, const char * _Nonnull name, \n                       size_t extraBytes) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Registers a class that was allocated using \\c objc_allocateClassPair.\n * \n * @param cls The class you want to register.\n */\nOBJC_EXPORT void\nobjc_registerClassPair(Class _Nonnull cls) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Used by Foundation's Key-Value Observing.\n * \n * @warning Do not call this function yourself.\n */\nOBJC_EXPORT Class _Nonnull\nobjc_duplicateClass(Class _Nonnull original, const char * _Nonnull name,\n                    size_t extraBytes)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Destroy a class and its associated metaclass. \n * \n * @param cls The class to be destroyed. It must have been allocated with \n *  \\c objc_allocateClassPair\n * \n * @warning Do not call if instances of this class or a subclass exist.\n */\nOBJC_EXPORT void\nobjc_disposeClassPair(Class _Nonnull cls) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n\n/* Working with Methods */\n\n/** \n * Returns the name of a method.\n * \n * @param m The method to inspect.\n * \n * @return A pointer of type SEL.\n * \n * @note To get the method name as a C string, call \\c sel_getName(method_getName(method)).\n */\nOBJC_EXPORT SEL _Nonnull\nmethod_getName(Method _Nonnull m) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the implementation of a method.\n * \n * @param m The method to inspect.\n * \n * @return A function pointer of type IMP.\n */\nOBJC_EXPORT IMP _Nonnull\nmethod_getImplementation(Method _Nonnull m) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a string describing a method's parameter and return types.\n * \n * @param m The method to inspect.\n * \n * @return A C string. The string may be \\c NULL.\n */\nOBJC_EXPORT const char * _Nullable\nmethod_getTypeEncoding(Method _Nonnull m) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the number of arguments accepted by a method.\n * \n * @param m A pointer to a \\c Method data structure. Pass the method in question.\n * \n * @return An integer containing the number of arguments accepted by the given method.\n */\nOBJC_EXPORT unsigned int\nmethod_getNumberOfArguments(Method _Nonnull m)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a string describing a method's return type.\n * \n * @param m The method to inspect.\n * \n * @return A C string describing the return type. You must free the string with \\c free().\n */\nOBJC_EXPORT char * _Nonnull\nmethod_copyReturnType(Method _Nonnull m) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a string describing a single parameter type of a method.\n * \n * @param m The method to inspect.\n * @param index The index of the parameter to inspect.\n * \n * @return A C string describing the type of the parameter at index \\e index, or \\c NULL\n *  if method has no parameter index \\e index. You must free the string with \\c free().\n */\nOBJC_EXPORT char * _Nullable\nmethod_copyArgumentType(Method _Nonnull m, unsigned int index) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns by reference a string describing a method's return type.\n * \n * @param m The method you want to inquire about. \n * @param dst The reference string to store the description.\n * @param dst_len The maximum number of characters that can be stored in \\e dst.\n *\n * @note The method's return type string is copied to \\e dst.\n *  \\e dst is filled as if \\c strncpy(dst, parameter_type, dst_len) were called.\n */\nOBJC_EXPORT void\nmethod_getReturnType(Method _Nonnull m, char * _Nonnull dst, size_t dst_len) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns by reference a string describing a single parameter type of a method.\n * \n * @param m The method you want to inquire about. \n * @param index The index of the parameter you want to inquire about.\n * @param dst The reference string to store the description.\n * @param dst_len The maximum number of characters that can be stored in \\e dst.\n * \n * @note The parameter type string is copied to \\e dst. \\e dst is filled as if \\c strncpy(dst, parameter_type, dst_len) \n *  were called. If the method contains no parameter with that index, \\e dst is filled as\n *  if \\c strncpy(dst, \"\", dst_len) were called.\n */\nOBJC_EXPORT void\nmethod_getArgumentType(Method _Nonnull m, unsigned int index, \n                       char * _Nullable dst, size_t dst_len) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\nOBJC_EXPORT struct objc_method_description * _Nonnull\nmethod_getDescription(Method _Nonnull m) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Sets the implementation of a method.\n * \n * @param m The method for which to set an implementation.\n * @param imp The implemention to set to this method.\n * \n * @return The previous implementation of the method.\n */\nOBJC_EXPORT IMP _Nonnull\nmethod_setImplementation(Method _Nonnull m, IMP _Nonnull imp) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Exchanges the implementations of two methods.\n * \n * @param m1 Method to exchange with second method.\n * @param m2 Method to exchange with first method.\n * \n * @note This is an atomic version of the following:\n *  \\code \n *  IMP imp1 = method_getImplementation(m1);\n *  IMP imp2 = method_getImplementation(m2);\n *  method_setImplementation(m1, imp2);\n *  method_setImplementation(m2, imp1);\n *  \\endcode\n */\nOBJC_EXPORT void\nmethod_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n\n/* Working with Instance Variables */\n\n/** \n * Returns the name of an instance variable.\n * \n * @param v The instance variable you want to enquire about.\n * \n * @return A C string containing the instance variable's name.\n */\nOBJC_EXPORT const char * _Nullable\nivar_getName(Ivar _Nonnull v) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the type string of an instance variable.\n * \n * @param v The instance variable you want to enquire about.\n * \n * @return A C string containing the instance variable's type encoding.\n *\n * @note For possible values, see Objective-C Runtime Programming Guide > Type Encodings.\n */\nOBJC_EXPORT const char * _Nullable\nivar_getTypeEncoding(Ivar _Nonnull v) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the offset of an instance variable.\n * \n * @param v The instance variable you want to enquire about.\n * \n * @return The offset of \\e v.\n * \n * @note For instance variables of type \\c id or other object types, call \\c object_getIvar\n *  and \\c object_setIvar instead of using this offset to access the instance variable data directly.\n */\nOBJC_EXPORT ptrdiff_t\nivar_getOffset(Ivar _Nonnull v) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n\n/* Working with Properties */\n\n/** \n * Returns the name of a property.\n * \n * @param property The property you want to inquire about.\n * \n * @return A C string containing the property's name.\n */\nOBJC_EXPORT const char * _Nonnull\nproperty_getName(objc_property_t _Nonnull property) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the attribute string of a property.\n * \n * @param property A property.\n *\n * @return A C string containing the property's attributes.\n * \n * @note The format of the attribute string is described in Declared Properties in Objective-C Runtime Programming Guide.\n */\nOBJC_EXPORT const char * _Nullable\nproperty_getAttributes(objc_property_t _Nonnull property) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns an array of property attributes for a property. \n * \n * @param property The property whose attributes you want copied.\n * @param outCount The number of attributes returned in the array.\n * \n * @return An array of property attributes; must be free'd() by the caller. \n */\nOBJC_EXPORT objc_property_attribute_t * _Nullable\nproperty_copyAttributeList(objc_property_t _Nonnull property,\n                           unsigned int * _Nullable outCount)\n    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);\n\n/** \n * Returns the value of a property attribute given the attribute name.\n * \n * @param property The property whose attribute value you are interested in.\n * @param attributeName C string representing the attribute name.\n *\n * @return The value string of the attribute \\e attributeName if it exists in\n *  \\e property, \\c nil otherwise. \n */\nOBJC_EXPORT char * _Nullable\nproperty_copyAttributeValue(objc_property_t _Nonnull property,\n                            const char * _Nonnull attributeName)\n    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);\n\n\n/* Working with Protocols */\n\n/** \n * Returns a specified protocol.\n * \n * @param name The name of a protocol.\n * \n * @return The protocol named \\e name, or \\c NULL if no protocol named \\e name could be found.\n * \n * @note This function acquires the runtime lock.\n */\nOBJC_EXPORT Protocol * _Nullable\nobjc_getProtocol(const char * _Nonnull name)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns an array of all the protocols known to the runtime.\n * \n * @param outCount Upon return, contains the number of protocols in the returned array.\n * \n * @return A C array of all the protocols known to the runtime. The array contains \\c *outCount\n *  pointers followed by a \\c NULL terminator. You must free the list with \\c free().\n * \n * @note This function acquires the runtime lock.\n */\nOBJC_EXPORT Protocol * __unsafe_unretained _Nonnull * _Nullable\nobjc_copyProtocolList(unsigned int * _Nullable outCount)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a Boolean value that indicates whether one protocol conforms to another protocol.\n * \n * @param proto A protocol.\n * @param other A protocol.\n * \n * @return \\c YES if \\e proto conforms to \\e other, otherwise \\c NO.\n * \n * @note One protocol can incorporate other protocols using the same syntax \n *  that classes use to adopt a protocol:\n *  \\code\n *  @protocol ProtocolName < protocol list >\n *  \\endcode\n *  All the protocols listed between angle brackets are considered part of the ProtocolName protocol.\n */\nOBJC_EXPORT BOOL\nprotocol_conformsToProtocol(Protocol * _Nullable proto,\n                            Protocol * _Nullable other)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a Boolean value that indicates whether two protocols are equal.\n * \n * @param proto A protocol.\n * @param other A protocol.\n * \n * @return \\c YES if \\e proto is the same as \\e other, otherwise \\c NO.\n */\nOBJC_EXPORT BOOL\nprotocol_isEqual(Protocol * _Nullable proto, Protocol * _Nullable other)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the name of a protocol.\n * \n * @param proto A protocol.\n * \n * @return The name of the protocol \\e p as a C string.\n */\nOBJC_EXPORT const char * _Nonnull\nprotocol_getName(Protocol * _Nonnull proto)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a method description structure for a specified method of a given protocol.\n * \n * @param proto A protocol.\n * @param aSel A selector.\n * @param isRequiredMethod A Boolean value that indicates whether aSel is a required method.\n * @param isInstanceMethod A Boolean value that indicates whether aSel is an instance method.\n * \n * @return An \\c objc_method_description structure that describes the method specified by \\e aSel,\n *  \\e isRequiredMethod, and \\e isInstanceMethod for the protocol \\e p.\n *  If the protocol does not contain the specified method, returns an \\c objc_method_description structure\n *  with the value \\c {NULL, \\c NULL}.\n * \n * @note This function recursively searches any protocols that this protocol conforms to.\n */\nOBJC_EXPORT struct objc_method_description\nprotocol_getMethodDescription(Protocol * _Nonnull proto, SEL _Nonnull aSel,\n                              BOOL isRequiredMethod, BOOL isInstanceMethod)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns an array of method descriptions of methods meeting a given specification for a given protocol.\n * \n * @param proto A protocol.\n * @param isRequiredMethod A Boolean value that indicates whether returned methods should\n *  be required methods (pass YES to specify required methods).\n * @param isInstanceMethod A Boolean value that indicates whether returned methods should\n *  be instance methods (pass YES to specify instance methods).\n * @param outCount Upon return, contains the number of method description structures in the returned array.\n * \n * @return A C array of \\c objc_method_description structures containing the names and types of \\e p's methods \n *  specified by \\e isRequiredMethod and \\e isInstanceMethod. The array contains \\c *outCount pointers followed\n *  by a \\c NULL terminator. You must free the list with \\c free().\n *  If the protocol declares no methods that meet the specification, \\c NULL is returned and \\c *outCount is 0.\n * \n * @note Methods in other protocols adopted by this protocol are not included.\n */\nOBJC_EXPORT struct objc_method_description * _Nullable\nprotocol_copyMethodDescriptionList(Protocol * _Nonnull proto,\n                                   BOOL isRequiredMethod,\n                                   BOOL isInstanceMethod,\n                                   unsigned int * _Nullable outCount)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the specified property of a given protocol.\n * \n * @param proto A protocol.\n * @param name The name of a property.\n * @param isRequiredProperty \\c YES searches for a required property, \\c NO searches for an optional property.\n * @param isInstanceProperty \\c YES searches for an instance property, \\c NO searches for a class property.\n * \n * @return The property specified by \\e name, \\e isRequiredProperty, and \\e isInstanceProperty for \\e proto,\n *  or \\c NULL if none of \\e proto's properties meets the specification.\n */\nOBJC_EXPORT objc_property_t _Nullable\nprotocol_getProperty(Protocol * _Nonnull proto,\n                     const char * _Nonnull name,\n                     BOOL isRequiredProperty, BOOL isInstanceProperty)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns an array of the required instance properties declared by a protocol.\n * \n * @note Identical to \n * \\code\n * protocol_copyPropertyList2(proto, outCount, YES, YES);\n * \\endcode\n */\nOBJC_EXPORT objc_property_t _Nonnull * _Nullable\nprotocol_copyPropertyList(Protocol * _Nonnull proto,\n                          unsigned int * _Nullable outCount)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns an array of properties declared by a protocol.\n * \n * @param proto A protocol.\n * @param outCount Upon return, contains the number of elements in the returned array.\n * @param isRequiredProperty \\c YES returns required properties, \\c NO returns optional properties.\n * @param isInstanceProperty \\c YES returns instance properties, \\c NO returns class properties.\n * \n * @return A C array of pointers of type \\c objc_property_t describing the properties declared by \\e proto.\n *  Any properties declared by other protocols adopted by this protocol are not included. The array contains\n *  \\c *outCount pointers followed by a \\c NULL terminator. You must free the array with \\c free().\n *  If the protocol declares no matching properties, \\c NULL is returned and \\c *outCount is \\c 0.\n */\nOBJC_EXPORT objc_property_t _Nonnull * _Nullable\nprotocol_copyPropertyList2(Protocol * _Nonnull proto,\n                           unsigned int * _Nullable outCount,\n                           BOOL isRequiredProperty, BOOL isInstanceProperty)\n    OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);\n\n/** \n * Returns an array of the protocols adopted by a protocol.\n * \n * @param proto A protocol.\n * @param outCount Upon return, contains the number of elements in the returned array.\n * \n * @return A C array of protocols adopted by \\e proto. The array contains \\e *outCount pointers\n *  followed by a \\c NULL terminator. You must free the array with \\c free().\n *  If the protocol declares no properties, \\c NULL is returned and \\c *outCount is \\c 0.\n */\nOBJC_EXPORT Protocol * __unsafe_unretained _Nonnull * _Nullable\nprotocol_copyProtocolList(Protocol * _Nonnull proto,\n                          unsigned int * _Nullable outCount)\n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Creates a new protocol instance that cannot be used until registered with\n * \\c objc_registerProtocol()\n * \n * @param name The name of the protocol to create.\n *\n * @return The Protocol instance on success, \\c nil if a protocol\n *  with the same name already exists. \n * @note There is no dispose method for this. \n */\nOBJC_EXPORT Protocol * _Nullable\nobjc_allocateProtocol(const char * _Nonnull name) \n    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);\n\n/** \n * Registers a newly constructed protocol with the runtime. The protocol\n * will be ready for use and is immutable after this.\n * \n * @param proto The protocol you want to register.\n */\nOBJC_EXPORT void\nobjc_registerProtocol(Protocol * _Nonnull proto) \n    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);\n\n/** \n * Adds a method to a protocol. The protocol must be under construction.\n * \n * @param proto The protocol to add a method to.\n * @param name The name of the method to add.\n * @param types A C string that represents the method signature.\n * @param isRequiredMethod YES if the method is not an optional method.\n * @param isInstanceMethod YES if the method is an instance method. \n */\nOBJC_EXPORT void\nprotocol_addMethodDescription(Protocol * _Nonnull proto, SEL _Nonnull name,\n                              const char * _Nullable types,\n                              BOOL isRequiredMethod, BOOL isInstanceMethod) \n    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);\n\n/** \n * Adds an incorporated protocol to another protocol. The protocol being\n * added to must still be under construction, while the additional protocol\n * must be already constructed.\n * \n * @param proto The protocol you want to add to, it must be under construction.\n * @param addition The protocol you want to incorporate into \\e proto, it must be registered.\n */\nOBJC_EXPORT void\nprotocol_addProtocol(Protocol * _Nonnull proto, Protocol * _Nonnull addition) \n    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);\n\n/** \n * Adds a property to a protocol. The protocol must be under construction. \n * \n * @param proto The protocol to add a property to.\n * @param name The name of the property.\n * @param attributes An array of property attributes.\n * @param attributeCount The number of attributes in \\e attributes.\n * @param isRequiredProperty YES if the property (accessor methods) is not optional. \n * @param isInstanceProperty YES if the property (accessor methods) are instance methods. \n *  This is the only case allowed fo a property, as a result, setting this to NO will \n *  not add the property to the protocol at all. \n */\nOBJC_EXPORT void\nprotocol_addProperty(Protocol * _Nonnull proto, const char * _Nonnull name,\n                     const objc_property_attribute_t * _Nullable attributes,\n                     unsigned int attributeCount,\n                     BOOL isRequiredProperty, BOOL isInstanceProperty)\n    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);\n\n\n/* Working with Libraries */\n\n/** \n * Returns the names of all the loaded Objective-C frameworks and dynamic\n * libraries.\n * \n * @param outCount The number of names returned.\n * \n * @return An array of C strings of names. Must be free()'d by caller.\n */\nOBJC_EXPORT const char * _Nonnull * _Nonnull\nobjc_copyImageNames(unsigned int * _Nullable outCount) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the dynamic library name a class originated from.\n * \n * @param cls The class you are inquiring about.\n * \n * @return The name of the library containing this class.\n */\nOBJC_EXPORT const char * _Nullable\nclass_getImageName(Class _Nullable cls) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns the names of all the classes within a library.\n * \n * @param image The library or framework you are inquiring about.\n * @param outCount The number of class names returned.\n * \n * @return An array of C strings representing the class names.\n */\nOBJC_EXPORT const char * _Nonnull * _Nullable\nobjc_copyClassNamesForImage(const char * _Nonnull image,\n                            unsigned int * _Nullable outCount) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n\n/* Working with Selectors */\n\n/** \n * Returns the name of the method specified by a given selector.\n * \n * @param sel A pointer of type \\c SEL. Pass the selector whose name you wish to determine.\n * \n * @return A C string indicating the name of the selector.\n */\nOBJC_EXPORT const char * _Nonnull\nsel_getName(SEL _Nonnull sel)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n\n/** \n * Registers a method with the Objective-C runtime system, maps the method \n * name to a selector, and returns the selector value.\n * \n * @param str A pointer to a C string. Pass the name of the method you wish to register.\n * \n * @return A pointer of type SEL specifying the selector for the named method.\n * \n * @note You must register a method name with the Objective-C runtime system to obtain the\n *  method’s selector before you can add the method to a class definition. If the method name\n *  has already been registered, this function simply returns the selector.\n */\nOBJC_EXPORT SEL _Nonnull\nsel_registerName(const char * _Nonnull str)\n    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Returns a Boolean value that indicates whether two selectors are equal.\n * \n * @param lhs The selector to compare with rhs.\n * @param rhs The selector to compare with lhs.\n * \n * @return \\c YES if \\e lhs and \\e rhs are equal, otherwise \\c NO.\n * \n * @note sel_isEqual is equivalent to ==.\n */\nOBJC_EXPORT BOOL\nsel_isEqual(SEL _Nonnull lhs, SEL _Nonnull rhs) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n\n/* Objective-C Language Features */\n\n/** \n * This function is inserted by the compiler when a mutation\n * is detected during a foreach iteration. It gets called \n * when a mutation occurs, and the enumerationMutationHandler\n * is enacted if it is set up. A fatal error occurs if a handler is not set up.\n *\n * @param obj The object being mutated.\n * \n */\nOBJC_EXPORT void\nobjc_enumerationMutation(id _Nonnull obj) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Sets the current mutation handler. \n * \n * @param handler Function pointer to the new mutation handler.\n */\nOBJC_EXPORT void\nobjc_setEnumerationMutationHandler(void (*_Nullable handler)(id _Nonnull )) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Set the function to be called by objc_msgForward.\n * \n * @param fwd Function to be jumped to by objc_msgForward.\n * @param fwd_stret Function to be jumped to by objc_msgForward_stret.\n * \n * @see message.h::_objc_msgForward\n */\nOBJC_EXPORT void\nobjc_setForwardHandler(void * _Nonnull fwd, void * _Nonnull fwd_stret) \n    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);\n\n/** \n * Creates a pointer to a function that will call the block\n * when the method is called.\n * \n * @param block The block that implements this method. Its signature should\n *  be: method_return_type ^(id self, method_args...). \n *  The selector is not available as a parameter to this block.\n *  The block is copied with \\c Block_copy().\n * \n * @return The IMP that calls this block. Must be disposed of with\n *  \\c imp_removeBlock.\n */\nOBJC_EXPORT IMP _Nonnull\nimp_implementationWithBlock(id _Nonnull block)\n    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);\n\n/** \n * Return the block associated with an IMP that was created using\n * \\c imp_implementationWithBlock.\n * \n * @param anImp The IMP that calls this block.\n * \n * @return The block called by \\e anImp.\n */\nOBJC_EXPORT id _Nullable\nimp_getBlock(IMP _Nonnull anImp)\n    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);\n\n/** \n * Disassociates a block from an IMP that was created using\n * \\c imp_implementationWithBlock and releases the copy of the \n * block that was created.\n * \n * @param anImp An IMP that was created using \\c imp_implementationWithBlock.\n * \n * @return YES if the block was released successfully, NO otherwise. \n *  (For example, the block might not have been used to create an IMP previously).\n */\nOBJC_EXPORT BOOL\nimp_removeBlock(IMP _Nonnull anImp)\n    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);\n\n/** \n * This loads the object referenced by a weak pointer and returns it, after\n * retaining and autoreleasing the object to ensure that it stays alive\n * long enough for the caller to use it. This function would be used\n * anywhere a __weak variable is used in an expression.\n * \n * @param location The weak pointer address\n * \n * @return The object pointed to by \\e location, or \\c nil if \\e *location is \\c nil.\n */\nOBJC_EXPORT id _Nullable\nobjc_loadWeak(id _Nullable * _Nonnull location)\n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\n/** \n * This function stores a new value into a __weak variable. It would\n * be used anywhere a __weak variable is the target of an assignment.\n * \n * @param location The address of the weak pointer itself\n * @param obj The new object this weak ptr should now point to\n * \n * @return The value stored into \\e location, i.e. \\e obj\n */\nOBJC_EXPORT id _Nullable\nobjc_storeWeak(id _Nullable * _Nonnull location, id _Nullable obj) \n    OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);\n\n\n/* Associative References */\n\n/**\n * Policies related to associative references.\n * These are options to objc_setAssociatedObject()\n */\ntypedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {\n    OBJC_ASSOCIATION_ASSIGN = 0,           /**< Specifies a weak reference to the associated object. */\n    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object. \n                                            *   The association is not made atomically. */\n    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   /**< Specifies that the associated object is copied. \n                                            *   The association is not made atomically. */\n    OBJC_ASSOCIATION_RETAIN = 01401,       /**< Specifies a strong reference to the associated object.\n                                            *   The association is made atomically. */\n    OBJC_ASSOCIATION_COPY = 01403          /**< Specifies that the associated object is copied.\n                                            *   The association is made atomically. */\n};\n\n/** \n * Sets an associated value for a given object using a given key and association policy.\n * \n * @param object The source object for the association.\n * @param key The key for the association.\n * @param value The value to associate with the key key for object. Pass nil to clear an existing association.\n * @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”\n * \n * @see objc_setAssociatedObject\n * @see objc_removeAssociatedObjects\n */\nOBJC_EXPORT void\nobjc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,\n                         id _Nullable value, objc_AssociationPolicy policy)\n    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);\n\n/** \n * Returns the value associated with a given object for a given key.\n * \n * @param object The source object for the association.\n * @param key The key for the association.\n * \n * @return The value associated with the key \\e key for \\e object.\n * \n * @see objc_setAssociatedObject\n */\nOBJC_EXPORT id _Nullable\nobjc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)\n    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);\n\n/** \n * Removes all associations for a given object.\n * \n * @param object An object that maintains associated objects.\n * \n * @note The main purpose of this function is to make it easy to return an object \n *  to a \"pristine state”. You should not use this function for general removal of\n *  associations from objects, since it also removes associations that other clients\n *  may have added to the object. Typically you should use \\c objc_setAssociatedObject \n *  with a nil value to clear an association.\n * \n * @see objc_setAssociatedObject\n * @see objc_getAssociatedObject\n */\nOBJC_EXPORT void\nobjc_removeAssociatedObjects(id _Nonnull object)\n    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);\n\n\n/* Hooks for Swift */\n\n/**\n * Function type for a hook that intercepts class_getImageName().\n *\n * @param cls The class whose image name is being looked up.\n * @param outImageName On return, the result of the image name lookup.\n * @return YES if an image name for this class was found, NO otherwise.\n *\n * @see class_getImageName\n * @see objc_setHook_getImageName\n */\ntypedef BOOL (*objc_hook_getImageName)(Class _Nonnull cls, const char * _Nullable * _Nonnull outImageName);\n\n/**\n * Install a hook for class_getImageName().\n *\n * @param newValue The hook function to install.\n * @param outOldValue The address of a function pointer variable. On return,\n *  the old hook function is stored in the variable.\n *\n * @note The store to *outOldValue is thread-safe: the variable will be\n *  updated before class_getImageName() calls your new hook to read it,\n *  even if your new hook is called from another thread before this\n *  setter completes.\n * @note The first hook in the chain is the native implementation of\n *  class_getImageName(). Your hook should call the previous hook for\n *  classes that you do not recognize.\n *\n * @see class_getImageName\n * @see objc_hook_getImageName\n */\nOBJC_EXPORT void objc_setHook_getImageName(objc_hook_getImageName _Nonnull newValue,\n                                           objc_hook_getImageName _Nullable * _Nonnull outOldValue)\n    OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);\n\n\n#define _C_ID       '@'\n#define _C_CLASS    '#'\n#define _C_SEL      ':'\n#define _C_CHR      'c'\n#define _C_UCHR     'C'\n#define _C_SHT      's'\n#define _C_USHT     'S'\n#define _C_INT      'i'\n#define _C_UINT     'I'\n#define _C_LNG      'l'\n#define _C_ULNG     'L'\n#define _C_LNG_LNG  'q'\n#define _C_ULNG_LNG 'Q'\n#define _C_FLT      'f'\n#define _C_DBL      'd'\n#define _C_BFLD     'b'\n#define _C_BOOL     'B'\n#define _C_VOID     'v'\n#define _C_UNDEF    '?'\n#define _C_PTR      '^'\n#define _C_CHARPTR  '*'\n#define _C_ATOM     '%'\n#define _C_ARY_B    '['\n#define _C_ARY_E    ']'\n#define _C_UNION_B  '('\n#define _C_UNION_E  ')'\n#define _C_STRUCT_B '{'\n#define _C_STRUCT_E '}'\n#define _C_VECTOR   '!'\n#define _C_CONST    'r'\n\n\n/* Obsolete types */\n\n#if !__OBJC2__\n\n#define CLS_GETINFO(cls,infomask)        ((cls)->info & (infomask))\n#define CLS_SETINFO(cls,infomask)        ((cls)->info |= (infomask))\n\n// class is not a metaclass\n#define CLS_CLASS               0x1\n// class is a metaclass\n#define CLS_META                0x2\n// class's +initialize method has completed\n#define CLS_INITIALIZED         0x4\n// class is posing\n#define CLS_POSING              0x8\n// unused\n#define CLS_MAPPED              0x10\n// class and subclasses need cache flush during image loading\n#define CLS_FLUSH_CACHE         0x20\n// method cache should grow when full\n#define CLS_GROW_CACHE          0x40\n// unused\n#define CLS_NEED_BIND           0x80\n// methodLists is array of method lists\n#define CLS_METHOD_ARRAY        0x100\n// the JavaBridge constructs classes with these markers\n#define CLS_JAVA_HYBRID         0x200\n#define CLS_JAVA_CLASS          0x400\n// thread-safe +initialize\n#define CLS_INITIALIZING        0x800\n// bundle unloading\n#define CLS_FROM_BUNDLE         0x1000\n// C++ ivar support\n#define CLS_HAS_CXX_STRUCTORS   0x2000\n// Lazy method list arrays\n#define CLS_NO_METHOD_ARRAY     0x4000\n// +load implementation\n#define CLS_HAS_LOAD_METHOD     0x8000\n// objc_allocateClassPair API\n#define CLS_CONSTRUCTING        0x10000\n// class compiled with bigger class structure\n#define CLS_EXT                 0x20000\n\n\nstruct objc_method_description_list {\n    int count;\n    struct objc_method_description list[1];\n};\n\n\nstruct objc_protocol_list {\n    struct objc_protocol_list * _Nullable next;\n    long count;\n    __unsafe_unretained Protocol * _Nullable list[1];\n};\n\n\nstruct objc_category {\n    char * _Nonnull category_name                            OBJC2_UNAVAILABLE;\n    char * _Nonnull class_name                               OBJC2_UNAVAILABLE;\n    struct objc_method_list * _Nullable instance_methods     OBJC2_UNAVAILABLE;\n    struct objc_method_list * _Nullable class_methods        OBJC2_UNAVAILABLE;\n    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;\n}                                                            OBJC2_UNAVAILABLE;\n\n\nstruct objc_ivar {\n    char * _Nullable ivar_name                               OBJC2_UNAVAILABLE;\n    char * _Nullable ivar_type                               OBJC2_UNAVAILABLE;\n    int ivar_offset                                          OBJC2_UNAVAILABLE;\n#ifdef __LP64__\n    int space                                                OBJC2_UNAVAILABLE;\n#endif\n}                                                            OBJC2_UNAVAILABLE;\n\nstruct objc_ivar_list {\n    int ivar_count                                           OBJC2_UNAVAILABLE;\n#ifdef __LP64__\n    int space                                                OBJC2_UNAVAILABLE;\n#endif\n    /* variable length structure */\n    struct objc_ivar ivar_list[1]                            OBJC2_UNAVAILABLE;\n}                                                            OBJC2_UNAVAILABLE;\n\n\nstruct objc_method {\n    SEL _Nonnull method_name                                 OBJC2_UNAVAILABLE;\n    char * _Nullable method_types                            OBJC2_UNAVAILABLE;\n    IMP _Nonnull method_imp                                  OBJC2_UNAVAILABLE;\n}                                                            OBJC2_UNAVAILABLE;\n\nstruct objc_method_list {\n    struct objc_method_list * _Nullable obsolete             OBJC2_UNAVAILABLE;\n\n    int method_count                                         OBJC2_UNAVAILABLE;\n#ifdef __LP64__\n    int space                                                OBJC2_UNAVAILABLE;\n#endif\n    /* variable length structure */\n    struct objc_method method_list[1]                        OBJC2_UNAVAILABLE;\n}                                                            OBJC2_UNAVAILABLE;\n\n\ntypedef struct objc_symtab *Symtab                           OBJC2_UNAVAILABLE;\n\nstruct objc_symtab {\n    unsigned long sel_ref_cnt                                OBJC2_UNAVAILABLE;\n    SEL _Nonnull * _Nullable refs                            OBJC2_UNAVAILABLE;\n    unsigned short cls_def_cnt                               OBJC2_UNAVAILABLE;\n    unsigned short cat_def_cnt                               OBJC2_UNAVAILABLE;\n    void * _Nullable defs[1] /* variable size */             OBJC2_UNAVAILABLE;\n}                                                            OBJC2_UNAVAILABLE;\n\n\ntypedef struct objc_cache *Cache                             OBJC2_UNAVAILABLE;\n\n#define CACHE_BUCKET_NAME(B)  ((B)->method_name)\n#define CACHE_BUCKET_IMP(B)   ((B)->method_imp)\n#define CACHE_BUCKET_VALID(B) (B)\n#ifndef __LP64__\n#define CACHE_HASH(sel, mask) (((uintptr_t)(sel)>>2) & (mask))\n#else\n#define CACHE_HASH(sel, mask) (((unsigned int)((uintptr_t)(sel)>>3)) & (mask))\n#endif\nstruct objc_cache {\n    unsigned int mask /* total = mask + 1 */                 OBJC2_UNAVAILABLE;\n    unsigned int occupied                                    OBJC2_UNAVAILABLE;\n    Method _Nullable buckets[1]                              OBJC2_UNAVAILABLE;\n};\n\n\ntypedef struct objc_module *Module                           OBJC2_UNAVAILABLE;\n\nstruct objc_module {\n    unsigned long version                                    OBJC2_UNAVAILABLE;\n    unsigned long size                                       OBJC2_UNAVAILABLE;\n    const char * _Nullable name                              OBJC2_UNAVAILABLE;\n    Symtab _Nullable symtab                                  OBJC2_UNAVAILABLE;\n}                                                            OBJC2_UNAVAILABLE;\n\n#else\n\nstruct objc_method_list;\n\n#endif\n\n\n/* Obsolete functions */\n\nOBJC_EXPORT IMP _Nullable\nclass_lookupMethod(Class _Nullable cls, SEL _Nonnull sel) \n    __OSX_DEPRECATED(10.0, 10.5, \"use class_getMethodImplementation instead\") \n    __IOS_DEPRECATED(2.0, 2.0, \"use class_getMethodImplementation instead\") \n    __TVOS_DEPRECATED(9.0, 9.0, \"use class_getMethodImplementation instead\") \n    __WATCHOS_DEPRECATED(1.0, 1.0, \"use class_getMethodImplementation instead\")\n    __BRIDGEOS_DEPRECATED(2.0, 2.0, \"use class_getMethodImplementation instead\");\nOBJC_EXPORT BOOL\nclass_respondsToMethod(Class _Nullable cls, SEL _Nonnull sel)\n    __OSX_DEPRECATED(10.0, 10.5, \"use class_respondsToSelector instead\") \n    __IOS_DEPRECATED(2.0, 2.0, \"use class_respondsToSelector instead\") \n    __TVOS_DEPRECATED(9.0, 9.0, \"use class_respondsToSelector instead\") \n    __WATCHOS_DEPRECATED(1.0, 1.0, \"use class_respondsToSelector instead\")\n    __BRIDGEOS_DEPRECATED(2.0, 2.0, \"use class_respondsToSelector instead\");\n\nOBJC_EXPORT void\n_objc_flush_caches(Class _Nullable cls) \n    __OSX_DEPRECATED(10.0, 10.5, \"not recommended\") \n    __IOS_DEPRECATED(2.0, 2.0, \"not recommended\") \n    __TVOS_DEPRECATED(9.0, 9.0, \"not recommended\") \n    __WATCHOS_DEPRECATED(1.0, 1.0, \"not recommended\")\n    __BRIDGEOS_DEPRECATED(2.0, 2.0, \"not recommended\");\n\nOBJC_EXPORT id _Nullable\nobject_copyFromZone(id _Nullable anObject, size_t nBytes, void * _Nullable z) \n    __OSX_DEPRECATED(10.0, 10.5, \"use object_copy instead\") \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE\n    OBJC_ARC_UNAVAILABLE;\n\nOBJC_EXPORT id _Nullable\nobject_realloc(id _Nullable anObject, size_t nBytes)\n    OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT id _Nullable\nobject_reallocFromZone(id _Nullable anObject, size_t nBytes, void * _Nullable z)\n    OBJC2_UNAVAILABLE;\n\n#define OBSOLETE_OBJC_GETCLASSES 1\nOBJC_EXPORT void * _Nonnull\nobjc_getClasses(void)\n    OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT void\nobjc_addClass(Class _Nonnull myClass)\n    OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT void\nobjc_setClassHandler(int (* _Nullable )(const char * _Nonnull))\n    OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT void\nobjc_setMultithreaded(BOOL flag)\n    OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT id _Nullable\nclass_createInstanceFromZone(Class _Nullable, size_t idxIvars,\n                             void * _Nullable z)\n    __OSX_DEPRECATED(10.0, 10.5, \"use class_createInstance instead\") \n    __IOS_UNAVAILABLE __TVOS_UNAVAILABLE\n    __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE\n    OBJC_ARC_UNAVAILABLE;\n\nOBJC_EXPORT void\nclass_addMethods(Class _Nullable, struct objc_method_list * _Nonnull)\n    OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT void\nclass_removeMethods(Class _Nullable, struct objc_method_list * _Nonnull)\n    OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT void\n_objc_resolve_categories_for_class(Class _Nonnull cls)\n    OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT Class _Nonnull\nclass_poseAs(Class _Nonnull imposter, Class _Nonnull original)\n    OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT unsigned int\nmethod_getSizeOfArguments(Method _Nonnull m)\n    OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT unsigned\nmethod_getArgumentInfo(struct objc_method * _Nonnull m, int arg,\n                       const char * _Nullable * _Nonnull type,\n                       int * _Nonnull offset)\n    UNAVAILABLE_ATTRIBUTE  // This function was accidentally deleted in 10.9.\n    OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT Class _Nullable\nobjc_getOrigClass(const char * _Nonnull name)\n    OBJC2_UNAVAILABLE;\n\n#define OBJC_NEXT_METHOD_LIST 1\nOBJC_EXPORT struct objc_method_list * _Nullable\nclass_nextMethodList(Class _Nullable, void * _Nullable * _Nullable)\n    OBJC2_UNAVAILABLE;\n// usage for nextMethodList\n//\n// void *iterator = 0;\n// struct objc_method_list *mlist;\n// while ( mlist = class_nextMethodList( cls, &iterator ) )\n//    ;\n \nOBJC_EXPORT id _Nullable\n(* _Nonnull _alloc)(Class _Nullable, size_t)\n    OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT id _Nullable\n(* _Nonnull _copy)(id _Nullable, size_t)\n     OBJC2_UNAVAILABLE;\n     \nOBJC_EXPORT id _Nullable\n(* _Nonnull _realloc)(id _Nullable, size_t)\n     OBJC2_UNAVAILABLE;\n\nOBJC_EXPORT id _Nullable\n(* _Nonnull _dealloc)(id _Nullable)\n     OBJC2_UNAVAILABLE;\n     \nOBJC_EXPORT id _Nullable\n(* _Nonnull _zoneAlloc)(Class _Nullable, size_t, void * _Nullable)\n     OBJC2_UNAVAILABLE;\n     \nOBJC_EXPORT id _Nullable\n(* _Nonnull _zoneRealloc)(id _Nullable, size_t, void * _Nullable)\n     OBJC2_UNAVAILABLE;\n     \nOBJC_EXPORT id _Nullable\n(* _Nonnull _zoneCopy)(id _Nullable, size_t, void * _Nullable)\n     OBJC2_UNAVAILABLE;\n     \nOBJC_EXPORT void\n(* _Nonnull _error)(id _Nullable, const char * _Nonnull, va_list)\n     OBJC2_UNAVAILABLE;\n\n#endif\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/unexported_symbols",
    "content": ".objc_class_name___IncompleteProtocol\n__Znam\n__ZnamRKSt9nothrow_t\n__Znwm\n__ZnwmRKSt9nothrow_t\n__ZdaPv\n__ZdaPvRKSt9nothrow_t\n__ZdlPv\n__ZdlPvRKSt9nothrow_t\n__ZTISt9bad_alloc\n__ZTISt9exception\n__ZTISt11logic_error\n__ZTISt12length_error\n__ZTSSt9bad_alloc\n__ZTSSt9exception\n__ZTSSt11logic_error\n__ZTSSt12length_error\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/version.bat",
    "content": ":: version.bat\n:: Writes version numbers from B&I into version.h for use by version.rc.\n\n@ECHO OFF\n\n:: Set default values for environment variables if not set by B&I\nIF \"%OBJROOT%\"==\"\" SET OBJROOT=.\nIF \"%RC_PROJECTSOURCEVERSION%\"==\"\" SET RC_PROJECTSOURCEVERSION=0.0\nIF \"%RC_PROJECTBUILDVERSION%\"==\"\" SET RC_PROJECTBUILDVERSION=0\n\n:: Get version numbers from environment variables\nSET major=1\nSET patch=0\nFOR /F \"tokens=1* eol= delims=.\" %%i IN (\"%RC_PROJECTSOURCEVERSION%\") DO ( \n\tSET minor=%%i\n\tIF NOT \"%%j\"==\"\" SET patch=%%j\n)\nSET build=%RC_PROJECTBUILDVERSION%\n\nECHO version %major% . %minor% . %patch% . %build%\n\n:: Write version.h\nECHO // This file is automatically generated by version.bat. > \"%OBJROOT%\\version.h\"\nECHO // DO NOT EDIT >> \"%OBJROOT%\\version.h\"\nECHO #define major %major% >> \"%OBJROOT%\\version.h\"\nECHO #define minor %minor% >> \"%OBJROOT%\\version.h\"\nECHO #define patch %patch% >> \"%OBJROOT%\\version.h\"\nECHO #define build %build% >> \"%OBJROOT%\\version.h\"\nECHO #define string \"%major%,%minor%,%patch%,%build%\" >> \"%OBJROOT%\\version.h\"\n"
  },
  {
    "path": "InterView-obj-isa-class/objc4-750/version.rc",
    "content": "#include \"Winver.h\"\n\n// built by version.bat; sets variables major, minor, patch, build, string\n#include \"version.h\"\n\nVS_VERSION_INFO VERSIONINFO\n FILEVERSION major,minor,patch,build\n PRODUCTVERSION major,minor,patch,build\n FILEFLAGSMASK 0x17L\n#ifdef _DEBUG\n FILEFLAGS VS_FF_DEBUG\n#else\n FILEFLAGS 0x0L\n#endif\n FILEOS VOS_NT_WINDOWS32\n FILETYPE VFT_DLL\n FILESUBTYPE VFT2_UNKNOWN\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904b0\"\n        BEGIN\n            VALUE \"CompanyName\", \"Apple Inc.\"\n            VALUE \"FileDescription\", \"Objective-C Runtime Library\"\n            VALUE \"FileVersion\", string\n            VALUE \"ProductVersion\", string\n            VALUE \"ProductName\", \"objc4\"\n            VALUE \"InternalName\", \"objc4\"\n            VALUE \"LegalCopyright\", \"Copyright (C) 2007-2009, Apple Inc.\"\n            VALUE \"OriginalFilename\", \"objc.dll\"\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x409, 1200\n    END\nEND\n\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "![伪装成首页.jpg](https://upload-images.jianshu.io/upload_images/4563271-78c96d2cb4ee43c7.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n# iOS初级到中级的进阶之路~\n\n- 一个NSObject 对象，占用多少内存\n- 对象方法 与 类方法的存放在哪\n- 什么是isa指针\n- 什么是meta-class\n- megsend 是如何找到方法的\n\n```\n@implementation MNSubclass\n\n- (void)compareSelfWithSuperclass{\n    NSLog(@\"self class = %@\",[self class]);\n    NSLog(@\"super class = %@\",[super class]);\n}\n@end\n```\n- 输出的结果是什么\n- 。。。\n\n<br>\n\n### *友情tips：如果上诉问题你都知道答案，或者没有兴趣知道，就可以不用继续往下看了，兴趣是最好的老师，如果没有兴趣知道这些，往下很难读得进去~*\n\n<br>\n\n## 底层探究专栏\n\n### [isa&&Class&&meta-class 初步认识](https://minilv.github.io/2018/07/01/ias-class-metaClass)\n\n### [isa与class详解](https://minilv.github.io/2019/03/18/isa%E8%AF%A6%E8%A7%A3-&&-class%E5%86%85%E9%83%A8%E7%BB%93%E6%9E%84/)\n\n### [Category && 关联对象](https://minilv.github.io/2019/02/27/category/)\n\n### [KVO && KVC 常考点](https://minilv.github.io/2018/03/27/KVO&KVC/)\n\n### [Block看我就够了](https://minilv.github.io/2019/02/27/BlockFile/)\n\n### [runtime消息机制](https://minilv.github.io/2019/03/17/Runtime-%E6%B6%88%E6%81%AF%E6%9C%BA%E5%88%B6%E5%9C%9F%E5%91%B3%E8%AE%B2%E8%A7%A3/)\n\n### [一道高级iOS面试题(runtime方向)](https://minilv.github.io/2019/03/27/%E4%B8%80%E9%81%93%E9%AB%98%E7%BA%A7iOS%E9%9D%A2%E8%AF%95%E9%A2%98(runtime%E6%96%B9%E5%90%91)/)\n\n<br>\n\n## 性能优化专栏\n### [UITableView的性能优化 - 中级篇](https://minilv.github.io/2018/06/29/TableViewCellOptimization/)\n\n## 架构专栏\n### [iOS架构入门 - MVC模式实例演示](https://minilv.github.io/2018/05/29/MVC/)\n\n<br>\n\n## 面试专栏\n\n### [iOS 初中级工程师简历指北](https://minilv.github.io/2019/05/05/iOS%E5%88%9D%E4%B8%AD%E7%BA%A7%E5%BC%80%E5%8F%91%E7%AE%80%E5%8E%86%E6%8C%87%E5%8C%97/)\n\n### [萌新iOS面试官迷你厂第一视角](https://minilv.github.io/2019/12/29/interviewer/)\n"
  },
  {
    "path": "category分析.md",
    "content": "# 面试驱动技术 - Category 相关考点\n\n> 面试驱动技术合集（初中级iOS开发），关注仓库，及时获取更新 [Interview-series](https://github.com/miniLV/Interview-series)\n\n![](https://user-gold-cdn.xitu.io/2019/2/28/1693261e7f1da012?w=1050&h=700&f=jpeg&s=130669)\n\n<br>\n\n## I. Category\n\n<br>\n\n\n### Category相关面试题\n\n- Category实现原理？\n- 实际开发中，你用Category做了哪些事？\n- Category能否添加成员变量，如果可以，如何添加？\n- load 、initialize方法的区别是什么，他们在category中的调用顺序？以及出现继承时他们之间的调用过程？\n- Category 和 Class Extension的区别是什么？\n- 为什么分类会“覆盖”宿主类的方法？\n\n\n\n<br>\n<br>\n\n---\n\n\n\n#### 1.Category的特点\n- 运行时决议\n    - 通过 `runtime` 动态将分类的方法合并到类对象、元类对象中\n    - 实例方法合并到类对象中，类方法合并到元类对象中\n- 可以为系统类添加分类\n\n<br>\n\n#### 2.分类中可以添加哪些内容\n\n- 实例方法\n- 类方法\n- 协议\n- 属性\n\n<br>\n\n### 分类中原理解析\n\n使用 `xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc MNPerson+Test.m` 函数，生产一个cpp文件,窥探其底层结构(编译状态)\n\n```\nstruct _category_t {\n    //宿主类名称 - 这里的MNPerson\n    const char *name;\n\t\n    //宿主类对象,里面有isa\n    struct _class_t *cls;\n    \n    //实例方法列表\n    const struct _method_list_t *instance_methods;\n    \n    //类方法列表\n    const struct _method_list_t *class_methods;\n    \n    //协议列表\n    const struct _protocol_list_t *protocols;\n    \n    //属性列表\n    const struct _prop_list_t *properties;\n};\n\n//_class_t 结构\nstruct _class_t {\n\tstruct _class_t *isa;\n\tstruct _class_t *superclass;\n\tvoid *cache;\n\tvoid *vtable;\n\tstruct _class_ro_t *ro;\n};\n```\n\n- 每个分类都是独立的\n- 每个分类的结构都一致，都是`category_t`\n\n\n#### 函数转换\n```\n@implementation MNPerson (Test)\n\n- (void)test{\n    NSLog(@\"test - rua~\");\n}\n\n@end\n```\n\n![](https://user-gold-cdn.xitu.io/2019/2/26/1692a2b47788e5c7)\n\n```\nstatic void \nattachCategories(Class cls, category_list *cats, bool flush_caches)\n{\n    if (!cats) return;\n    if (PrintReplacedMethods) printReplacements(cls, cats);\n\n    bool isMeta = cls->isMetaClass();\n\n    // fixme rearrange to remove these intermediate allocations\n    \n    /* 二维数组( **mlists => 两颗星星，一个)\n     [\n        [method_t,],\n        [method_t,method_t],\n        [method_t,method_t,method_t],\n     ]\n     \n     */\n    method_list_t **mlists = (method_list_t **)\n        malloc(cats->count * sizeof(*mlists));\n    property_list_t **proplists = (property_list_t **)\n        malloc(cats->count * sizeof(*proplists));\n    protocol_list_t **protolists = (protocol_list_t **)\n        malloc(cats->count * sizeof(*protolists));\n\n    // Count backwards through cats to get newest categories first\n    int mcount = 0;\n    int propcount = 0;\n    int protocount = 0;\n    int i = cats->count;//宿主类，分类的总数\n    bool fromBundle = NO;\n    while (i--) {//倒序遍历，最先访问最后编译的分类\n        \n        // 获取某一个分类\n        auto& entry = cats->list[i];\n\n        // 分类的方法列表\n        method_list_t *mlist = entry.cat->methodsForMeta(isMeta);\n        if (mlist) {\n            //最后编译的分类，最先添加到分类数组中\n            mlists[mcount++] = mlist;\n            fromBundle |= entry.hi->isBundle();\n        }\n\n        property_list_t *proplist = \n            entry.cat->propertiesForMeta(isMeta, entry.hi);\n        if (proplist) {\n            proplists[propcount++] = proplist;\n        }\n\n        protocol_list_t *protolist = entry.cat->protocols;\n        if (protolist) {\n            protolists[protocount++] = protolist;\n        }\n    }\n\n    auto rw = cls->data();\n\n    prepareMethodLists(cls, mlists, mcount, NO, fromBundle);\n    \n    // 核心：将所有分类的对象方法，附加到类对象的方法列表中\n    rw->methods.attachLists(mlists, mcount);\n    free(mlists);\n    if (flush_caches  &&  mcount > 0) flushCaches(cls);\n\n    rw->properties.attachLists(proplists, propcount);\n    free(proplists);\n\n    rw->protocols.attachLists(protolists, protocount);\n    free(protolists);\n}\n```\n\n```\nvoid attachLists(List* const * addedLists, uint32_t addedCount) {\n    if (addedCount == 0) return;\n    \n    if (hasArray()) {\n        // many lists -> many lists\n        uint32_t oldCount = array()->count;\n        uint32_t newCount = oldCount + addedCount;\n        \n        //realloc - 重新分配内存 - 扩容了\n        setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));\n        array()->count = newCount;\n        \n        //memmove,内存挪动\n        //array()->lists 原来的方法列表\n        memmove(array()->lists + addedCount,\n                array()->lists,\n                oldCount * sizeof(array()->lists[0]));\n        \n        //memcpy - 将分类的方法列表 copy 到原来的方法列表中\n        memcpy(array()->lists,\n               addedLists,\n               addedCount * sizeof(array()->lists[0]));\n    }\n    ...\n}\n```\n\n画图分析就是\n\n![](https://user-gold-cdn.xitu.io/2019/2/26/1692a68348190846?w=1534&h=554&f=png&s=1437034)\n\n\n![](https://user-gold-cdn.xitu.io/2019/2/26/1692a687869587d1?w=1590&h=762&f=png&s=2050449)\n\n\n![](https://user-gold-cdn.xitu.io/2019/2/26/1692a688d74c9d22?w=1600&h=742&f=png&s=1982328)\n\n\n![](https://user-gold-cdn.xitu.io/2019/2/26/1692a68b11df0d39?w=1670&h=1224&f=png&s=3393364)\n\n\n![](https://user-gold-cdn.xitu.io/2019/2/26/1692a68d560570e4?w=1668&h=1150&f=png&s=3209517)\n\n\n#### 3.实际开发中，你用Category做了哪些事？\n\n- 声明私有方法\n- 分解体积庞大的类文件   \n- - 把`Framework`的私有方法公开\n- 。。。\n\n#### 4.Category实现原理？\n- Category编译之后，底层结构是category_t，里面存储着分类的各种信息，包括 对象方法、类方法、属性、协议信息\n- 分类的在编译后，方法并不会直接添加到类信息中，而是要在程序运行的时候，通过 `runtime`, 讲Category的数据，\n\n#### 5.为什么分类会“覆盖”宿主类的方法？\n- 其实不是真正的“覆盖”，宿主类的同名方法还是存在 \n- 分类将附加到类对象的方法列表中，整合的时候，分类的方法优先放到前面\n- OC的函数调用底层走的是msg_send() 函数，它做的是方法查找，因为分类的方法优先放在前面，所以通过选择器查找到分类的方法之后直接调用，宿主类的方法看上去就像被“覆盖”而没有生效\n\n#### 6.Category 和 Class Extension的区别是什么？\n\n#### *Class Extension(扩展)*\n\n- 声明私有属性\n- 声明私有方法\n- 声明私有成员变量\n- 编译时决议，Category 运行时决议\n- 不能为系统类添加扩展\n- 只能以声明的形式存在，多数情况下，寄生于宿主类的.m文件中\n\n<br>\n<br>\n\n\n## II. load 、initialize\n\n### load实现原理\n> - 类第一次加载进内存的时候，会调用 `+ load` 方法，无需导入，无需使用\n> - 每个类、分类的 `+ load` 在程序运行过程中只会执行一次\n> - `+ load` 走的不是消息发送的 `objc_msgSend` 调用，而是找到 `+ load` 函数的地址，直接调用\n\n\n```\nvoid call_load_methods(void)\n{\n    static bool loading = NO;\n    bool more_categories;\n\n    loadMethodLock.assertLocked();\n\n    // Re-entrant calls do nothing; the outermost call will finish the job.\n    if (loading) return;\n    loading = YES;\n\n    void *pool = objc_autoreleasePoolPush();\n\n    do {\n        // 1. Repeatedly call class +loads until there aren’t any more\n        while (loadable_classes_used > 0) {\n            //先加载宿主类的load方法(按照编译顺序，调用load方法)\n            call_class_loads();\n        }\n\n        // 2. Call category +loads ONCE\n        more_categories = call_category_loads();\n\n        // 3. Run more +loads if there are classes OR more untried categories\n    } while (loadable_classes_used > 0  ||  more_categories);\n\n    objc_autoreleasePoolPop(pool);\n\n    loading = NO;\n}\n```\n\n```\nstatic void schedule_class_load(Class cls)\n{\n    if (!cls) return;\n    assert(cls->isRealized());  // _read_images should realize\n\n    if (cls->data()->flags & RW_LOADED) return;\n\n    // Ensure superclass-first ordering\n    // 递归调用，先将父类添加到load方法列表中，再将自己加进去\n    schedule_class_load(cls->superclass);\n\n    add_class_to_loadable_list(cls);\n    cls->setInfo(RW_LOADED); \n}\n```\n<br>\n\n---\n\n\n<br>\n\n#### 调用顺序\n\n1. 先调用宿主类的`+ load` 函数\n    - 按照编译先后顺序调用（先编译，先调用）\n    - 调用子类的+load之前会先调用父类的+load\n2. 再调用分类的的`+ load` 函数\n    - 按照编译先后顺序调用（先编译，先调用）\n\n实验证明：宿主类先调用，分类再调用\n```\n2019-02-27 17:28:00.519862+0800 load-Initialize-Demo[91107:2281575] MNPerson + load\n2019-02-27 17:28:00.520032+0800 load-Initialize-Demo[91107:2281575] MNPerson (Play) + load\n2019-02-27 17:28:00.520047+0800 load-Initialize-Demo[91107:2281575] MNPerson (Eat) + load\n```\n\n\n![](https://user-gold-cdn.xitu.io/2019/2/27/1692e5511b580ce9?w=716&h=194&f=png&s=37322)\n\n---\n\n```\n2019-02-27 17:39:10.354050+0800 load-Initialize-Demo[91308:2303030] MNDog + load (宿主类1)\n2019-02-27 17:39:10.354237+0800 load-Initialize-Demo[91308:2303030] MNPerson + load (宿主类2)\n2019-02-27 17:39:10.354252+0800 load-Initialize-Demo[91308:2303030] MNDog (Rua) + load (分类1)\n2019-02-27 17:39:10.354263+0800 load-Initialize-Demo[91308:2303030] MNPerson (Play) + load(分类2)\n2019-02-27 17:39:10.354274+0800 load-Initialize-Demo[91308:2303030] MNPerson (Eat) + load(分类3)\n2019-02-27 17:39:10.354285+0800 load-Initialize-Demo[91308:2303030] MNDog (Run) + load(分类4)\n```\n\n<br>\n\n#### Initialize实现原理\n> - 类第一次接收到消息的时候，会调用该方法，需导入，并使用\n> - `+ Initialize` 走的是消息发送的 `objc_msgSend` 调用\n\n#### Initialize题目出现\n\n```\n/*父类*/\n@interface MNPerson : NSObject\n\n@end\n\n@implementation MNPerson\n\n+ (void)initialize{\n    NSLog(@\"MNPerson + initialize\");\n}\n\n@end\n\n/*子类1*/\n@interface MNTeacher : MNPerson\n\n@end\n\n@implementation MNTeacher\n\n@end\n\n/*子类2*/\n@interface MNStudent : MNPerson\n\n@end\n\n@implementation MNStudent\n\n@end\n\n\n---------------------------------------------\n问题出现:以下会输出什么结果\nint main(int argc, const char * argv[]) {\n    @autoreleasepool {\n\n        [MNTeacher alloc];\n        [MNStudent alloc];\n    }\n    return 0;\n}\n\n```\n<br>\n\n---\n\n<br>\n\n结果如下：\n```\n2019-02-27 17:57:33.305655+0800 load-Initialize-Demo[91661:2331296] MNPerson + initialize\n2019-02-27 17:57:33.305950+0800 load-Initialize-Demo[91661:2331296] MNPerson + initialize\n2019-02-27 17:57:33.306476+0800 load-Initialize-Demo[91661:2331296] MNPerson + initialize\n```\n\n**exo me? 为啥打印三次呢**\n\n![](https://user-gold-cdn.xitu.io/2019/2/28/169321d806839d28?w=225&h=225&f=jpeg&s=5766)\n\n原理分析：\n1. `initialize` 在类第一次接收消息的时候会调用，OC里面的 `[ xxx ]` 调用都可以看成 `objc_msgSend`,所以这时候，`[MNTeacher alloc]` 其实内部会调用 `[MNTeacher initialize]`\n2. `initialize` 调用的时候，要先实现自己父类的 `initialize` 方法，第一次调用的时候，`MNPerson` 没被使用过，所以未被初始化，要先调用一下父类的 `[MNPerson initialize]`,输出第一个`MNPerson + initialize`\n3. `MNPerson` 调用了 `initialize` 之后，轮到`MNTeacher` 类自己了，由于他内部没有实现 `initialize`方法，所以调用父类的`initialize`, 输出第二个`MNPerson + initialize`\n4. 然后轮到`[MNStudent alloc]`，内部也是调用 `[MNStudent initialize]`, 然后判断得知 父类`MNPerson`类调用过`initialize`了，因此调用自身的就够了，由于他和`MNTeacher` 一样，也没实现`initialize` 方法，所以同理调用父类的`[MNPerson initialize]`,输出第3个`MNPerson + initialize`\n\n\n---\n\n<br>\n\n### initialize 与 load 的区别\n\n- load 是类第一次加载的时候调用，initialize 是类第一次接收到消息的时候调用，每个类只会initialize一次（父类的initialize方法可能被调用多次）\n- load 和 initialize，加载or调用的时候，都会先调用父类对应的 `load` or `initialize` 方法，再调用自己本身的;\n- load 和 initialize 都是系统自动调用的话，都只会调用一次\n- 调用方式也不一样，load 是根据函数地址直接调用，initialize 是通过`objc_msgSend`\n- 调用时刻，load是runtime加载类、分类的时候调用（只会调用一次）\n- 调用顺序:\n    - load: \n        - 先调用类的load\n            - 先编译的类，优先调用load\n            - 调用子类的load之前，会先调用父类的load\n        - 在调用分类的load\n    - initialize：\n        - 先初始化父列\n        - 再初始化子类（可能最终调用的是父类的初始化方法）\n      \n```\n/*父类*/\n@interface MNPerson : NSObject\n\n@end\n\n@implementation MNPerson\n\n+ (void)initialize{\n    NSLog(@\"MNPerson + initialize\");\n}\n\n+ (void)load{\n    NSLog(@\"MNPerson + load\");\n}\n\n/*子类1*/\n@interface MNTeacher : MNPerson\n\n@end\n\n@implementation MNTeacher\n\n+ (void)load{\n    NSLog(@\"MNTeacher + load\");\n}\n\n/*子类2*/\n@interface MNStudent : MNPerson\n\n@end\n\n@implementation MNStudent\n\n+ (void)load{\n    NSLog(@\"MNStudent + load\");\n}\n\n\n------------------------------------\n问题出现:以下会输出什么结果?\n\nint main(int argc, const char * argv[]) {\n    @autoreleasepool {\n\n        [MNTeacher load];\n    }\n    return 0;\n}\n\n```\n\n#### 答案出现！！！\n\n```\n2019-02-27 18:17:12.034392+0800 load-Initialize-Demo[92064:2370496] MNPerson + load\n2019-02-27 18:17:12.034555+0800 load-Initialize-Demo[92064:2370496] MNStudent + load\n2019-02-27 18:17:12.034569+0800 load-Initialize-Demo[92064:2370496] MNTeacher + load\n2019-02-27 18:17:12.034627+0800 load-Initialize-Demo[92064:2370496] MNPerson + initialize\n2019-02-27 18:17:12.034645+0800 load-Initialize-Demo[92064:2370496] MNPerson + initialize\n2019-02-27 18:17:12.034658+0800 load-Initialize-Demo[92064:2370496] MNTeacher + load\n```\n\nexo me again！怎么这么多！连load 也有了？\n\n![](https://user-gold-cdn.xitu.io/2019/2/28/169321e995812c15?w=225&h=225&f=jpeg&s=12623)\n\n解释：\n\n1. 前三个load不多bb了吧，程序一运行，runtime直接将全部的类加载到内存中，肯定最先输出；\n2. 第一个 `MNPerson + initialize`，因为是`MNTeacher`的调用，所以会先让父类`MNPerson` 调用一次`initialize`，输出第一个 `MNPerson + initialize`\n3. 第二个 `MNPerson + initialize`, `MNTeacher` 自身调用，由于他自己没有实现 `initialize`, 调用父类的`initialize`， 输出第二个 `MNPerson + initialize`\n4. 最后一个`MNTeacher + load`可能其实有点奇怪，不是说 `load`只会加载一次吗，而且他还不走 `objc_msgSend` 吗，怎么还能调用这个方法？\n    - 因为！当类第一次加载进内存的时候，调用的 `load` 方法是系统调的，这时候不走 `objc_msgSend`\n    - 但是，你现在是`[MNTeacher load]`啊，这个就是objc_msgSend(MNTeacher,@selector(MNTeacher))，这就跑到`MNTeacher + load`里了！\n    - 只是一般没人手动调用`load` 函数，但是，还是可以调用的！\n\n\n<br>\n\n## III. 关联对象AssociatedObject\n\n### Category能否添加成员变量，如果可以，如何添加？\n> 这道题实际上考的就是关联对象\n\n<br>\n\n如果是普通类声明生命属性的话\n\n```\n@interface MNPerson : NSObject\n\n@property (nonatomic, copy)NSString *property;\n\n@end\n```\n\n上述代码系统内部会自动三件事：\n1. 帮我们生成一个生成变量_property \n2. 生成一个 `get` 方法 `- (NSString *)property`\n3. 生成一个 `set` 方法 `- (void)setProperty:(NSString *)property`\n```\n@implementation MNPerson{\n    NSString *_property;\n}\n\n- (void)setProperty:(NSString *)property{\n    _property = property;\n}\n\n- (NSString *)property{\n    return _property;\n}\n\n@end\n\n```\n<br>\n\n\n分类也是可以添加属性的 - 类结构里面，有个`properties` 列表，里面就是\n存放属性的;\n\n分类里面，生成属性，只会生成方法的声明，不会生成成员变量 && 方法实现！\n\n\n![](https://user-gold-cdn.xitu.io/2019/2/27/1692f73fd3b74f8d?w=1938&h=222&f=png&s=39210)\n>人工智障翻译：实例变量不能放在分类中\n\n所以：\n\n**不能直接给category 添加成员变量，但是可以间接实现分类有成员变量的效果(效果上感觉像成员变量)**\n\n\n```\n@interface MNPerson (Test)\n\n@property (nonatomic, assign) NSInteger age;\n\n@end\n\n@implementation MNPerson (Test)\n\n@end\n```\n\n![](https://user-gold-cdn.xitu.io/2019/2/27/1692f88838824ba5?w=1944&h=940&f=png&s=274895)\n\n`person.age = 10`等价于 `[person setAge:10]`，所以证明了，给分类声明属性之后，并没有添加其对应的实现！\n\n<br>\n\n### 关联对象\n\nobjc_setAssociatedObject Api\n\n```\nobjc_setAssociatedObject(    <#id  _Nonnull object#>, (对象)\n                             <#const void * _Nonnull key#>,(key)\n                             <#id  _Nullable value#>,(关联的值)\n                             <#objc_AssociationPolicy policy#>)(关联策略)\n```\n\n关联策略，等价于属性声明\n```\ntypedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {\n    OBJC_ASSOCIATION_ASSIGN = 0,          \n    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, \n    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,  \n    OBJC_ASSOCIATION_RETAIN = 01401,      \n    OBJC_ASSOCIATION_COPY = 01403         \n};\n```\n\n\n![](https://user-gold-cdn.xitu.io/2019/2/27/1692f9182dcd9a6f?w=1614&h=998&f=png&s=2116741)\n\n比如这里的age属性，默认声明是`@property (nonatomic, assign) NSInteger age;`，就是 assign，所以这里选择`OBJC_ASSOCIATION_ASSIGN`\n\n\n\n<br>\n\n取值\n\n```\nobjc_getAssociatedObject(<#id  _Nonnull object#>, <#const void * _Nonnull key#>)\n```\n\n\n### 面试题 - 以下代码输出的结果是啥\n\n```\nint main(int argc, const char * argv[]) {\n    @autoreleasepool {\n\n        MNPerson *person = [[MNPerson alloc]init];\n\n        {\n            MNPerson *test = [[MNPerson alloc]init];\n            objc_setAssociatedObject(person,\n                                     @\"test\",\n                                     test,\n                                     OBJC_ASSOCIATION_ASSIGN);\n        }\n        \n        NSLog(@\"%@\",objc_getAssociatedObject(person, @\"test\"));\n    }\n    return 0;\n}\n\n```\n\n\n![](https://user-gold-cdn.xitu.io/2019/2/28/1692fb5b60a63547?w=2004&h=644&f=png&s=115737)\n\n>原因，关联的对象是person，关联的value是 test，test变量 出了他们的`{}` 作用域之后，就会销毁;\n>此时通过key 找到 对应的对象，访问对象内部的value，因为test变量已经销毁了，所以程序崩溃了，这也说明了 => **内部 test 对 value是强引用！**\n\n\n\n### 关联对象的本质\n\n\n> 在分类中，因为类的实例变量的布局已经固定，使用 @property 已经无法向固定的布局中添加新的实例变量（这样做可能会覆盖子类的实例变量），所以我们需要使用关联对象以及两个方法来模拟构成属性的三个要素。\n\n引用自 [关联对象 AssociatedObject 完全解析](https://draveness.me/ao)\n\n\n---\n\n### 关联对象的原理\n实现关联对象技术的核心对象有\n\n- AssociationsManager\n- AssociationsHashMap\n- ObjectAssociationMap\n- ObjcAssociation\n\n```\nclass AssociationsManager {\n    static spinlock_t _lock;//自旋锁，保证线程安全\n    static AssociationsHashMap *_map;\n}\n```\n\n```\nclass AssociationsHashMap : public unordered_map<disguised_ptr_t, ObjectAssociationMap> \n```\n\n```\nclass ObjectAssociationMap : public std::map<void *, ObjcAssociation>\n```\n\n```\nclass ObjcAssociation {\n    uintptr_t _policy;\n    id _value;\n}\n```\n\n\n\n以关联对象代码为例:\n```\n  objc_setAssociatedObject(obj, @selector(key), @\"hello world\", OBJC_ASSOCIATION_COPY_NONATOMIC);\n```\n\n![](https://user-gold-cdn.xitu.io/2019/2/28/16931f33935797e0?w=1000&h=696&f=png&s=1223486)\n- 关联对象并不是存储在被关联对象本身的内存中的\n- 关联对象，存储在全局的一个统一的`AssociationsManager`中\n- 关联对象其实就是 `ObjcAssociation` 对象,关联的 `value` 就放在 `ObjcAssociation` 内\n- 关联对象由 `AssociationsManager` 管理并在  `AssociationsHashMap` 存储\n- 对象的指针以及其对应 `ObjectAssociationMap` 以键值对的形式存储在 `AssociationsHashMap` 中\n- `ObjectAssociationMap` 则是用于存储关联对象的数据结构\n- 每一个对象都有一个标记位 `has_assoc` 指示对象是否含有关联对象\n- 存储在全局的一个统一的`AssociationsManager` 内部有一持有一个`_lock`，他其实是一个spinlock_t(自旋锁),用来保证`AssociationsHashMap`操作的时候，是线程安全的\n\n\n<br>\n\n\n \n`Category` 相关的问题一般初中级问的比较多，一般最深的就问到`关联对象`，上面的问题以及解答已经把比较常见的 `Category` 的问题都罗列解决了一下，如果还有其他常见的 `Category` 的试题欢迎补充~\n\n<br>\n\n传言的互联网寒冬貌似真的来临了，在这种环境下，无法得知公司是否不裁员，还是让自己💪起来！19年的 **铜三铁四** 从明天就要开始拉开帷幕了，也希望近期找工作的iOS们能找到一份满意的工作，看下寒冬下，iOS开发是不是叕没人要了~\n\n<br>\n<br>\n\n---\n\n*本文基于 [MJ老师](https://github.com/CoderMJLee) 的基础知识之上，结合了包括 [draveness](https://github.com/draveness) 在内的一系列大神的文章总结的，如果不当之处，欢迎讨论~*\n\n<br>\n\n友情演出:[小马哥MJ](https://github.com/CoderMJLee)\n\n参考资料:\n\n[关联对象 AssociatedObject 完全解析](https://draveness.me/ao)\n\n[associated-objects](https://nshipster.com/associated-objects/)\n\n\n\n"
  },
  {
    "path": "isa&&Class&&meta-class.md",
    "content": "## OC对象的分类\n- 实例对象(instance对象)\n- 类对象(class对象)\n- 元类对象(meta-class对象)\n\n<br>\n\n### instance 对象\n- 通过类 `alloc` 出来的对象\n- 每次 `alloc` 都会产生新的`instance` 对象(内存不相同)\n- `instance` 对象存储的信息\n    - isa 指针\n    - 其他成员变量\n\n<br>\n\n### class 对象\n- 是创建对象的蓝图，描述了所创建的对象共同的属性和方法(*made in 维基百科*)\n- 类在内存中只有一份，每个类在内存中都有且只有一个 `class` 对象\n- `class`对象在内存中存储的信息\n    - isa 指针\n    - superclass 指针\n    - 类的对象方法 && 协议\n    - 类的属性 && 成员变量信息\n    - 。。。\n\n<br>\n\n### meta-class\n\n` Class metaClass = object_getClass([NSObject class]);`\n\n- `metaclss` 是 `NSObject`的`meta-class`对象\n- `meta-class` 在内存中只有一份，每个类都有且只有一个 `meta-class` 对象\n- `meta-class` 也是类，与`class`的对象结构一样，但是内部的数据不一样(用途不同)\n- `meta-clas` 包括:\n    - isa指针\n    - superclass\n    - 类方法\n    - 。。。\n\n<br>\n\n\n![image](http://upload-images.jianshu.io/upload_images/4563271-1b7e14a38f761d54?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n提问：`object_getClass` 与 `objc_getClass`的区别\n\n```\nClass object_getClass(id obj)\n{\n    if (obj) return obj->getIsa();\n    else return Nil;\n}\n```\n- object_getClass ： 传入的是可以是任意对象(id类型)，返回的是类 or 元类\n    - 如果传入 `instance` 对象，返回 `class `\n    - 如果传入 `class`, 返回的是 `meta-class` 对象\n    - 如果传入的是 `meta-class`，返回的是 `root-meta-class` 对象\n<br>\n\n```\nClass objc_getClass(const char *aClassName)\n{\n    if (!aClassName) return Nil;\n\n    // NO unconnected, YES class handler\n    return look_up_class(aClassName, NO, YES);\n}\n```\n- 传入的是类名字符串，返回的是该类名对应的类\n- 不能返回元类\n\n\n\n![指向图.png](http://upload-images.jianshu.io/upload_images/4563271-eb09268ab87a4671?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n\n(图片来自于 http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html)\n\n> 看懂这张图 - 就等价于看懂 `isa` && `superclass`了\n\n探究流程：\n\n```\n@interface MNSuperclass : NSObject\n\n- (void)superclassInstanceMethod;\n+ (void)superClassMethod;\n\n@end\n\n@implementation MNSuperclass\n\n- (void)superclassInstanceMethod{\n    NSLog(@\"superclass-InstanceMethod - %p\",self);\n}\n\n+ (void)superClassMethod{\n    NSLog(@\"+ superClass-classMethod- %p\",self);\n}\n\n@end\n\n@interface MNSubclass : MNSuperclass\n\n- (void)subclassInstanceMethod;\n\n@end\n\n@implementation MNSubclass\n\n- (void)subclassInstanceMethod{\n    NSLog(@\"subclassInstanceMethod- %p\",self);\n}\n\n@end\n```\n\n<br>\n\n#### 问: 子类调用父类的对象方法，执行的流程是如何的？\n\n```\nMNSubclass *subclass = [[MNSubclass alloc]init];\n[subclass superclassInstanceMethod];\n```\n\n- 思路：\n    - `subclass` 调用对象方法，对象方法存在 `class` 中\n    - 第一步，先找到 `subclass`对象,通过 `isa` 指针，找到其对应的 `MNSubclass` 类\n    - 看`MNSubclass` 是否有 `superclassInstanceMethod` 方法的实现，发现没有，`MNSubclass` 沿着 `superclass` 指针找到他的父类 - `MNSuperclass`\n    - 此时，`MNSuperclass` 中找到 `superclassInstanceMethod` 的实现，调用它，整个流程结束\n\n\n![image](http://upload-images.jianshu.io/upload_images/4563271-08adc97b80c3923e?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n\n\n`[MNSubclass superClassMethod];`\n\n<br>\n\n#### 问: 子类调用父类的类方法，执行的流程是如何的？\n- 思路：\n    - 类方法存在`meta-class`中\n    - 第一步，找到对应的`MNSubclass`,沿着`isa`指针，找到其对应的`meta-class`\n    - 看`MNSubclass` 的 `meta-class` 中是否有 `superClassMethod` 方法的实现，发现没有，沿着 `superclass` 指针找到 `MNSuperclass` 的 `meta-class`\n    - 发现 `MNSuperclass` 的 `meta-class` 有`superClassMethod` 方法实现，调用，流程结束\n\n\n![image](http://upload-images.jianshu.io/upload_images/4563271-baf53d692b8ac300?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n<br>\n\n#### 图中比较难理解的一根线\n\n![image](http://upload-images.jianshu.io/upload_images/4563271-5554fa08fb461169?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n#### 探究 : 元类对象的superclass 指针是否指向 rootclass\n\n- 分析：\n    - `meta-class` 对象存储的是类方法，`class` 存储的是 对象方法\n    - 从面向对象的角度来讲，一个类调用一个类方法，不应该最后调用到 对象方法\n    - 这里的`Root class` 就是 `NSObject`, 要给 `NSObject` 添加方法就要用到 `分类`\n    - 验证 `NSObject` 的对象方法是否会被调用\n    \n<br>\n\n```\n//\"NSObject+MNTest\"类的声明 && 实现\n\n@interface NSObject (MNTest)\n\n+ (void)checkSuperclass;\n\n@end\n\n@implementation NSObject (MNTest)\n\n+ (void)checkSuperclass{\n    NSLog(@\"+NSObject checkSuperclass - %p\",self);\n}\n\n@end\n\n//main函数中调用\nint main(int argc, char * argv[]) {\n    @autoreleasepool\n    {\n        [MNSubclass checkSuperclass];\n        NSLog(@\"MNSubclass = %p\",[MNSubclass class]);\n    }\n    \n    return 0;\n}\n\n--------------------------------------------------------\n控制台输出：\n+NSObject checkSuperclass - 0x105817040\nInterView-obj-isa-class[36303:7016608] MNSubclass = 0x105817040\n\n```\n>1. 发现，调用`checkSuperclass` 类方法的，是`MNSubclass`类\n>2. 这时候要验证上面那条 `meta-class` 指向 `root-class`的线, 这里的`root-class` 即等于 `NSObject`\n>3. `root-class`中只存对象方法，这里，只要验证,`NSObject` 中同名的类方法实现取消，变成同名的对象方法测试，即可得出结论\n>4. 声明的还是`+ (void)checkSuperclass`，实现的方法用 `- (void)checkSuperclass`对象方法替换\n\n<br>\n\n```\n@interface NSObject (MNTest)\n\n+ (void)checkSuperclass;\n\n@end\n\n@implementation NSObject (MNTest)\n\n//+ (void)checkSuperclass{\n//    NSLog(@\"+NSObject checkSuperclass - %p\",self);\n//}\n\n- (void)checkSuperclass{\n    NSLog(@\"-NSObject checkSuperclass - %p\",self);\n}\n\n@end\n\n//main函数中调用\nint main(int argc, char * argv[]) {\n    @autoreleasepool\n    {\n        [MNSubclass checkSuperclass];\n        NSLog(@\"MNSubclass = %p\",[MNSubclass class]);\n    }\n    \n    return 0;\n}\n\n--------------------------------------------------------\n控制台输出：\n-NSObject checkSuperclass - 0x101239040\nInterView-obj-isa-class[36391:7022301] MNSubclass = 0x101239040\n\n```\n\n发现 - 调用的还是类方法 `+ (void)checkSuperclass` ，但是最终实现的，却是对象方法 `- (void)checkSuperclass` \n\n- 原因： \n    - `[MNSubclass checkSuperclass]` 其实本质上，调用的是发送消息方法，函数类似是`objc_msgsend([MNSubclass class], @selector(checkSuperclass))`\n    - 这里的`@selector(checkSuperclass)` 并未说明是 类方法 or 对象方法\n    - 所以最终走流程图的话，`root-meta-class`通过`isa`找到了`root-class` (NSObject)，\n    - `NSObject` 类不是元类，存储的是对象方法，所以 最终调用了`NSObject -checkSuperclass`这个对象方法\n\n\n![image](http://upload-images.jianshu.io/upload_images/4563271-8d5a450e2e10afd4?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n#### 叮叮叮！循循循序渐进之面试题叒来了！！\n\n```\n@implementation MNSubclass\n\n- (void)compareSelfWithSuperclass{\n    NSLog(@\"self class = %@\",[self class]);\n    NSLog(@\"super class = %@\",[super class]);\n}\n@end\n\n调用:\n    MNSubclass *subclass = [[MNSubclass alloc]init];\n    [subclass subclassInstanceMethod];\n\n```\n\n- 问: `[self class]` && `[super class]` 分别输出什么\n\n```\n@protocol NSObject\n- (Class)class OBJC_SWIFT_UNAVAILABLE(\"use 'type(of: anObject)' instead\");\n```\n\n- 思路：\n    - `class` 方法 是`NSObject` 的一个对象方法,对方方法存在 `class` 中\n    - 第一步，先找到 `subclass`对象,通过 `isa` 指针，找到其对应的 `MNSubclass` 类\n    - 看`MNSubclass` 是否有 `class` 方法的实现，发现没有，`MNSubclass` 沿着 `superclass` 指针找到他的父类 - `MNSuperclass`\n    - 查询`MNSuperclass` 中是否有 `class` 方法的实现，发现没有，`MNSuperclass` 沿着 `superclass` 指针找到他的父类 - `NSObject`\n    - 最终在 `NSObject` 中找到 `class` 的实现\n    - 而调用方都是都是当前对象，所以最后输出都是 - `MNSubclass`\n\n<br>\n\n#### 验证:\n\n```\nNSLog(@\"self class = %@\",[self class]);\nNSLog(@\"super class = %@\",[super class]);\n\n----------------------------------------------------------------------\n控制台输出:\nInterView-obj-isa-class[36796:7048007] self class = MNSubclass\nInterView-obj-isa-class[36796:7048007] super class = MNSubclass\n```\n\n<br>\n<br>\n\n感谢[小码哥](https://github.com/CoderMJLee) 的精彩演出，文章中如果有说错的地方，欢迎提出，一起学习~\n\n<br>\n<br>\n\n\n--- \n\n<br>\n\n友情客串：\n\n[小码哥](https://github.com/CoderMJLee)\n\n[神经病院runtime入学考试](https://blog.sunnyxx.com/2014/11/06/runtime-nuts/)\n\n[gun](https://www.gnu.org/software/libc/)\n\n[www.sealiesoftware.com](http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html)\n"
  },
  {
    "path": "什么是NSObject.md",
    "content": "# OC对象的本质\n\n---\n\n我们平时编写的Objetcive-C,底层实现都是C/C++实现的\n![image](http://upload-images.jianshu.io/upload_images/4563271-21c7bda6f74b2c42?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n- 问 : Objetcive-C 基于 C/C++ 实现的话，Objetcive-C 对象相当于C/C++ 中的什么数据结构呢？\n\n```\n@interface MNPerson : NSObject\n{\n    int _age;\n    double _height;\n    NSString *name;\n}\n```\n\n以`MNPerson`为例，里面的成员变量有不同类型是，比如`int`、`double`、`NSString` 类型，假如在C/C++ 中用`数组`存储，显然是不太合理的\n\n- 答: C/C++中用 `结构体` 的数据格式，表示oc对象。\n\n```\n// 转成c/c++ 代码后，MNPerson 的结构如下\n\nstruct NSObject_IMPL {\n\tClass isa;\n};\n\nstruct MNPerson_IMPL {\n\tstruct NSObject_IMPL NSObject_IVARS;\n\tint _age;\n\tdouble _height;\n\tNSString *name;\n};\n```\n\n> 使用指令 `xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc oc源文件 -o 输出的c++文件`\n将 `oc` 代码转成 `c++` 代码之后，发现内部确实是结构体\n\n<br>\n\n---\n\n## 面试题来袭！前方请做好准备！！\n\n- 一个NSObject 对象，占用多少内存\n\n- 思路：\n    - 1. 由上面可知，`NSObject`的本质是结构体，通过`NSObject.m` 可以发现，`NSObject` 只有一个 `isa` 成员，`isa` 的本质是 `class`, `struct objc_object *` 类型，所以应该占据 8 字节\n    - 2.`NSLog(@\"%zu\",class_getInstanceSize([NSObject class]));` 输出 - size = 8\n\n- 注意！实际上，\n\n```\n{\n    //获得 - NSObject 一个实例对象的成员变量所占用的大小 >> 8\n    NSLog(@\"%zu\",class_getInstanceSize([NSObject class]));\n    \n    NSObject *obj = [[NSObject alloc]init];\n    // 获取 obj 指针，指向的内存大小 >> 16\n    NSLog(@\"%zu\",malloc_size((__bridge const void *)obj));\n}\n```\n\n```\n//基于 `objc-class.m` 文件 750 版本\n\nsize_t class_getInstanceSize(Class cls)\n{\n    if (!cls) return 0;\n    return cls->alignedInstanceSize();\n}\n\n// Class‘s ivar size rounded up to a pointer-size boundary.\n// 点击一下 - 智能翻译 ==> （返回类的成员变量所占据的大小）\n\nuint32_t alignedInstanceSize() \n{\n    return word_align(unalignedInstanceSize());\n}\n```\n\n\n[opensource 源码](https://opensource.apple.com/tarballs/)\n\n\n### 对象创建 - `alloc init`, 查找alloc底层实现\n\n```\nsize_t instanceSize(size_t extraBytes) {\n    size_t size = alignedInstanceSize() + extraBytes;\n    // CF requires all objects be at least 16 bytes.\n    if (size < 16) size = 16;\n    return size;\n}\n```\n\n> - `CoreFoundation` 硬性规定，一个对象，至少有 16 字节\n> - 以 `NSObject`为例，这里传入的 `size` 是 `alignedInstanceSize`, 而`alignedInstanceSize` 已经知道 = 8, 8 < 16,retun 16, 最终 NSObject 创建的对象，占据的内存大小是 16\n\n\n<br>\n\n### lldb 调试下，使用 `memory read` 查看对象内存\n\n```\n(lldb) p obj\n(NSObject *) $0 = 0x000060000000eb90\n(lldb) memory read 0x000060000000eb90\n0x60000000eb90: a8 6e 3a 0b 01 00 00 00 00 00 00 00 00 00 00 00\n```\n\n也能发现，前8 位存储 `isa` 指针，后 8 位都是0，但是整个对象还是占据了 16 个字节\n\n<br>\n\n### 一个NSObject内存分配示意图\n\n![一个NSObject内存分配示意图](http://upload-images.jianshu.io/upload_images/4563271-0fd026ab7f8f05b3?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n## 总结：\n    \n- 问 ：一个NSObject 对象，占用多少内存?\n- 答 ：\n     -  系统在alloc的时候，分配了16个字节给 `NSObject` 对象(`malloc_size`函数获得)\n     -  但是实际上 `NSObject` 只使用了 8个字节的存储空间(64bit系统下)\n     -  可以通过`class_getInstanceSize()`\n\n\n<br>\n\n### 循序渐进之面试题又来了！！\n\n```\n@interface MNStudent : NSObject\n{\n    int _age;\n    int _no;\n}\n@end\n```\n\n- 问:一个MNStudent 对象，占用多少内存\n- 答: \n    - 由上面 `NSObject`占据16个字节可知，base = 16\n    -  一个int占4字节，age = 4， no = 4\n    -  最终结果， 16 + 4 + 4 = 24！\n    \n![image](http://upload-images.jianshu.io/upload_images/4563271-03d4237d5e54005f?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n*哈哈！中计了！*\n\n![image](http://upload-images.jianshu.io/upload_images/4563271-7978dbb47c0a4286?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n原理解释：\n\n![image](http://upload-images.jianshu.io/upload_images/4563271-4ffee21e94d8ad99?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n> 1. 之前 `NSObject` 创建一个对象，确实是分配了 16 个字节的空间\n> 2. 但是，他还有未使用的空间8个字节，还是可以存储的\n> 3. 这里的`age` && `no` 存进去，正好 `16`,之前分配的空间正好够用！所以答案是 16！\n \n<br>\n\n### 循循序渐进之面试题双来了！！\n(大哥别打了，这次保证不挖坑了，别打，疼，别打脸别打脸。。。)\n\n```\n@interface MNPerson : NSObject\n{\n    int _age;\n    int _height;\n    NSString *name;\n}\n```\n\n- 问:  一个`MNPerson`对象，占用多少内存\n- 答: 这题我真的会了！上面的坑老夫已经知道了！\n    - 默认创建的时候，分配的内容是16\n    - `isa` = 8, `int age` = 4, `int height` = 4, `NSString` = char * = 8\n    -  最终分配: 8 + 4 + 4 + 8 = 24\n\n\n![image](http://upload-images.jianshu.io/upload_images/4563271-ccfa1407c65170cc?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n哈哈哈哈！ 又中计了！\n\n\n![image](http://upload-images.jianshu.io/upload_images/4563271-2984c712cdb346c7?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n<br>\n\n这时候你肯定好奇了\n\n```\n    uint32_t alignedInstanceSize() {\n        return word_align(unalignedInstanceSize());\n    }\n\n    \n    size_t instanceSize(size_t extraBytes) {\n        size_t size = alignedInstanceSize() + extraBytes;\n        // CF requires all objects be at least 16 bytes.\n        if (size < 16) size = 16;\n        return size;\n    }\n    \n```\n\n> - `extraBytes` 一般都是 0，这里可以理解为 `size = alignedInstanceSize()`；\n> - `alignedInstanceSize = class_getInstanceSize`, `class_getInstanceSize` 由上图的log信息也可以知道 = `24`\n> - 内心os: who tm fucking 32?\n\n\n![image](http://upload-images.jianshu.io/upload_images/4563271-c7bddeced8471c44?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n\n[ios内存分配源码](https://opensource.apple.com/tarballs/libmalloc/)\n\n```\n下载`libmalloc`,找到`calloc`的实现\n\nvoid *\ncalloc(size_t num_items, size_t size)\n{\n\tvoid *retval;\n\tretval = malloc_zone_calloc(default_zone, num_items, size);\n\tif (retval == NULL) {\n\t\terrno = ENOMEM;\n\t}\n\treturn retval;\n}\n\n发现这个函数，就是我们调用的`calloc`函数的底层\n\nvoid *\nmalloc_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size)\n{\n\tMALLOC_TRACE(TRACE_calloc | DBG_FUNC_START, (uintptr_t)zone, num_items, size, 0);\n\n\tvoid *ptr;\n\tif (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) {\n\t\tinternal_check();\n\t}\n\n\tptr = zone->calloc(zone, num_items, size);\n\t\n\tif (malloc_logger) {\n\t\tmalloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE | MALLOC_LOG_TYPE_CLEARED, (uintptr_t)zone,\n\t\t\t\t(uintptr_t)(num_items * size), 0, (uintptr_t)ptr, 0);\n\t}\n\n\tMALLOC_TRACE(TRACE_calloc | DBG_FUNC_END, (uintptr_t)zone, num_items, size, (uintptr_t)ptr);\n\treturn ptr;\n}\n\n```\n\n内心os: exo me? 这传入的 `size_t size = 24`,怎么返回32的？？\n\n#### 涉及到 - 内存对齐\n\n检索`Buckets` - (libmalloc 源码)\n\n```\n#define NANO_MAX_SIZE\t\t\t256 \n/* Buckets sized {16, 32, 48, ..., 256} */\n```\n\n\n> 1. 发现，iOS 系统分配的时候，有自己的分配规则, 不是说你需要的size多大，就创建多大\n> 2. 操作系统内部有自己的一套规则，这里的都是 16 的倍数，而操作系统在此基础之上，操作系统的操作访问最快\n> 3. 所以，在`MNPerson` 对象需要 24 的size的时候，操作系统根据他的规则，直接创建了 32 的size的空间，所以这里的答案是 32！\n\n\n![image](http://upload-images.jianshu.io/upload_images/4563271-85cdba9dd850a245?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n<br>\n\n补充说明: `sizeof` 运算符\n```\n(lldb) po [obj class]\nMNPerson\n\n(lldb) po sizeof(obj)\n8\n\n(lldb) po sizeof(int)\n4\n```\n\n> - `sizeof`是运算符，不是函数，编译时即知道，不是函数\n> - 这里的 `obj` 是对象， *obj - 指针指向，编译器知道他是指针类型，所以 sizeof = 8(指针占据8个字节) - 特别注意，这里传入的不是对象！是指针\n> - `sizeof`是告诉你传入的类型，占多少存储空间\n\n\n\n\n<br>\n\n--- \n\n*欢迎点赞fork~*\n\n<br>\n\n友情客串：\n\n[小码哥](https://github.com/CoderMJLee)\n\n[gun](https://www.gnu.org/software/libc/)\n\n[libmalloc](https://opensource.apple.com/tarballs/libmalloc/)\n\n[objc4](https://opensource.apple.com/tarballs/objc4/)\n\n"
  }
]