GSP Code

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

GSP Code

Sergei Rahouski

I stumbled across some GSP generated code. This is the code that gets generated for a GSP tag we have.

 

The line in GSP file looks like this:

 

                <il:singleSelectorListAddButton inputName="contactAdditionalEmailsTextField" selectorList="customerContactAdditionalEmails" duplicateError="Email already exists"/>

 

The code seems to be this:

 

    public Object doCall(Object it)

    {

        CallSite acallsite[] = $getCallSiteArray();

        acallsite[0].callCurrent(this, Integer.valueOf(5));

        acallsite[1].callCurrent(this, ArrayUtil.createArray("singleSelectorListAddButton", "il", Integer.valueOf(26), ScriptBytecodeAdapter.createGroovyObjectWrapper((GroovyPageAttributes)ScriptBytecodeAdapter.asType(ScriptBytecodeAdapter.createMap(new Object[] {

            "inputName", "contactAdditionalEmailsTextField", "selectorList", "customerContactAdditionalEmails", "duplicateError", "Email already exists"

        }), $get$$class$org$codehaus$groovy$grails$web$taglib$GroovyPageAttributes()), $get$$class$org$codehaus$groovy$grails$web$taglib$GroovyPageAttributes()), null));

        return acallsite[2].callCurrent(this, Integer.valueOf(2));

    }

 

What bothers me is the amount of processing that needs to happen in runtime. Could the above code be generated into something more executable similar to what JSP normally does:

 

Map attrs = new LinkedHashMap(3);

attrs.put(‘inputName’, ‘contactAdditionalEmailsTextField’);

attrs.put(‘selectorList, ‘customerContactAdditionalEmails);

attrs.put(‘duplicateError, ‘Email already exists);

// don’t take this line  literally I don’t fully understand magic behind CallSite and how it creates taglib object

new SingleSelectorListAddButton().call(attrs, body = null)

 

What is the price we are paying at runtime for this?

 

Thanks

 

Reply | Threaded
Open this post in threaded view
|

Re: GSP Code

Lari Hotari -

That's what you get with a dynamic language like Groovy. :)

The overhead is very relative. Of course it's much slower than direct Java static byte code, but it is still very fast. You might "only" get a few procents of more throughput performance by optimizing those parts of the GSP code.

Some attempts have been made by Stefan Maldini to use AST transformations for optimizing GSP bytecode instructions.
For example:
https://github.com/grails/grails-core/blob/master/grails-web/src/main/groovy/org/codehaus/groovy/grails/compiler/web/pages/GroovyPageInjectionOperation.java
https://github.com/grails/grails-core/tree/master/grails-plugin-gsp/src/ast/groovy/org/codehaus/groovy/grails/compiler/web/gsp

Some optimizations have been disabled because of GRAILS-8679:
https://github.com/grails/grails-core/commit/cc6d2f76474326664c67aee6b988923bc6533ff2

Currently the encodeAsHTML is relatively slow and it's a much bigger bottleneck than dynamic calls in GSP.
Grails 2.3 will have a "streaming encoder" which is much faster. It's also much easier to implement XSS safety apps with the new solution. See http://jira.grails.org/browse/GRAILS-9906

Lari




23.04.2013 22:29, Sergei Rahouski wrote:

I stumbled across some GSP generated code. This is the code that gets generated for a GSP tag we have.

 

The line in GSP file looks like this:

 

                <il:singleSelectorListAddButton inputName="contactAdditionalEmailsTextField" selectorList="customerContactAdditionalEmails" duplicateError="Email already exists"/>

 

The code seems to be this:

 

    public Object doCall(Object it)

    {

        CallSite acallsite[] = $getCallSiteArray();

        acallsite[0].callCurrent(this, Integer.valueOf(5));

        acallsite[1].callCurrent(this, ArrayUtil.createArray("singleSelectorListAddButton", "il", Integer.valueOf(26), ScriptBytecodeAdapter.createGroovyObjectWrapper((GroovyPageAttributes)ScriptBytecodeAdapter.asType(ScriptBytecodeAdapter.createMap(new Object[] {

            "inputName", "contactAdditionalEmailsTextField", "selectorList", "customerContactAdditionalEmails", "duplicateError", "Email already exists"

        }), $get$$class$org$codehaus$groovy$grails$web$taglib$GroovyPageAttributes()), $get$$class$org$codehaus$groovy$grails$web$taglib$GroovyPageAttributes()), null));

        return acallsite[2].callCurrent(this, Integer.valueOf(2));

    }

 

