It does two things. First, instead of converting the JSValueRef * arguments in invokeWithContext: into an NSArray, I created an NSArray subclass: JSKitArgumentArray. It overrides objectAtIndex: and does the conversion to an id there. This means, it only does the conversion from JSValueRef to id on demand. Handy for variable length arguments, but it also avoids calling NSMutableArray addObject:. I also added this method:

This also means, an ObjC method can grab the JSValueRef directly, instead of converting to an id. For primitive types like JavaScript numbers, this avoids the conversion to NSNumber.

The second change of this patch allows an ObjC method to return a JSValueRef instead of an id. Again, this means if a JavaScript number is returned, we can avoid the overhead of wrapping it in an NSNumber.

Best of all, this patch is completely backwards compatible. How? Because JSKitArgumentArray is a subclass of NSArray, all existing functions added to the interpreter still work. Also, I added this method to JSKitInterpreter:

If convertReturnValue is YES, then the ObjC function is expected to return an id, just as before, and it is converted to JSValueRef. The original addFunction: method calls this new method with YES. If convertReturnValue is NO, then the ObjC function is expected to return a JSValueRef. In essence, the signature is:

Since this is a new method, it is essentially an "opt-in" optimization.

In one of my benchmarks (which evaluates a script 5,000 times), this patch increases performance from 12.6 seconds to 11.1 seconds, i.e. a 12% speedup. Of course, this benchmark has a function that uses JavaScript numbers, so this speedup won't be universal.

I like the idea of encapsulating the JavaScript parameters, though I'm going to have to give it some more thought. At the very least there are problems with the fact that the JS parameters are stack based, and the object encapsulating them could be be retained and live on past their existence (for example, some sort of bizarre Undo mechanism, or in some sort of future debugging enhancement). So the subclass should at least make its own copies of the parameters and make sure that they are retained in the JS world. Of course, that'll slow it down somewhat, but make it safe.

The "return a JSValueRef" enhancement is more curious. The problem is that I want to avoid having the embedding app needed to know anything about JS internals (if for no other reason than the fact that it prevents building on 10.4 using SDKs). And so while there are "void *" definitions for the various JSValueRef, etc... the embedding app doesn't actually see any of the JavaScriptCore interfaces to be able to manipulate these.

So perhaps the better solution is to combine both of these features, and provide a different method signature for the callback that both expects and returns raw JSValueRef's.

The addFunction method would be unchanged, it would just add logic to check what kind of selector was passed (perhaps checking the NSMethodSignature information).

It would be the "in for a penny, in for a pound" optimization (you either get the completely transparent, but slower, version, or the fast as possible, but you need to handle all the dirty details, version).

Basically, one deals with the "raw" JavaScriptCore APIs and data types. Obviously, this isn't for everybody (especially since it will require dealing with the APIs that aren't going to be easy to get to if you compile against a 10.4u SDK), but it should be faster.