NAME
Text::Xslate::PP::Booster - Text::Xslate code generator for pure Perl
SYNOPSIS
# If you want to check created codes, you can use it directly.
use Text::Xslate::PP;
use Text::Xslate::PP::Booster;
my $tx = Text::Xslate->new();
my $booster = Text::Xslate::PP::Booster->new();
my $optext = q{<: $value :>};
my $code = $booster->opcode_to_perlcode_string( $tx->compile( $optext ) );
my $coderef = $booster->opcode_to_perlcode( $tx->compile( $optext ) );
# $coderef takes a Text::Xslate::PP::State object
DESCRIPTION
This module is a pure Perl engine, which is much faster than Text::Xslate::PP::Opcode, but might be less stable.
The motivation to implement this engine is the performance. You know the default pure Perl engine was really slow. For example:
$ XSLATE=pp=opcode perl -Mblib benchmark/others.pl
Perl/5.10.1 i686-linux
Text::Xslate/0.1025
Text::MicroTemplate/0.11
Template/2.22
Text::ClearSilver/0.10.5.4
HTML::Template::Pro/0.94
...
Benchmarks with 'list' (datasize=100)
Rate Xslate TT MT TCS HT
Xslate 155/s -- -52% -83% -94% -95%
TT 324/s 109% -- -64% -88% -90%
MT 906/s 486% 180% -- -66% -73%
TCS 2634/s 1604% 713% 191% -- -21%
HT 3326/s 2051% 927% 267% 26% --
All right, it is slower than Template-Toolkit! But now Text::Xslate::PP::Booster is available, and is as fast as Text::MicroTemplate:
$ XSLATE=pp perl -Mblib benchmark/others.pl
...
Benchmarks with 'list' (datasize=100)
Rate TT Xslate MT TCS HT
TT 330/s -- -63% -65% -87% -90%
Xslate 896/s 172% -- -5% -65% -73%
MT 941/s 185% 5% -- -63% -72%
TCS 2543/s 671% 184% 170% -- -24%
HT 3338/s 912% 272% 255% 31% --
Text::Xslate::PP becomes much faster than the default pure Perl engine!
The engine is enabled with $ENV{ENV}='pp=booster'
.
APIs
new
Constructor.
$booster = Text::Xslate::PP::Booster->new();
opcode_to_perlcode
Takes a virtual machine code created by Text::Xslate::Compiler, and returns a code reference.
$coderef = $booster->opcode_to_perlcode( $ops );
The code reference takes Text::Xslate::PP::State
object in Xslate runtime processes. Don't execute this code reference directly.
opcode_to_perlcode_string
Takes a virtual machine code created by Text::Xslate::Compiler
, and returns a perl subroutine code text.
$str = $booster->opcode_to_perlcode_string( $ops );
ABOUT BOOST CODE
Text::Xslate::PP::Booster
creates a code reference from a virtual machine code.
$tx->render_string( <<'CODE', {} );
: macro foo -> $arg {
Hello <:= $arg :>!
: }
: foo($value)
CODE
Firstly the template data is converted to opcodes:
pushmark
fetch_s "value"
push
macro "foo"
macrocall
print
end
macro_begin "foo"
print_raw_s " Hello "
fetch_lvar 0
print
print_raw_s "!\n"
macro_end
And the booster converted them into a perl subroutine code (you can get that code by XSLATE=dump=pp
).
sub {
no warnings 'recursion';
my ( $st ) = @_;
my ( $sv, $pad, %macro, $depth );
my $output = q{};
my $vars = $st->{ vars };
$st->{pad} = $pad = [ [ ] ];
# macro
$macro{"foo"} = $st->{ booster_macro }->{"foo"} ||= sub {
my ( $st, $pad, $f_l ) = @_;
my $vars = $st->{ vars };
my $mobj = $st->symbol->{ "foo" };
my $output = q{};
if ( @{$pad->[-1]} != $mobj->nargs ) {
$st->error( $f_l, _macro_args_error( $mobj, $pad ) );
return '';
}
if ( my $outer = $mobj->outer ) {
my @temp = @{$pad->[-1]};
@{$pad->[-1]}[ 0 .. $outer - 1 ] = @{$pad->[-2]}[ 0 .. $outer - 1 ];
@{$pad->[-1]}[ $outer .. $outer + $mobj->nargs ] = @temp;
}
Carp::croak('Macro call is too deep (> 100) on "foo"') if ++$depth > 100;
# print_raw_s
$output .= " Hello ";
# print
$sv = $pad->[ -1 ]->[ 0 ];
if ( ref($sv) eq 'Text::Xslate::Type::Raw' ) {
if(defined ${$sv}) {
$output .= $sv;
}
else {
$st->warn( ["foo", 13], "Use of nil to print" );
}
}
elsif ( defined $sv ) {
$sv =~ s/($html_metachars)/$html_escape{$1}/xmsgeo;
$output .= $sv;
}
else {
$st->warn( ["foo", 13], "Use of nil to print" );
}
# print_raw_s
$output .= "!\n";
$depth--;
pop( @$pad );
return mark_raw($output);
};
# process start
# print
$sv = $macro{ "foo" }->( $st, push_pad( $pad, [ $vars->{ "value" } ] ), [ "main", 5 ] );
if ( ref($sv) eq 'Text::Xslate::Type::Raw' ) {
if(defined ${$sv}) {
$output .= $sv;
}
else {
$st->warn( ["main", 6], "Use of nil to print" );
}
}
elsif ( defined $sv ) {
$sv =~ s/($html_metachars)/$html_escape{$1}/xmsgeo;
$output .= $sv;
}
else {
$st->warn( ["main", 6], "Use of nil to print" );
}
# process end
return $output;
}
So it makes the runtime speed much faster. Of course, its initial converting process costs time and memory.
SEE ALSO
AUTHOR
Makamaka Hannyaharamitu <makamaka at cpan.org>
LICENSE AND COPYRIGHT
Copyright (c) 2010 by Makamaka Hannyaharamitu (makamaka).
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.