ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Faster/Faster.pm
(Generate patch)

Comparing Faster/Faster.pm (file contents):
Revision 1.2 by root, Thu Mar 9 06:03:12 2006 UTC vs.
Revision 1.28 by root, Sun Mar 12 17:03:39 2006 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines