FLEXIvar.m 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. //
  2. // FLEXIvar.m
  3. // FLEX
  4. //
  5. // Derived from MirrorKit.
  6. // Created by Tanner on 6/30/15.
  7. // Copyright (c) 2015 Tanner Bennett. All rights reserved.
  8. //
  9. #import "FLEXIvar.h"
  10. #import "FLEXRuntimeUtility.h"
  11. #import "FLEXRuntimeSafety.h"
  12. #import "FLEXTypeEncodingParser.h"
  13. @interface FLEXIvar () {
  14. NSString *_flex_description;
  15. }
  16. @end
  17. @implementation FLEXIvar
  18. #pragma mark Initializers
  19. - (id)init {
  20. [NSException
  21. raise:NSInternalInconsistencyException
  22. format:@"Class instance should not be created with -init"
  23. ];
  24. return nil;
  25. }
  26. + (instancetype)ivar:(Ivar)ivar {
  27. return [[self alloc] initWithIvar:ivar];
  28. }
  29. + (instancetype)named:(NSString *)name onClass:(Class)cls {
  30. Ivar ivar = class_getInstanceVariable(cls, name.UTF8String);
  31. return [self ivar:ivar];
  32. }
  33. - (id)initWithIvar:(Ivar)ivar {
  34. NSParameterAssert(ivar);
  35. self = [super init];
  36. if (self) {
  37. _objc_ivar = ivar;
  38. [self examine];
  39. }
  40. return self;
  41. }
  42. #pragma mark Other
  43. - (NSString *)description {
  44. if (!_flex_description) {
  45. NSString *readableType = [FLEXRuntimeUtility readableTypeForEncoding:self.typeEncoding];
  46. _flex_description = [FLEXRuntimeUtility appendName:self.name toType:readableType];
  47. }
  48. return _flex_description;
  49. }
  50. - (NSString *)debugDescription {
  51. return [NSString stringWithFormat:@"<%@ name=%@, encoding=%@, offset=%ld>",
  52. NSStringFromClass(self.class), self.name, self.typeEncoding, (long)self.offset];
  53. }
  54. - (void)examine {
  55. _name = @(ivar_getName(self.objc_ivar) ?: "(nil)");
  56. _offset = ivar_getOffset(self.objc_ivar);
  57. _typeEncoding = @(ivar_getTypeEncoding(self.objc_ivar) ?: "");
  58. NSString *typeForDetails = _typeEncoding;
  59. NSString *sizeForDetails = nil;
  60. if (_typeEncoding.length) {
  61. _type = (FLEXTypeEncoding)[_typeEncoding characterAtIndex:0];
  62. FLEXGetSizeAndAlignment(_typeEncoding.UTF8String, &_size, nil);
  63. sizeForDetails = [@(_size).stringValue stringByAppendingString:@" bytes"];
  64. } else {
  65. _type = FLEXTypeEncodingNull;
  66. typeForDetails = @"no type info";
  67. sizeForDetails = @"unknown size";
  68. }
  69. _details = [NSString stringWithFormat:
  70. @"%@, offset %@ — %@",
  71. sizeForDetails, @(_offset), typeForDetails
  72. ];
  73. }
  74. - (id)getValue:(id)target {
  75. id value = nil;
  76. if (!FLEXIvarIsSafe(_objc_ivar) || _type == FLEXTypeEncodingNull) {
  77. return nil;
  78. }
  79. #ifdef __arm64__
  80. // See http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html
  81. if (self.type == FLEXTypeEncodingObjcClass && [self.name isEqualToString:@"isa"]) {
  82. value = object_getClass(target);
  83. } else
  84. #endif
  85. if (self.type == FLEXTypeEncodingObjcObject || self.type == FLEXTypeEncodingObjcClass) {
  86. value = object_getIvar(target, self.objc_ivar);
  87. } else {
  88. void *pointer = (__bridge void *)target + self.offset;
  89. value = [FLEXRuntimeUtility
  90. valueForPrimitivePointer:pointer
  91. objCType:self.typeEncoding.UTF8String
  92. ];
  93. }
  94. return value;
  95. }
  96. - (void)setValue:(id)value onObject:(id)target {
  97. const char *typeEncodingCString = self.typeEncoding.UTF8String;
  98. if (self.type == FLEXTypeEncodingObjcObject) {
  99. object_setIvar(target, self.objc_ivar, value);
  100. } else if ([value isKindOfClass:[NSValue class]]) {
  101. // Primitive - unbox the NSValue.
  102. NSValue *valueValue = (NSValue *)value;
  103. // Make sure that the box contained the correct type.
  104. NSAssert(
  105. strcmp(valueValue.objCType, typeEncodingCString) == 0,
  106. @"Type encoding mismatch (value: %s; ivar: %s) in setting ivar named: %@ on object: %@",
  107. valueValue.objCType, typeEncodingCString, self.name, target
  108. );
  109. NSUInteger bufferSize = 0;
  110. if (FLEXGetSizeAndAlignment(typeEncodingCString, &bufferSize, NULL)) {
  111. void *buffer = calloc(bufferSize, 1);
  112. [valueValue getValue:buffer];
  113. void *pointer = (__bridge void *)target + self.offset;
  114. memcpy(pointer, buffer, bufferSize);
  115. free(buffer);
  116. }
  117. }
  118. }
  119. - (id)getPotentiallyUnboxedValue:(id)target {
  120. return [FLEXRuntimeUtility
  121. potentiallyUnwrapBoxedPointer:[self getValue:target]
  122. type:self.typeEncoding.UTF8String
  123. ];
  124. }
  125. @end