What bothers me is the amount of processing that needs to happen in runtime. Could the above code be generated into something more executable similar to what JSP normally does:

 

Map attrs = new LinkedHashMap(3);

attrs.put(‘inputName’, ‘contactAdditionalEmailsTextField’);

attrs.put(‘selectorList, ‘customerContactAdditionalEmails);

attrs.put(‘duplicateError, ‘Email already exists);

// don’t take this line  literally I don’t fully understand magic behind CallSite and how it creates taglib object

new SingleSelectorListAddButton().call(attrs, body = null)

 

What is the price we are paying at runtime for this?

 

Thanks

 



Reply | Threaded
Open this post in threaded view
|

RE: GSP Code

Sergei Rahouski

Thanks Lari!

 

From: Lari Hotari [mailto:[hidden email]]
Sent: Wednesday, April 24, 2013 1:36 AM
To: [hidden email]
Cc: Sergei Rahouski
Subject: Re: [grails-user] GSP Code

 


That's what you get with a dynamic language like Groovy. :)

The overhead is very relative. Of course it's much slower than direct Java static byte code, but it is still very fast. You might "only" get a few procents of more throughput performance by optimizing those parts of the GSP code.

Some attempts have been made by Stefan Maldini to use AST transformations for optimizing GSP bytecode instructions.
For example:
https://github.com/grails/grails-core/blob/master/grails-web/src/main/groovy/org/codehaus/groovy/grails/compiler/web/pages/GroovyPageInjectionOperation.java
https://github.com/grails/grails-core/tree/master/grails-plugin-gsp/src/ast/groovy/org/codehaus/groovy/grails/compiler/web/gsp

Some optimizations have been disabled because of GRAILS-8679:
https://github.com/grails/grails-core/commit/cc6d2f76474326664c67aee6b988923bc6533ff2

Currently the encodeAsHTML is relatively slow and it's a much bigger bottleneck than dynamic calls in GSP.
Grails 2.3 will have a "streaming encoder" which is much faster. It's also much easier to implement XSS safety apps with the new solution. See http://jira.grails.org/browse/GRAILS-9906

Lari




23.04.2013 22:29, Sergei Rahouski wrote:

I stumbled across some GSP generated code. This is the code that gets generated for a GSP tag we have.

 

The line in GSP file looks like this:

 

                <il:singleSelectorListAddButton inputName="contactAdditionalEmailsTextField" selectorList="customerContactAdditionalEmails" duplicateError="Email already exists"/>

 

The code seems to be this:

 

    public Object doCall(Object it)

    {

        CallSite acallsite[] = $getCallSiteArray();

        acallsite[0].callCurrent(this, Integer.valueOf(5));

        acallsite[1].callCurrent(this, ArrayUtil.createArray("singleSelectorListAddButton", "il", Integer.valueOf(26), ScriptBytecodeAdapter.createGroovyObjectWrapper((GroovyPageAttributes)ScriptBytecodeAdapter.asType(ScriptBytecodeAdapter.createMap(new Object[] {

            "inputName", "contactAdditionalEmailsTextField", "selectorList", "customerContactAdditionalEmails", "duplicateError", "Email already exists"

        }), $get$$class$org$codehaus$groovy$grails$web$taglib$GroovyPageAttributes()), $get$$class$org$codehaus$groovy$grails$web$taglib$GroovyPageAttributes()), null));

        return acallsite[2].callCurrent(this, Integer.valueOf(2));

    }

 

What bothers me is the amount of processing that needs to happen in runtime. Could the above code be generated into something more executable similar to what JSP normally does:

 

Map attrs = new LinkedHashMap(3);

attrs.put(‘inputName’, ‘contactAdditionalEmailsTextField’);

attrs.put(‘selectorList, ‘customerContactAdditionalEmails);

attrs.put(‘duplicateError, ‘Email already exists);

// don’t take this line  literally I don’t fully understand magic behind CallSite and how it creates taglib object

new SingleSelectorListAddButton().call(attrs, body = null)

 

What is the price we are paying at runtime for this?

 

Thanks