Getting the IMP of the current method

Once in a very great while, you come across a weird situation where you want to know the IMP of the current method. I’ll just say right now that if you think you need this, you probably don’t. That’s how rare this situation is.

Regardless, it’s an interesting question. How do you get the function pointer for the currently-executing method?

A few years ago, Matt Gallagher came up with a clever solution to this using a compiler function called __builtin_return_address(). His code still works great with the LLVM 3.0 compiler. My only beef with it is that there’s a lot of looping going on. He’s looping over the entire superchain, over every single method, looking at the IMP's address and comparing them to another pointer.

Pretty Pretty

This morning I was thinking about a question on Stack Overflow and thought of another way to get the current IMP:

static inline IMP __CurrentIMP(const char *info, SEL _cmd) {
  IMP imp = NULL;
  if (info[0] == '-' || info[0] == '+') {
    NSString *tmp = [NSString stringWithCString:info+2 encoding:NSUTF8StringEncoding];
    NSRange r = [tmp rangeOfString:@" "];
    NSString *className = [tmp substringToIndex:r.location];
    Class thisClass = NSClassFromString(className);
    if (thisClass != nil) {
      Method m = NULL;
      if (info[0] == '+') {
        m = class_getClassMethod(thisClass, _cmd);
      } else {
        m = class_getInstanceMethod(thisClass, _cmd);
      }
      if (m != NULL) {
        imp = method_getImplementation(m);
      }
    }
  }
  return imp;
}

#define CurrentIMP __CurrentIMP(__PRETTY_FUNCTION__, _cmd)

So, what’s going on? Basically, we’re parsing a special string that’s generated by the compiler and then doing a single lookup. The important bit is the __PRETTY_FUNCTION__. This is a built-in “magic” value that, when compiled, becomes a very nice-looking description of the current function (it’s “pretty”).

For a regular C function, __PRETTY_FUNCTION__ becomes a const char* that includes the name of the function and some type information. The main() function has a __PRETTY_FUNCTION__ of this: "int main(int, const char **)". Ooooo, pretty! :)

An Objective-C method’s pretty description doesn’t include type information, but it does include some very important information. Let’s say we have a class Bar that has this method:

- (id)doAwesomeThingWithFoo:(Foo *)foo {
    ...
}

The pretty description for this is "-[Bar doAwesomeThingWithFoo:]". Here, we see two very important pieces of information:

  • The first character is a -, indicating that the method is an instance method
  • The name of the implementing class is clearly visible.

The selector is also in there, but we would have that anyway through _cmd, so that’s not very interesting. (We could forego passing in _cmd to the __CurrentIMP function and parse it out of the description, but since _cmd is there already, let’s use that.)

The really important thing to realize here is that the name of the class in the description is the class on which the method is implemented, and not the class of any instance. This makes sense, because this is all happening at compile time, not runtime.

Armed with these two pieces of information, we can quickly get the appropriate IMP. First, we do some really simple string parsing to extract the name of the class from the description, and turn it in to a Class object with the NSClassFromString function.

Now that we have the Class and the selector (we’re just using _cmd), we can get the IMP. However, we need to know which runtime function we should be using. For this, we can simply look at the first character in the description string. If it’s a +, then we use the class-specific function, otherwise we’ll use the instance-specific function.

These functions (class_getClassMethod and class_getInstanceMethod) both return Method references. From this Method, we can simply use method_getImplemention to get the method’s IMP. Simple!

Some may ask: why are we getting the Method reference instead of using the class_getMethodImplementation function, which returns an IMP directly? The answer for that is that while that would usually work, it would fail for methods that have large return values (i.e. where the size of the return value is larger than sizeof(id)). In that case, we’d have to use the class_getMethodImplementation_stret function, which means we’d have to get an NSMethodSignature object and check the methodReturnLength to decide which function to use. I figure that getting the Method and asking it for its IMP is probably simpler.

Now, there is a downside to this approach (that are not present in Matt’s implementation). Since this is relying on a compile time detail (the pretty description), this totally and utterly breaks when you start add methods, swizzling implementations, make IMPs from blocks, etc.

But for those times where you, for whatever reason, need to know what your IMP is, this works pretty well.


Steve Weller pointed on on Twitter that if you combine this code with Matt’s version, you can reasonably determine when a method has been swizzled. Cool!

Method Swizzling

Recently I wrote about how to dynamically subclass objects in Objective-C, and when that might be useful.

While dynamic subclassing can be really useful, there is one major gotcha that can make it not very effective, and that was hinted at the end of my post: Key-Value Observing.

When you add an observer to an object, the KVO mechanism will dynamically subclass that object to implement the observation logic. For example, consider the following class:

@interface DataObject : NSObject

@property NSInteger dataValue;

@end

When you observe an instance of DataObject<, a dynamic subclass is created. This class is called NSKVONotifying_DataObject, but even that is hidden from you. The KVO subclass is devious; it hides its existence. Consider this:

DataObject * dataObject = [[DataObject alloc] init];

[dataObject addObserver:self forKeyPath:@"dataValue" options:0 context:NULL];

NSLog(@"%@", [dataObject class]);  //logs "DataObject"
NSLog(@"%@", object_getClass(dataObject));  //logs "NSKVONotifying_DataObject"

In other words, the class of an observed object does everything it can to look and behave exactly like the original class. For the most part, this is appropriate behavior. However, when you want to implement your own dynamic subclassing mechanism, it can wreak havoc. A dynamic KVO subclass does not like to be subclassed, because when you remove all the observers from the object, the class of the object is changed back to its original class. This means that even if you manage to dynamically subclass a KVO class, those changes will be lost when the class of the object is changed back to its original class.

So in the case of CHLayoutManager, a different mechanism for automatic cleanup was needed, since it is not uncommon to observe a UI element in order to react to state changes.

After some experimentation, I came up with an alternative: replace the -dealloc method of NSView with a new version.

Now, I don’t have the source to AppKit. I don’t know what NSView is doing under the hood. Fortunately, with Objective-C, that’s not really a problem, because there’s this really neat function in the runtime called method_exchangeImplementations, and it works like this:

+ (void) initialize {
  if (self == [CHLayoutManager class]) {
    Class nsview = [NSView class];

    SEL dynamicDealloc = @selector(chlayoutautoremove_dynamicDealloc);

    Method newDealloc = class_getInstanceMethod(self, dynamicDealloc);
    if (newDealloc != NULL) {
      class_addMethod(nsview, dynamicDealloc, method_getImplementation(newDealloc), method_getTypeEncoding(newDealloc));
      newDealloc = class_getInstanceMethod(nsview, dynamicDealloc);

      if (newDealloc != NULL) {
        Method originalDealloc = class_getInstanceMethod(nsview, @selector(dealloc));
        method_exchangeImplementations(originalDealloc, newDealloc);
      }
    }
  }
}

- (void) chlayoutautoremove_dynamicDealloc {
  if ([self isKindOfClass:[NSView class]]) { //to prevent people from being stupid
    [[CHLayoutManager sharedLayoutManager] removeConstraintsFromView:(NSView *)self];
    [[CHLayoutManager sharedLayoutManager] setLayoutName:nil forView:(NSView *)self];
    //THIS IS NOT A RECURSIVE CALL
    [self chlayoutautoremove_dynamicDealloc];
  }
}

This is a two step process:

First, we find the NSView class and add a new method to it. This method, called -chlayoutautoremove_dynamicDealloc simply performs cleanup with the layout manager singleton. After we add the method to NSView, we swap the implementations of -dealloc and -chlayoutautoremove_dynamicDealloc. This means that -[NSView dealloc] will invoke the implementation of -chlayoutautoremove_dynamicDealloc, and -[NSView chlayoutautoremove_dynamicDealloc] will invoke the original -dealloc code. Essentially, this is more or less injecting code into NSView that will be executed right before the -dealloc code gets executed.

Neat!

Dynamic Subclassing

If you’ve seen my github.com page or my portfolio link, you’re probably aware of a project of mine called CHLayoutManager. CHLayoutManager, for those of you not in-the-know, is a way to define the layout of a user interface on the Mac via constraints (as opposed to autoresizing masks). For example, if you have two buttons “A” and “B”, you can say “I want the right edge of button ‘A’ to always stay 10 points to the left of the left edge of button ‘B’”. Then, as button “B” moves around (via autoresizing masks or positioning it programmatically), button “A” automatically moves as well. If you do a lot of programmatic UI layouting, this can be insanely useful. In fact, a couple forthcoming products from Mozy will be using CHLayoutManager in them.

