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

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines