File Coverage

blib/lib/Faster.pm
Criterion Covered Total %
statement 27 281 9.6
branch 0 116 0.0
condition 0 32 0.0
subroutine 9 37 24.3
pod 0 25 0.0
total 36 491 7.3


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Faster - do some things faster
4              
5             =head1 SYNOPSIS
6              
7             use Faster;
8              
9             perl -MFaster ...
10              
11             =head1 DESCRIPTION
12              
13             This module implements a very simple-minded "JIT" (or actually AIT, ahead
14             of time compiler). It works by more or less translating every function it
15             sees into a C program, compiling it and then replacing the function by the
16             compiled code.
17              
18             As a result, startup times are immense, as every function might lead to a
19             full-blown compilation.
20              
21             The speed improvements are also not great, you can expect 20% or so on
22             average, for code that runs very often. The reason for this is that data
23             handling is mostly being done by the same old code, it just gets called
24             a bit faster. Regexes and string operations won't get faster. Airhtmetic
25             doresn't become any faster. Just the operands and other stuff is put on
26             the stack faster, and the opcodes themselves have a bit less overhead.
27              
28             Faster is in the early stages of development. Due to its design its
29             relatively safe to use (it will either work or simply slowdown the program
30             immensely, but rarely cause bugs).
31              
32             More intelligent algorithms (loop optimisation, type inference) could
33             improve that easily, but requires a much more elaborate presentation and
34             optimiser than what is in place. There are no plans to improve Faster in
35             this way, yet, but it would provide a reasonably good place to start.
36              
37             Usage is very easy, just C and every function called from then
38             on will be compiled.
39              
40             Right now, Faster can leave lots of F<*.c> and F<*.so> files in your
41             F<$FASTER_CACHEDIR> (by default F<$HOME/.perl-faster-cache>), and it will
42             even create those temporary files in an insecure manner, so watch out.
43              
44             =over 4
45              
46             =cut
47              
48             package Faster;
49              
50 1     1   1950 no warnings;
  1         2  
  1         48  
51              
52 1     1   6 use strict;
  1         1  
  1         31  
53 1     1   6 use Config;
  1         13  
  1         42  
54 1     1   5 use B ();
  1         1  
  1         13  
55 1     1   5 use DynaLoader ();
  1         8  
  1         13  
56 1     1   5 use Digest::MD5 ();
  1         2  
  1         18  
57 1     1   2543 use Storable ();
  1         4782  
  1         31  
58 1     1   11 use Fcntl ();
  1         2  
  1         48  
