File Coverage

blib/lib/Language/P/Intermediate/BasicBlock.pm
Criterion Covered Total %
statement 79 80 98.7
branch 15 20 75.0
condition 9 12 75.0
subroutine 12 12 100.0
pod 1 5 20.0
total 116 129 89.9


line stmt bran cond sub pod time code
1             package Language::P::Intermediate::BasicBlock;
2              
3 37     37   210 use strict;
  37         83  
  37         1462  
4 37     37   207 use warnings;
  37         78  
  37         1140  
5 37     37   190 use base qw(Class::Accessor::Fast);
  37         83  
  37         4542  
6              
7             __PACKAGE__->mk_ro_accessors( qw(bytecode start_label start_stack_size
8             predecessors successors) );
9              
10 37     37   211 use Scalar::Util qw();
  37         92  
  37         1055  
11 37     37   21144 use Language::P::Assembly qw(label);
  37         118  
  37         2398  
12 37     37   263 use Language::P::Opcodes qw(OP_JUMP);
  37         70  
  37         31204  
13              
14             sub new {
15 770     770 1 1147 my( $class, $args ) = @_;
16 770         2842 my $self = $class->SUPER::new( $args );
17              
18 770   50     10451 $self->{predecessors} ||= [];
19 770   50     3312 $self->{successors} ||= [];
20 770   50     3009 $self->{bytecode} ||= [];
21 770         5219 push @{$self->bytecode}, label( $self->start_label )
  770         2202  
22 770 50       860 unless @{$self->bytecode};
23              
24 770         15703 return $self;
25             }
26              
27 770     770 0 4002 sub new_from_label { $_[0]->new( { start_label => $_[1] } ) }
28              
29             sub _change_successor {
30 87     87   314 my( $self, $from, $to ) = @_;
31              
32             # remove $from from successors and insert $to
33 87         108 foreach my $succ ( @{$self->successors} ) {
  87         239  
34 132 100       586 if( $succ == $from ) {
35 87         155 $succ = $to;
36 87         224 Scalar::Util::weaken( $succ );
37 87         139 last;
38             }
39             }
40              
41             # patch jump target to $to
42 87         351 my $jump = $self->bytecode->[-1];
43 87 100       673 if( $jump->{opcode_n} == OP_JUMP ) {
    100          
    50          
44 21         54 $jump->{attributes}->{to} = $to;
45             } elsif( $jump->{attributes}->{true} == $from ) {
46 31         71 $jump->{attributes}->{true} = $to;
47             } elsif( $jump->{attributes}->{false} == $from ) {
48 35         81 $jump->{attributes}->{false} = $to;
49             } else {
50 0         0 die "Could not backpatch jump target";
51             }
52              
53             # fix up predecessors
54 87         205 $to->add_predecessor( $self );
55             # remove $sel from $from predecessors
56 87         437 foreach my $i ( 0 .. $#{$from->{predecessors}} ) {
  87         279  
57 107 100       354 if( $from->{predecessors}[$i] == $self ) {
58 87         106 splice @{$from->{predecessors}}, $i, 0;
  87         311  
59 87         346 last;
60             }
61             }
62             }
63              
64             sub add_jump {
65 486     486 0 3818 my( $self, $op, @to ) = @_;
66              
67 486 100 100     1792 if( $op->{opcode_n} == OP_JUMP && @{$self->bytecode} == 1
  351   100     909  
  92         734  
68             && @{$self->predecessors} ) {
69 27         186 $to[0] = $to[0]->successors->[0] until @{$to[0]->bytecode};
  29         107  
70 27         160 foreach my $pred ( @{$self->predecessors} ) {
  27         75  
71 37         321 _change_successor( $pred, $self, $to[0] );
72             }
73              
74             # keep track where this block goes
75 27         84 $self->add_successor( $to[0] );
76 27         139 undef @{$self->bytecode};
  27         77  
77              
78 27         266 return;
79             }
80              
81 459         2424 push @{$self->bytecode}, $op;
  459         1220  
82 459         2113 foreach my $to ( @to ) {
83 594         1888 $self->add_successor( $to );
84 594         3570 $to->add_predecessor( $self );
85             # FIXME either move empty-block optimization later
86             # or backpatch goto/redo/last/... labels in parse tree!
87 594         1502 _change_successor( $self, $to, $to->successors->[0] )
88 594 50       3011 unless @{$to->bytecode};
89             }
90             }
91              
92             sub add_predecessor {
93 681     681 0 1014 my( $self, $block ) = @_;
94 681 50       746 return if grep $block == $_, @{$self->predecessors};
  681         1738  
95              
96 681         3720 push @{$self->predecessors}, $block;
  681         1528  
97 681         4079 Scalar::Util::weaken( $self->predecessors->[-1] );
98             }
99              
100             sub add_successor {
101 621     621 0 798 my( $self, $block ) = @_;
102 621 50       661 return if grep $block == $_, @{$self->successors};
  621         1635  
103              
104 621         3902 push @{$self->successors}, $block;
  621         1694  
105 621         3938 Scalar::Util::weaken( $self->successors->[-1] );
106             }
107              
108             1;