> Can anyone tell me offhand what the overhead for a regular method
> invocation vs. a primitive invocation, assuming that both are
> already in the inline cache?
You can't quite compare them that way. The "invokation" is really
split into two parts:
* method lookup
This is the same for both regardless of whether it's primitive or not
(except for a few Very Special Byte Codes such as #+ which is handled
straight from the byte code).
* method activation
This implies running a primitive (if present) and (upon absence or
failure of the prim) setting up a stack frame for the method to make
it run. Naturally, if a primitive is present and successful, this part
will be "faster" for primitive methods.
In general, I would say that the "invokation" is really the method
lookup, and here there's no difference in speed. However, whether a
method is run by the primitive or not does make a difference (if
called often enough at least) - regardless of whether the response is
a no-op or not.
> I had in mind a named primitive, but this brings
> to mind the question: is there any difference in overhead between a
> numbered primitive and a named primitive? (my guess is yes, because
> the numbered primitive has a special bytecode to invoke it, right?)
No, the numbered primitive doesn't have a "bytecode" - the primitive
is a property of the method (again, except for a few extremely rare
and extremely critical bytecodes which map directly to prims if
invoked with the right arguments).
A named primitive is very slightly slower since it requires a bit of
extra work, much of which is cached though, and in fact it could be
made exactly as fast as an indexed primitive if we wanted to by using
a similar trick which we do already use for "ultra-fast failure
responses" from named primitives[**]. For all practical purposes
(which means, unless someone shows that this is an issue ;-) named
primitives are as fast as numbered primitives.
[**] The trick is to rewrite the primitive index in the method cache.
As long as the method is in the cache, any activation will trigger an
immediate "primitive failure" (well, to be honest, the primitive isn't
even attempted to run ;-) We found this to be a valuable improvement
for situations where you'd really like to have a named primitive in
a low-level place which you can expect to be called very often but
where you do have a reasonable chance that the plugin may not be
present. The concrete situation in which (I think Dan) invented this
scheme was when upon introduction of the LargeIntegersPlugin a few
people noted that things really slowed down when the plugin was
absent - triggered by the (repeatedly) failing attempts to look up the
method from the plugin.
However, given that the primitive index is a full 32bit value and we
only use about 1k out of it for "regular" indexed primitives, we could
easily use the same trick for rewriting the primitive index of a
succesfully looked up named primitive. This would make named primitive
invokation exactly as fast as numbered primitives (module a few ABI
issues which might affect the actual outcome of a benchmark).
Cheers,
- Andreas