How perl compiles subs and methods

This was just added to perloptree.pod in B::C

Call a subroutine

subname(args...) =>

pushmark
    args ...
gv => *subname
entersub

Call a method

Here we have several combinations to define the package and the method name, either compile-time (static as constant string), or dynamic as GV (for the method name) or PADSV (package name).

method_named holds the method name as sv if known at compile time. If not gv (of the name) and method is used. The package name is at the top of the stack. A call stack is added with pushmark.

Static compile time package and method

Class->subname(args...) =>

pushmark
const => PV "Class"
    args ...
method_named => PV "subname"
entersub

Run-time package and compile-time method

$obj->subname(args...) =>

pushmark
padsv => GV *packagename
    args ...
method_named => PV "subname"
entersub

Run-time package and run-time method

$obj->$meth(args...) =>

pushmark
padsv => GV *packagename
    args ...
gvsv => GV *meth
method
entersub

Compile-time package and run-time method

Class->$meth(args...) =>

pushmark
const => PV "Class"
    args ...
gvsv => GV *meth
method
entersub

Possible Optimizations

Optimization of static methods, e.g. Class->new

The purely static case is of course lame and can be massively optimized. See http://www.perl.com/pub/2000/06/dougpatch.html for the discussion of the old patch

The case

Class->subname(args...) =>

pushmark
const PV => "Class"
    args ...
method_named => PV "subname"
entersub

can be optimized if &Class::subname is defined. Otherwise we'd need to ensure a complle-time const @ISA with some sort of new package attribute. :locked for subs and packages is free. Only a package attribute make sense here really.

The optimization would get rid of the run-time stash lookup for the string "Class", use the string as first arg to entersub, and the method_named op can be replaced by gv => &Class::subname.

pushmark
const PV => "Class"
    args ...
gv => *Class::subname
entersub

Voila, static method calls almost as fast as function calls, and no ops have to be added.

Benchmark

method calls get +3.95 % faster, and only 6.21% slower than sub calls. Without this optimization method calls are 10.87% slower than subs.

Optimization of methods with typed objects

A similar optimization can be done for typed objects if the object class contains that method, or the found method or defined package is locked. A Class declaration binds the package to $obj, and can therefore be optimized.

my Class $obj;
$obj->method(); # and `&Class::method` is defined, 
       # or `package Child :locked; `
       # or sub `Child::method :locked {}` and `@Class::ISA` is Readonly

Easy enough.

Locked classes

Moose came up with immutable classes. If CORE needs to optimize such semantics, either we would need to come up with such a type hint, best for packages.

package NAME :locked # or 
package NAME :immutable #or
package NAME :const #or
package NAME :readonly #or
package NAME :final

would make sense.

Or Readonly %{NAME::}; Readonly @NAME::ISA; for all packages in the inheritance list until the method is found.

Or Moose could just implement those fixes in a CHECK block via B::Generate or XS. This would be much faster than inlining methods or caching for most methods.

Call CV's directly

In case of XSUB's or in any case when the CV slot of the subname glob is known not to be changed since compile-time (type-hints: sub :locked :const or :immutable), it would make sense to create a faster entersub perl op, which calls the CV directly and does not do the glob run-time lookup.

gv => *Class::subname
entersub

=>

entersubcv  => &Class::subname

or maybe

cv => &Class::subname
entersubcv

entersubxs for the XSUB counterpart.

XSUB's should be seperated from normal CV's for Safe to work correctly. perl subs are generally safe, xsubs generally unsafe.

1 Comment

About Reini Urban

user-pic Working at cPanel on cperl, B::C (the perl-compiler), parrot, B::Generate, cygwin perl and more guts, keeping the system alive.