在Forth裡DoLit指令是用來取字面值(literal)的巧妙機制,當定義高階詞時,如有字面值(literal)編入詞典時,會同時夾帶DoLit編入字面值(literal)的前一個位址,如此一來,當Forth執行到DoLit指令時,便會自動取下一個位址的字面值(literal),這技巧在以低階語言開發的Forth系統上很有效率
不過,JForthBlocks所依賴的以Javascript開發的JeForth,DoLit是否還保有同樣的優勢?
Jimmy's papa動手修改JeForth部份程式碼,再用JForthBlocks同一份積木程式,測試看看有無DoLit的效能,是否有很大的差異,底下是跑五百萬次迴圈的輸出結果,第一次跑出的結果,有無DoLit指令似乎只有幾百微秒(milliseconds)的差異,隨後兩次的結果,執行時間會爆增,或許是垃圾收集機制的干擾
首先,測試compilecode('doLit',n)的效能
function call(xt){// high level definition inner execution loop
highLevelLooping=true; ip=xt;
do{
var id=dictionary[ip++];
//if(typeof(id)=='object'){var v=id['lit'];stack.push(v);continue;}
........
........
}
}
function exec(src){ //source code interpreting loop
.....
.....
do{token=nexttoken(); word=token;
var id=findword(token);
......
......
if(typeof(n)==='string'||n<=0||n>0){
if(compiling)
compilecode('doLit',n);// compile an literal
//compilecode({lit : n});
......
......
}while(error===0&&ntib<tib.length);}
}
連續執行三次的結果
再來,測試compilecode({lit : n})的效能,執行時則統一由call(xt)代勞取字面值(literal)
function call(xt){// high level definition inner execution loop
highLevelLooping=true; ip=xt;
do{
var id=dictionary[ip++];
if(typeof(id)=='object'){var v=id['lit'];stack.push(v);continue;}
........
........
}
}
function exec(src){ //source code interpreting loop
.....
.....
do{token=nexttoken(); word=token;
var id=findword(token);
......
......
if(typeof(n)==='string'||n<=0||n>0){
if(compiling)
//compilecode('doLit',n);// compile an literal
compilecode({lit : n});
......
......
}while(error===0&&ntib<tib.length);}
}
連續執行三次的結果,看來三戰兩勝,以微幅差距領先
底下是積木的XML,可以貼到JForthBlocks的XML編輯區,便會將這次測試所用到的積木載入
<xml xmlns="http://www.w3.org/1999/xhtml">
<block type="procedures_defnoreturn" notchtype="Top_Bottom_Right" inline="false" x="137" y="55">
<title name="NAME">TestLiteral</title>
<statement name="STACK">
<block type="math_PushNumber" notchtype="TOP_BOTTOM">
<title name="NUM">5000000</title>
<next>
<block type="control_ForNext" notchtype="Top_Bottom_Right" inline="false">
<statement name="STACK">
<block type="math_PushNumber" notchtype="TOP_BOTTOM_RIGHT" inline="false">
<title name="NUM">0</title>
<value name="NEXTWORD">
<block type="math_PushNumber" notchtype="LEFT_RIGHT" inline="false">
<title name="NUM">0</title>
<value name="NEXTWORD">
<block type="stack_2drop" notchtype="LEFT_RIGHT" inline="false"></block>
</value>
</block>
</value>
<next>
<block type="math_PushNumber" notchtype="TOP_BOTTOM_RIGHT" inline="false">
<title name="NUM">0</title>
<value name="NEXTWORD">
<block type="math_PushNumber" notchtype="LEFT_RIGHT" inline="false">
<title name="NUM">0</title>
<value name="NEXTWORD">
<block type="stack_2drop" notchtype="LEFT_RIGHT" inline="false"></block>
</value>
</block>
</value>
</block>
</next>
</block>
</statement>
</block>
</next>
</block>
</statement>
</block>
<block type="utility_milliseconds" notchtype="LEFT_RIGHT" inline="false" x="89" y="289">
<value name="NEXTWORD">
<block type="procedures_callnoreturn" notchtype="LEFT_RIGHT" inline="false">
<mutation name="TestLiteral"></mutation>
<value name="NEXTWORD">
<block type="utility_milliseconds" notchtype="LEFT_RIGHT" inline="false">
<value name="NEXTWORD">
<block type="stack_swap" notchtype="LEFT_RIGHT" inline="false">
<value name="NEXTWORD">
<block type="math_Minus" notchtype="LEFT_RIGHT" inline="false">
<value name="NEXTWORD">
<block type="print_DotS" notchtype="LEFT_RIGHT" inline="false"></block>
</value>
</block>
</value>
</block>
</value>
</block>
</value>
</block>
</value>
</block>
</xml>