59              
60             BEGIN {
61 1     1   2 our $VERSION = '0.1';
62              
63 1         5 require XSLoader;
64 1         14575 XSLoader::load __PACKAGE__, $VERSION;
65             }
66              
67             my $CACHEDIR =
68             $ENV{FASTER_CACHE}
69             || (exists $ENV{HOME} && "$ENV{HOME}/.perl-faster-cache")
70             || do {
71             require File::Temp;
72             File::Temp::tempdir (CLEANUP => 1)
73             };
74              
75             my $COMPILE = "$Config{cc} -c -I$Config{archlibexp}/CORE $Config{optimize} $Config{ccflags} $Config{cccdlflags}";
76             my $LINK = "$Config{ld} $Config{ldflags} $Config{lddlflags} $Config{ccdlflags}";
77             my $LIBS = "";
78             my $_o = $Config{_o};
79             my $_so = ".so";
80              
81             # we don't need no steenking PIC on x86
82             $COMPILE =~ s/-f(?:PIC|pic)//g
83             if $Config{archname} =~ /^(i[3456]86)-/;
84              
85             my $opt_assert = $ENV{FASTER_DEBUG} & 2;
86             my $verbose = $ENV{FASTER_VERBOSE}+0;
87              
88             warn "Faster: CACHEDIR is $CACHEDIR\n" if $verbose > 2;
89              
90             our $source;
91              
92             our @ops;
93             our $insn;
94             our $op;
95             our $op_name;
96             our %op_regcomp;
97              
98             # ops that cause immediate return to the interpreter
99             my %f_unsafe = map +($_ => undef), qw(
100             leavesub leavesublv return
101             goto last redo next
102             eval flip leaveeval entertry
103             formline grepstart mapstart
104             substcont entereval require
105             );
106              
107             # ops with known stack extend behaviour
108             # the values given are maximum values
109             my %extend = (
110             pushmark => 0,
111             nextstate => 0, # might reduce the stack
112             unstack => 0,
113             enter => 0,
114              
115             stringify => 0,
116             not => 0,
117             and => 0,
118             or => 0,
119             gvsv => 0,
120             rv2gv => 0,
121             preinc => 0,
122             predec => 0,
123             postinc => 0,
124             postdec => 0,
125             aelem => 0,
126             helem => 0,
127             qr => 1, #???
128             pushre => 1,
129             gv => 1,
130             aelemfast => 1,
131             aelem => 0,
132             padsv => 1,
133             const => 1,
134             pop => 1,
135             shift => 1,
136             eq => -1,
137             ne => -1,
138             gt => -1,
139             lt => -1,
140             ge => -1,
141             lt => -1,
142             cond_expr => -1,
143             add => -1,
144             subtract => -1,
145             multiply => -1,
146             divide => -1,
147             aassign => 0,
148             sassign => -2,
149             method => 0,
150             method_named => 1,
151             );
152              
153             # ops that do not need an ASYNC_CHECK
154             my %f_noasync = map +($_ => undef), qw(
155             mapstart grepstart match entereval
156             enteriter entersub leaveloop
157              
158             pushmark nextstate caller
159              
160             const stub unstack
161             last next redo goto seq
162             padsv padav padhv padany
163             aassign sassign orassign
164             rv2av rv2cv rv2gv rv2hv refgen
165             gv gvsv
166             add subtract multiply divide
167             complement cond_expr and or not
168             bit_and bit_or bit_xor
169             defined
170             method method_named bless
171             preinc postinc predec postdec
172             aelem aelemfast helem delete exists
173             pushre subst list lslice join split concat
174             length substr stringify ord
175             push pop shift unshift
176             eq ne gt lt ge le
177             regcomp regcreset regcmaybe
178             );
179              
180             my %callop = (
181             entersub => "(PL_op->op_ppaddr) (aTHX)",
182             mapstart => "Perl_pp_grepstart (aTHX)",
183             );
184              
185             sub callop {
186 0 0   0 0   $callop{$op_name} || "Perl_pp_$op_name (aTHX)"
187             }
188              
189             sub assert {
190 0 0   0 0   return unless $opt_assert;
191 0           $source .= " assert ((\"$op_name\", ($_[0])));\n";
192             }
193              
194             sub out_callop {
195 0     0 0   assert "nextop == (OP *)$$op";
196 0           $source .= " PL_op = nextop; nextop = " . (callop $op) . ";\n";
197             }
198              
199             sub out_jump {
200 0     0 0   assert "nextop == (OP *)${$_[0]}L";
  0            
201 0           $source .= " goto op_${$_[0]};\n";
  0            
202             }
203              
204             sub out_cond_jump {
205 0     0 0   $source .= " if (nextop == (OP *)${$_[0]}L) goto op_${$_[0]};\n";
  0            
  0            
206             }
207              
208             sub out_jump_next {
209 0 0   0 0   out_cond_jump $op_regcomp{$$op}
210             if $op_regcomp{$$op};
211              
212 0           assert "nextop == (OP *)${$op->next}";
  0            
213 0           $source .= " goto op_${$op->next};\n";
  0            
214             }
215              
216             sub out_next {
217 0     0 0   $source .= " nextop = (OP *)${$op->next}L;\n";
  0            
218              
219 0           out_jump_next;
220             }
221              
222             sub out_linear {
223 0     0 0   out_callop;
224 0           out_jump_next;
225             }
226              
227             sub op_entersub {
228 0     0 0   out_callop;
229 0           $source .= " RUNOPS_TILL ((OP *)${$op->next}L);\n";
  0            
230 0           out_jump_next;
231             }
232              
233             *op_require = \&op_entersub;
234              
235             sub op_nextstate {
236 0     0 0   $source .= " PL_curcop = (COP *)nextop;\n";
237 0           $source .= " PL_stack_sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;\n";
238 0           $source .= " FREETMPS;\n";
239              
240 0           out_next;
241             }
242              
243             sub op_pushmark {
244 0     0 0   $source .= " faster_PUSHMARK (PL_stack_sp);\n";
245              
246 0           out_next;
247             }
248              
249             if ($Config{useithreads} ne "define") {
250             # disable optimisations on ithreads
251              
252             *op_const = sub {
253 0     0     $source .= " { dSP; PUSHs ((SV *)${$op->sv}L); PUTBACK; }\n";
  0            
254              
255 0 0         $ops[0]{follows_const}++ if @ops;#d#
256              
257 0           out_next;
258             };
259              
260             *op_gv = \&op_const;
261              
262             *op_aelemfast = sub {
263 0     0     my $targ = $op->targ;
264 0           my $private = $op->private;
265              
266 0           $source .= " {\n";
267              
268 0 0         if ($op->flags & B::OPf_SPECIAL) {
269 0           $source .= " AV *av = (AV*)PAD_SV((PADOFFSET)$targ);\n";
270             } else {
271 0           $source .= " AV *av = GvAV ((GV *)${$op->sv}L);\n";
  0            
272             }
273              
274 0 0         if ($op->flags & B::OPf_MOD) {
275 0           $source .= " SV *sv = *av_fetch (av, $private, 1);\n";
276             } else {
277 0           $source .= " SV **svp = av_fetch (av, $private, 0); SV *sv = svp ? *svp : &PL_sv_undef;\n";
278             }
279              
280 0 0         if (!($op->flags & B::OPf_MOD)) {
281 0           $source .= " if (SvGMAGICAL (sv)) sv = sv_mortalcopy (sv);\n";
282             }
283              
284 0           $source .= " dSP;\n";
285 0           $source .= " PUSHs (sv);\n";
286 0           $source .= " PUTBACK;\n";
287 0           $source .= " }\n";
288              
289 0           out_next;
290             };
291              
292             *op_gvsv = sub {
293 0     0     $source .= " {\n";
294 0           $source .= " dSP;\n";
295              
296 0 0         if ($op->private & B::OPpLVAL_INTRO) {
297 0           $source .= " PUSHs (save_scalar ((GV *)${$op->sv}L));\n";
  0            
298             } else {
299 0           $source .= " PUSHs (GvSV ((GV *)${$op->sv}L));\n";
  0            
300             }
301              
302 0           $source .= " PUTBACK;\n";
303 0           $source .= " }\n";
304              
305 0           out_next;
306             };
307             }
308              
309             # does kill Crossfire/res2pm
310             sub op_stringify {
311 0     0 0   my $targ = $op->targ;
312              
313 0           $source .= <
314             {
315             dSP;
316             SV *targ = PAD_SV ((PADOFFSET)$targ);
317             sv_copypv (TARG, TOPs);
318             SETTARG;
319             PUTBACK;
320             }
321             EOF
322              
323 0           out_next;
324             }
325              
326             sub op_and {
327 0     0 0   $source .= <
328             {
329             dSP;
330              
331             if (SvTRUE (TOPs))
332             {
333             --SP;
334             PUTBACK;
335 0           nextop = (OP *)${$op->other}L;
  0            
336             goto op_${$op->other};
337             }
338             }
339             EOF
340              
341 0           out_next;
342             }
343              
344             sub op_or {
345 0     0 0   $source .= <
346             {
347             dSP;
348              
349             if (!SvTRUE (TOPs))
350             {
351             --SP;
352             PUTBACK;
353 0           nextop = (OP *)${$op->other}L;
  0            
354             goto op_${$op->other};
355             }
356             }
357             EOF
358              
359 0           out_next;
360             }
361              
362             sub op_padsv {
363 0     0 0   my $flags = $op->flags;
364 0           my $padofs = "(PADOFFSET)" . $op->targ;
365              
366 0           $source .= <
367             {
368             dSP;
369             SV *sv = PAD_SVl ($padofs);
370             EOF
371              
372 0 0 0       if (($flags & B::OPf_MOD) && ($op->private & B::OPpLVAL_INTRO)) {
373 0           $source .= " SAVECLEARSV (PAD_SVl ($padofs));\n";
374 0 0         $ops[0]{follows_padsv_lval_intro}++ if @ops;#d#
375             }
376            
377 0           $source .= <
378             PUSHs (sv);
379             PUTBACK;
380             EOF
381              
382 0 0 0       if (($flags & B::OPf_MOD) && ($op->private & B::OPpDEREF)) {
383 0           $source .= " if (!SvROK (sv)) vivify_ref (sv, " . $op->private . " & OPpDEREF);\n";
384             }
385 0           $source .= " }\n";
386              
387 0           out_next;
388             }
389              
390             sub op_sassign {
391 0     0 0   $source .= <
392             {
393             dSP;
394             dPOPTOPssrl;
395             EOF
396 0 0         $source .= " SV *temp = left; left = right; right = temp;\n"
397             if $op->private & B::OPpASSIGN_BACKWARDS;
398              
399 0 0 0       if ($insn->{follows_padsv_lval_intro} && !($op->private & B::OPpASSIGN_BACKWARDS)) {
400             # simple assignment - the target exists, but is basically undef
401 0           $source .= " SvSetSV (right, left);\n";
402             } else {
403 0           $source .= " SvSetMagicSV (right, left);\n";
404             }
405              
406 0           $source .= <
407             SETs (right);
408             PUTBACK;
409             }
410             EOF
411              
412 0           out_next;
413             }
414              
415             # pattern const+ (or general push1)
416             # pattern pushmark gv rv2av pushmark padsv+o.ä. aassign
417              
418             sub op_method_named {
419 0 0   0 0   if ($insn->{follows_const}) {
420 0           $source .= <
421             {
422             dSP;
423             static SV *last_cv;
424             static U32 last_sub_generation;
425              
426             /* simple "polymorphic" inline cache */
427             if (PL_sub_generation == last_sub_generation)
428             {
429             PUSHs (last_cv);
430             PUTBACK;
431             }
432             else
433             {
434             PL_op = nextop; nextop = Perl_pp_method_named (aTHX);
435              
436             SPAGAIN;
437             last_sub_generation = PL_sub_generation;
438             last_cv = TOPs;
439             }
440             }
441             EOF
442             } else {
443 0           $source .= <
444             {
445             static HV *last_stash;
446             static SV *last_cv;
447             static U32 last_sub_generation;
448              
449             SV *obj = *(PL_stack_base + TOPMARK + 1);
450              
451             if (!SvGMAGICAL (obj) && SvROK (obj) && SvOBJECT (SvRV (obj)))
452             {
453             dSP;
454             HV *stash = SvSTASH (SvRV (obj));
455              
456             /* simple "polymorphic" inline cache */
457             if (stash == last_stash
458             && PL_sub_generation == last_sub_generation)
459             {
460             PUSHs (last_cv);
461             PUTBACK;
462             }
463             else
464             {
465             PL_op = nextop; nextop = Perl_pp_method_named (aTHX);
466              
467             SPAGAIN;
468             last_sub_generation = PL_sub_generation;
469             last_stash = stash;
470             last_cv = TOPs;
471             }
472             }
473             else
474             {
475             /* error case usually */
476             PL_op = nextop; nextop = Perl_pp_method_named (aTHX);
477             }
478             }
479             EOF
480             }
481              
482 0           out_next;
483             }
484              
485             sub op_grepstart {
486 0     0 0   out_callop;
487 0           $op = $op->next;
488 0           out_cond_jump $op->other;
489 0           out_jump_next;
490             }
491              
492             *op_mapstart = \&op_grepstart;
493              
494             sub op_substcont {
495 0     0 0   out_callop;
496 0           out_cond_jump $op->other->pmreplstart;
497 0           assert "nextop == (OP *)${$op->other->next}L";
  0            
498 0           $source .= " goto op_${$op->other->next};\n";
  0            
499             }
500              
501             sub out_break_op {
502 0     0 0   my ($idx) = @_;
503              
504 0 0 0       if ($op->flags & B::OPf_SPECIAL && $insn->{loop}) {
    0          
505             # common case: no label, innermost loop only
506 0           my $next = $insn->{loop}{loop_targ}[$idx];
507 0           out_callop;
508 0           out_jump $next;
509             } elsif (my $loop = $insn->{loop}) {
510             # less common case: maybe break to some outer loop
511 0           $source .= " return nextop;\n";
512             # todo: walk stack up
513             } else {
514             # fuck yourself for writing such hacks
515 0           $source .= " return nextop;\n";
516             }
517             }
518              
519             sub op_next {
520 0     0 0   out_break_op 0;
521             }
522              
523             sub op_last {
524 0     0 0   out_break_op 1;
525             }
526              
527             # TODO: does not seem to work
528             #sub op_redo {
529             # out_break_op 2;
530             #}
531              
532             sub cv2c {
533 0     0 0   my ($cv) = @_;
534              
535 0           local @ops;
536 0           local %op_regcomp;
537              
538 0           my $curloop;
539 0           my @todo = $cv->START;
540 0           my %op_target;
541             my $numpushmark;
542 0           my $scope;
543              
544 0           my %op_seen;
545 0           while (my $op = shift @todo) {
546 0           my $next;
547 0           for (; $$op; $op = $next) {
548 0 0         last if $op_seen{$$op}++;
549              
550 0           $next = $op->next;
551              
552 0           my $name = $op->name;
553 0           my $class = B::class $op;
554              
555 0           my $insn = { op => $op };
556              
557             # end of loop reached?
558 0 0 0       $curloop = $curloop->{loop} if $curloop && $$op == ${$curloop->{loop_targ}[1]};
  0            
559              
560             # remember enclosing loop
561 0 0         $insn->{loop} = $curloop if $curloop;
562              
563 0           push @ops, $insn;
564              
565 0 0         if (exists $extend{$name}) {
566 0           my $extend = $extend{$name};
567 0 0         $extend = $extend->($op) if ref $extend;
568 0 0         $insn->{extend} = $extend if defined $extend;
569             }
570              
571             # TODO: mark scopes similar to loops, make them comparable
572             # static cxstack(?)
573 0 0         if ($class eq "LOGOP") {
    0          
    0          
    0          
574 0           push @todo, $op->other;
575 0           $op_target{${$op->other}}++;
  0            
576              
577             # regcomp/o patches ops at runtime, lets expect that
578 0 0 0       if ($name eq "regcomp" && $op->other->pmflags & B::PMf_KEEP) {
579 0           $op_target{${$op->first}}++;
  0            
580 0           $op_regcomp{${$op->first}} = $op->next;
  0            
581             }
582              
583             } elsif ($class eq "PMOP") {
584 0 0         if (${$op->pmreplstart}) {
  0            
585 0           unshift @todo, $op->pmreplstart;
586 0           $op_target{${$op->pmreplstart}}++;
  0            
587             }
588              
589             } elsif ($class eq "LOOP") {
590 0           my @targ = ($op->nextop, $op->lastop->next, $op->redoop);
591              
592 0           unshift @todo, $next, $op->redoop, $op->nextop, $op->lastop;
593 0           $next = $op->redoop;
594              
595 0           $op_target{$$_}++ for @targ;
596              
597 0           $insn->{loop_targ} = \@targ;
598 0           $curloop = $insn;
599              
600             } elsif ($class eq "COP") {
601 0 0         if (defined $op->label) {
602 0           $insn->{bblock}++;
603 0 0         $curloop->{contains_label}{$op->label}++ if $curloop; #TODO: should be within loop
604             }
605              
606             } else {
607 0 0         if ($name eq "pushmark") {
608 0           $numpushmark++;
609             }
610             }
611             }
612             }
613              
614 0           $_->{bblock}++ for grep $op_target{${$_->{op}}}, @ops;
  0            
615              
616 0           local $source = <
617             OP *%%%FUNC%%% (pTHX)
618             {
619 0           register OP *nextop = (OP *)${$ops[0]->{op}}L;
620             EOF
621              
622 0 0         $source .= " faster_PUSHMARK_PREALLOC ($numpushmark);\n"
623             if $numpushmark;
624              
625 0           while (@ops) {
626 0           $insn = shift @ops;
627              
628 0           $op = $insn->{op};
629 0           $op_name = $op->name;
630              
631 0           my $class = B::class $op;
632              
633 0 0         $source .= "\n/* start basic block */\n" if exists $insn->{bblock};#d#
634 0           $source .= "op_$$op: /* $op_name */\n";
635             #$source .= "fprintf (stderr, \"$$op in op $op_name\\n\");\n";#d#
636             #$source .= "{ dSP; sv_dump (TOPs); }\n";#d#
637              
638 0 0         $source .= " PERL_ASYNC_CHECK ();\n"
639             unless exists $f_noasync{$op_name};
640              
641 0 0         if (my $can = __PACKAGE__->can ("op_$op_name")) {
    0          
    0          
    0          
642             # handcrafted replacement
643              
644 0 0         if ($insn->{extend} > 0) {
645             # coalesce EXTENDs
646             # TODO: properly take negative preceeding and following EXTENDs into account
647 0           for my $i (@ops) {
648 0 0         last if exists $i->{bblock};
649 0 0         last unless exists $i->{extend};
650 0           my $extend = delete $i->{extend};
651 0 0         $insn->{extend} += $extend if $extend > 0;
652             }
653              
654 0 0         $source .= " { dSP; EXTEND (SP, $insn->{extend}); PUTBACK; }\n"
655             if $insn->{extend} > 0;
656             }
657              
658 0           $can->($op);
659              
660             } elsif (exists $f_unsafe{$op_name}) {
661             # unsafe, return to interpreter
662 0           assert "nextop == (OP *)$$op";
663 0           $source .= " return nextop;\n";
664              
665             } elsif ("LOGOP" eq $class) {
666             # logical operation with optional branch
667 0           out_callop;
668 0           out_cond_jump $op->other;
669 0           out_jump_next;
670              
671             } elsif ("PMOP" eq $class) {
672             # regex-thingy
673 0           out_callop;
674 0 0 0       out_cond_jump $op->pmreplroot if $op_name ne "pushre" && ${$op->pmreplroot};
  0            
675 0           out_jump_next;
676              
677             } else {
678             # normal operator, linear execution
679 0           out_linear;
680             }
681             }
682              
683 0           $op_name = "func exit"; assert (0);
  0            
684              
685 0           $source .= <
686             op_0:
687             return 0;
688             }
689             EOF
690             #warn $source;
691              
692 0           $source
693             }
694              
695             my $uid = "aaaaaaa0";
696             my %so;
697              
698             sub func2ptr {
699 0     0 0   my (@func) = @_;
700              
701             #LOCK
702 0           mkdir $CACHEDIR, 0777;
703 0 0         sysopen my $meta_fh, "$CACHEDIR/meta", &Fcntl::O_RDWR | &Fcntl::O_CREAT, 0666
704             or die "$$CACHEDIR/meta: $!";
705 0           binmode $meta_fh, ":raw:perlio";
706 0 0         fcntl_lock fileno $meta_fh
707             or die "$CACHEDIR/meta: $!";
708              
709 0   0       my $meta = eval { Storable::fd_retrieve $meta_fh } || { version => 1 };
710              
711 0           for my $f (@func) {
712 0           $f->{func} = "F" . Digest::MD5::md5_hex ($f->{source});
713 0           $f->{so} = $meta->{$f->{func}};
714             }
715              
716 0 0         if (grep !$_->{so}, @func) {
717 0           my $stem;
718            
719 0           do {
720 0           $stem = "$CACHEDIR/$$-" . $uid++;
721             } while -e "$stem$_so";
722              
723 0           open my $fh, ">:raw", "$stem.c";
724 0           print $fh <
725             #define PERL_NO_GET_CONTEXT
726             #define PERL_CORE
727              
728             #include
729              
730             #include "EXTERN.h"
731             #include "perl.h"
732             #include "XSUB.h"
733              
734             #if 1
735             # define faster_PUSHMARK_PREALLOC(count) while (PL_markstack_ptr + (count) >= PL_markstack_max) markstack_grow ()
736             # define faster_PUSHMARK(p) *++PL_markstack_ptr = (p) - PL_stack_base
737             #else
738             # define faster_PUSHMARK_PREALLOC(count) 1
739             # define faster_PUSHMARK(p) PUSHMARK(p)
740             #endif
741              
742             #define RUNOPS_TILL(op) \\
743             while (nextop != (op)) \\
744             { \\
745             PERL_ASYNC_CHECK (); \\
746             PL_op = nextop; nextop = (PL_op->op_ppaddr)(aTHX); \\
747             }
748              
749             EOF
750 0           for my $f (grep !$_->{so}, @func) {
751 0 0         next if $f->{so} = $meta->{$f->{func}}; # some cv's alias others
752              
753 0 0         warn "compiling $f->{name} to $stem$_so:$f->{func}\n" if $verbose > 1;
754 0           my $source = $f->{source};
755 0           $source =~ s/%%%FUNC%%%/$f->{func}/g;
756 0           print $fh $source;
757 0           $meta->{$f->{func}} = $f->{so} = $stem;
758             }
759              
760 0           close $fh;
761 0           system "$COMPILE -o $stem$_o $stem.c";
762 0 0         unlink "$stem.c" unless $ENV{FASTER_DEBUG} & 1;
763 0           system "$LINK -o $stem$_so $stem$_o $LIBS";
764 0           unlink "$stem$_o";
765             }
766              
767 0           for my $f (@func) {
768 0           my $stem = $f->{so};
769              
770 0 0 0       my $so = ($so{$stem} ||= DynaLoader::dl_load_file "$stem$_so")
771             or die "$stem$_so: $!";
772              
773             #unlink "$stem$_so";
774              
775 0 0         $f->{ptr} = DynaLoader::dl_find_symbol $so, $f->{func}
776             or die "$f->{func} not found in $stem$_so: $!";
777             }
778              
779 0 0         seek $meta_fh, 0, 0 or die "$CACHEDIR/meta: $!";
780 0           Storable::nstore_fd $meta, $meta_fh;
781 0           truncate $meta_fh, tell $meta_fh;
782              
783             # UNLOCK (by closing $meta_fh)
784             }
785              
786             my %ignore;
787              
788             sub entersub {
789 0     0 0   my ($cv) = @_;
790              
791 0           my $pkg = $cv->STASH->NAME;
792              
793 0 0         return if $ignore{$pkg};
794              
795 0 0         warn "optimising ", $cv->STASH->NAME, "\n"
796             if $verbose;
797              
798 0           eval {
799 0           my @func;
800              
801 0           push @func, {
802             cv => $cv,
803             name => "<>",
804             source => cv2c $cv,
805             };
806              
807             # always compile the whole stash
808 0           my %stash = $cv->STASH->ARRAY;
809 0           while (my ($k, $v) = each %stash) {
810 0 0         $v->isa (B::GV::)
811             or next;
812              
813 0           my $cv = $v->CV;
814              
815 0 0 0       if ($cv->isa (B::CV::)
  0   0        
816             && ${$cv->START}
817             && $cv->START->name ne "null") {
818              
819 0           push @func, {
820             cv => $cv,
821             name => $k,
822             source => cv2c $cv,
823             };
824             }
825             }
826              
827 0           func2ptr @func;
828              
829 0           for my $f (@func) {
830 0           patch_cv $f->{cv}, $f->{ptr};
831             }
832             };
833              
834 0 0         if ($@) {
835 0           $ignore{$pkg}++;
836 0           warn $@;
837             }
838             }
839              
840             hook_entersub;
841              
842             1;
843              
844             =back
845              
846             =head1 ENVIRONMENT VARIABLES
847              
848             The following environment variables influence the behaviour of Faster:
849              
850             =over 4
851              
852             =item FASTER_VERBOSE
853              
854             Faster will output more informational messages when set to values higher
855             than C<0>. Currently, C<1> outputs which packages are being compiled, C<3>
856             outputs the cache directory and C<10> outputs information on which perl
857             function is compiled into which shared object.
858              
859             =item FASTER_DEBUG
860              
861             Add debugging code when set to values higher than C<0>. Currently, this
862             adds 1-3 C's per perl op (FASTER_DEBUG > 1), to ensure that opcode
863             order and C execution order are compatible.
864              
865             =item FASTER_CACHE
866              
867             Set a persistent cache directory that caches compiled code fragments. The
868             default is C<$HOME/.perl-faster-cache> if C is set and a temporary
869             directory otherwise.
870              
871             This directory will always grow in size, so you might need to erase it
872             from time to time.
873              
874             =back
875              
876             =head1 BUGS/LIMITATIONS
877              
878             Perl will check much less often for asynchronous signals in
879             Faster-compiled code. It tries to check on every function call, loop
880             iteration and every I/O operator, though.
881              
882             The following things will disable Faster. If you manage to enable them at
883             runtime, bad things will happen. Enabling them at startup will be fine,
884             though.
885              
886             enabled tainting
887             enabled debugging
888              
889             Thread-enabled builds of perl will dramatically reduce Faster's
890             performance, but you don't care about speed if you enable threads anyway.
891              
892             These constructs will force the use of the interpreter for the currently
893             executed function as soon as they are being encountered during execution.
894              
895             goto
896             next, redo (but not well-behaved last's)
897             labels, if used
898             eval
899             require
900             any use of formats
901             .., ... (flipflop operators)
902              
903             =head1 AUTHOR
904              
905             Marc Lehmann
906             http://home.schmorp.de/
907              
908             =cut
909