… | |
… | |
72 | File::Temp::tempdir (CLEANUP => 1) |
72 | File::Temp::tempdir (CLEANUP => 1) |
73 | }; |
73 | }; |
74 | |
74 | |
75 | my $COMPILE = "$Config{cc} -c -I$Config{archlibexp}/CORE $Config{optimize} $Config{ccflags} $Config{cccdlflags}"; |
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}"; |
76 | my $LINK = "$Config{ld} $Config{ldflags} $Config{lddlflags} $Config{ccdlflags}"; |
77 | my $LIBS = "$Config{libs}"; |
77 | my $LIBS = ""; |
78 | my $_o = $Config{_o}; |
78 | my $_o = $Config{_o}; |
79 | my $_so = ".so"; |
79 | my $_so = ".so"; |
80 | |
80 | |
81 | # we don't need no steenking PIC on x86 |
81 | # we don't need no steenking PIC on x86 |
82 | $COMPILE =~ s/-f(?:PIC|pic)//g |
82 | $COMPILE =~ s/-f(?:PIC|pic)//g |
83 | if $Config{archname} =~ /^(i[3456]86)-/; |
83 | if $Config{archname} =~ /^(i[3456]86)-/; |
84 | |
84 | |
85 | my $opt_assert = $ENV{FASTER_DEBUG} > 1; |
85 | my $opt_assert = $ENV{FASTER_DEBUG} & 2; |
86 | my $verbose = $ENV{FASTER_VERBOSE}+0; |
86 | my $verbose = $ENV{FASTER_VERBOSE}+0; |
87 | |
87 | |
88 | warn "Faster: CACHEDIR is $CACHEDIR\n" if $verbose > 2; |
88 | warn "Faster: CACHEDIR is $CACHEDIR\n" if $verbose > 2; |
89 | |
89 | |
90 | our $source; |
90 | our $source; |
91 | |
91 | |
92 | our @ops; |
92 | our @ops; |
93 | our $insn; |
93 | our $insn; |
94 | our $op; |
94 | our $op; |
95 | our $op_name; |
95 | our $op_name; |
96 | our @op_loop; |
|
|
97 | our %op_regcomp; |
96 | our %op_regcomp; |
98 | |
97 | |
99 | # ops that cause immediate return to the interpreter |
98 | # ops that cause immediate return to the interpreter |
100 | my %f_unsafe = map +($_ => undef), qw( |
99 | my %f_unsafe = map +($_ => undef), qw( |
101 | leavesub leavesublv return |
100 | leavesub leavesublv return |
… | |
… | |
195 | sub out_callop { |
194 | sub out_callop { |
196 | assert "nextop == (OP *)$$op"; |
195 | assert "nextop == (OP *)$$op"; |
197 | $source .= " PL_op = nextop; nextop = " . (callop $op) . ";\n"; |
196 | $source .= " PL_op = nextop; nextop = " . (callop $op) . ";\n"; |
198 | } |
197 | } |
199 | |
198 | |
|
|
199 | sub out_jump { |
|
|
200 | assert "nextop == (OP *)${$_[0]}L"; |
|
|
201 | $source .= " goto op_${$_[0]};\n"; |
|
|
202 | } |
|
|
203 | |
200 | sub out_cond_jump { |
204 | sub out_cond_jump { |
201 | $source .= " if (nextop == (OP *)${$_[0]}L) goto op_${$_[0]};\n"; |
205 | $source .= " if (nextop == (OP *)${$_[0]}L) goto op_${$_[0]};\n"; |
202 | } |
206 | } |
203 | |
207 | |
204 | sub out_jump_next { |
208 | sub out_jump_next { |
… | |
… | |
495 | } |
499 | } |
496 | |
500 | |
497 | sub out_break_op { |
501 | sub out_break_op { |
498 | my ($idx) = @_; |
502 | my ($idx) = @_; |
499 | |
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]; |
500 | out_callop; |
507 | out_callop; |
501 | |
508 | out_jump $next; |
502 | out_cond_jump $_->[$idx] |
509 | } elsif (my $loop = $insn->{loop}) { |
503 | for reverse @op_loop; |
510 | # less common case: maybe break to some outer loop |
504 | |
|
|
505 | $source .= " return nextop;\n"; |
511 | $source .= " return nextop;\n"; |
|
|
512 | # todo: walk stack up |
|
|
513 | } else { |
|
|
514 | $source .= " return nextop;\n"; |
|
|
515 | } |
506 | } |
516 | } |
507 | |
517 | |
508 | sub xop_next { |
518 | sub op_next { |
509 | out_break_op 0; |
519 | out_break_op 0; |
510 | } |
520 | } |
511 | |
521 | |
512 | sub op_last { |
522 | sub op_last { |
513 | out_break_op 1; |
523 | out_break_op 1; |
… | |
… | |
519 | |
529 | |
520 | sub cv2c { |
530 | sub cv2c { |
521 | my ($cv) = @_; |
531 | my ($cv) = @_; |
522 | |
532 | |
523 | local @ops; |
533 | local @ops; |
524 | local @op_loop; |
|
|
525 | local %op_regcomp; |
534 | local %op_regcomp; |
526 | |
535 | |
527 | my %opsseen; |
536 | my $curloop; |
528 | my @todo = $cv->START; |
537 | my @todo = $cv->START; |
529 | my %op_target; |
538 | my %op_target; |
530 | my $numpushmark; |
539 | my $numpushmark; |
|
|
540 | my $scope; |
531 | |
541 | |
|
|
542 | my %op_seen; |
532 | while (my $op = shift @todo) { |
543 | while (my $op = shift @todo) { |
|
|
544 | my $next; |
533 | for (; $$op; $op = $op->next) { |
545 | for (; $$op; $op = $next) { |
534 | last if $opsseen{$$op}++; |
546 | last if $op_seen{$$op}++; |
|
|
547 | |
|
|
548 | $next = $op->next; |
535 | |
549 | |
536 | my $name = $op->name; |
550 | my $name = $op->name; |
537 | my $class = B::class $op; |
551 | my $class = B::class $op; |
538 | |
552 | |
539 | my $insn = { op => $op }; |
553 | my $insn = { op => $op }; |
|
|
554 | |
|
|
555 | # end of loop reached? |
|
|
556 | $curloop = $curloop->{loop} if $curloop && $$op == ${$curloop->{loop_targ}[1]}; |
|
|
557 | |
|
|
558 | # remember enclosing loop |
|
|
559 | $insn->{loop} = $curloop if $curloop; |
540 | |
560 | |
541 | push @ops, $insn; |
561 | push @ops, $insn; |
542 | |
562 | |
543 | if (exists $extend{$name}) { |
563 | if (exists $extend{$name}) { |
544 | my $extend = $extend{$name}; |
564 | my $extend = $extend{$name}; |
545 | $extend = $extend->($op) if ref $extend; |
565 | $extend = $extend->($op) if ref $extend; |
546 | $insn->{extend} = $extend if defined $extend; |
566 | $insn->{extend} = $extend if defined $extend; |
547 | } |
567 | } |
548 | |
568 | |
549 | push @todo, $op->next; |
569 | # TODO: mark scopes similar to loops, make them comparable |
550 | |
570 | # static cxstack(?) |
551 | if ($class eq "LOGOP") { |
571 | if ($class eq "LOGOP") { |
552 | push @todo, $op->other; |
572 | push @todo, $op->other; |
553 | $op_target{${$op->other}}++; |
573 | $op_target{${$op->other}}++; |
554 | |
574 | |
555 | # regcomp/o patches ops at runtime, lets expect that |
575 | # regcomp/o patches ops at runtime, lets expect that |
… | |
… | |
563 | unshift @todo, $op->pmreplstart; |
583 | unshift @todo, $op->pmreplstart; |
564 | $op_target{${$op->pmreplstart}}++; |
584 | $op_target{${$op->pmreplstart}}++; |
565 | } |
585 | } |
566 | |
586 | |
567 | } elsif ($class eq "LOOP") { |
587 | } elsif ($class eq "LOOP") { |
568 | my @targ = ($op->nextop, $op->lastop->next, $op->redoop->next); |
588 | my @targ = ($op->nextop, $op->lastop->next, $op->redoop); |
569 | |
589 | |
570 | push @op_loop, \@targ; |
590 | unshift @todo, $next, $op->redoop, $op->nextop, $op->lastop; |
571 | push @todo, @targ; |
591 | $next = $op->redoop; |
572 | |
592 | |
573 | $op_target{$$_}++ for @targ; |
593 | $op_target{$$_}++ for @targ; |
574 | |
594 | |
|
|
595 | $insn->{loop_targ} = \@targ; |
|
|
596 | $curloop = $insn; |
|
|
597 | |
575 | } elsif ($class eq "COP") { |
598 | } elsif ($class eq "COP") { |
576 | $insn->{bblock}++ if defined $op->label; |
599 | if (defined $op->label) { |
|
|
600 | $insn->{bblock}++; |
|
|
601 | $curloop->{contains_label}{$op->label}++ if $curloop; #TODO: should be within loop |
|
|
602 | } |
577 | |
603 | |
578 | } else { |
604 | } else { |
579 | if ($name eq "pushmark") { |
605 | if ($name eq "pushmark") { |
580 | $numpushmark++; |
606 | $numpushmark++; |
581 | } |
607 | } |
… | |
… | |
729 | $meta->{$f->{func}} = $f->{so} = $stem; |
755 | $meta->{$f->{func}} = $f->{so} = $stem; |
730 | } |
756 | } |
731 | |
757 | |
732 | close $fh; |
758 | close $fh; |
733 | system "$COMPILE -o $stem$_o $stem.c"; |
759 | system "$COMPILE -o $stem$_o $stem.c"; |
734 | unlink "$stem.c" unless $ENV{FASTER_DEBUG} > 0; |
760 | unlink "$stem.c" unless $ENV{FASTER_DEBUG} & 1; |
735 | system "$LINK -o $stem$_so $stem$_o $LIBS"; |
761 | system "$LINK -o $stem$_so $stem$_o $LIBS"; |
736 | unlink "$stem$_o"; |
762 | unlink "$stem$_o"; |
737 | } |
763 | } |
738 | |
764 | |
739 | for my $f (@func) { |
765 | for my $f (@func) { |
… | |
… | |
864 | These constructs will force the use of the interpreter for the currently |
890 | These constructs will force the use of the interpreter for the currently |
865 | executed function as soon as they are being encountered during execution. |
891 | executed function as soon as they are being encountered during execution. |
866 | |
892 | |
867 | goto |
893 | goto |
868 | next, redo (but not well-behaved last's) |
894 | next, redo (but not well-behaved last's) |
|
|
895 | labels, if used |
869 | eval |
896 | eval |
870 | require |
897 | require |
871 | any use of formats |
898 | any use of formats |
872 | .., ... (flipflop operators) |
899 | .., ... (flipflop operators) |
873 | |
900 | |