Development to pre-alpha4
[p5sagit/p5-mst-13.2.git] / B / CC.pm
1 #      CC.pm
2 #
3 #      Copyright (c) 1996 Malcolm Beattie
4 #
5 #      You may distribute under the terms of either the GNU General Public
6 #      License or the Artistic License, as specified in the README file.
7 #
8 package B::CC;
9 use strict;
10 use B qw(main_start main_root class comppadlist peekop svref_2object
11         timing_info);
12 use B::C qw(push_decl init_init push_init save_unused_subs objsym
13             output_all output_boilerplate output_main);
14 use B::Bblock qw(find_leaders);
15 use B::Stackobj qw(:types :flags);
16
17 # These should probably be elsewhere
18 # Flags for $op->flags
19 sub OPf_LIST () { 1 }
20 sub OPf_KNOW () { 2 }
21 sub OPf_MOD () { 32 }
22 sub OPf_STACKED () { 64 }
23 sub OPf_SPECIAL () { 128 }
24 # op-specific flags for $op->private 
25 sub OPpASSIGN_BACKWARDS () { 64 }
26 sub OPpLVAL_INTRO () { 128 }
27 sub OPpDEREF_AV () { 32 }
28 sub OPpDEREF_HV () { 64 }
29 sub OPpFLIP_LINENUM () { 64 }
30 sub G_ARRAY () { 1 }
31 # cop.h
32 sub CXt_NULL () { 0 }
33 sub CXt_SUB () { 1 }
34 sub CXt_EVAL () { 2 }
35 sub CXt_LOOP () { 3 }
36 sub CXt_SUBST () { 4 }
37 sub CXt_BLOCK () { 5 }
38
39 my $module;             # module name (when compiled with -m)
40 my %done;               # hash keyed by $$op of leaders of basic blocks
41                         # which have already been done.
42 my $leaders;            # ref to hash of basic block leaders. Keys are $$op
43                         # addresses, values are the $op objects themselves.
44 my @bblock_todo;        # list of leaders of basic blocks that need visiting
45                         # sometime.
46 my @cc_todo;            # list of tuples defining what PP code needs to be
47                         # saved (e.g. CV, main or PMOP repl code). Each tuple
48                         # is [$name, $root, $start, @padlist]. PMOP repl code
49                         # tuples inherit padlist.
50 my @stack;              # shadows perl's stack when contents are known.
51                         # Values are objects derived from class B::Stackobj
52 my @pad;                # Lexicals in current pad as Stackobj-derived objects
53 my @padlist;            # Copy of current padlist so PMOP repl code can find it
54 my @cxstack;            # Shadows the (compile-time) cxstack for next,last,redo
55 my $jmpbuf_ix = 0;      # Next free index for dynamically allocated jmpbufs
56 my %constobj;           # OP_CONST constants as Stackobj-derived objects
57                         # keyed by $$sv.
58 my $need_freetmps = 0;  # We may postpone FREETMPS to the end of each basic
59                         # block or even to the end of each loop of blocks,
60                         # depending on optimisation options.
61 my $know_op = 0;        # Set when C variable op already holds the right op
62                         # (from an immediately preceding DOOP(ppname)).
63 my $errors = 0;         # Number of errors encountered
64 my %skip_stack;         # Hash of PP names which don't need write_back_stack
65 my %skip_lexicals;      # Hash of PP names which don't need write_back_lexicals
66 my %skip_invalidate;    # Hash of PP names which don't need invalidate_lexicals
67 my %ignore_op;          # Hash of ops which do nothing except returning op_next
68
69 BEGIN {
70     foreach (qw(pp_scalar pp_regcmaybe pp_lineseq pp_scope pp_null)) {
71         $ignore_op{$_} = 1;
72     }
73 }
74
75 my @unused_sub_packages; # list of packages (given by -u options) to search
76                          # explicitly and save every sub we find there, even
77                          # if apparently unused (could be only referenced from
78                          # an eval "" or from a $SIG{FOO} = "bar").
79
80 my ($module_name);
81 my ($debug_op, $debug_stack, $debug_cxstack, $debug_pad, $debug_runtime,
82     $debug_shadow, $debug_queue, $debug_lineno, $debug_timings);
83
84 # Optimisation options. On the command line, use hyphens instead of
85 # underscores for compatibility with gcc-style options. We use
86 # underscores here because they are OK in (strict) barewords.
87 my ($freetmps_each_bblock, $freetmps_each_loop, $omit_taint);
88 my %optimise = (freetmps_each_bblock    => \$freetmps_each_bblock,
89                 freetmps_each_loop      => \$freetmps_each_loop,
90                 omit_taint              => \$omit_taint);
91
92 # Could rewrite push_runtime() and output_runtime() to use a
93 # temporary file if memory is at a premium.
94 my $ppname;             # name of current fake PP function
95 my $runtime_list_ref;
96 my $declare_ref;        # Hash ref keyed by C variable type of declarations.
97
98 my @pp_list;            # list of [$ppname, $runtime_list_ref, $declare_ref]
99                         # tuples to be written out.
100
101 sub init_hash { map { $_ => 1 } @_ }
102
103 #
104 # Initialise the hashes for the default PP functions where we can avoid
105 # either write_back_stack, write_back_lexicals or invalidate_lexicals.
106 #
107 %skip_lexicals = init_hash qw(pp_enter pp_enterloop);
108 %skip_invalidate = init_hash qw(pp_enter pp_enterloop);
109
110 sub debug {
111     if ($debug_runtime) {
112         warn(@_);
113     } else {
114         runtime(map { chomp; "/* $_ */"} @_);
115     }
116 }
117
118 sub declare {
119     my ($type, $var) = @_;
120     push(@{$declare_ref->{$type}}, $var);
121 }
122
123 sub push_runtime {
124     push(@$runtime_list_ref, @_);
125     warn join("\n", @_) . "\n" if $debug_runtime;
126 }
127
128 sub save_runtime {
129     push(@pp_list, [$ppname, $runtime_list_ref, $declare_ref]);
130 }
131
132 sub output_runtime {
133     my $ppdata;
134     print qq(#include "cc_runtime.h"\n);
135     foreach $ppdata (@pp_list) {
136         my ($name, $runtime, $declare) = @$ppdata;
137         print "\nstatic\nPP($name)\n{\n";
138         my ($type, $varlist, $line);
139         while (($type, $varlist) = each %$declare) {
140             print "\t$type ", join(", ", @$varlist), ";\n";
141         }
142         foreach $line (@$runtime) {
143             print $line, "\n";
144         }
145         print "}\n";
146     }
147 }
148
149 sub runtime {
150     my $line;
151     foreach $line (@_) {
152         push_runtime("\t$line");
153     }
154 }
155
156 sub init_pp {
157     $ppname = shift;
158     $runtime_list_ref = [];
159     $declare_ref = {};
160     runtime("dSP;");
161     declare("I32", "oldsave");
162     declare("SV", "**svp");
163     map { declare("SV", "*$_") } qw(sv src dst left right);
164     declare("MAGIC", "*mg");
165     push_decl("static OP * $ppname _((ARGSproto));");
166     debug "init_pp: $ppname\n" if $debug_queue;
167 }
168
169 # Initialise runtime_callback function for Stackobj class
170 BEGIN { B::Stackobj::set_callback(\&runtime) }
171
172 # Initialise saveoptree_callback for B::C class
173 sub cc_queue {
174     my ($name, $root, $start, @pl) = @_;
175     debug "cc_queue: name $name, root $root, start $start, padlist (@pl)\n"
176         if $debug_queue;
177     if ($name eq "*ignore*") {
178         $name = 0;
179     } else {
180         push(@cc_todo, [$name, $root, $start, (@pl ? @pl : @padlist)]);
181     }
182     my $fakeop = new B::FAKEOP ("next" => 0, sibling => 0, ppaddr => $name);
183     $start = $fakeop->save;
184     debug "cc_queue: name $name returns $start\n" if $debug_queue;
185     return $start;
186 }
187 BEGIN { B::C::set_callback(\&cc_queue) }
188
189 sub valid_int { $_[0]->{flags} & VALID_INT }
190 sub valid_double { $_[0]->{flags} & VALID_DOUBLE }
191 sub valid_numeric { $_[0]->{flags} & (VALID_INT | VALID_DOUBLE) }
192 sub valid_sv { $_[0]->{flags} & VALID_SV }
193
194 sub top_int { @stack ? $stack[-1]->as_int : "TOPi" }
195 sub top_double { @stack ? $stack[-1]->as_double : "TOPn" }
196 sub top_numeric { @stack ? $stack[-1]->as_numeric : "TOPn" }
197 sub top_sv { @stack ? $stack[-1]->as_sv : "TOPs" }
198 sub top_bool { @stack ? $stack[-1]->as_numeric : "SvTRUE(TOPs)" }
199
200 sub pop_int { @stack ? (pop @stack)->as_int : "POPi" }
201 sub pop_double { @stack ? (pop @stack)->as_double : "POPn" }
202 sub pop_numeric { @stack ? (pop @stack)->as_numeric : "POPn" }
203 sub pop_sv { @stack ? (pop @stack)->as_sv : "POPs" }
204 sub pop_bool {
205     if (@stack) {
206         return ((pop @stack)->as_numeric);
207     } else {
208         # Careful: POPs has an auto-decrement and SvTRUE evaluates
209         # its argument more than once.
210         runtime("sv = POPs;");
211         return "SvTRUE(sv)";
212     }
213 }
214
215 sub write_back_lexicals {
216     my $avoid = shift || 0;
217     debug "write_back_lexicals($avoid) called from @{[(caller(1))[3]]}\n"
218         if $debug_shadow;
219     my $lex;
220     foreach $lex (@pad) {
221         next unless ref($lex);
222         $lex->write_back unless $lex->{flags} & $avoid;
223     }
224 }
225
226 sub write_back_stack {
227     my $obj;
228     return unless @stack;
229     runtime(sprintf("EXTEND(sp, %d);", scalar(@stack)));
230     foreach $obj (@stack) {
231         runtime(sprintf("PUSHs((SV*)%s);", $obj->as_sv));
232     }
233     @stack = ();
234 }
235
236 sub invalidate_lexicals {
237     my $avoid = shift || 0;
238     debug "invalidate_lexicals($avoid) called from @{[(caller(1))[3]]}\n"
239         if $debug_shadow;
240     my $lex;
241     foreach $lex (@pad) {
242         next unless ref($lex);
243         $lex->invalidate unless $lex->{flags} & $avoid;
244     }
245 }
246
247 sub reload_lexicals {
248     my $lex;
249     foreach $lex (@pad) {
250         next unless ref($lex);
251         my $type = $lex->{type};
252         if ($type == T_INT) {
253             $lex->as_int;
254         } elsif ($type == T_DOUBLE) {
255             $lex->as_double;
256         } else {
257             $lex->as_sv;
258         }
259     }
260 }
261
262 {
263     package B::Pseudoreg;
264     #
265     # This class allocates pseudo-registers (OK, so they're C variables).
266     #
267     my %alloc;          # Keyed by variable name. A value of 1 means the
268                         # variable has been declared. A value of 2 means
269                         # it's in use.
270     
271     sub new_scope { %alloc = () }
272     
273     sub new ($$$) {
274         my ($class, $type, $prefix) = @_;
275         my ($ptr, $i, $varname, $status, $obj);
276         $prefix =~ s/^(\**)//;
277         $ptr = $1;
278         $i = 0;
279         do {
280             $varname = "$prefix$i";
281             $status = $alloc{$varname};
282         } while $status == 2;
283         if ($status != 1) {
284             # Not declared yet
285             B::CC::declare($type, "$ptr$varname");
286             $alloc{$varname} = 2;       # declared and in use
287         }
288         $obj = bless \$varname, $class;
289         return $obj;
290     }
291     sub DESTROY {
292         my $obj = shift;
293         $alloc{$$obj} = 1; # no longer in use but still declared
294     }
295 }
296 {
297     package B::Shadow;
298     #
299     # This class gives a standard API for a perl object to shadow a
300     # C variable and only generate reloads/write-backs when necessary.
301     #
302     # Use $obj->load($foo) instead of runtime("shadowed_c_var = foo").
303     # Use $obj->write_back whenever shadowed_c_var needs to be up to date.
304     # Use $obj->invalidate whenever an unknown function may have
305     # set shadow itself.
306
307     sub new {
308         my ($class, $write_back) = @_;
309         # Object fields are perl shadow variable, validity flag
310         # (for *C* variable) and callback sub for write_back
311         # (passed perl shadow variable as argument).
312         bless [undef, 1, $write_back], $class;
313     }
314     sub load {
315         my ($obj, $newval) = @_;
316         $obj->[1] = 0;          # C variable no longer valid
317         $obj->[0] = $newval;
318     }
319     sub write_back {
320         my $obj = shift;
321         if (!($obj->[1])) {
322             $obj->[1] = 1;      # C variable will now be valid
323             &{$obj->[2]}($obj->[0]);
324         }
325     }
326     sub invalidate { $_[0]->[1] = 0 } # force C variable to be invalid
327 }
328 my $curcop = new B::Shadow (sub {
329     my $opsym = shift->save;
330     runtime("curcop = (COP*)$opsym;");
331 });
332
333 #
334 # Context stack shadowing. Mimics stuff in pp_ctl.c, cop.h and so on.
335 #
336 sub dopoptoloop {
337     my $cxix = $#cxstack;
338     while ($cxix >= 0 && $cxstack[$cxix]->{type} != CXt_LOOP) {
339         $cxix--;
340     }
341     debug "dopoptoloop: returning $cxix" if $debug_cxstack;
342     return $cxix;
343 }
344
345 sub dopoptolabel {
346     my $label = shift;
347     my $cxix = $#cxstack;
348     while ($cxix >= 0 && $cxstack[$cxix]->{type} != CXt_LOOP
349            && $cxstack[$cxix]->{label} ne $label) {
350         $cxix--;
351     }
352     debug "dopoptolabel: returning $cxix" if $debug_cxstack;
353     return $cxix;
354 }
355
356 sub error {
357     my $format = shift;
358     my $file = $curcop->[0]->filegv->SV->PV;
359     my $line = $curcop->[0]->line;
360     $errors++;
361     if (@_) {
362         warn sprintf("%s:%d: $format\n", $file, $line, @_);
363     } else {
364         warn sprintf("%s:%d: %s\n", $file, $line, $format);
365     }
366 }
367
368 #
369 # Load pad takes (the elements of) a PADLIST as arguments and loads
370 # up @pad with Stackobj-derived objects which represent those lexicals.
371 # If/when perl itself can generate type information (my int $foo) then
372 # we'll take advantage of that here. Until then, we'll use various hacks
373 # to tell the compiler when we want a lexical to be a particular type
374 # or to be a register.
375 #
376 sub load_pad {
377     my ($namelistav, $valuelistav) = @_;
378     @padlist = @_;
379     my @namelist = $namelistav->ARRAY;
380     my @valuelist = $valuelistav->ARRAY;
381     my $ix;
382     @pad = ();
383     debug "load_pad: $#namelist names, $#valuelist values\n" if $debug_pad;
384     # Temporary lexicals don't get named so it's possible for @valuelist
385     # to be strictly longer than @namelist. We count $ix up to the end of
386     # @valuelist but index into @namelist for the name. Any temporaries which
387     # run off the end of @namelist will make $namesv undefined and we treat
388     # that the same as having an explicit SPECIAL sv_undef object in @namelist.
389     # [XXX If/when @_ becomes a lexical, we must start at 0 here.]
390     for ($ix = 1; $ix < @valuelist; $ix++) {
391         my $namesv = $namelist[$ix];
392         my $type = T_UNKNOWN;
393         my $flags = 0;
394         my $name = "tmp$ix";
395         my $class = class($namesv);
396         if (!defined($namesv) || $class eq "SPECIAL") {
397             # temporaries have &sv_undef instead of a PVNV for a name
398             $flags = VALID_SV|TEMPORARY|REGISTER;
399         } else {
400             if ($namesv->PV =~ /^\$(.*)_([di])(r?)$/) {
401                 $name = $1;
402                 if ($2 eq "i") {
403                     $type = T_INT;
404                     $flags = VALID_SV|VALID_INT;
405                 } elsif ($2 eq "d") {
406                     $type = T_DOUBLE;
407                     $flags = VALID_SV|VALID_DOUBLE;
408                 }
409                 $flags |= REGISTER if $3;
410             }
411         }
412         $pad[$ix] = new B::Stackobj::Padsv ($type, $flags, $ix,
413                                             "i_$name", "d_$name");
414         declare("IV", $type == T_INT ? "i_$name = 0" : "i_$name");
415         declare("double", $type == T_DOUBLE ? "d_$name = 0" : "d_$name");
416         debug sprintf("curpad[$ix] = %s\n", $pad[$ix]->peek) if $debug_pad;
417     }
418 }
419
420 #
421 # Debugging stuff
422 #
423 sub peek_stack { sprintf "stack = %s\n", join(" ", map($_->minipeek, @stack)) }
424
425 #
426 # OP stuff
427 #
428
429 sub label {
430     my $op = shift;
431     # XXX Preserve original label name for "real" labels?
432     return sprintf("lab_%x", $$op);
433 }
434
435 sub write_label {
436     my $op = shift;
437     push_runtime(sprintf("  %s:", label($op)));
438 }
439
440 sub loadop {
441     my $op = shift;
442     my $opsym = $op->save;
443     runtime("op = $opsym;") unless $know_op;
444     return $opsym;
445 }
446
447 sub doop {
448     my $op = shift;
449     my $ppname = $op->ppaddr;
450     my $sym = loadop($op);
451     runtime("DOOP($ppname);");
452     $know_op = 1;
453     return $sym;
454 }
455
456 sub gimme {
457     my $op = shift;
458     my $flags = $op->flags;
459     return (($flags & OPf_KNOW) ? ($flags & OPf_LIST) : "dowantarray()");
460 }
461
462 #
463 # Code generation for PP code
464 #
465
466 sub pp_null {
467     my $op = shift;
468     return $op->next;
469 }
470
471 sub pp_stub {
472     my $op = shift;
473     my $gimme = gimme($op);
474     if ($gimme != 1) {
475         # XXX Change to push a constant sv_undef Stackobj onto @stack
476         write_back_stack();
477         runtime("if ($gimme != G_ARRAY) XPUSHs(&sv_undef);");
478     }
479     return $op->next;
480 }
481
482 sub pp_unstack {
483     my $op = shift;
484     @stack = ();
485     runtime("PP_UNSTACK;");
486     return $op->next;
487 }
488
489 sub pp_and {
490     my $op = shift;
491     my $next = $op->next;
492     reload_lexicals();
493     unshift(@bblock_todo, $next);
494     if (@stack >= 1) {
495         my $bool = pop_bool();
496         write_back_stack();
497         runtime(sprintf("if (!$bool) goto %s;", label($next)));
498     } else {
499         runtime(sprintf("if (!%s) goto %s;", top_bool(), label($next)),
500                 "*sp--;");
501     }
502     return $op->other;
503 }
504             
505 sub pp_or {
506     my $op = shift;
507     my $next = $op->next;
508     reload_lexicals();
509     unshift(@bblock_todo, $next);
510     if (@stack >= 1) {
511         my $obj = pop @stack;
512         write_back_stack();
513         runtime(sprintf("if (%s) { XPUSHs(%s); goto %s; }",
514                         $obj->as_numeric, $obj->as_sv, label($next)));
515     } else {
516         runtime(sprintf("if (%s) goto %s;", top_bool(), label($next)),
517                 "*sp--;");
518     }
519     return $op->other;
520 }
521             
522 sub pp_cond_expr {
523     my $op = shift;
524     my $false = $op->false;
525     unshift(@bblock_todo, $false);
526     reload_lexicals();
527     my $bool = pop_bool();
528     write_back_stack();
529     runtime(sprintf("if (!$bool) goto %s;", label($false)));
530     return $op->true;
531 }
532             
533
534 sub pp_padsv {
535     my $op = shift;
536     my $ix = $op->targ;
537     push(@stack, $pad[$ix]);
538     if ($op->flags & OPf_MOD) {
539         my $private = $op->private;
540         if ($private & OPpLVAL_INTRO) {
541             runtime("SAVECLEARSV(curpad[$ix]);");
542         } elsif ($private & (OPpDEREF_HV|OPpDEREF_AV)) {
543             loadop($op);
544             runtime("provide_ref(op, curpad[$ix]);");
545             $pad[$ix]->invalidate;
546         }
547     }
548     return $op->next;
549 }
550
551 sub pp_const {
552     my $op = shift;
553     my $sv = $op->sv;
554     my $obj = $constobj{$$sv};
555     if (!defined($obj)) {
556         $obj = $constobj{$$sv} = new B::Stackobj::Const ($sv);
557     }
558     push(@stack, $obj);
559     return $op->next;
560 }
561
562 sub pp_nextstate {
563     my $op = shift;
564     $curcop->load($op);
565     @stack = ();
566     debug(sprintf("%s:%d\n", $op->filegv->SV->PV, $op->line)) if $debug_lineno;
567     runtime("TAINT_NOT;") unless $omit_taint;
568     runtime("sp = stack_base + cxstack[cxstack_ix].blk_oldsp;");
569     if ($freetmps_each_bblock || $freetmps_each_loop) {
570         $need_freetmps = 1;
571     } else {
572         runtime("FREETMPS;");
573     }
574     return $op->next;
575 }
576
577 sub pp_dbstate {
578     my $op = shift;
579     $curcop->invalidate; # XXX?
580     return default_pp($op);
581 }
582
583 sub pp_rv2gv { $curcop->write_back; default_pp(@_) }
584 sub pp_bless { $curcop->write_back; default_pp(@_) }
585 sub pp_repeat { $curcop->write_back; default_pp(@_) }
586 # The following subs need $curcop->write_back if we decide to support arybase:
587 # pp_pos, pp_substr, pp_index, pp_rindex, pp_aslice, pp_lslice, pp_splice
588 sub pp_sort { $curcop->write_back; default_pp(@_) }
589 sub pp_caller { $curcop->write_back; default_pp(@_) }
590 sub pp_reset { $curcop->write_back; default_pp(@_) }
591
592 sub pp_gv {
593     my $op = shift;
594     my $gvsym = $op->gv->save;
595     write_back_stack();
596     runtime("XPUSHs((SV*)$gvsym);");
597     return $op->next;
598 }
599
600 sub pp_gvsv {
601     my $op = shift;
602     my $gvsym = $op->gv->save;
603     write_back_stack();
604     if ($op->private & OPpLVAL_INTRO) {
605         runtime("XPUSHs(save_scalar($gvsym));");
606     } else {
607         runtime("XPUSHs(GvSV($gvsym));");
608     }
609     return $op->next;
610 }
611
612 sub pp_aelemfast {
613     my $op = shift;
614     my $gvsym = $op->gv->save;
615     my $ix = $op->private;
616     my $flag = $op->flags & OPf_MOD;
617     write_back_stack();
618     runtime("svp = av_fetch(GvAV($gvsym), $ix, $flag);",
619             "PUSHs(svp ? *svp : &sv_undef);");
620     return $op->next;
621 }
622
623 sub int_binop {
624     my ($op, $operator) = @_;
625     if ($op->flags & OPf_STACKED) {
626         my $right = pop_int();
627         if (@stack >= 1) {
628             my $left = top_int();
629             $stack[-1]->set_int(&$operator($left, $right));
630         } else {
631             runtime(sprintf("sv_setiv(TOPs, %s);",&$operator("TOPi", $right)));
632         }
633     } else {
634         my $targ = $pad[$op->targ];
635         my $right = new B::Pseudoreg ("IV", "riv");
636         my $left = new B::Pseudoreg ("IV", "liv");
637         runtime(sprintf("$$right = %s; $$left = %s;", pop_int(), pop_int));
638         $targ->set_int(&$operator($$left, $$right));
639         push(@stack, $targ);
640     }
641     return $op->next;
642 }
643
644 sub INTS_CLOSED () { 0x1 }
645 sub INT_RESULT () { 0x2 }
646 sub NUMERIC_RESULT () { 0x4 }
647
648 sub numeric_binop {
649     my ($op, $operator, $flags) = @_;
650     my $force_int = 0;
651     $force_int ||= ($flags & INT_RESULT);
652     $force_int ||= ($flags & INTS_CLOSED && @stack >= 2
653                     && valid_int($stack[-2]) && valid_int($stack[-1]));
654     if ($op->flags & OPf_STACKED) {
655         my $right = pop_numeric();
656         if (@stack >= 1) {
657             my $left = top_numeric();
658             if ($force_int) {
659                 $stack[-1]->set_int(&$operator($left, $right));
660             } else {
661                 $stack[-1]->set_numeric(&$operator($left, $right));
662             }
663         } else {
664             if ($force_int) {
665                 runtime(sprintf("sv_setiv(TOPs, %s);",
666                                 &$operator("TOPi", $right)));
667             } else {
668                 runtime(sprintf("sv_setnv(TOPs, %s);",
669                                 &$operator("TOPn", $right)));
670             }
671         }
672     } else {
673         my $targ = $pad[$op->targ];
674         $force_int ||= ($targ->{type} == T_INT);
675         if ($force_int) {
676             my $right = new B::Pseudoreg ("IV", "riv");
677             my $left = new B::Pseudoreg ("IV", "liv");
678             runtime(sprintf("$$right = %s; $$left = %s;",
679                             pop_numeric(), pop_numeric));
680             $targ->set_int(&$operator($$left, $$right));
681         } else {
682             my $right = new B::Pseudoreg ("double", "rnv");
683             my $left = new B::Pseudoreg ("double", "lnv");
684             runtime(sprintf("$$right = %s; $$left = %s;",
685                             pop_numeric(), pop_numeric));
686             $targ->set_numeric(&$operator($$left, $$right));
687         }
688         push(@stack, $targ);
689     }
690     return $op->next;
691 }
692
693 sub sv_binop {
694     my ($op, $operator, $flags) = @_;
695     if ($op->flags & OPf_STACKED) {
696         my $right = pop_sv();
697         if (@stack >= 1) {
698             my $left = top_sv();
699             if ($flags & INT_RESULT) {
700                 $stack[-1]->set_int(&$operator($left, $right));
701             } elsif ($flags & NUMERIC_RESULT) {
702                 $stack[-1]->set_numeric(&$operator($left, $right));
703             } else {
704                 # XXX Does this work?
705                 runtime(sprintf("sv_setsv($left, %s);",
706                                 &$operator($left, $right)));
707                 $stack[-1]->invalidate;
708             }
709         } else {
710             my $f;
711             if ($flags & INT_RESULT) {
712                 $f = "sv_setiv";
713             } elsif ($flags & NUMERIC_RESULT) {
714                 $f = "sv_setnv";
715             } else {
716                 $f = "sv_setsv";
717             }
718             runtime(sprintf("%s(TOPs, %s);", $f, &$operator("TOPs", $right)));
719         }
720     } else {
721         my $targ = $pad[$op->targ];
722         runtime(sprintf("right = %s; left = %s;", pop_sv(), pop_sv));
723         if ($flags & INT_RESULT) {
724             $targ->set_int(&$operator("left", "right"));
725         } elsif ($flags & NUMERIC_RESULT) {
726             $targ->set_numeric(&$operator("left", "right"));
727         } else {
728             # XXX Does this work?
729             runtime(sprintf("sv_setsv(%s, %s);",
730                             $targ->as_sv, &$operator("left", "right")));
731             $targ->invalidate;
732         }
733         push(@stack, $targ);
734     }
735     return $op->next;
736 }
737     
738 sub bool_int_binop {
739     my ($op, $operator) = @_;
740     my $right = new B::Pseudoreg ("IV", "riv");
741     my $left = new B::Pseudoreg ("IV", "liv");
742     runtime(sprintf("$$right = %s; $$left = %s;", pop_int(), pop_int()));
743     my $bool = new B::Stackobj::Bool (new B::Pseudoreg ("int", "b"));
744     $bool->set_int(&$operator($$left, $$right));
745     push(@stack, $bool);
746     return $op->next;
747 }
748
749 sub bool_numeric_binop {
750     my ($op, $operator) = @_;
751     my $right = new B::Pseudoreg ("double", "rnv");
752     my $left = new B::Pseudoreg ("double", "lnv");
753     runtime(sprintf("$$right = %s; $$left = %s;",
754                     pop_numeric(), pop_numeric()));
755     my $bool = new B::Stackobj::Bool (new B::Pseudoreg ("int", "b"));
756     $bool->set_numeric(&$operator($$left, $$right));
757     push(@stack, $bool);
758     return $op->next;
759 }
760
761 sub bool_sv_binop {
762     my ($op, $operator) = @_;
763     runtime(sprintf("right = %s; left = %s;", pop_sv(), pop_sv()));
764     my $bool = new B::Stackobj::Bool (new B::Pseudoreg ("int", "b"));
765     $bool->set_numeric(&$operator("left", "right"));
766     push(@stack, $bool);
767     return $op->next;
768 }
769
770 sub infix_op {
771     my $opname = shift;
772     return sub { "$_[0] $opname $_[1]" }
773 }
774
775 sub prefix_op {
776     my $opname = shift;
777     return sub { sprintf("%s(%s)", $opname, join(", ", @_)) }
778 }
779
780 BEGIN {
781     my $plus_op = infix_op("+");
782     my $minus_op = infix_op("-");
783     my $multiply_op = infix_op("*");
784     my $divide_op = infix_op("/");
785     my $modulo_op = infix_op("%");
786     my $lshift_op = infix_op("<<");
787     my $rshift_op = infix_op("<<");
788     my $ncmp_op = sub { "($_[0] > $_[1] ? 1 : ($_[0] < $_[1]) ? -1 : 0)" };
789     my $scmp_op = prefix_op("sv_cmp");
790     my $seq_op = prefix_op("sv_eq");
791     my $sne_op = prefix_op("!sv_eq");
792     my $slt_op = sub { "sv_cmp($_[0], $_[1]) < 0" };
793     my $sgt_op = sub { "sv_cmp($_[0], $_[1]) > 0" };
794     my $sle_op = sub { "sv_cmp($_[0], $_[1]) <= 0" };
795     my $sge_op = sub { "sv_cmp($_[0], $_[1]) >= 0" };
796     my $eq_op = infix_op("==");
797     my $ne_op = infix_op("!=");
798     my $lt_op = infix_op("<");
799     my $gt_op = infix_op(">");
800     my $le_op = infix_op("<=");
801     my $ge_op = infix_op(">=");
802
803     #
804     # XXX The standard perl PP code has extra handling for
805     # some special case arguments of these operators.
806     #
807     sub pp_add { numeric_binop($_[0], $plus_op, INTS_CLOSED) }
808     sub pp_subtract { numeric_binop($_[0], $minus_op, INTS_CLOSED) }
809     sub pp_multiply { numeric_binop($_[0], $multiply_op, INTS_CLOSED) }
810     sub pp_divide { numeric_binop($_[0], $divide_op) }
811     sub pp_modulo { int_binop($_[0], $modulo_op) } # differs from perl's
812     sub pp_ncmp { numeric_binop($_[0], $ncmp_op, INT_RESULT) }
813
814     sub pp_left_shift { int_binop($_[0], $lshift_op) }
815     sub pp_right_shift { int_binop($_[0], $rshift_op) }
816     sub pp_i_add { int_binop($_[0], $plus_op) }
817     sub pp_i_subtract { int_binop($_[0], $minus_op) }
818     sub pp_i_multiply { int_binop($_[0], $multiply_op) }
819     sub pp_i_divide { int_binop($_[0], $divide_op) }
820     sub pp_i_modulo { int_binop($_[0], $modulo_op) }
821
822     sub pp_eq { bool_numeric_binop($_[0], $eq_op) }
823     sub pp_ne { bool_numeric_binop($_[0], $ne_op) }
824     sub pp_lt { bool_numeric_binop($_[0], $lt_op) }
825     sub pp_gt { bool_numeric_binop($_[0], $gt_op) }
826     sub pp_le { bool_numeric_binop($_[0], $le_op) }
827     sub pp_ge { bool_numeric_binop($_[0], $ge_op) }
828
829     sub pp_i_eq { bool_int_binop($_[0], $eq_op) }
830     sub pp_i_ne { bool_int_binop($_[0], $ne_op) }
831     sub pp_i_lt { bool_int_binop($_[0], $lt_op) }
832     sub pp_i_gt { bool_int_binop($_[0], $gt_op) }
833     sub pp_i_le { bool_int_binop($_[0], $le_op) }
834     sub pp_i_ge { bool_int_binop($_[0], $ge_op) }
835
836     sub pp_scmp { sv_binop($_[0], $scmp_op, INT_RESULT) }
837     sub pp_slt { bool_sv_binop($_[0], $slt_op) }
838     sub pp_sgt { bool_sv_binop($_[0], $sgt_op) }
839     sub pp_sle { bool_sv_binop($_[0], $sle_op) }
840     sub pp_sge { bool_sv_binop($_[0], $sge_op) }
841     sub pp_seq { bool_sv_binop($_[0], $seq_op) }
842     sub pp_sne { bool_sv_binop($_[0], $sne_op) }
843 }
844
845
846 sub pp_sassign {
847     my $op = shift;
848     my $backwards = $op->private & OPpASSIGN_BACKWARDS;
849     my ($dst, $src);
850     if (@stack >= 2) {
851         $dst = pop @stack;
852         $src = pop @stack;
853         ($src, $dst) = ($dst, $src) if $backwards;
854         my $type = $src->{type};
855         if ($type == T_INT) {
856             $dst->set_int($src->as_int);
857         } elsif ($type == T_DOUBLE) {
858             $dst->set_numeric($src->as_numeric);
859         } else {
860             $dst->set_sv($src->as_sv);
861         }
862         push(@stack, $dst);
863     } elsif (@stack == 1) {
864         if ($backwards) {
865             my $src = pop @stack;
866             my $type = $src->{type};
867             runtime("if (tainting && tainted) TAINT_NOT;");
868             if ($type == T_INT) {
869                 runtime sprintf("sv_setiv(TOPs, %s);", $src->as_int);
870             } elsif ($type == T_DOUBLE) {
871                 runtime sprintf("sv_setnv(TOPs, %s);", $src->as_double);
872             } else {
873                 runtime sprintf("sv_setsv(TOPs, %s);", $src->as_sv);
874             }
875             runtime("SvSETMAGIC(TOPs);");
876         } else {
877             my $dst = pop @stack;
878             my $type = $dst->{type};
879             runtime("sv = POPs;");
880             runtime("MAYBE_TAINT_SASSIGN_SRC(sv);");
881             if ($type == T_INT) {
882                 $dst->set_int("SvIV(sv)");
883             } elsif ($type == T_DOUBLE) {
884                 $dst->set_double("SvNV(sv)");
885             } else {
886                 runtime("SvSetSV($dst->{sv}, sv);");
887                 $dst->invalidate;
888             }
889         }
890     } else {
891         if ($backwards) {
892             runtime("src = POPs; dst = TOPs;");
893         } else {
894             runtime("dst = POPs; src = TOPs;");
895         }
896         runtime("MAYBE_TAINT_SASSIGN_SRC(src);",
897                 "SvSetSV(dst, src);",
898                 "SvSETMAGIC(dst);",
899                 "SETs(dst);");
900     }
901     return $op->next;
902 }
903
904 sub pp_preinc {
905     my $op = shift;
906     if (@stack >= 1) {
907         my $obj = $stack[-1];
908         my $type = $obj->{type};
909         if ($type == T_INT || $type == T_DOUBLE) {
910             $obj->set_int($obj->as_int . " + 1");
911         } else {
912             runtime sprintf("PP_PREINC(%s);", $obj->as_sv);
913             $obj->invalidate();
914         }
915     } else {
916         runtime sprintf("PP_PREINC(TOPs);");
917     }
918     return $op->next;
919 }
920
921 sub pp_pushmark {
922     my $op = shift;
923     write_back_stack();
924     runtime("PUSHMARK(sp);");
925     return $op->next;
926 }
927
928 sub pp_list {
929     my $op = shift;
930     write_back_stack();
931     my $gimme = gimme($op);
932     if ($gimme == 1) { # sic
933         runtime("POPMARK;"); # need this even though not a "full" pp_list
934     } else {
935         runtime("PP_LIST($gimme);");
936     }
937     return $op->next;
938 }
939
940 sub pp_entersub {
941     my $op = shift;
942     write_back_lexicals(REGISTER|TEMPORARY);
943     write_back_stack();
944     my $sym = doop($op);
945     runtime("if (op != ($sym)->op_next) op = (*op->op_ppaddr)();");
946     runtime("SPAGAIN;");
947     $know_op = 0;
948     invalidate_lexicals(REGISTER|TEMPORARY);
949     return $op->next;
950 }
951
952 sub pp_enterwrite {
953     my $op = shift;
954     pp_entersub($op);
955 }
956
957 sub pp_leavewrite {
958     my $op = shift;
959     write_back_lexicals(REGISTER|TEMPORARY);
960     write_back_stack();
961     my $sym = doop($op);
962     # XXX Is this the right way to distinguish between it returning
963     # CvSTART(cv) (via doform) and pop_return()?
964     runtime("if (op) op = (*op->op_ppaddr)();");
965     runtime("SPAGAIN;");
966     $know_op = 0;
967     invalidate_lexicals(REGISTER|TEMPORARY);
968     return $op->next;
969 }
970
971 sub doeval {
972     my $op = shift;
973     $curcop->write_back;
974     write_back_lexicals(REGISTER|TEMPORARY);
975     write_back_stack();
976     my $sym = loadop($op);
977     my $ppaddr = $op->ppaddr;
978     runtime("PP_EVAL($ppaddr, ($sym)->op_next);");
979     $know_op = 1;
980     invalidate_lexicals(REGISTER|TEMPORARY);
981     return $op->next;
982 }
983
984 sub pp_entereval { doeval(@_) }
985 sub pp_require { doeval(@_) }
986 sub pp_dofile { doeval(@_) }
987
988 sub pp_entertry {
989     my $op = shift;
990     $curcop->write_back;
991     write_back_lexicals(REGISTER|TEMPORARY);
992     write_back_stack();
993     my $sym = doop($op);
994     my $jmpbuf = sprintf("jmpbuf%d", $jmpbuf_ix++);
995     declare("Sigjmp_buf", $jmpbuf);
996     runtime(sprintf("PP_ENTERTRY(%s,%s);", $jmpbuf, label($op->other->next)));
997     invalidate_lexicals(REGISTER|TEMPORARY);
998     return $op->next;
999 }
1000
1001 sub pp_grepstart {
1002     my $op = shift;
1003     if ($need_freetmps && $freetmps_each_loop) {
1004         runtime("FREETMPS;"); # otherwise the grepwhile loop messes things up
1005         $need_freetmps = 0;
1006     }
1007     write_back_stack();
1008     doop($op);
1009     return $op->next->other;
1010 }
1011
1012 sub pp_mapstart {
1013     my $op = shift;
1014     if ($need_freetmps && $freetmps_each_loop) {
1015         runtime("FREETMPS;"); # otherwise the mapwhile loop messes things up
1016         $need_freetmps = 0;
1017     }
1018     write_back_stack();
1019     doop($op);
1020     return $op->next->other;
1021 }
1022
1023 sub pp_grepwhile {
1024     my $op = shift;
1025     my $next = $op->next;
1026     unshift(@bblock_todo, $next);
1027     write_back_lexicals();
1028     write_back_stack();
1029     my $sym = doop($op);
1030     # pp_grepwhile can return either op_next or op_other and we need to
1031     # be able to distinguish the two at runtime. Since it's possible for
1032     # both ops to be "inlined", the fields could both be zero. To get
1033     # around that, we hack op_next to be our own op (purely because we
1034     # know it's a non-NULL pointer and can't be the same as op_other).
1035     push_init("((LOGOP*)$sym)->op_next = $sym;");
1036     runtime(sprintf("if (op == ($sym)->op_next) goto %s;", label($next)));
1037     $know_op = 0;
1038     return $op->other;
1039 }
1040
1041 sub pp_mapwhile {
1042     pp_grepwhile(@_);
1043 }
1044
1045 sub pp_return {
1046     my $op = shift;
1047     write_back_lexicals(REGISTER|TEMPORARY);
1048     write_back_stack();
1049     doop($op);
1050     runtime("PUTBACK;", "return 0;");
1051     $know_op = 0;
1052     return $op->next;
1053 }
1054
1055 sub nyi {
1056     my $op = shift;
1057     warn sprintf("%s not yet implemented properly\n", $op->ppaddr);
1058     return default_pp($op);
1059 }
1060
1061 sub pp_range {
1062     my $op = shift;
1063     my $flags = $op->flags;
1064     if (!($flags & OPf_KNOW)) {
1065         error("context of range unknown at compile-time");
1066     }
1067     write_back_lexicals();
1068     write_back_stack();
1069     if (!($flags & OPf_LIST)) {
1070         # We need to save our UNOP structure since pp_flop uses
1071         # it to find and adjust out targ. We don't need it ourselves.
1072         $op->save;
1073         runtime sprintf("if (SvTRUE(curpad[%d])) goto %s;",
1074                         $op->targ, label($op->false));
1075         unshift(@bblock_todo, $op->false);
1076     }
1077     return $op->true;
1078 }
1079
1080 sub pp_flip {
1081     my $op = shift;
1082     my $flags = $op->flags;
1083     if (!($flags & OPf_KNOW)) {
1084         error("context of flip unknown at compile-time");
1085     }
1086     if ($flags & OPf_LIST) {
1087         return $op->first->false;
1088     }
1089     write_back_lexicals();
1090     write_back_stack();
1091     # We need to save our UNOP structure since pp_flop uses
1092     # it to find and adjust out targ. We don't need it ourselves.
1093     $op->save;
1094     my $ix = $op->targ;
1095     my $rangeix = $op->first->targ;
1096     runtime(($op->private & OPpFLIP_LINENUM) ?
1097             "if (last_in_gv && SvIV(TOPs) == IoLINES(GvIOp(last_in_gv))) {"
1098           : "if (SvTRUE(TOPs)) {");
1099     runtime("\tsv_setiv(curpad[$rangeix], 1);");
1100     if ($op->flags & OPf_SPECIAL) {
1101         runtime("sv_setiv(curpad[$ix], 1);");
1102     } else {
1103         runtime("\tsv_setiv(curpad[$ix], 0);",
1104                 "\tsp--;",
1105                 sprintf("\tgoto %s;", label($op->first->false)));
1106     }
1107     runtime("}",
1108           qq{sv_setpv(curpad[$ix], "");},
1109             "SETs(curpad[$ix]);");
1110     $know_op = 0;
1111     return $op->next;
1112 }
1113
1114 sub pp_flop {
1115     my $op = shift;
1116     default_pp($op);
1117     $know_op = 0;
1118     return $op->next;
1119 }
1120
1121 sub enterloop {
1122     my $op = shift;
1123     my $nextop = $op->nextop;
1124     my $lastop = $op->lastop;
1125     my $redoop = $op->redoop;
1126     $curcop->write_back;
1127     debug "enterloop: pushing on cxstack" if $debug_cxstack;
1128     push(@cxstack, {
1129         type => CXt_LOOP,
1130         op => $op,
1131         "label" => $curcop->[0]->label,
1132         nextop => $nextop,
1133         lastop => $lastop,
1134         redoop => $redoop
1135     });
1136     $nextop->save;
1137     $lastop->save;
1138     $redoop->save;
1139     return default_pp($op);
1140 }
1141
1142 sub pp_enterloop { enterloop(@_) }
1143 sub pp_enteriter { enterloop(@_) }
1144
1145 sub pp_leaveloop {
1146     my $op = shift;
1147     if (!@cxstack) {
1148         die "panic: leaveloop";
1149     }
1150     debug "leaveloop: popping from cxstack" if $debug_cxstack;
1151     pop(@cxstack);
1152     return default_pp($op);
1153 }
1154
1155 sub pp_next {
1156     my $op = shift;
1157     my $cxix;
1158     if ($op->flags & OPf_SPECIAL) {
1159         $cxix = dopoptoloop();
1160         if ($cxix < 0) {
1161             error('"next" used outside loop');
1162             return $op->next; # ignore the op
1163         }
1164     } else {
1165         $cxix = dopoptolabel($op->pv);
1166         if ($cxix < 0) {
1167             error('Label not found at compile time for "next %s"', $op->pv);
1168             return $op->next; # ignore the op
1169         }
1170     }
1171     default_pp($op);
1172     my $nextop = $cxstack[$cxix]->{nextop};
1173     push(@bblock_todo, $nextop);
1174     runtime(sprintf("goto %s;", label($nextop)));
1175     return $op->next;
1176 }
1177
1178 sub pp_redo {
1179     my $op = shift;
1180     my $cxix;
1181     if ($op->flags & OPf_SPECIAL) {
1182         $cxix = dopoptoloop();
1183         if ($cxix < 0) {
1184             error('"redo" used outside loop');
1185             return $op->next; # ignore the op
1186         }
1187     } else {
1188         $cxix = dopoptolabel($op->pv);
1189         if ($cxix < 0) {
1190             error('Label not found at compile time for "redo %s"', $op->pv);
1191             return $op->next; # ignore the op
1192         }
1193     }
1194     default_pp($op);
1195     my $redoop = $cxstack[$cxix]->{redoop};
1196     push(@bblock_todo, $redoop);
1197     runtime(sprintf("goto %s;", label($redoop)));
1198     return $op->next;
1199 }
1200
1201 sub pp_last {
1202     my $op = shift;
1203     my $cxix;
1204     if ($op->flags & OPf_SPECIAL) {
1205         $cxix = dopoptoloop();
1206         if ($cxix < 0) {
1207             error('"last" used outside loop');
1208             return $op->next; # ignore the op
1209         }
1210     } else {
1211         $cxix = dopoptolabel($op->pv);
1212         if ($cxix < 0) {
1213             error('Label not found at compile time for "last %s"', $op->pv);
1214             return $op->next; # ignore the op
1215         }
1216         # XXX Add support for "last" to leave non-loop blocks
1217         if ($cxstack[$cxix]->{type} != CXt_LOOP) {
1218             error('Use of "last" for non-loop blocks is not yet implemented');
1219             return $op->next; # ignore the op
1220         }
1221     }
1222     default_pp($op);
1223     my $lastop = $cxstack[$cxix]->{lastop}->next;
1224     push(@bblock_todo, $lastop);
1225     runtime(sprintf("goto %s;", label($lastop)));
1226     return $op->next;
1227 }
1228
1229 sub pp_subst {
1230     my $op = shift;
1231     write_back_lexicals();
1232     write_back_stack();
1233     my $sym = doop($op);
1234     my $replroot = $op->pmreplroot;
1235     if ($$replroot) {
1236         runtime sprintf("if (op == ((PMOP*)(%s))->op_pmreplroot) goto %s;",
1237                         $sym, label($replroot));
1238         $op->pmreplstart->save;
1239         push(@bblock_todo, $replroot);
1240     }
1241     invalidate_lexicals();
1242     return $op->next;
1243 }
1244
1245 sub pp_substcont {
1246     my $op = shift;
1247     write_back_lexicals();
1248     write_back_stack();
1249     doop($op);
1250     my $pmop = $op->other;
1251     warn sprintf("substcont: op = %s, pmop = %s\n",
1252                  peekop($op), peekop($pmop));#debug
1253 #    my $pmopsym = objsym($pmop);
1254     my $pmopsym = $pmop->save; # XXX can this recurse?
1255     warn "pmopsym = $pmopsym\n";#debug
1256     runtime sprintf("if (op == ((PMOP*)(%s))->op_pmreplstart) goto %s;",
1257                     $pmopsym, label($pmop->pmreplstart));
1258     invalidate_lexicals();
1259     return $pmop->next;
1260 }
1261
1262 sub default_pp {
1263     my $op = shift;
1264     my $ppname = $op->ppaddr;
1265     write_back_lexicals() unless $skip_lexicals{$ppname};
1266     write_back_stack() unless $skip_stack{$ppname};
1267     doop($op);
1268     # XXX If the only way that ops can write to a TEMPORARY lexical is
1269     # when it's named in $op->targ then we could call
1270     # invalidate_lexicals(TEMPORARY) and avoid having to write back all
1271     # the temporaries. For now, we'll play it safe and write back the lot.
1272     invalidate_lexicals() unless $skip_invalidate{$ppname};
1273     return $op->next;
1274 }
1275
1276 sub compile_op {
1277     my $op = shift;
1278     my $ppname = $op->ppaddr;
1279     if (exists $ignore_op{$ppname}) {
1280         return $op->next;
1281     }
1282     debug peek_stack() if $debug_stack;
1283     if ($debug_op) {
1284         debug sprintf("%s [%s]\n",
1285                      peekop($op),
1286                      $op->flags & OPf_STACKED ? "OPf_STACKED" : $op->targ);
1287     }
1288     no strict 'refs';
1289     if (defined(&$ppname)) {
1290         $know_op = 0;
1291         return &$ppname($op);
1292     } else {
1293         return default_pp($op);
1294     }
1295 }
1296
1297 sub compile_bblock {
1298     my $op = shift;
1299     #warn "compile_bblock: ", peekop($op), "\n"; # debug
1300     write_label($op);
1301     $know_op = 0;
1302     do {
1303         $op = compile_op($op);
1304     } while (defined($op) && $$op && !exists($leaders->{$$op}));
1305     write_back_stack(); # boo hoo: big loss
1306     reload_lexicals();
1307     return $op;
1308 }
1309
1310 sub cc {
1311     my ($name, $root, $start, @padlist) = @_;
1312     my $op;
1313     init_pp($name);
1314     load_pad(@padlist);
1315     B::Pseudoreg->new_scope;
1316     @cxstack = ();
1317     if ($debug_timings) {
1318         warn sprintf("Basic block analysis at %s\n", timing_info);
1319     }
1320     $leaders = find_leaders($root, $start);
1321     @bblock_todo = ($start, values %$leaders);
1322     if ($debug_timings) {
1323         warn sprintf("Compilation at %s\n", timing_info);
1324     }
1325     while (@bblock_todo) {
1326         $op = shift @bblock_todo;
1327         #warn sprintf("Considering basic block %s\n", peekop($op)); # debug
1328         next if !defined($op) || !$$op || $done{$$op};
1329         #warn "...compiling it\n"; # debug
1330         do {
1331             $done{$$op} = 1;
1332             $op = compile_bblock($op);
1333             if ($need_freetmps && $freetmps_each_bblock) {
1334                 runtime("FREETMPS;");
1335                 $need_freetmps = 0;
1336             }
1337         } while defined($op) && $$op && !$done{$$op};
1338         if ($need_freetmps && $freetmps_each_loop) {
1339             runtime("FREETMPS;");
1340             $need_freetmps = 0;
1341         }
1342         if (!$$op) {
1343             runtime("PUTBACK;", "return 0;");
1344         } elsif ($done{$$op}) {
1345             runtime(sprintf("goto %s;", label($op)));
1346         }
1347     }
1348     if ($debug_timings) {
1349         warn sprintf("Saving runtime at %s\n", timing_info);
1350     }
1351     save_runtime();
1352 }
1353
1354 sub cc_recurse {
1355     my $ccinfo;
1356     my $start;
1357     $start = cc_queue(@_) if @_;
1358     while ($ccinfo = shift @cc_todo) {
1359         cc(@$ccinfo);
1360     }
1361     return $start;
1362 }    
1363
1364 sub cc_obj {
1365     my ($name, $cvref) = @_;
1366     my $cv = svref_2object($cvref);
1367     my @padlist = $cv->PADLIST->ARRAY;
1368     my $curpad_sym = $padlist[1]->save;
1369     cc_recurse($name, $cv->ROOT, $cv->START, @padlist);
1370 }
1371
1372 sub cc_main {
1373     my @comppadlist = comppadlist->ARRAY;
1374     my $curpad_sym = $comppadlist[1]->save;
1375     my $start = cc_recurse("pp_main", main_root, main_start, @comppadlist);
1376     save_unused_subs(@unused_sub_packages);
1377     cc_recurse();
1378
1379     return if $errors;
1380     if (!defined($module)) {
1381         push_init(sprintf("main_root = sym_%x;", ${main_root()}),
1382                   "main_start = $start;",
1383                   "curpad = AvARRAY($curpad_sym);");
1384     }
1385     output_boilerplate();
1386     print "\n";
1387     output_all("perl_init");
1388     output_runtime();
1389     print "\n";
1390     output_main();
1391     if (defined($module)) {
1392         my $cmodule = $module;
1393         $cmodule =~ s/::/__/g;
1394         print <<"EOT";
1395
1396 #include "XSUB.h"
1397 XS(boot_$cmodule)
1398 {
1399     dXSARGS;
1400     perl_init();
1401     ENTER;
1402     SAVETMPS;
1403     SAVESPTR(curpad);
1404     SAVESPTR(op);
1405     curpad = AvARRAY($curpad_sym);
1406     op = $start;
1407     pp_main(ARGS);
1408     FREETMPS;
1409     LEAVE;
1410     ST(0) = &sv_yes;
1411     XSRETURN(1);
1412 }
1413 EOT
1414     }
1415     if ($debug_timings) {
1416         warn sprintf("Done at %s\n", timing_info);
1417     }
1418 }
1419
1420 sub compile {
1421     my @options = @_;
1422     my ($option, $opt, $arg);
1423   OPTION:
1424     while ($option = shift @options) {
1425         if ($option =~ /^-(.)(.*)/) {
1426             $opt = $1;
1427             $arg = $2;
1428         } else {
1429             unshift @options, $option;
1430             last OPTION;
1431         }
1432         if ($opt eq "-" && $arg eq "-") {
1433             shift @options;
1434             last OPTION;
1435         } elsif ($opt eq "o") {
1436             $arg ||= shift @options;
1437             open(STDOUT, ">$arg") or return "$arg: $!\n";
1438         } elsif ($opt eq "n") {
1439             $arg ||= shift @options;
1440             $module_name = $arg;
1441         } elsif ($opt eq "u") {
1442             $arg ||= shift @options;
1443             push(@unused_sub_packages, $arg);
1444         } elsif ($opt eq "f") {
1445             $arg ||= shift @options;
1446             my $value = $arg !~ s/^no-//;
1447             $arg =~ s/-/_/g;
1448             my $ref = $optimise{$arg};
1449             if (defined($ref)) {
1450                 $$ref = $value;
1451             } else {
1452                 warn qq(ignoring unknown optimisation option "$arg"\n);
1453             }
1454         } elsif ($opt eq "O") {
1455             $arg = 1 if $arg eq "";
1456             my $ref;
1457             foreach $ref (values %optimise) {
1458                 $$ref = 0;
1459             }
1460             if ($arg >= 2) {
1461                 $freetmps_each_loop = 1;
1462             }
1463             if ($arg >= 1) {
1464                 $freetmps_each_bblock = 1 unless $freetmps_each_loop;
1465             }
1466         } elsif ($opt eq "m") {
1467             $module = $arg;
1468         } elsif ($opt eq "D") {
1469             $arg ||= shift @options;
1470             foreach $arg (split(//, $arg)) {
1471                 if ($arg eq "o") {
1472                     B->debug(1);
1473                 } elsif ($arg eq "O") {
1474                     $debug_op = 1;
1475                 } elsif ($arg eq "s") {
1476                     $debug_stack = 1;
1477                 } elsif ($arg eq "c") {
1478                     $debug_cxstack = 1;
1479                 } elsif ($arg eq "p") {
1480                     $debug_pad = 1;
1481                 } elsif ($arg eq "r") {
1482                     $debug_runtime = 1;
1483                 } elsif ($arg eq "S") {
1484                     $debug_shadow = 1;
1485                 } elsif ($arg eq "q") {
1486                     $debug_queue = 1;
1487                 } elsif ($arg eq "l") {
1488                     $debug_lineno = 1;
1489                 } elsif ($arg eq "t") {
1490                     $debug_timings = 1;
1491                 }
1492             }
1493         }
1494     }
1495     init_init();
1496     if (@options) {
1497         return sub {
1498             my ($objname, $ppname);
1499             foreach $objname (@options) {
1500                 $objname = "main::$objname" unless $objname =~ /::/;
1501                 ($ppname = $objname) =~ s/^.*?:://;
1502                 eval "cc_obj(qq(pp_sub_$ppname), \\&$objname)";
1503                 die "cc_obj(qq(pp_sub_$ppname, \\&$objname) failed: $@" if $@;
1504                 return if $errors;
1505             }
1506             output_boilerplate();
1507             print "\n";
1508             output_all($module_name || "init_module");
1509             output_runtime();
1510         }
1511     } else {
1512         return sub { cc_main() };
1513     }
1514 }
1515
1516 1;