"Just Curious" VM question

Andreas Raab andreas.raab at gmx.de
Mon Sep 15 22:50:45 UTC 2003


> 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



More information about the Squeak-dev mailing list