Internally, there’s a singleton object called the CHLayoutManager. This object is the one responsible for noticing when a view changes its frame, and then also determining if any other views need to change because of it. This layout manager also has an NSMapTable for storing all of the constraint information related to views. The key of the map table is the view itself, and the value is a container for storing the constraints and the layout name. Because this is supposed to operate silently in the background, the map table maintains a weak reference on the view, and a strong reference to the constraint container. That means if you’re using garbage collection and a view is deallocated, the garbage collector will automatically clean up the entry in the map table, and all will be well in the world.

However, if you’re not using garbage collection, some interesting behavior can crop up. For example, let’s say the map table contains a number of key-value pairs, and some of the keys point to views that have been deallocated (ie, the pointers are invalid). At some point in the future, when you attempt to add a constraint to a new view, the map table will need to resize itself. This means that it will reorganize its contents. Part of this step involves invoking -hash on each key.

But wait. Some of the keys are invalid pointers. If you try to send a message to a deallocated object, you’re (almost definitely) going to crash. Herein lies the crux of the problem: how can we ensure that each view automatically gets cleaned up from the map table without requiring the programmer to do it manually, and without relying on garbage collection?

The answer: dynamic subclassing.

When the user adds a constraint to a view, the layout manager is going to introspect this view and see if the view needs to be altered. If it does, then the manager is going to create a new class that’s a subclass of the view’s class. To this new class gets added a new method: a custom -dealloc method. This method performs the cleanup of the view’s constraints (and other layout information), then invokes [super dealloc]. Once we’ve created this subclass, we simply change the class of the view, and we’re good to go.

What does this look like? Like this:

- (void) dynamicallySubclassView:(NSView *)view {
  const char * prefix = "CHLayoutAutoremove_";
  Class viewClass = [view class];
  NSString * className = NSStringFromClass(viewClass);
  if (strncmp(prefix, [className UTF8String], strlen(prefix)) == 0) { return; }

  NSString * subclassName = [NSString stringWithFormat:@"%s%@", prefix, className];
  Class subclass = NSClassFromString(subclassName);

  if (subclass == nil) {
    subclass = objc_allocateClassPair(viewClass, [subclassName UTF8String], 0);
    if (subclass != nil) {
      IMP dealloc = class_getMethodImplementation([self class], @selector(dynamicDealloc));

      class_addMethod(subclass, @selector(dealloc), dealloc, "v@:");
      objc_registerClassPair(subclass);
    }
  }

  if (subclass != nil) {
    object_setClass(view, subclass);
  }
}

Here you can see what’s going on:

  1. Extract the view’s class
  2. See if the name of this class begins with the prefix used to indicate one of these dynamic subclasses
  3. If it doesn’t have the prefix, then build the name of the new class (+[NSString stringWithFormat:])
  4. Look in the runtime to see if a class of this name already exists
  5. If it doesn’t exist, create the class using objc_allocateClassPair()
  6. Add the custom -dealloc method to the new subclass
  7. Register the class with the runtime
  8. If everything went well, set the class of the view to the new subclass

So if you have an NSPopUpButton and add some constraints to it, it’s actually going to be an CHLayoutAutoremove_NSPopUpButton.

This is, incidentally, how Key-Value Observing is implemented in Cocoa and Cocoa Touch.

Isn’t Objective-C fun?

Aspect Oriented Programming

Recently in a CS class of mine, we briefly discussed Aspect Oriented Programming. The idea intrigued me, and knowing some of the capabilities of the Objective-C runtime, I decided to play around with it and see what I could do.

I first needed a good aspect that I could work on. After a bit of thought, I decided that NSCoding was a good candidate. Usually, Cocoa developers implement NSCoding in order to serialize a custom object. My preferred way is via NSKeyedArchiver and NSKeyedUnarchiver. I realized that whenever I implement the requisite initWithCoder: and encodeWithCoder: methods, they’re almost always the same thing: Save all the instance variables.

So what I’ve come up with is what I call “NSCodingAspect”. The idea of the class is simple: It has one public class method called addToClass:error:, and that method will add NSCoding compliance to whatever class is passed in.

Included below is the full .m file for NSCodingAspect. This is my first stab at it, and it’s probably not the cleanest, but I think it’s pretty darn nifty:

#import "NSCodingAspect.h"
#import <objc/runtime.h>

@implementation NSCodingAspect

+ (void) addMethod:(SEL)aSelector toClass:(Class)aClass error:(NSError **)error {
  IMP implementation = class_getMethodImplementation([self class], aSelector);
  Method method = class_getInstanceMethod([self class], aSelector);
  NSLog(@"  Adding -[%@ %@]", NSStringFromClass(aClass), NSStringFromSelector(aSelector));
  BOOL worked = class_addMethod(aClass, aSelector, implementation, method_getTypeEncoding(method));
  if (!worked) {
    *error = [NSError errorWithDomain:NSStringFromClass(aClass) 
                             code:0 
                         userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Error adding method: %@", 
                                                                     NSStringFromSelector(aSelector)] 
                                                              forKey:@"errMsg"]];
  } else {
    error = nil;
  }
}

+ (void) addToClass:(Class)aClass error:(NSError **)error {
  Protocol * codingProtocol = objc_getProtocol("NSCoding");
  BOOL classConforms = class_conformsToProtocol(aClass, codingProtocol);
  NSString * className = NSStringFromClass(aClass);
  NSLog(@"Conforming [%@ class] to <NSCoding>", className);

  if (!classConforms) {
    class_addProtocol(aClass, codingProtocol);

    if (!class_getInstanceMethod(aClass, @selector(initWithCoder:))) {
      [NSCodingAspect addMethod:@selector(initWithCoder:) toClass:aClass error:error];
      if (error) { return; }
    }
    if (!class_getInstanceMethod(aClass, @selector(encodeWithCoder:))) {
      [NSCodingAspect addMethod:@selector(encodeWithCoder:) toClass:aClass error:error];
      if (error) { return; }
    }
    //all the ivars need to conform to NSCoding, too
    unsigned int numIvars = 0;
    Ivar * ivars = class_copyIvarList(aClass, &numIvars);
    for(int i = 0; i < numIvars; i++) {
      NSString * type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivars[i])];
      if ([type length] > 3) {
        NSString * class = [type substringWithRange:NSMakeRange(2, [type length]-3)];
        Class ivarClass = NSClassFromString(class);
        [NSCodingAspect addToClass:ivarClass error:error];
      }
    }
  }
}

- (id) initWithCoder:(NSCoder *)decoder {
  if ([super respondsToSelector:@selector(initWithCoder:)] && ![self isKindOfClass:[super class]]) {
    self = [super performSelector:@selector(initWithCoder:) withObject:decoder];
  } else {
    self = [super init];
  }
  if (self == nil) { return nil; }

  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  unsigned int numIvars = 0;
  Ivar * ivars = class_copyIvarList([self class], &numIvars);
  for(int i = 0; i < numIvars; i++) {
    Ivar thisIvar = ivars[i];
    NSString * key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];
    id value = [decoder decodeObjectForKey:key];
    if (value == nil) { value = [NSNumber numberWithFloat:0.0]; }
    [self setValue:value forKey:key];
  }
  if (numIvars > 0) { free(ivars); }
  [pool drain];
  return self;
}

- (void) encodeWithCoder:(NSCoder *)encoder {
  if ([super respondsToSelector:@selector(encodeWithCoder:)] && ![self isKindOfClass:[super class]]) {
    [super performSelector:@selector(encodeWithCoder:) withObject:encoder];
  }
  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  unsigned int numIvars = 0;
  Ivar * ivars = class_copyIvarList([self class], &numIvars);
  for (int i = 0; i < numIvars; i++) {
    Ivar thisIvar = ivars[i];
    NSString * key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];
    id value = [self valueForKey:key];
    [encoder encodeObject:value forKey:key];
  }
  if (numIvars > 0) { free(ivars); }
  [pool drain];
}

@end

Here’s the general idea of what it’s doing:

  1. It checks to see if the class already conforms to NSCoding. If it does, then it exits.
  2. If not, it proceeds to copy the two NSCoding methods from NSCodingAspect into the target class.
  3. It then loops through all the instance variables of the target class to make sure that they all conform to NSCoding as well. If any don’t, NSCoding gets added to them, too

The implementation of the initWithCoder: and encodeWithCoder: methods are as follows:

  1. Check to see if the superclass needs to init or encode. If so, then go do that.
  2. Get the list of all the instance variables
  3. For each instance variable, get its name, convert it to an NSString, and then either encode or decode the value that corresponds to that instance variable

In reality, the logic is pretty straightforward. What’s so neat about this is that it’s even possible! You can’t do this with most compiled languages, since the information on what methods or instance variables a class has are statically compiled into the code.

It’s stuff like this that make me absolutely LOVE working in Objective-C.

(While not tested, the above code should work just fine on the iPhone)