[stringtemplate-interest] StringTemplate Compiler for .NET
Sam Harwell
sharwell at pixelminegames.com
Wed Mar 18 17:25:38 PDT 2009
So here we go/you've inspired me. :) For syntax highlighting, view in
HTML.
I'm starting with the if condition evaluation in ConditionalExpr. The
delegate returned can call either the interpreted version or a dynamic
method to evaluate the expression. The delegates are created on-demand
inside ConditionalExpr.Write, and called instead of directly creating
instances of ActionEvaluator like before.
public static bool EnableDynamicMethods = true;
static int _evaluatorNumber = 1;
static System.Func<StringTemplate, IStringTemplateWriter, bool>
GetEvaluator( ASTExpr chunk, ITree condition )
{
if ( EnableDynamicMethods )
{
try
{
Type[] parameterTypes = { typeof( StringTemplate ), typeof(
IStringTemplateWriter ) };
DynamicMethod method = new DynamicMethod(
"ConditionEvaluator" + _evaluatorNumber++, typeof( bool ),
parameterTypes );
var gen = method.GetILGenerator();
ActionEvaluator evalCompiled = new ActionEvaluator( null,
chunk, null, condition );
evalCompiled.ifConditionCompiled( gen );
gen.Emit( OpCodes.Ret );
var dynamicEvaluator = (System.Func<StringTemplate,
IStringTemplateWriter, bool>)method.CreateDelegate( typeof(
System.Func<StringTemplate, IStringTemplateWriter, bool> ) );
return dynamicEvaluator;
}
catch
{
// fall back to interpreted version
}
}
return new System.Func<StringTemplate, IStringTemplateWriter, bool>(
( self, @out ) =>
{
ActionEvaluator eval = new ActionEvaluator( self, chunk, @out,
condition );
return eval.ifCondition();
} );
}
Inside ActionEvaluator.g3, I'm working my way up, and it throws
System.NotImplementedException if it doesn't know how to emit IL for the
[sub]expression. The exception results in automatic fallback to the
interpreted code that we know works.
public
ifConditionCompiled[System.Reflection.Emit.ILGenerator gen]
: ifAtomCompiled[$gen]
| ^(NOT ifAtomCompiled[$gen])
{EmitNot($gen);}
;
ifAtomCompiled[System.Reflection.Emit.ILGenerator gen]
: exprCompiled[$gen] {EmitTest($gen);}
;
exprCompiled[System.Reflection.Emit.ILGenerator gen]
: ^(PLUS exprCompiled[$gen] exprCompiled[$gen])
{throw new System.NotImplementedException();}
| templateApplication
{throw new System.NotImplementedException();}
| attribute
{throw new System.NotImplementedException();}
| templateInclude
{throw new System.NotImplementedException();}
| function
{throw new System.NotImplementedException();}
| list
{throw new System.NotImplementedException();}
| ^(VALUE exprCompiled[$gen])
{throw new System.NotImplementedException();}
;
Helper methods do the actual emit:
static void EmitNot( ILGenerator gen )
{
gen.Emit( OpCodes.Not );
}
static void EmitTest( ILGenerator gen )
{
var label = gen.DefineLabel();
var label2 = gen.DefineLabel();
gen.Emit( OpCodes.Brtrue_S, label );
gen.Emit( OpCodes.Ldc_I4_0 );
gen.Emit( OpCodes.Br_S, label2 );
gen.MarkLabel( label );
gen.Emit( OpCodes.Ldc_I4_1 );
gen.MarkLabel( label2 );
}
Sam
-----Original Message-----
From: stringtemplate-interest-bounces at antlr.org
[mailto:stringtemplate-interest-bounces at antlr.org] On Behalf Of Volkan
Ceylan
Sent: Tuesday, March 17, 2009 3:52 AM
To: stringtemplate-interest at antlr.org
Subject: [stringtemplate-interest] StringTemplate Compiler for .NET
> I'm extremely interested to see how the compiled code performs
compared
> to my C# port of StringTemplate.
Hi, is your C# port open source? Would like to see what optimizations
you did. I'm currently working on public 3.1beta at stringtemplate.org
> That aside, I think the idea of compiling templates to an assembly is
great.
Actually, i'm not thinking about compiling to an assembly, but to
dynamic methods. AFAIK, due to some problems with .NET, when you load
an assembly, there is no way to unload it, unless you use a separate
application domain to load assemblies, and unload the domain
completely.
Dynamic methods can be garbage collected when you have no delegates or
references to them. That's why i prefer dynamic methods versus
assemblies. The only problem with dynamic methods i see is that they
are harder to debug :(
>I used a sampling method to profile the library. The test was a batch
conversion
> of the 8 grammars that are used in the C# port of the ANTLR >Tool.
54.33% (inclusive)
> of the samples were in Antlr3.StringTemplate.dll. Only 6.59%
(inclusive) was spent
> in >ASTExpr.rawGetObjectProperty, which is responsible for all
measurable uses of .NET reflection.
> 35.31% (inclusive) of the time was spent in >ActionEvaluator.action,
> (note: this call encapsulates all calls to
ASTExpr.rawGetObjectProperty).
ActionEvaluator.action is walking a tree and consists of some costly
CASE statements. When a template is compiled, there will not be any of
them in the generated IL. Currently i'm having about 10x speed for
simple templates.
> By implementing a System.Type -> System.Reflection.MemberInfo map in
ASTExpr and
> caching the property accessors, I was able to reduce the time spent in
> ASTExpr.rawGetObjectProperty to 2.36% (inclusive).
This is a nice idea, would like to see implementation. There may be
even a further improvement by compiling property accessors as dynamic
methods such as (type, property) -> dynamic get delegate (though i'm
not %100 sure about that, need to see source code of new DLR)
> PS: I've thought about doing something similar to the CLI compilation
with
> ANTLR grammars, but profiling the generated code has shown that it's
not the bottleneck right now.
I don't know much about ANTLR and its grammars, other than a general
overview of what it is used for :(
_______________________________________________
stringtemplate-interest mailing list
stringtemplate-interest at antlr.org
http://www.antlr.org/mailman/listinfo/stringtemplate-interest
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.antlr.org/pipermail/stringtemplate-interest/attachments/20090318/94ee6415/attachment-0001.html
More information about the stringtemplate-interest
mailing list