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

Comparing Faster/Faster.pm (file contents):
Revision 1.7 by root, Fri Mar 10 00:13:15 2006 UTC vs.
Revision 1.20 by root, Fri Mar 10 22:32:15 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
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
31F</tmp>, and it will even create those temporary files in an insecure
32manner, so watch out.
10 33
11=over 4 34=over 4
12 35
13=cut 36=cut
14 37
15package Faster; 38package Faster;
16 39
17use strict; 40use strict;
18use Config; 41use Config;
19use B (); 42use B ();
20use Digest::MD5 (); 43#use Digest::MD5 ();
21use DynaLoader (); 44use DynaLoader ();
22 45
23BEGIN { 46BEGIN {
24 our $VERSION = '0.01'; 47 our $VERSION = '0.01';
25 48
31my $LINK = "$Config{ld} $Config{ldflags} $Config{lddlflags} $Config{ccdlflags}"; 54my $LINK = "$Config{ld} $Config{ldflags} $Config{lddlflags} $Config{ccdlflags}";
32my $LIBS = "$Config{libs}"; 55my $LIBS = "$Config{libs}";
33my $_o = $Config{_o}; 56my $_o = $Config{_o};
34my $_so = ".so"; 57my $_so = ".so";
35 58
59# we don't need no steenking PIC on x86
60$COMPILE =~ s/-f(?:PIC|pic)//g
61 if $Config{archname} =~ /^(i[3456]86)-/;
62
63my $opt_assert = 0;
64
36our $source; 65our $source;
37our $label_next;
38our $label_last;
39our $label_redo;
40 66
41my %flag; 67our @ops;
68our $op;
69our $op_name;
70our @op_loop;
71our %op_regcomp;
42 72
43for (split /\n/, <<EOF) { 73my %f_unsafe = map +($_ => undef), qw(
44 leavesub unsafe 74 leavesub leavesublv return
45 leavesublv unsafe 75 goto last redo next
46 return unsafe 76 eval flip leaveeval entertry
47 flip unsafe 77 formline grepstart mapstart
48 goto unsafe 78 substcont entereval require
49 last unsafe 79);
50 redo unsafe
51 next unsafe
52 eval unsafe
53 leaveeval unsafe
54 entertry unsafe
55 substconst unsafe
56 formline unsafe
57 grepstart unsafe
58 require unsafe
59 match unsafe todo
60 subst unsafe todo
61 entereval unsafe todo
62 mapstart unsafe todo
63 80
64 pushmark noasync 81# pushmark extend=0
65 padsv noasync 82# padsv extend=1
66 entersub noasync 83# padav extend=1
67 aassign noasync 84# padhv extend=1
68 sassign noasync 85# padany extend=1
69 rv2av noasync 86# const extend=1
70 nextstate noasync 87
71 gv noasync 88my %f_noasync = map +($_ => undef), qw(
72 gvsv noasync 89 mapstart grepstart match entereval
73 add noasync 90 enteriter entersub leaveloop
74 subtract noasync 91
75 multiply noasync 92 pushmark nextstate
76 divide noasync 93
77 complement noasync 94 const stub unstack
78 cond_expr noasync 95 last next redo seq
79 and noasync 96 padsv padav padhv padany
80 or noasync 97 aassign sassign orassign
81 not noasync 98 rv2av rv2cv rv2gv rv2hv refgen
99 gv gvsv
100 add subtract multiply divide
101 complement cond_expr and or not
102 defined
82 method_named noasync 103 method_named
83 preinc noasync 104 preinc postinc predec postdec
84 postinc noasync 105 aelem aelemfast helem delete exists
85 predec noasync 106 pushre subst list join split concat
86 postdec noasync 107 length substr stringify ord
87 stub noasync 108 push pop shift unshift
88 unstack noasync 109 eq ne gt lt ge le
89 leaveloop noasync 110 regcomp regcreset regcmaybe
90 shift noasync 111);
91 aelemA noasync
92 aelemfast noasync
93EOF
94 my (undef, $op, @flags) = split /\s+/;
95 112
96 undef $flag{$_}{$op} 113my %callop = (
97 for ("known", @flags); 114 entersub => "(PL_ppaddr [OP_ENTERSUB]) (aTHX)",
115 mapstart => "Perl_pp_grepstart (aTHX)",
116);
117
118sub callop {
119 $callop{$op_name} || "Perl_pp_$op_name (aTHX)"
120}
121
122sub assert {
123 return unless $opt_assert;
124 $source .= " assert ((\"$op_name\", ($_[0])));\n";
125}
126
127sub out_callop {
128 assert "nextop == (OP *)$$op";
129 $source .= " PL_op = nextop; nextop = " . (callop $op) . ";\n";
130}
131
132sub out_cond_jump {
133 $source .= " if (nextop == (OP *)${$_[0]}L) goto op_${$_[0]};\n";
134}
135
136sub out_jump_next {
137 out_cond_jump $op_regcomp{$$op}
138 if $op_regcomp{$$op};
139
140 assert "nextop == (OP *)${$op->next}";
141 $source .= " goto op_${$op->next};\n";
98} 142}
99 143
100sub out_next { 144sub out_next {
101 my ($op) = @_;
102
103 if (${$op->next}) {
104 $source .= " nextop = (OP *)${$op->next}L;\n"; 145 $source .= " nextop = (OP *)${$op->next}L;\n";
105 $source .= " goto op_${$op->next};\n";
106 } else {
107 $source .= " return 0;\n";
108 }
109}
110 146
111sub callop { 147 out_jump_next;
112 my ($op) = @_;
113
114 my $name = $op->name;
115
116 $name eq "entersub"
117 ? "(PL_ppaddr [OP_ENTERSUB]) (aTHX)"
118 : $name eq "mapstart"
119 ? "Perl_pp_grepstart (aTHX)"
120 : "Perl_pp_$name (aTHX)"
121} 148}
149
150sub out_linear {
151 out_callop;
152 out_jump_next;
153}
154
155sub op_entersub {
156 out_callop;
157 $source .= " RUNOPS_TILL ((OP *)${$op->next}L);\n";
158 out_jump_next;
159}
160
161*op_require = \&op_entersub;
122 162
123sub op_nextstate { 163sub op_nextstate {
124 my ($op) = @_;
125
126 $source .= " PL_curcop = (COP *)nextop;\n"; 164 $source .= " PL_curcop = (COP *)nextop;\n";
127 $source .= " PL_stack_sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;\n"; 165 $source .= " PL_stack_sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;\n";
128 $source .= " FREETMPS;\n"; 166 $source .= " FREETMPS;\n";
129 167
130 out_next $op; 168 out_next;
131} 169}
132 170
133sub op_pushmark { 171sub op_pushmark {
134 my ($op) = @_;
135
136 $source .= " PUSHMARK (PL_stack_sp);\n"; 172 $source .= " PUSHMARK (PL_stack_sp);\n";
137 173
138 out_next $op; 174 out_next;
139} 175}
140 176
141sub op_const { 177if ($Config{useithreads} ne "define") {
142 my ($op) = @_; 178 # disable optimisations on ithreads
143 179
180 *op_const = sub {
144 $source .= " { dSP; XPUSHs ((SV *)${$op->sv}L); PUTBACK; }\n"; 181 $source .= " { dSP; XPUSHs ((SV *)${$op->sv}L); PUTBACK; }\n";
145 182
146 out_next $op; 183 out_next;
147} 184 };
148 185
149*op_gv = \&op_const; 186 *op_gv = \&op_const;
150 187
188 *op_aelemfast = sub {
189 my $targ = $op->targ;
190 my $private = $op->private;
191
192 $source .= " {\n";
193
194 if ($op->flags & B::OPf_SPECIAL) {
195 $source .= " AV *av = (AV*)PAD_SV((PADOFFSET)$targ);\n";
196 } else {
197 $source .= " AV *av = GvAV ((GV *)${$op->sv}L);\n";
198 }
199
200 if ($op->flags & B::OPf_MOD) {
201 $source .= " SV *sv = *av_fetch (av, $private, 1);\n";
202 } else {
203 $source .= " SV **svp = av_fetch (av, $private, 0); SV *sv = svp ? *svp : &PL_sv_undef;\n";
204 }
205
206 if (!($op->flags & B::OPf_MOD)) {
207 $source .= " if (SvGMAGICAL (sv)) sv = sv_mortalcopy (sv);\n";
208 }
209
210 $source .= " dSP;\n";
211 $source .= " XPUSHs (sv);\n";
212 $source .= " PUTBACK;\n";
213 $source .= " }\n";
214
215 out_next;
216 };
217
218 *op_gvsv = sub {
219 $source .= " {\n";
220 $source .= " dSP;\n";
221 $source .= " EXTEND (SP, 1);\n";
222
223 if ($op->private & B::OPpLVAL_INTRO) {
224 $source .= " PUSHs (save_scalar ((GV *)${$op->sv}L));\n";
225 } else {
226 $source .= " PUSHs (GvSV ((GV *)${$op->sv}L));\n";
227 }
228
229 $source .= " PUTBACK;\n";
230 $source .= " }\n";
231
232 out_next;
233 };
234}
235
236# does kill Crossfire/res2pm
151sub op_stringify { 237sub op_stringify {
152 my ($op) = @_; 238 my $targ = $op->targ;
153 239
154 $source .= " { dSP; dTARGET; sv_copypv (TARG, TOPs); SETTARG; }\n"; 240 $source .= <<EOF;
241 {
242 dSP;
243 SV *targ = PAD_SV ((PADOFFSET)$targ);
244 sv_copypv (TARG, TOPs);
245 SETTARG;
246 PUTBACK;
247 }
248EOF
155 249
156 out_next $op; 250 out_next;
157} 251}
158 252
159sub op_and { 253sub op_and {
160 my ($op) = @_;
161
162 $source .= <<EOF; 254 $source .= <<EOF;
163 { 255 {
164 dSP; 256 dSP;
165 257
166 if (SvTRUE (TOPs)) 258 if (SvTRUE (TOPs))
171 goto op_${$op->other}; 263 goto op_${$op->other};
172 } 264 }
173 } 265 }
174EOF 266EOF
175 267
176 out_next $op; 268 out_next;
177} 269}
178 270
179sub op_or { 271sub op_or {
180 my ($op) = @_;
181
182 $source .= <<EOF; 272 $source .= <<EOF;
183 { 273 {
184 dSP; 274 dSP;
185 275
186 if (!SvTRUE (TOPs)) 276 if (!SvTRUE (TOPs))
191 goto op_${$op->other}; 281 goto op_${$op->other};
192 } 282 }
193 } 283 }
194EOF 284EOF
195 285
196 out_next $op; 286 out_next;
197} 287}
198 288
199sub op_padsv { 289sub op_padsv {
200 my ($op) = @_;
201
202 my $flags = $op->flags; 290 my $flags = $op->flags;
203 my $target = $op->targ; 291 my $target = $op->targ;
204 292
205 $source .= <<EOF; 293 $source .= <<EOF;
206 { 294 {
218 } 306 }
219 $source .= <<EOF; 307 $source .= <<EOF;
220 } 308 }
221EOF 309EOF
222 310
223 out_next $op; 311 out_next;
224}
225
226sub op_aelemfast {
227 my ($op) = @_;
228
229 my $targ = $op->targ;
230 my $private = $op->private;
231
232 $source .= " {\n";
233
234 if ($op->flags & B::OPf_SPECIAL) {
235 $source .= " AV *av = (AV*)PAD_SV((PADOFFSET)$targ);\n";
236 } else {
237 $source .= " AV *av = GvAV ((GV *)${$op->sv}L);\n";
238 }
239
240 if ($op->flags & B::OPf_MOD) {
241 $source .= " SV *sv = *av_fetch (av, $private, 1);\n";
242 } else {
243 $source .= " SV **svp = av_fetch (av, $private, 0); SV *sv = svp ? *svp : &PL_sv_undef;\n";
244 }
245
246 if (!($op->flags & B::OPf_MOD)) {
247 $source .= " if (SvGMAGICAL (sv)) sv = sv_mortalcopy (sv);\n";
248 }
249
250 $source .= " dSP;\n";
251 $source .= " XPUSHs (sv);\n";
252 $source .= " PUTBACK;\n";
253 $source .= " }\n";
254
255 out_next $op;
256} 312}
257 313
258# pattern const+ (or general push1) 314# pattern const+ (or general push1)
259# pattern pushmark return(?) 315# pattern pushmark return(?)
260# pattern pushmark gv rv2av pushmark padsv+o.ä. aassign 316# pattern pushmark gv rv2av pushmark padsv+o.ä. aassign
261 317
262# pattern const method_named 318# pattern const method_named
263sub op_method_named { 319sub op_method_named {
264 my ($op) = @_;
265
266 $source .= <<EOF; 320 $source .= <<EOF;
267 { 321 {
268 static HV *last_stash; 322 static HV *last_stash;
269 static SV *last_res; 323 static SV *last_cv;
324 static U32 last_sub_generation;
270 325
271 SV *obj = *(PL_stack_base + TOPMARK + 1); 326 SV *obj = *(PL_stack_base + TOPMARK + 1);
272 327
273 if (SvROK (obj) && SvOBJECT (SvRV (obj))) 328 if (!SvGMAGICAL (obj) && SvROK (obj) && SvOBJECT (SvRV (obj)))
274 { 329 {
275 dSP; 330 dSP;
276 HV *stash = SvSTASH (SvRV (obj)); 331 HV *stash = SvSTASH (SvRV (obj));
277 332
278 /* simple "polymorphic" inline cache */ 333 /* simple "polymorphic" inline cache */
279 if (stash == last_stash) 334 if (stash == last_stash
335 && PL_sub_generation == last_sub_generation)
280 { 336 {
281 XPUSHs (last_res); 337 XPUSHs (last_cv);
282 PUTBACK; 338 PUTBACK;
283 } 339 }
284 else 340 else
285 { 341 {
286 PL_op = nextop;
287 nextop = Perl_pp_method_named (aTHX); 342 PL_op = nextop; nextop = Perl_pp_method_named (aTHX);
288 343
289 SPAGAIN; 344 SPAGAIN;
345 last_sub_generation = PL_sub_generation;
290 last_stash = stash; 346 last_stash = stash;
291 last_res = TOPs; 347 last_cv = TOPs;
292 } 348 }
293 } 349 }
294 else 350 else
295 { 351 {
296 /* error case usually */ 352 /* error case usually */
297 PL_op = nextop;
298 nextop = Perl_pp_method_named (aTHX); 353 PL_op = nextop; nextop = Perl_pp_method_named (aTHX);
299 } 354 }
300 } 355 }
301EOF 356EOF
302 357
303 out_next $op; 358 out_next;
359}
360
361sub op_grepstart {
362 out_callop;
363 $op = $op->next;
364 out_cond_jump $op->other;
365 out_jump_next;
366}
367
368*op_mapstart = \&op_grepstart;
369
370sub op_substcont {
371 out_callop;
372 out_cond_jump $op->other->pmreplstart;
373 assert "nextop == (OP *)${$op->other->next}L";
374 $source .= " goto op_${$op->other->next};\n";
375}
376
377sub out_break_op {
378 my ($idx) = @_;
379
380 out_callop;
381
382 out_cond_jump $_->[$idx]
383 for reverse @op_loop;
384
385 $source .= " return nextop;\n";
386}
387
388sub xop_next {
389 out_break_op 0;
390}
391
392sub op_last {
393 out_break_op 1;
394}
395
396sub xop_redo {
397 out_break_op 2;
304} 398}
305 399
306sub cv2c { 400sub cv2c {
307 my ($cv) = @_; 401 my ($cv) = @_;
308 402
403 local @ops;
404 local @op_loop;
405 local %op_regcomp;
406
309 my %opsseen; 407 my %opsseen;
310 my @ops;
311 my @todo = $cv->START; 408 my @todo = $cv->START;
312 409
313 while (my $op = shift @todo) { 410 while (my $op = shift @todo) {
314 for (; $$op; $op = $op->next) { 411 for (; $$op; $op = $op->next) {
315 last if $opsseen{$$op}++; 412 last if $opsseen{$$op}++;
316 push @ops, $op; 413 push @ops, $op;
414
317 my $name = $op->name; 415 my $name = $op->name;
416 my $class = B::class $op;
417
318 if (B::class($op) eq "LOGOP") { 418 if ($class eq "LOGOP") {
319 push @todo, $op->other; 419 unshift @todo, $op->other; # unshift vs. push saves jumps
320 } elsif ($name eq "subst" and ${ $op->pmreplstart }) { 420
321 push @todo, $op->pmreplstart; 421 # regcomp/o patches ops at runtime, lets expect that
322 } elsif ($name =~ /^enter(loop|iter)$/) { 422 $op_regcomp{${$op->first}} = $op->next
323# if ($] > 5.009) { 423 if $name eq "regcomp" && $op->other->pmflags & B::PMf_KEEP;
324# $labels{${$op->nextop}} = "NEXT"; 424
325# $labels{${$op->lastop}} = "LAST"; 425 } elsif ($class eq "PMOP") {
326# $labels{${$op->redoop}} = "REDO"; 426 unshift @todo, $op->pmreplstart if ${$op->pmreplstart};
327# } else { 427
328# $labels{$op->nextop->seq} = "NEXT"; 428 } elsif ($class eq "LOOP") {
329# $labels{$op->lastop->seq} = "LAST"; 429 push @op_loop, [$op->nextop, $op->lastop->next, $op->redoop->next];
330# $labels{$op->redoop->seq} = "REDO"; 430 push @todo, $op->nextop, $op->lastop->next, $op->redoop->next;
331# }
332 } 431 }
333 } 432 }
334 } 433 }
335 434
336 local $source = <<EOF; 435 local $source = <<EOF;
436OP *%%%FUNC%%% (pTHX)
437{
438 register OP *nextop = (OP *)${$ops[0]}L;
439EOF
440
441 while (@ops) {
442 $op = shift @ops;
443 $op_name = $op->name;
444
445 $source .= "op_$$op: /* $op_name */\n";
446 #$source .= "fprintf (stderr, \"$$op in op $op_name\\n\");\n";#d#
447 #$source .= "{ dSP; sv_dump (TOPs); }\n";#d#
448
449 $source .= " PERL_ASYNC_CHECK ();\n"
450 unless exists $f_noasync{$op_name};
451
452 if (my $can = __PACKAGE__->can ("op_$op_name")) {
453 # handcrafted replacement
454 $can->($op);
455
456 } elsif (exists $f_unsafe{$op_name}) {
457 # unsafe, return to interpreter
458 assert "nextop == (OP *)$$op";
459 $source .= " return nextop;\n";
460
461 } elsif ("LOGOP" eq B::class $op) {
462 # logical operation with optionaö branch
463 out_callop;
464 out_cond_jump $op->other;
465 out_jump_next;
466
467 } elsif ("PMOP" eq B::class $op) {
468 # regex-thingy
469 out_callop;
470 out_cond_jump $op->pmreplroot if ${$op->pmreplroot};
471 out_jump_next;
472
473 } else {
474 # normal operator, linear execution
475 out_linear;
476 }
477 }
478
479 $op_name = "func exit"; assert (0);
480
481 $source .= <<EOF;
482op_0:
483 return 0;
484}
485EOF
486 #warn $source;
487
488 $source
489}
490
491my $uid = "aaaaaaa0";
492
493sub source2ptr {
494 my (@source) = @_;
495
496 my $stem = "/tmp/Faster-$$-" . $uid++;
497
498 open FILE, ">:raw", "$stem.c";
499 print FILE <<EOF;
337#define PERL_NO_GET_CONTEXT 500#define PERL_NO_GET_CONTEXT
338 501
339#include <assert.h> 502#include <assert.h>
340 503
341#include "EXTERN.h" 504#include "EXTERN.h"
342#include "perl.h" 505#include "perl.h"
343#include "XSUB.h" 506#include "XSUB.h"
344 507
345/*typedef OP *(*PPFUNC)(pTHX);*/ 508#define RUNOPS_TILL(op) \\
346 509while (nextop != (op)) \\
347OP *%%%FUNC%%% (pTHX) 510 { \\
348{
349 register OP *nextop = (OP *)${$ops[0]}L;
350EOF
351
352 for my $op (@ops) {
353 my $name = $op->name;
354 my $ppaddr = ppaddr $op->type;
355
356 $source .= "op_$$op: /* $name */\n";
357 #$source .= "fprintf (stderr, \"$$op in op $name\\n\");\n";#d#
358 #$source .= "{ dSP; sv_dump (TOPs); }\n";#d#
359
360 unless (exists $flag{noasync}{$name}) {
361 $source .= " PERL_ASYNC_CHECK ();\n";
362 }
363
364 if (my $can = __PACKAGE__->can ("op_$name")) {
365 $can->($op);
366 } elsif (exists $flag{unsafe}{$name}) {
367 $source .= " assert ((\"$name\", nextop == (OP *)$$op));\n";#d#
368 $source .= " PL_op = nextop; return " . (callop $op) . ";\n";
369 } elsif ("LOGOP" eq B::class $op or exists $flag{otherop}{$name}) {
370 $source .= " assert ((\"$name\", nextop == (OP *)$$op));\n";#d#
371 $source .= " PL_op = nextop; nextop = " . (callop $op) . ";\n";
372 $source .= " if (nextop == (OP *)${$op->other}L) goto op_${$op->other};\n";
373 $source .= " assert ((\"$name\", nextop == (OP *)${$op->next}));\n";#d#
374 $source .= ${$op->next} ? " goto op_${$op->next};\n" : " return 0;\n";
375 } else {
376 $source .= " assert ((\"$name\", nextop == (OP *)$$op));\n";#d#
377 $source .= " PL_op = nextop; nextop = " . (callop $op) . ";\n";
378 if ($name eq "entersub") {
379 $source .= <<EOF;
380while (nextop != (OP *)${$op->next})
381 {
382 PERL_ASYNC_CHECK (); 511 PERL_ASYNC_CHECK (); \\
383 PL_op = nextop; nextop = (PL_op->op_ppaddr)(aTHX); 512 PL_op = nextop; nextop = (PL_op->op_ppaddr)(aTHX); \\
384 } 513 }
514
385EOF 515EOF
386 } 516 for (@source) {
387 $source .= " assert ((\"$name\", nextop == (OP *)${$op->next}));\n";#d# 517 my $func = $uid++;
388 $source .= ${$op->next} ? " goto op_${$op->next};\n" : " return 0;\n"; 518 $_ =~ s/%%%FUNC%%%/$func/g;
389 } 519 print FILE $_;
520 $_ = $func;
390 } 521 }
391 522
392 $source .= "}\n";
393 #warn $source;
394
395 $source
396}
397
398sub source2ptr {
399 my ($source) = @_;
400
401 my $md5 = Digest::MD5::md5_hex $source;
402 $source =~ s/%%%FUNC%%%/Faster_$md5/;
403
404 my $stem = "/tmp/$md5";
405
406 unless (-e "$stem$_so") {
407 open FILE, ">:raw", "$stem.c";
408 print FILE $source;
409 close FILE; 523 close FILE;
410 system "$COMPILE -o $stem$_o $stem.c"; 524 system "$COMPILE -o $stem$_o $stem.c";
525 #d#unlink "$stem.c";
411 system "$LINK -o $stem$_so $stem$_o $LIBS"; 526 system "$LINK -o $stem$_so $stem$_o $LIBS";
412 } 527 unlink "$stem$_o";
413 528
414# warn $source;
415 my $so = DynaLoader::dl_load_file "$stem$_so" 529 my $so = DynaLoader::dl_load_file "$stem$_so"
416 or die "$stem$_so: $!"; 530 or die "$stem$_so: $!";
417 531
418 DynaLoader::dl_find_symbol $so, "Faster_$md5" 532 #unlink "$stem$_so";
419 or die "Faster_$md5: $!" 533
534 map +(DynaLoader::dl_find_symbol $so, $_), @source
420} 535}
536
537my %ignore;
421 538
422sub entersub { 539sub entersub {
423 my ($cv) = @_; 540 my ($cv) = @_;
424 541
542 my $pkg = $cv->STASH->NAME;
543
544 return if $ignore{$pkg};
545
546 warn "compiling ", $cv->STASH->NAME;#d#
547
425 eval { 548 eval {
426 my $source = cv2c $cv; 549 my @cv;
550 my @cv_source;
427 551
552 # always compile the whole stash
553 my %stash = $cv->STASH->ARRAY;
554 while (my ($k, $v) = each %stash) {
555 $v->isa (B::GV::)
556 or next;
557
558 my $cv = $v->CV;
559
560 if ($cv->isa (B::CV::)
561 && ${$cv->START}
562 && $cv->START->name ne "null") {
563 push @cv, $cv;
564 push @cv_source, cv2c $cv;
565 }
566 }
567
428 my $ptr = source2ptr $source; 568 my @ptr = source2ptr @cv_source;
429 569
570 for (0 .. $#cv) {
430 patch_cv $cv, $ptr; 571 patch_cv $cv[$_], $ptr[$_];
572 }
431 }; 573 };
432 574
433 warn $@ if $@; 575 if ($@) {
576 $ignore{$pkg}++;
577 warn $@;
578 }
434} 579}
435 580
436hook_entersub; 581hook_entersub;
437 582
4381; 5831;
439 584
440=back 585=back
441 586
442=head1 LIMITATIONS 587=head1 BUGS/LIMITATIONS
443 588
444Tainting and debugging will disable Faster. 589Perl will check much less often for asynchronous signals in
590Faster-compiled code. It tries to check on every function call, loop
591iteration and every I/O operator, though.
592
593The following things will disable Faster. If you manage to enable them at
594runtime, bad things will happen. Enabling them at startup will be fine,
595though.
596
597 enabled tainting
598 enabled debugging
599
600Thread-enabled builds of perl will dramatically reduce Faster's
601performance, but you don't care about speed if you enable threads anyway.
602
603These constructs will force the use of the interpreter for the currently
604executed function as soon as they are being encountered during execution.
605
606 goto
607 next, redo (but not well-behaved last's)
608 eval
609 require
610 any use of formats
611 .., ... (flipflop operators)
445 612
446=head1 AUTHOR 613=head1 AUTHOR
447 614
448 Marc Lehmann <schmorp@schmorp.de> 615 Marc Lehmann <schmorp@schmorp.de>
449 http://home.schmorp.de/ 616 http://home.schmorp.de/

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines