[Laszlo-dev] application/lfc file size

P T Withington ptw at pobox.com
Thu Aug 28 07:11:42 PDT 2008


On 2008-08-27, at 20:30EDT, André Bargull wrote:

> The code-expansion in "dataBindAttribute" is the "setAttribute"- 
> inlining. That is made by purpose to improve performance.

André is right, setAttribute is intentionally in-lined because it is  
the most common operation in LZX code.  We have to keep in mind that  
in addition to the code size goal, there is also a performance goal.   
We can't trade one for the other.

> But that snippet shows some other optimization points:
> - the "is"-test could be optimized away, because "Function" will  
> never have a "$lzsc$isa"-method (same goes for LzEvent) (this is  
> LPP-6692)
> - the "ondatapath" variable is quite long ("$lzsc$1375182235"),  
> possible to use a shorter form?

The fix for this is to re-organize the function-local analyzer to run  
_after_ inline expansions happen, so that the var's introduced by  
inline expansion get rewritten to the short $<number> names.

http://jira.openlaszlo.org/jira/browse/LPP-6691

> - the compiler should know that there is a setter for "datapath"  
> defined in LzNode, this setter could be called directly

This would be a _great_ optimization to have because it would improve  
both speed and space.  It would mean our compiler would need to start  
tracking type declarations (or inferring them), and we would have to  
make them.

Other random thoughts:

All runtimes do support setter methods (in various forms).  We could  
take this effort as the impetus to finally utilize them.  I thought  
there was a Jira for this (because it has been discussed, and there  
are significant ramifications on how we use setters in LZX -- storing  
setter state in an attribute with the same name), but I can't find it  
at the moment.

If all runtimes supported a 'does not understand' or 'no such method'  
we could use that to trampoline to the generic setter method.

Since our compiler does 'whole program' compilation, it could know all  
the calls to setAttribute and/or delegate registration, and just  
ensure that there is a setter method defined for every such  
attribute.  (Is there ever a need to set or register on a non-constant  
attribute?)

> Concerning LPP-6017: the original changeset may work, if there is a  
> possibility to add certain properties early enough to the LzNode- 
> instance (primarily functions). That way, the LzDelegate bug should  
> go away (LPP-6370).
>
>
>> Some initial thoughts:
>>
>> In LzNode.lzs, dataBindAttribute(),
>> this:
>>
>>     if ( !this.datapath ){
>>       this.setAttribute('datapath', ".");
>>     }
>>
>> Is translated to:
>>
>> if(!this.datapath){
>> if(!this.__LZdeleted){
>> if(Function["$lzsc$isa"]?Function.$lzsc$isa(this["$lzc  
>> $set_datapath"]):this["$lzc$set_datapath"] instanceof Function){
>> this["$lzc$set_datapath"](".")
>> }else{
>> this["datapath"]=".";var $lzsc  
>> $1375182235=this["ondatapath"];if(LzEvent["$lzsc$isa"]?LzEvent. 
>> $lzsc $isa($lzsc$1375182235):$lzsc$1375182235 instanceof LzEvent){
>> if($lzsc$1375182235.ready){
>> $lzsc$1375182235.sendEvent(".")
>> }}}}}
>>
>> I wonder if we could improve this by using some global helper  
>> functions:
>>
>>     if ( !this.datapath ){
>>       $lzsc$Util.setAttribute(this, 'datapath', ".");
>>     }
>>
>> or even:
>>
>>     if ( !this.datapath ){
>>       $lzsc$Util.setAttribute(this, 'datapath', "$lzsc 
>> $set_datapath",  "ondatapath", ".");
>>     }
>>
>> If we could do the former, we might get a savings of 250 bytes per.
>> There are at about 40 occurrences of this code.  10K savings.
>> Not huge, but maybe this sort of simple technique can be
>> applied in other situations.
>>
>> For example, there are 85 occurrences of something like this in the  
>> LFC:
>>
>>   (arguments.callee.superclass?  
>> arguments.callee.superclass.prototype["$lzsc  
>> $initialize"]:this.nextMethod(arguments.callee,"$lzsc  
>> $initialize")).call(this,$1,$2,$3,$4)
>>
>> Maybe something like:
>>
>>   $lzsc$Util.superFcn(this, "$lzsc$initialize",  
>> arguments).call(this, $1,$2,$3,$4);
>>
>> Another 6K savings.
>>
>> ================================================================
>> Common subexpressions (CSE) elimination:
>>
>> I think about 42K of the LFC (347K) is strings.
>>   $ grep '"'  LFCdhtml.js | sed -e 's/^[^"]*//' -e 's/[^"]*$//' -e   
>> 's/"\([^"]*\)"[^"]*/"\1"/g' | tr '"' '\012' | grep . | sort | wc -c
>>   42509
>>
>> About 24K of that is unique:
>> $ grep '"'  LFCdhtml.js | sed -e 's/^[^"]*//' -e 's/[^"]*$//' -e  
>> 's/"\ ([^"]*\)"[^"]*/"\1"/g' | tr '"' '\012' | grep . | sort | uniq  
>> | wc -c
>>   24300
>>
>> So 18K of strings are redundant (used more than once).
>> When strings are used more then a couple times, a variable could
>> be used.  This could happen automatically (recognizing it in the
>> compiler), or looking for extreme cases and fixing them manually.
>>
>> ================================================================
>> Wacky CSE idea #1
>>
>> There are lots of occurrences of 'this.', for example this.foo,   
>> this.bar().
>> When we see a lot of these in a function, could set $1 = this;
>> and then use $1.foo instead of this.foo.
>> With 4400 occurrences in the LFC, that saves us up to 8K bytes.
>> I know, it's wacky.
>>
>> If it's done in the compiler, it would be the first step for more
>> sophisticated CSE elimination  Finding commonalities like:
>>    this.foo.x, this.foo.bar
>> and setting a common variable $1 = this.foo .
>> ================================================================
>> There are some commentary here about how things got larger and
>> some attempts to fix things:
>>
>>    http://www.openlaszlo.org/jira/browse/LPP-6017
>>
>>
>> --
>>
>> Don Anderson
>> Java/C/C++, Berkeley DB, systems consultant
>>
>> voice: 617-547-7881
>> email: dda at ddanderson.com
>> www: http://www.ddanderson.com
>
>




More information about the Laszlo-dev mailing list