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

Comparing Faster/Faster.pm (file contents):
Revision 1.30 by root, Mon Mar 13 16:59:36 2006 UTC vs.
Revision 1.36 by root, Sat Feb 21 08:27:38 2009 UTC

8 8
9 perl -MFaster ... 9 perl -MFaster ...
10 10
11=head1 DESCRIPTION 11=head1 DESCRIPTION
12 12
13This module implements a very simple-minded JIT. It works by more or less 13This module implements a very simple-minded "JIT" (or actually AIT, ahead
14translating every function it sees into a C program, compiling it and then 14of time compiler). It works by more or less translating every function it
15replacing the function by the compiled code. 15sees into a C program, compiling it and then replacing the function by the
16compiled code.
16 17
17As a result, startup times are immense, as every function might lead to a 18As a result, startup times are immense, as every function might lead to a
18full-blown compilation. 19full-blown compilation.
19 20
20The speed improvements are also not great, you can expect 20% or so on 21The speed improvements are also not great, you can expect 20% or so on
21average, for code that runs very often. 22average, for code that runs very often. The reason for this is that data
23handling is mostly being done by the same old code, it just gets called
24a bit faster. Regexes and string operations won't get faster. Airhtmetic
25doresn't become any faster. Just the operands and other stuff is put on
26the stack faster, and the opcodes themselves have a bit less overhead.
22 27
23Faster is in the early stages of development. Due to its design its 28Faster 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 29relatively safe to use (it will either work or simply slowdown the program
25immensely, but rarely cause bugs). 30immensely, but rarely cause bugs).
26 31
32More intelligent algorithms (loop optimisation, type inference) could
33improve that easily, but requires a much more elaborate presentation and
34optimiser than what is in place. There are no plans to improve Faster in
35this way, yet, but it would provide a reasonably good place to start.
36
27Usage is very easy, just C<use Faster> and every function called from then 37Usage is very easy, just C<use Faster> and every function called from then
28on will be compiled. 38on will be compiled.
29 39
30Right now, Faster will leave lots of F<*.c>, F<*.o> and F<*.so> files in 40Right now, Faster can leave lots of F<*.c> and F<*.so> files in your
31your F<$FASTER_CACHEDIR> (by default F<$HOME/.perl-faster-cache>), and it 41F<$FASTER_CACHEDIR> (by default F<$HOME/.perl-faster-cache>), and it will
32will even create those temporary files in an insecure manner, so watch 42even create those temporary files in an insecure manner, so watch out.
33out.
34 43
35=over 4 44=over 4
36 45
37=cut 46=cut
38 47
47use Digest::MD5 (); 56use Digest::MD5 ();
48use Storable (); 57use Storable ();
49use Fcntl (); 58use Fcntl ();
50 59
51BEGIN { 60BEGIN {
52 our $VERSION = '0.01'; 61 our $VERSION = '0.1';
53 62
54 require XSLoader; 63 require XSLoader;
55 XSLoader::load __PACKAGE__, $VERSION; 64 XSLoader::load __PACKAGE__, $VERSION;
56} 65}
57 66
63 File::Temp::tempdir (CLEANUP => 1) 72 File::Temp::tempdir (CLEANUP => 1)
64 }; 73 };
65 74
66my $COMPILE = "$Config{cc} -c -I$Config{archlibexp}/CORE $Config{optimize} $Config{ccflags} $Config{cccdlflags}"; 75my $COMPILE = "$Config{cc} -c -I$Config{archlibexp}/CORE $Config{optimize} $Config{ccflags} $Config{cccdlflags}";
67my $LINK = "$Config{ld} $Config{ldflags} $Config{lddlflags} $Config{ccdlflags}"; 76my $LINK = "$Config{ld} $Config{ldflags} $Config{lddlflags} $Config{ccdlflags}";
68my $LIBS = "$Config{libs}"; 77my $LIBS = "";
69my $_o = $Config{_o}; 78my $_o = $Config{_o};
70my $_so = ".so"; 79my $_so = ".so";
71 80
72# we don't need no steenking PIC on x86 81# we don't need no steenking PIC on x86
73$COMPILE =~ s/-f(?:PIC|pic)//g 82$COMPILE =~ s/-f(?:PIC|pic)//g
74 if $Config{archname} =~ /^(i[3456]86)-/; 83 if $Config{archname} =~ /^(i[3456]86)-/;
75 84
76my $opt_assert = $ENV{FASTER_DEBUG} > 1; 85my $opt_assert = $ENV{FASTER_DEBUG} & 2;
77my $verbose = $ENV{FASTER_VERBOSE}+0; 86my $verbose = $ENV{FASTER_VERBOSE}+0;
78 87
79warn "Faster: CACHEDIR is $CACHEDIR\n" if $verbose > 2; 88warn "Faster: CACHEDIR is $CACHEDIR\n" if $verbose > 2;
80 89
81our $source; 90our $source;
82 91
83our @ops; 92our @ops;
84our $insn; 93our $insn;
85our $op; 94our $op;
86our $op_name; 95our $op_name;
87our @op_loop;
88our %op_regcomp; 96our %op_regcomp;
89 97
90# ops that cause immediate return to the interpreter 98# ops that cause immediate return to the interpreter
91my %f_unsafe = map +($_ => undef), qw( 99my %f_unsafe = map +($_ => undef), qw(
92 leavesub leavesublv return 100 leavesub leavesublv return
154 padsv padav padhv padany 162 padsv padav padhv padany
155 aassign sassign orassign 163 aassign sassign orassign
156 rv2av rv2cv rv2gv rv2hv refgen 164 rv2av rv2cv rv2gv rv2hv refgen
157 gv gvsv 165 gv gvsv
158 add subtract multiply divide 166 add subtract multiply divide
159 complement cond_expr and or not bit_and bit_or bit_xor 167 complement cond_expr and or not
168 bit_and bit_or bit_xor
160 defined 169 defined
161 method method_named bless 170 method method_named bless
162 preinc postinc predec postdec 171 preinc postinc predec postdec
163 aelem aelemfast helem delete exists 172 aelem aelemfast helem delete exists
164 pushre subst list lslice join split concat 173 pushre subst list lslice join split concat
185sub out_callop { 194sub out_callop {
186 assert "nextop == (OP *)$$op"; 195 assert "nextop == (OP *)$$op";
187 $source .= " PL_op = nextop; nextop = " . (callop $op) . ";\n"; 196 $source .= " PL_op = nextop; nextop = " . (callop $op) . ";\n";
188} 197}
189 198
199sub out_jump {
200 assert "nextop == (OP *)${$_[0]}L";
201 $source .= " goto op_${$_[0]};\n";
202}
203
190sub out_cond_jump { 204sub out_cond_jump {
191 $source .= " if (nextop == (OP *)${$_[0]}L) goto op_${$_[0]};\n"; 205 $source .= " if (nextop == (OP *)${$_[0]}L) goto op_${$_[0]};\n";
192} 206}
193 207
194sub out_jump_next { 208sub out_jump_next {
485} 499}
486 500
487sub out_break_op { 501sub out_break_op {
488 my ($idx) = @_; 502 my ($idx) = @_;
489 503
504 if ($op->flags & B::OPf_SPECIAL && $insn->{loop}) {
505 # common case: no label, innermost loop only
506 my $next = $insn->{loop}{loop_targ}[$idx];
490 out_callop; 507 out_callop;
491 508 out_jump $next;
492 out_cond_jump $_->[$idx] 509 } elsif (my $loop = $insn->{loop}) {
493 for reverse @op_loop; 510 # less common case: maybe break to some outer loop
494
495 $source .= " return nextop;\n"; 511 $source .= " return nextop;\n";
512 # todo: walk stack up
513 } else {
514 # fuck yourself for writing such hacks
515 $source .= " return nextop;\n";
516 }
496} 517}
497 518
498sub xop_next { 519sub op_next {
499 out_break_op 0; 520 out_break_op 0;
500} 521}
501 522
502sub op_last { 523sub op_last {
503 out_break_op 1; 524 out_break_op 1;
504} 525}
505 526
527# TODO: does not seem to work
506sub xop_redo { 528#sub op_redo {
507 out_break_op 2; 529# out_break_op 2;
508} 530#}
509 531
510sub cv2c { 532sub cv2c {
511 my ($cv) = @_; 533 my ($cv) = @_;
512 534
513 local @ops; 535 local @ops;
514 local @op_loop;
515 local %op_regcomp; 536 local %op_regcomp;
516 537
517 my %opsseen; 538 my $curloop;
518 my @todo = $cv->START; 539 my @todo = $cv->START;
519 my %op_target; 540 my %op_target;
520 my $numpushmark; 541 my $numpushmark;
542 my $scope;
521 543
544 my %op_seen;
522 while (my $op = shift @todo) { 545 while (my $op = shift @todo) {
546 my $next;
523 for (; $$op; $op = $op->next) { 547 for (; $$op; $op = $next) {
524 last if $opsseen{$$op}++; 548 last if $op_seen{$$op}++;
549
550 $next = $op->next;
525 551
526 my $name = $op->name; 552 my $name = $op->name;
527 my $class = B::class $op; 553 my $class = B::class $op;
528 554
529 my $insn = { op => $op }; 555 my $insn = { op => $op };
556
557 # end of loop reached?
558 $curloop = $curloop->{loop} if $curloop && $$op == ${$curloop->{loop_targ}[1]};
559
560 # remember enclosing loop
561 $insn->{loop} = $curloop if $curloop;
530 562
531 push @ops, $insn; 563 push @ops, $insn;
532 564
533 if (exists $extend{$name}) { 565 if (exists $extend{$name}) {
534 my $extend = $extend{$name}; 566 my $extend = $extend{$name};
535 $extend = $extend->($op) if ref $extend; 567 $extend = $extend->($op) if ref $extend;
536 $insn->{extend} = $extend if defined $extend; 568 $insn->{extend} = $extend if defined $extend;
537 } 569 }
538 570
539 push @todo, $op->next; 571 # TODO: mark scopes similar to loops, make them comparable
540 572 # static cxstack(?)
541 if ($class eq "LOGOP") { 573 if ($class eq "LOGOP") {
542 push @todo, $op->other; 574 push @todo, $op->other;
543 $op_target{${$op->other}}++; 575 $op_target{${$op->other}}++;
544 576
545 # regcomp/o patches ops at runtime, lets expect that 577 # regcomp/o patches ops at runtime, lets expect that
553 unshift @todo, $op->pmreplstart; 585 unshift @todo, $op->pmreplstart;
554 $op_target{${$op->pmreplstart}}++; 586 $op_target{${$op->pmreplstart}}++;
555 } 587 }
556 588
557 } elsif ($class eq "LOOP") { 589 } elsif ($class eq "LOOP") {
558 my @targ = ($op->nextop, $op->lastop->next, $op->redoop->next); 590 my @targ = ($op->nextop, $op->lastop->next, $op->redoop);
559 591
560 push @op_loop, \@targ; 592 unshift @todo, $next, $op->redoop, $op->nextop, $op->lastop;
561 push @todo, @targ; 593 $next = $op->redoop;
562 594
563 $op_target{$$_}++ for @targ; 595 $op_target{$$_}++ for @targ;
564 596
597 $insn->{loop_targ} = \@targ;
598 $curloop = $insn;
599
565 } elsif ($class eq "COP") { 600 } elsif ($class eq "COP") {
566 $insn->{bblock}++ if defined $op->label; 601 if (defined $op->label) {
602 $insn->{bblock}++;
603 $curloop->{contains_label}{$op->label}++ if $curloop; #TODO: should be within loop
604 }
567 605
568 } else { 606 } else {
569 if ($name eq "pushmark") { 607 if ($name eq "pushmark") {
570 $numpushmark++; 608 $numpushmark++;
571 } 609 }
719 $meta->{$f->{func}} = $f->{so} = $stem; 757 $meta->{$f->{func}} = $f->{so} = $stem;
720 } 758 }
721 759
722 close $fh; 760 close $fh;
723 system "$COMPILE -o $stem$_o $stem.c"; 761 system "$COMPILE -o $stem$_o $stem.c";
724 unlink "$stem.c" unless $ENV{FASTER_DEBUG} > 0; 762 unlink "$stem.c" unless $ENV{FASTER_DEBUG} & 1;
725 system "$LINK -o $stem$_so $stem$_o $LIBS"; 763 system "$LINK -o $stem$_so $stem$_o $LIBS";
726 unlink "$stem$_o"; 764 unlink "$stem$_o";
727 } 765 }
728 766
729 for my $f (@func) { 767 for my $f (@func) {
854These constructs will force the use of the interpreter for the currently 892These constructs will force the use of the interpreter for the currently
855executed function as soon as they are being encountered during execution. 893executed function as soon as they are being encountered during execution.
856 894
857 goto 895 goto
858 next, redo (but not well-behaved last's) 896 next, redo (but not well-behaved last's)
897 labels, if used
859 eval 898 eval
860 require 899 require
861 any use of formats 900 any use of formats
862 .., ... (flipflop operators) 901 .., ... (flipflop operators)
863 902

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines