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

Comparing Faster/Faster.pm (file contents):
Revision 1.18 by root, Fri Mar 10 19:52:07 2006 UTC vs.
Revision 1.25 by root, Sat Mar 11 04:58:53 2006 UTC

25immensely, but rarely cause bugs). 25immensely, but rarely cause bugs).
26 26
27Usage is very easy, just C<use Faster> and every function called from then 27Usage is very easy, just C<use Faster> and every function called from then
28on will be compiled. 28on will be compiled.
29 29
30Right now, Faster will leave ltos of F<*.c>, F<*.o> and F<*.so> files in 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 31F</tmp>, and it will even create those temporary files in an insecure
32manner, so watch out. 32manner, so watch out.
33 33
34=over 4 34=over 4
35 35
36=cut 36=cut
37 37
38package Faster; 38package Faster;
39
40no warnings;
39 41
40use strict; 42use strict;
41use Config; 43use Config;
42use B (); 44use B ();
43use Digest::MD5 (); 45#use Digest::MD5 ();
44use DynaLoader (); 46use DynaLoader ();
47use File::Temp ();
45 48
46BEGIN { 49BEGIN {
47 our $VERSION = '0.01'; 50 our $VERSION = '0.01';
48 51
49 require XSLoader; 52 require XSLoader;
58 61
59# we don't need no steenking PIC on x86 62# we don't need no steenking PIC on x86
60$COMPILE =~ s/-f(?:PIC|pic)//g 63$COMPILE =~ s/-f(?:PIC|pic)//g
61 if $Config{archname} =~ /^(i[3456]86)-/; 64 if $Config{archname} =~ /^(i[3456]86)-/;
62 65
63my $opt_assert = 1; 66my $opt_assert = $ENV{FASTER_DEBUG};
67my $verbose = $ENV{FASTER_VERBOSE}+0;
64 68
65our $source; 69our $source;
66 70
67our @ops; 71our @ops;
72our $insn;
68our $op; 73our $op;
69our $op_name; 74our $op_name;
70our @op_loop; 75our @op_loop;
71our %op_regcomp; 76our %op_regcomp;
72 77
73my %flag; 78# ops that cause immediate return to the interpreter
79my %f_unsafe = map +($_ => undef), qw(
80 leavesub leavesublv return
81 goto last redo next
82 eval flip leaveeval entertry
83 formline grepstart mapstart
84 substcont entereval require
85);
74 86
75# complex flag steting is no longer required, rewrite this ugly code 87# ops with known stack extend behaviour
76for (split /\n/, <<EOF) { 88# the values given are maximum values
77 leavesub unsafe 89my %extend = (
78 leavesublv unsafe 90 pushmark => 0,
79 return unsafe 91 nextstate => 0, # might reduce the stack
80 flip unsafe 92 unstack => 0,
81 goto unsafe 93 enter => 0,
82 last unsafe
83 redo unsafe
84 next unsafe
85 eval unsafe
86 leaveeval unsafe
87 entertry unsafe
88 formline unsafe
89 grepstart unsafe
90 mapstart unsafe
91 substcont unsafe
92 entereval unsafe noasync todo
93 require unsafe
94 94
95 mapstart noasync 95 stringify => 0,
96 grepstart noasync 96 not => 0,
97 match noasync 97 and => 0,
98 or => 0,
99 gvsv => 0,
100 rv2gv => 0,
101 preinc => 0,
102 predec => 0,
103 postinc => 0,
104 postdec => 0,
105 aelem => 0,
106 helem => 0,
107 qr => 1, #???
108 pushre => 1,
109 gv => 1,
110 aelemfast => 1,
111 aelem => 0,
112 padsv => 1,
113 const => 1,
114 pop => 1,
115 shift => 1,
116 eq => -1,
117 ne => -1,
118 gt => -1,
119 lt => -1,
120 ge => -1,
121 lt => -1,
122 cond_expr => -1,
123 add => -1,
124 subtract => -1,
125 multiply => -1,
126 divide => -1,
127 aassign => 0,
128 sassign => -2,
129 method => 0,
130 method_named => 1,
131);
98 132
99 last noasync 133# ops that do not need an ASYNC_CHECK
100 next noasync 134my %f_noasync = map +($_ => undef), qw(
101 redo noasync 135 mapstart grepstart match entereval
102 seq noasync 136 enteriter entersub leaveloop
103 pushmark noasync extend=0
104 padsv noasync extend=1
105 padav noasync extend=1
106 padhv noasync extend=1
107 padany noasync extend=1
108 entersub noasync
109 aassign noasync
110 sassign noasync
111 rv2av noasync
112 rv2cv noasync
113 rv2gv noasync
114 rv2hv noasync
115 refgen noasync
116 nextstate noasync
117 gv noasync
118 gvsv noasync
119 add noasync
120 subtract noasync
121 multiply noasync
122 divide noasync
123 complement noasync
124 cond_expr noasync
125 and noasync
126 or noasync
127 not noasync
128 defined noasync
129 method_named noasync
130 preinc noasync
131 postinc noasync
132 predec noasync
133 postdec noasync
134 stub noasync
135 unstack noasync
136 leaveloop noasync
137 aelem noasync
138 aelemfast noasync
139 helem noasync
140 pushre noasync
141 subst noasync
142 const noasync extend=1
143 list noasync
144 join noasync
145 split noasync
146 concat noasync
147 push noasync
148 pop noasync
149 shift noasync
150 unshift noasync
151 length noasync
152 substr noasync
153 stringify noasync
154 eq noasync
155 ne noasync
156 gt noasync
157 lt noasync
158 ge noasync
159 le noasync
160 enteriter noasync
161 ord noasync
162 orassign noasync
163 regcomp noasync
164 regcreset noasync
165 regcmaybe noasync
166 137
167 iter async 138 pushmark nextstate
168EOF
169 my (undef, $op, @flags) = split /\s+/;
170 139
171 undef $flag{$_}{$op} 140 const stub unstack
172 for ("known", @flags); 141 last next redo seq
173} 142 padsv padav padhv padany
143 aassign sassign orassign
144 rv2av rv2cv rv2gv rv2hv refgen
145 gv gvsv
146 add subtract multiply divide
147 complement cond_expr and or not
148 defined
149 method method_named bless
150 preinc postinc predec postdec
151 aelem aelemfast helem delete exists
152 pushre subst list join split concat
153 length substr stringify ord
154 push pop shift unshift
155 eq ne gt lt ge le
156 regcomp regcreset regcmaybe
157);
174 158
175my %callop = ( 159my %callop = (
176 entersub => "(PL_ppaddr [OP_ENTERSUB]) (aTHX)", 160 entersub => "(PL_ppaddr [OP_ENTERSUB]) (aTHX)",
177 mapstart => "Perl_pp_grepstart (aTHX)", 161 mapstart => "Perl_pp_grepstart (aTHX)",
178); 162);
238 222
239if ($Config{useithreads} ne "define") { 223if ($Config{useithreads} ne "define") {
240 # disable optimisations on ithreads 224 # disable optimisations on ithreads
241 225
242 *op_const = sub { 226 *op_const = sub {
243 $source .= " { dSP; XPUSHs ((SV *)${$op->sv}L); PUTBACK; }\n"; 227 $source .= " { dSP; PUSHs ((SV *)${$op->sv}L); PUTBACK; }\n";
244 228
245 out_next; 229 out_next;
246 }; 230 };
247 231
248 *op_gv = \&op_const; 232 *op_gv = \&op_const;
268 if (!($op->flags & B::OPf_MOD)) { 252 if (!($op->flags & B::OPf_MOD)) {
269 $source .= " if (SvGMAGICAL (sv)) sv = sv_mortalcopy (sv);\n"; 253 $source .= " if (SvGMAGICAL (sv)) sv = sv_mortalcopy (sv);\n";
270 } 254 }
271 255
272 $source .= " dSP;\n"; 256 $source .= " dSP;\n";
273 $source .= " XPUSHs (sv);\n"; 257 $source .= " PUSHs (sv);\n";
274 $source .= " PUTBACK;\n"; 258 $source .= " PUTBACK;\n";
275 $source .= " }\n"; 259 $source .= " }\n";
276 260
277 out_next; 261 out_next;
278 }; 262 };
279 263
280 *op_gvsv = sub { 264 *op_gvsv = sub {
281 $source .= " {\n"; 265 $source .= " {\n";
282 $source .= " dSP;\n"; 266 $source .= " dSP;\n";
283 $source .= " EXTEND (SP, 1);\n";
284 267
285 if ($op->private & B::OPpLVAL_INTRO) { 268 if ($op->private & B::OPpLVAL_INTRO) {
286 $source .= " PUSHs (save_scalar ((GV *)${$op->sv}L));\n"; 269 $source .= " PUSHs (save_scalar ((GV *)${$op->sv}L));\n";
287 } else { 270 } else {
288 $source .= " PUSHs (GvSV ((GV *)${$op->sv}L));\n"; 271 $source .= " PUSHs (GvSV ((GV *)${$op->sv}L));\n";
348 out_next; 331 out_next;
349} 332}
350 333
351sub op_padsv { 334sub op_padsv {
352 my $flags = $op->flags; 335 my $flags = $op->flags;
353 my $target = $op->targ; 336 my $padofs = "(PADOFFSET)" . $op->targ;
337
338 #d#TODO: why does our version break
339 # breaks gce with can't coerce array....
340 if (($flags & B::OPf_MOD) && ($op->private & B::OPpDEREF)) {#d#
341 return out_linear;#d#
342 }#d#
354 343
355 $source .= <<EOF; 344 $source .= <<EOF;
356 { 345 {
357 dSP; 346 dSP;
358 XPUSHs (PAD_SV ((PADOFFSET)$target)); 347 SV *sv = PAD_SVl ($padofs);
348EOF
349
350 if (($flags & B::OPf_MOD) && ($op->private & B::OPpLVAL_INTRO)) {
351 $source .= " SAVECLEARSV (PAD_SVl ($padofs));\n";
352 $ops[0]{pre_padsv_lval_intro}++ if @ops;#d#
353 }
354
355 $source .= <<EOF;
356 PUSHs (sv);
359 PUTBACK; 357 PUTBACK;
360EOF 358EOF
361 if ($op->flags & B::OPf_MOD) { 359
362 if ($op->private & B::OPpLVAL_INTRO) { 360 if (($flags & B::OPf_MOD) && ($op->private & B::OPpDEREF)) {
363 $source .= " SAVECLEARSV (PAD_SVl ((PADOFFSET)$target));\n"; 361 $source .= " vivify_ref (sv, $flags & OPpDEREF);\n";
364 } elsif ($op->private & B::OPpDEREF) {
365 my $deref = $op->private & B::OPpDEREF;
366 $source .= " Perl_vivify_ref (PAD_SVl ((PADOFFSET)$target), $deref);\n";
367 }
368 } 362 }
363 $source .= " }\n";
364
365 out_next;
366}
367
368sub op_sassign {
369 $source .= <<EOF;
370 {
371 dSP;
372 dPOPTOPssrl;
373EOF
374 $source .= " SV *temp = left; left = right; right = temp;\n"
375 if $op->private & B::OPpASSIGN_BACKWARDS;
376
377 if ($insn->{pre_padsv_lval_intro} && !($op->private & B::OPpASSIGN_BACKWARDS)) {
378 # simple assignment - the target exists, but is basically undef
379 $source .= " SvSetSV (right, left);\n";
380 } else {
381 $source .= " SvSetMagicSV (right, left);\n";
382 }
383
369 $source .= <<EOF; 384 $source .= <<EOF;
385 SETs (right);
386 PUTBACK;
370 } 387 }
371EOF 388EOF
372 389
373 out_next; 390 out_next;
374} 391}
375 392
376# pattern const+ (or general push1) 393# pattern const+ (or general push1)
377# pattern pushmark return(?) 394# pattern pushmark return(?)
378# pattern pushmark gv rv2av pushmark padsv+o.ä. aassign 395# pattern pushmark gv rv2av pushmark padsv+o.ä. aassign
394 411
395 /* simple "polymorphic" inline cache */ 412 /* simple "polymorphic" inline cache */
396 if (stash == last_stash 413 if (stash == last_stash
397 && PL_sub_generation == last_sub_generation) 414 && PL_sub_generation == last_sub_generation)
398 { 415 {
399 XPUSHs (last_cv); 416 PUSHs (last_cv);
400 PUTBACK; 417 PUTBACK;
401 } 418 }
402 else 419 else
403 { 420 {
404 PL_op = nextop; nextop = Perl_pp_method_named (aTHX); 421 PL_op = nextop; nextop = Perl_pp_method_named (aTHX);
466 local @op_loop; 483 local @op_loop;
467 local %op_regcomp; 484 local %op_regcomp;
468 485
469 my %opsseen; 486 my %opsseen;
470 my @todo = $cv->START; 487 my @todo = $cv->START;
488 my %op_target;
471 489
472 while (my $op = shift @todo) { 490 while (my $op = shift @todo) {
473 for (; $$op; $op = $op->next) { 491 for (; $$op; $op = $op->next) {
474 last if $opsseen{$$op}++; 492 last if $opsseen{$$op}++;
475 push @ops, $op;
476 493
477 my $name = $op->name; 494 my $name = $op->name;
478 my $class = B::class $op; 495 my $class = B::class $op;
479 496
497 my $insn = { op => $op };
498
499 push @ops, $insn;
500
501 if (exists $extend{$name}) {
502 my $extend = $extend{$name};
503 $extend = $extend->($op) if ref $extend;
504 $insn->{extend} = $extend if defined $extend;
505 }
506
507 push @todo, $op->next;
508
480 if ($class eq "LOGOP") { 509 if ($class eq "LOGOP") {
481 unshift @todo, $op->other; # unshift vs. push saves jumps 510 push @todo, $op->other;
511 $op_target{${$op->other}}++;
482 512
483 # regcomp/o patches ops at runtime, lets expect that 513 # regcomp/o patches ops at runtime, lets expect that
514 if ($name eq "regcomp" && $op->other->pmflags & B::PMf_KEEP) {
515 $op_target{${$op->first}}++;
484 $op_regcomp{${$op->first}} = $op->next 516 $op_regcomp{${$op->first}} = $op->next;
485 if $name eq "regcomp" && $op->other->pmflags & B::PMf_KEEP; 517 }
486 518
487 } elsif ($class eq "PMOP") { 519 } elsif ($class eq "PMOP") {
520 if (${$op->pmreplstart}) {
488 unshift @todo, $op->pmreplstart if ${$op->pmreplstart}; 521 unshift @todo, $op->pmreplstart;
522 $op_target{${$op->pmreplstart}}++;
523 }
489 524
490 } elsif ($class eq "LOOP") { 525 } elsif ($class eq "LOOP") {
491 push @op_loop, [$op->nextop, $op->lastop->next, $op->redoop->next];
492 push @todo, $op->nextop, $op->lastop->next, $op->redoop->next; 526 my @targ = ($op->nextop, $op->lastop->next, $op->redoop->next);
527
528 push @op_loop, \@targ;
529 push @todo, @targ;
530
531 $op_target{$$_}++ for @targ;
532 } elsif ($class eq "COP") {
533 $insn->{bblock}++ if defined $op->label;
493 } 534 }
494 } 535 }
495 } 536 }
537
538 $_->{bblock}++ for grep $op_target{${$_->{op}}}, @ops;
496 539
497 local $source = <<EOF; 540 local $source = <<EOF;
498OP *%%%FUNC%%% (pTHX) 541OP *%%%FUNC%%% (pTHX)
499{ 542{
500 register OP *nextop = (OP *)${$ops[0]}L; 543 register OP *nextop = (OP *)${$ops[0]->{op}}L;
501EOF 544EOF
502 545
503 while (@ops) { 546 while (@ops) {
504 $op = shift @ops; 547 $insn = shift @ops;
548
549 $op = $insn->{op};
505 $op_name = $op->name; 550 $op_name = $op->name;
506 551
552 my $class = B::class $op;
553
554 $source .= "\n/* start basic block */\n" if exists $insn->{bblock};#d#
507 $source .= "op_$$op: /* $op_name */\n"; 555 $source .= "op_$$op: /* $op_name */\n";
508 #$source .= "fprintf (stderr, \"$$op in op $op_name\\n\");\n";#d# 556 #$source .= "fprintf (stderr, \"$$op in op $op_name\\n\");\n";#d#
509 #$source .= "{ dSP; sv_dump (TOPs); }\n";#d# 557 #$source .= "{ dSP; sv_dump (TOPs); }\n";#d#
510 558
511 $source .= " PERL_ASYNC_CHECK ();\n" 559 $source .= " PERL_ASYNC_CHECK ();\n"
512 unless exists $flag{noasync}{$op_name}; 560 unless exists $f_noasync{$op_name};
513 561
514 if (my $can = __PACKAGE__->can ("op_$op_name")) { 562 if (my $can = __PACKAGE__->can ("op_$op_name")) {
515 # handcrafted replacement 563 # handcrafted replacement
564
565 if ($insn->{extend} > 0) {
566 # coalesce EXTENDs
567 # TODO: properly take negative preceeding and following EXTENDs into account
568 for my $i (@ops) {
569 last if exists $i->{bblock};
570 last unless exists $i->{extend};
571 my $extend = delete $i->{extend};
572 $insn->{extend} += $extend if $extend > 0;
573 }
574
575 $source .= " { dSP; EXTEND (SP, $insn->{extend}); PUTBACK; }\n"
576 if $insn->{extend} > 0;
577 }
578
516 $can->($op); 579 $can->($op);
517 580
518 } elsif (exists $flag{unsafe}{$op_name}) { 581 } elsif (exists $f_unsafe{$op_name}) {
519 # unsafe, return to interpreter 582 # unsafe, return to interpreter
520 assert "nextop == (OP *)$$op"; 583 assert "nextop == (OP *)$$op";
521 $source .= " return nextop;\n"; 584 $source .= " return nextop;\n";
522 585
523 } elsif ("LOGOP" eq B::class $op) { 586 } elsif ("LOGOP" eq $class) {
524 # logical operation with optionaö branch 587 # logical operation with optional branch
525 out_callop; 588 out_callop;
526 out_cond_jump $op->other; 589 out_cond_jump $op->other;
527 out_jump_next; 590 out_jump_next;
528 591
529 } elsif ("PMOP" eq B::class $op) { 592 } elsif ("PMOP" eq $class) {
530 # regex-thingy 593 # regex-thingy
531 out_callop; 594 out_callop;
532 out_cond_jump $op->pmreplroot if ${$op->pmreplroot}; 595 out_cond_jump $op->pmreplroot if $op_name ne "pushre" && ${$op->pmreplroot};
533 out_jump_next; 596 out_jump_next;
534 597
535 } else { 598 } else {
536 # normal operator, linear execution 599 # normal operator, linear execution
537 out_linear; 600 out_linear;
548 #warn $source; 611 #warn $source;
549 612
550 $source 613 $source
551} 614}
552 615
616my $uid = "aaaaaaa0";
617
553sub source2ptr { 618sub source2ptr {
554 my ($source) = @_; 619 my (@source) = @_;
555 620
556 my $md5 = Digest::MD5::md5_hex $source; 621 my $stem = "/tmp/Faster-$$-" . $uid++;
557 $source =~ s/%%%FUNC%%%/Faster_$md5/;
558 622
559 my $stem = "/tmp/$md5";
560
561 unless (-e "$stem$_so") {
562 open FILE, ">:raw", "$stem.c"; 623 open FILE, ">:raw", "$stem.c";
563 print FILE <<EOF; 624 print FILE <<EOF;
564#define PERL_NO_GET_CONTEXT 625#define PERL_NO_GET_CONTEXT
626#define PERL_CORE
565 627
566#include <assert.h> 628#include <assert.h>
567 629
568#include "EXTERN.h" 630#include "EXTERN.h"
569#include "perl.h" 631#include "perl.h"
570#include "XSUB.h" 632#include "XSUB.h"
571 633
572#define RUNOPS_TILL(op) \\ 634#define RUNOPS_TILL(op) \\
573 while (nextop != (op)) \\ 635while (nextop != (op)) \\
574 { \\ 636 { \\
575 PERL_ASYNC_CHECK (); \\ 637 PERL_ASYNC_CHECK (); \\
576 PL_op = nextop; nextop = (PL_op->op_ppaddr)(aTHX); \\ 638 PL_op = nextop; nextop = (PL_op->op_ppaddr)(aTHX); \\
577 } 639 }
578 640
579EOF 641EOF
642 for (@source) {
643 my $func = $uid++;
644 $_ =~ s/%%%FUNC%%%/$func/g;
580 print FILE $source; 645 print FILE $_;
581 close FILE; 646 $_ = $func;
582 system "$COMPILE -o $stem$_o $stem.c";
583 system "$LINK -o $stem$_so $stem$_o $LIBS";
584 } 647 }
585 648
586# warn $source; 649 close FILE;
650 system "$COMPILE -o $stem$_o $stem.c";
651 #d#unlink "$stem.c";
652 system "$LINK -o $stem$_so $stem$_o $LIBS";
653 unlink "$stem$_o";
654
587 my $so = DynaLoader::dl_load_file "$stem$_so" 655 my $so = DynaLoader::dl_load_file "$stem$_so"
588 or die "$stem$_so: $!"; 656 or die "$stem$_so: $!";
589 657
590 DynaLoader::dl_find_symbol $so, "Faster_$md5" 658 #unlink "$stem$_so";
591 or die "Faster_$md5: $!" 659
660 map +(DynaLoader::dl_find_symbol $so, $_), @source
592} 661}
662
663my %ignore;
593 664
594sub entersub { 665sub entersub {
595 my ($cv) = @_; 666 my ($cv) = @_;
596 667
597 # always compile the whole stash 668 my $pkg = $cv->STASH->NAME;
598# my @stash = $cv->STASH->ARRAY; 669
599# warn join ":", @stash; 670 return if $ignore{$pkg};
600# exit; 671
672 warn "compiling ", $cv->STASH->NAME, "\n"
673 if $verbose;
601 674
602 eval { 675 eval {
603 my $source = cv2c $cv; 676 my @cv;
677 my @cv_source;
604 678
679 # always compile the whole stash
680 my %stash = $cv->STASH->ARRAY;
681 while (my ($k, $v) = each %stash) {
682 $v->isa (B::GV::)
683 or next;
684
685 my $cv = $v->CV;
686
687 if ($cv->isa (B::CV::)
688 && ${$cv->START}
689 && $cv->START->name ne "null") {
690 push @cv, $cv;
691 push @cv_source, cv2c $cv;
692 }
693 }
694
605 my $ptr = source2ptr $source; 695 my @ptr = source2ptr @cv_source;
606 696
697 for (0 .. $#cv) {
607 patch_cv $cv, $ptr; 698 patch_cv $cv[$_], $ptr[$_];
699 }
608 }; 700 };
609 701
610 warn $@ if $@; 702 if ($@) {
703 $ignore{$pkg}++;
704 warn $@;
705 }
611} 706}
612 707
613hook_entersub; 708hook_entersub;
614 709
6151; 7101;
711
712=back
713
714=head1 ENVIRONMENT VARIABLES
715
716The following environment variables influence the behaviour of Faster:
717
718=over 4
719
720=item FASTER_VERBOSE
721
722Faster will output more informational messages when set to values higher
723than C<0>. Currently, C<1> outputs which packages are being compiled.
724
725=item FASTER_DEBUG
726
727Add debugging code when set to values higher than C<0>. Currently, this
728adds 1-3 C<assert>'s per perl op, to ensure that opcode order and C
729execution order are compatible.
730
731=item FASTER_CACHE
732
733NOT YET IMPLEMENTED
734
735Set a persistent cache directory that caches compiled code
736fragments. Normally, code compiled by Faster will be deleted immediately,
737and every restart will recompile everything. Setting this variable to a
738directory makes Faster cache the generated files for re-use.
739
740This directory will always grow in contents, so you might need to erase it
741from time to time.
616 742
617=back 743=back
618 744
619=head1 BUGS/LIMITATIONS 745=head1 BUGS/LIMITATIONS
620 746
621Perl will check much less often for asynchronous signals in 747Perl will check much less often for asynchronous signals in
622Faster-compiled code. It tries to check on every function call, loop 748Faster-compiled code. It tries to check on every function call, loop
623iteration and every I/O operator, though. 749iteration and every I/O operator, though.
624 750
625The following things will disable Faster. If you manage to enable them at 751The following things will disable Faster. If you manage to enable them at
626runtime, bad things will happen. 752runtime, bad things will happen. Enabling them at startup will be fine,
753though.
627 754
628 enabled tainting 755 enabled tainting
629 enabled debugging 756 enabled debugging
630 757
631This will dramatically reduce Faster's performance: 758Thread-enabled builds of perl will dramatically reduce Faster's
759performance, but you don't care about speed if you enable threads anyway.
632 760
633 threads (but you don't care about speed if you use threads anyway)
634
635These constructs will force the use of the interpreter as soon as they are 761These constructs will force the use of the interpreter for the currently
636being executed, for the rest of the currently executed: 762executed function as soon as they are being encountered during execution.
637 763
638 .., ... (flipflop operators)
639 goto 764 goto
640 next, redo (but not well-behaved last's) 765 next, redo (but not well-behaved last's)
641 eval 766 eval
642 require 767 require
643 any use of formats 768 any use of formats
769 .., ... (flipflop operators)
644 770
645=head1 AUTHOR 771=head1 AUTHOR
646 772
647 Marc Lehmann <schmorp@schmorp.de> 773 Marc Lehmann <schmorp@schmorp.de>
648 http://home.schmorp.de/ 774 http://home.schmorp.de/

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines