Page 1 of 1

Article 3.2: IMP Cacheing Deluxe

Posted: Wed Sep 01, 2004 12:20 am
by Nat!
Discusssion thread for this specific optimization article.


Posted: Fri Sep 03, 2004 2:50 pm
by znek
The requested URL /artikel/Optimization/opti-imp-autorelease.source.tgz was not found on this server.

Re: lame

Posted: Sun Sep 05, 2004 6:50 pm
by Nat!
znek wrote:The requested URL /artikel/Optimization/opti-imp-autorelease.source.tgz was not found on this server.

:oops: Fixed. Thanks for the hint.

Posted: Tue Sep 07, 2004 4:58 am
by whitenoise
You write in regard to the standard dyld stub: "I think this could be done a whole lot better".

I agree, but can it be done without breaking binary compatibility? The guy who designed DYLD wasn't an expert on position-independent code, and this stub has already been improved at least once prior to the current version you dissect in the article. But, it's embedded in the file format.

Posted: Tue Sep 07, 2004 9:59 pm
by Nat!
whitenoise wrote:I agree, but can it be done without breaking binary compatibility?

I think it should be possible to define a bit in the flags of the mach-o header, to alert that this is a new kind of object file. Or one could also use a different filetype. This would be only upward compatible, but the different filetype could preclude launches on not-supported platforms.

Posted: Thu Sep 09, 2004 6:06 pm
by Nat!
Well, I don't think I will really write a whole article on the subject. The topic is too narrow and I would actually have to do some serious coding, for which I am too lazy. 8)

This stub code would be much faster, if it were to contain just this:

Code: Select all

       lis     r12,0x1234
       ori     r12,r12,0x5678
       mtspr   ctr,r12

It would be twice as fast and it is half the size.

If the dynamic linker can generate a table with addresses it could also just generate or patch that code. Incidentally that code just takes 16 bytes, which means proper alignment (see below) for free without waste.

Because of prebinding the linked addresses wouldn't usually change, so this could be set already at link time and it usually wouldn't be necessary to change the stub code at all. Therefore there shouldn't be any penalty compared to the current state of affairs.

Now shared libraries can be relocated and therefore addresses can change. To accomodate that it would be required that the stubcodes reside on their own page(s), then map a fresh page at that address and write in the required new stubs. Finally clear the instruction cache and maybe fiddle with page protection and I think it should work.

A danger with forwarded messages

Posted: Wed Sep 13, 2006 2:18 pm
by Nat!
There is a problem that just bit me now, in a NSArray mapping method. I have an array mixed with objects that implement a certain method (lets say it's @selector( name)) directly and some, that implement them indirectly via forwarding (@selector( forwardInvocation:) -> forwarding it to another object).

If a class does not implement a method, then class_lookupMethod will return _objc_msgForward. This will in turn do the forwarding steps.

Unfortunately it is either the case that _objc_msgForward is written in a way, that it expects objc_msgSend to be called beforehand (setting the r11 register properly) or the gcc compiler 4.0 does not emit proper function pointer call code, because it does not set the r11 register then. I am undecided, but leaning towards the first conclusion.

To fix this in either case, you should change the code to something like this

Code: Select all

 // our IMP cacheing thing
      thisIsa = _isa( p);
      index   = ((unsigned long) thisIsa >> 4) & 15;
      if( lastIsa[ index] != thisIsa)
         extern id  _objc_msgForward( id, SEL, ...);

         imp = class_lookupMethod( thisIsa, sel);

         /* the problem is, that we don't preserve r11, but objc_msgForward
          * explicitly expects r11 to be set by objc_msgSend
         if( imp == _objc_msgForward)
            imp = objc_msgSend;
         /* otherwise continue as planned */
         lastSelIMP[ index] = imp;
         lastIsa[ index]    = thisIsa;
      (*lastSelIMP[ index])( p, sel, argument);

Performance with forwarding ain't so great anyway, so the loss in that case should be acceptable.