add instruction & changes in codegen

add some instructions that execute const values.
the first symbol called in assignment will use op_load instead of op_meq,op_pop to assign.
This commit is contained in:
ValKmjolnir 2021-06-29 17:18:05 +08:00
parent 706659ba3d
commit 0b2fe61e6e
4 changed files with 375 additions and 106 deletions

View File

@ -32,13 +32,15 @@ You could add your own built-in functions to change this interpreter to a useful
Better choose the latest update of the interpreter. Better choose the latest update of the interpreter.
MUST USE -O2/-O3 if want to optimize the interpreter! pragma gcc optimize(2) seems useless when using g++ MUST USE -O2/-O3 if want to optimize the interpreter!
> g++ -std=c++11 -O2 main.cpp -o nasal.exe Also remember to use g++ and clang++.
> g++|clang++ -std=c++11 -O2 main.cpp -o nasal.exe
Or use this in linux/macOS/Unix Or use this in linux/macOS/Unix
> g++ -std=c++11 -O2 main.cpp -o nasal > g++|clang++ -std=c++11 -O2 main.cpp -o nasal
## How to Use? ## How to Use?
@ -117,7 +119,7 @@ If i continue saving this interpreter,it will be harder for me to make the bytec
## Byte Code Interpreter ## Byte Code Interpreter
### Version 4.0(last update 2020/12/17) ### Version 4.0 (last update 2020/12/17)
I have just finished the first version of byte-code-interpreter. I have just finished the first version of byte-code-interpreter.
@ -150,7 +152,7 @@ for(var i=0;i<4000000;i+=1);
0x0000000b: nop 0x00000000 0x0000000b: nop 0x00000000
``` ```
### Version 5.0(last update 2021/3/7) ### Version 5.0 (last update 2021/3/7)
I decide to optimize bytecode vm in this version. I decide to optimize bytecode vm in this version.
@ -158,7 +160,7 @@ Because it takes more than 1.5s to count i from 0 to 4000000-1.This is not effic
2021/1/23 update: Now it can count from 0 to 4000000-1 in 1.5s. 2021/1/23 update: Now it can count from 0 to 4000000-1 in 1.5s.
### Version 6.0(last update 2021/6/1) ### Version 6.0 (last update 2021/6/1)
Use loadg loadl callg calll mcallg mcalll to avoid branches. Use loadg loadl callg calll mcallg mcalll to avoid branches.
@ -199,7 +201,7 @@ for(var i=0;i<4000000;i+=1);
0x0000000c: nop 0x00000000 0x0000000c: nop 0x00000000
``` ```
### Version 6.5(last update 2021/6/24) ### Version 6.5 (last update 2021/6/24)
2021/5/31 update: Now gc can collect garbage correctly without re-collecting,which will cause fatal error. 2021/5/31 update: Now gc can collect garbage correctly without re-collecting,which will cause fatal error.
@ -329,16 +331,62 @@ As you could see from the bytecode above,mcall/mcallv/mcallh operands' using fre
And because of the new structure of mcall, addr_stack, a stack used to store the memory address, is deleted from nasal_vm, and now nasal_vm use nasal_val** mem_addr to store the memory address. This will not cause fatal errors because the memory address is used __immediately__ after getting it. And because of the new structure of mcall, addr_stack, a stack used to store the memory address, is deleted from nasal_vm, and now nasal_vm use nasal_val** mem_addr to store the memory address. This will not cause fatal errors because the memory address is used __immediately__ after getting it.
### version 7.0(latest) ### version 7.0 (latest)
2021/6/26 update: 2021/6/26 update:
Instruction dispatch is changed from call-threading to computed-goto(with inline function).After changing the way of instruction dispatch,there is a great improvement in nasal_vm.Now vm can run test/bigloop and test/pi in 0.2s!And vm runs test/fib in 0.8s on linux.You could see the time use data below,in Test data section. Instruction dispatch is changed from call-threading to computed-goto(with inline function).After changing the way of instruction dispatch,there is a great improvement in nasal_vm.Now vm can run test/bigloop and test/pi in 0.2s!And vm runs test/fib in 0.8s on linux.You could see the time use data below,in Test data section.
This version uses gcc extension "labels as values", which is also supported by clang.(But i don't know if MSVC supports this) This version uses g++ extension "labels as values", which is also supported by clang++.(But i don't know if MSVC supports this)
There is also a change in nasal_gc: std::vector global is deleted,now the global values are all stored on stack(from val_stack+0 to val_stack+intg-1). There is also a change in nasal_gc: std::vector global is deleted,now the global values are all stored on stack(from val_stack+0 to val_stack+intg-1).
2021/6/29 update:
Add some instructions that execute const values:op_addc,op_subc,op_mulc,op_divc,op_lnkc,op_addeqc,op_subeqc,op_muleqc,op_diveqc,op_lnkeqc.
Now the bytecode of test/bigloop.nas seems like this:
```asm
.number 4e+006
.number 1
0x00000000: intg 0x00000001
0x00000001: pzero 0x00000000
0x00000002: loadg 0x00000000
0x00000003: callg 0x00000000
0x00000004: pnum 0x00000000 (4000000)
0x00000005: less 0x00000000
0x00000006: jf 0x0000000b
0x00000007: mcallg 0x00000000
0x00000008: addeqc 0x00000001 (1)
0x00000009: pop 0x00000000
0x0000000a: jmp 0x00000003
0x0000000b: nop 0x00000000
```
And this test file runs in 0.1s after this update.Most of the calculations are accelerated.
Also, assignment bytecode has changed a lot. Now the first identifier that called in assignment will use op_load to assign, instead of op_meq,op_pop.
```javascript
var (a,b)=(1,2);
a=b=0;
```
```asm
.number 2
0x00000000: intg 0x00000002
0x00000001: pone 0x00000000
0x00000002: loadg 0x00000000
0x00000003: pnum 0x00000000 (2)
0x00000004: loadg 0x00000001
0x00000005: pzero 0x00000000
0x00000006: mcallg 0x00000001
0x00000007: meq 0x00000000 (b=2 use meq,pop->a)
0x00000008: loadg 0x00000000 (a=b use loadg)
0x00000009: nop 0x00000000
```
## Test data ## Test data
### version 6.5(i5-8250U windows10 2021/6/19) ### version 6.5(i5-8250U windows10 2021/6/19)
@ -388,20 +436,20 @@ operands calling total times:
|quick_sort.nas|16226|5561|4144|3524|2833| |quick_sort.nas|16226|5561|4144|3524|2833|
|bfs.nas|24707|16297|14606|14269|8672| |bfs.nas|24707|16297|14606|14269|8672|
### version 7.0(i5-8250U ubuntu-WSL on windows10 2021/6/26) ### version 7.0(i5-8250U ubuntu-WSL on windows10 2021/6/29)
running time: running time:
|file|total time|info| |file|total time|info|
|:----|:----|:----| |:----|:----|:----|
|pi.nas|0.17s|great improvement| |pi.nas|0.15625s|great improvement|
|fib.nas|0.75s|great improvement| |fib.nas|0.75s|great improvement|
|bp.nas|0.32s(5467 epoch)|good improvement| |bp.nas|0.4218s(7162 epoch)|good improvement|
|bigloop.nas|0.11s|great improvement| |bigloop.nas|0.09375s|great improvement|
|mandelbrot.nas|0.04s|great improvment| |mandelbrot.nas|0.0312s|great improvement|
|life.nas|8.80s(windows) 1.34(ubuntu WSL)|little improvement| |life.nas|8.80s(windows) 1.25(ubuntu WSL)|little improvement|
|ascii-art.nas|0.015s|little improvement| |ascii-art.nas|0.015s|little improvement|
|calc.nas|0.0625s|little improvement| |calc.nas|0.0468s|little improvement|
|quick_sort.nas|0s|great improvement| |quick_sort.nas|0s|great improvement|
|bfs.nas|0.0156s|great improvement| |bfs.nas|0.0156s|great improvement|

View File

@ -28,11 +28,21 @@ enum op_code
op_mul, // * op_mul, // *
op_div, // / op_div, // /
op_lnk, // ~ op_lnk, // ~
op_addc, // + const
op_subc, // - const
op_mulc, // * const
op_divc, // / const
op_lnkc, // ~ const
op_addeq, // += op_addeq, // +=
op_subeq, // -= op_subeq, // -=
op_muleq, // *= op_muleq, // *=
op_diveq, // /= op_diveq, // /=
op_lnkeq, // ~= op_lnkeq, // ~=
op_addeqc, // += const
op_subeqc, // -= const
op_muleqc, // *= const
op_diveqc, // /= const
op_lnkeqc, // ~= const
op_meq, // = op_meq, // =
op_eq, // == op_eq, // ==
op_neq, // != op_neq, // !=
@ -98,11 +108,21 @@ struct
{op_mul, "mult "}, {op_mul, "mult "},
{op_div, "div "}, {op_div, "div "},
{op_lnk, "link "}, {op_lnk, "link "},
{op_addc, "addc "},
{op_subc, "subc "},
{op_mulc, "multc "},
{op_divc, "divc "},
{op_lnkc, "lnkc "},
{op_addeq, "addeq "}, {op_addeq, "addeq "},
{op_subeq, "subeq "}, {op_subeq, "subeq "},
{op_muleq, "muleq "}, {op_muleq, "muleq "},
{op_diveq, "diveq "}, {op_diveq, "diveq "},
{op_lnkeq, "lnkeq "}, {op_lnkeq, "lnkeq "},
{op_addeqc, "addeqc"},
{op_subeqc, "subeqc"},
{op_muleqc, "muleqc"},
{op_diveqc, "diveqc"},
{op_lnkeqc, "lnkeqc"},
{op_meq, "meq "}, {op_meq, "meq "},
{op_eq, "eq "}, {op_eq, "eq "},
{op_neq, "neq "}, {op_neq, "neq "},
@ -141,8 +161,8 @@ struct
struct opcode struct opcode
{ {
uint8_t op; uint8_t op;
uint32_t num; int32_t num;
opcode(uint8_t _op=op_nop,uint32_t _num=0) opcode(uint8_t _op=op_nop,int32_t _num=0)
{ {
op=_op; op=_op;
num=_num; num=_num;
@ -178,7 +198,7 @@ private:
void add_sym(std::string&); void add_sym(std::string&);
int local_find(std::string&); int local_find(std::string&);
int global_find(std::string&); int global_find(std::string&);
void gen(unsigned char,unsigned int); void gen(uint8_t,int32_t);
void num_gen(nasal_ast&); void num_gen(nasal_ast&);
void str_gen(nasal_ast&); void str_gen(nasal_ast&);
void vec_gen(nasal_ast&); void vec_gen(nasal_ast&);
@ -283,7 +303,7 @@ int nasal_codegen::global_find(std::string& name)
return -1; return -1;
} }
void nasal_codegen::gen(uint8_t op,uint32_t num) void nasal_codegen::gen(uint8_t op,int32_t num)
{ {
exec_code.push_back({op,num}); exec_code.push_back({op,num});
return; return;
@ -454,6 +474,7 @@ void nasal_codegen::call_hash(nasal_ast& ast)
void nasal_codegen::call_vec(nasal_ast& ast) void nasal_codegen::call_vec(nasal_ast& ast)
{ {
// maybe this place can use callv-const if ast's first child is ast_num
if(ast.get_children().size()==1 && ast.get_children()[0].get_type()!=ast_subvec) if(ast.get_children().size()==1 && ast.get_children()[0].get_type()!=ast_subvec)
{ {
calc_gen(ast.get_children()[0]); calc_gen(ast.get_children()[0]);
@ -620,20 +641,38 @@ void nasal_codegen::multi_assign_gen(nasal_ast& ast)
for(int i=0;i<size;++i) for(int i=0;i<size;++i)
{ {
mcall(ast.get_children()[0].get_children()[i]); mcall(ast.get_children()[0].get_children()[i]);
// multi assign user loadl and loadg to avoid meq's stack--
// and this operation changes local and global value directly
if(exec_code.back().op==op_mcalll)
exec_code.back().op=op_loadl;
else if(exec_code.back().op==op_mcallg)
exec_code.back().op=op_loadg;
else
{
gen(op_meq,0); gen(op_meq,0);
gen(op_pop,0); gen(op_pop,0);
} }
} }
}
else else
{ {
calc_gen(ast.get_children()[1]); calc_gen(ast.get_children()[1]);
for(int i=0;i<size;++i) for(int i=0;i<size;++i)
{ {
gen(op_callvi,i); gen(op_callvi,i);
// multi assign user loadl and loadg to avoid meq's stack--
// and this operation changes local and global value directly
mcall(ast.get_children()[0].get_children()[i]); mcall(ast.get_children()[0].get_children()[i]);
if(exec_code.back().op==op_mcalll)
exec_code.back().op=op_loadl;
else if(exec_code.back().op==op_mcallg)
exec_code.back().op=op_loadg;
else
{
gen(op_meq,0); gen(op_meq,0);
gen(op_pop,0); gen(op_pop,0);
} }
}
gen(op_pop,0); gen(op_pop,0);
} }
return; return;
@ -895,18 +934,57 @@ void nasal_codegen::calc_gen(nasal_ast& ast)
gen(op_meq,0); gen(op_meq,0);
break; break;
// ast_addeq(22)~ast_lnkeq(26) op_addeq(23)~op_lnkeq(27) // ast_addeq(22)~ast_lnkeq(26) op_addeq(23)~op_lnkeq(27)
case ast_addeq:case ast_subeq:case ast_multeq:case ast_diveq:case ast_lnkeq: case ast_addeq:case ast_subeq:case ast_multeq:case ast_diveq:
if(ast.get_children()[1].get_type()!=ast_num)
calc_gen(ast.get_children()[1]); calc_gen(ast.get_children()[1]);
mcall(ast.get_children()[0]); mcall(ast.get_children()[0]);
if(ast.get_children()[1].get_type()!=ast_num)
gen(ast.get_type()-ast_addeq+op_addeq,0); gen(ast.get_type()-ast_addeq+op_addeq,0);
else
{
regist_number(ast.get_children()[1].get_num());
gen(ast.get_type()-ast_addeq+op_addeqc,number_table[ast.get_children()[1].get_num()]);
}
break;
case ast_lnkeq:
if(ast.get_children()[1].get_type()!=ast_str)
calc_gen(ast.get_children()[1]);
else
regist_string(ast.get_children()[1].get_str());
mcall(ast.get_children()[0]);
if(ast.get_children()[1].get_type()!=ast_str)
gen(op_lnkeq,0);
else
gen(op_lnkeqc,string_table[ast.get_children()[1].get_str()]);
break; break;
case ast_or:or_gen(ast);break; case ast_or:or_gen(ast);break;
case ast_and:and_gen(ast);break; case ast_and:and_gen(ast);break;
// ast_add(33)~ast_link(37) op_add(18)~op_lnk(22) // ast_add(33)~ast_link(37) op_add(18)~op_lnk(22)
case ast_add:case ast_sub:case ast_mult:case ast_div:case ast_link: case ast_add:case ast_sub:case ast_mult:case ast_div:
calc_gen(ast.get_children()[0]); calc_gen(ast.get_children()[0]);
if(ast.get_children()[1].get_type()!=ast_num)
{
calc_gen(ast.get_children()[1]); calc_gen(ast.get_children()[1]);
gen(ast.get_type()-ast_add+op_add,0); gen(ast.get_type()-ast_add+op_add,0);
}
else
{
regist_number(ast.get_children()[1].get_num());
gen(ast.get_type()-ast_add+op_addc,number_table[ast.get_children()[1].get_num()]);
}
break;
case ast_link:
calc_gen(ast.get_children()[0]);
if(ast.get_children()[1].get_type()!=ast_str)
{
calc_gen(ast.get_children()[1]);
gen(op_lnk,0);
}
else
{
regist_string(ast.get_children()[1].get_str());
gen(op_lnkc,string_table[ast.get_children()[1].get_str()]);
}
break; break;
// ast_cmpeq(27)~ast_geq(32) op_eq(29)~op_geq(34) // ast_cmpeq(27)~ast_geq(32) op_eq(29)~op_geq(34)
case ast_cmpeq:case ast_neq:case ast_less:case ast_leq:case ast_grt:case ast_geq: case ast_cmpeq:case ast_neq:case ast_less:case ast_leq:case ast_grt:case ast_geq:
@ -952,11 +1030,27 @@ void nasal_codegen::block_gen(nasal_ast& ast)
case ast_for: case ast_for:
case ast_forindex: case ast_forindex:
case ast_foreach:loop_gen(tmp);break; case ast_foreach:loop_gen(tmp);break;
case ast_equal:
if(tmp.get_children()[0].get_type()==ast_id)
{
calc_gen(tmp.get_children()[1]);
mcall_id(tmp.get_children()[0]);
// only the first mcall_id can use load
if(exec_code.back().op==op_mcalll)
exec_code.back().op=op_loadl;
else
exec_code.back().op=op_loadg;
}
else
{
calc_gen(tmp);
gen(op_pop,0);
}
break;
case ast_id: case ast_id:
case ast_vec: case ast_vec:
case ast_hash: case ast_hash:
case ast_call: case ast_call:
case ast_equal:
case ast_addeq: case ast_addeq:
case ast_subeq: case ast_subeq:
case ast_multeq: case ast_multeq:
@ -1028,11 +1122,27 @@ void nasal_codegen::main_progress(nasal_ast& ast)
case ast_for: case ast_for:
case ast_forindex: case ast_forindex:
case ast_foreach:loop_gen(tmp);break; case ast_foreach:loop_gen(tmp);break;
case ast_equal:
if(tmp.get_children()[0].get_type()==ast_id)
{
calc_gen(tmp.get_children()[1]);
mcall_id(tmp.get_children()[0]);
// only the first mcall_id can use load
if(exec_code.back().op==op_mcalll)
exec_code.back().op=op_loadl;
else
exec_code.back().op=op_loadg;
}
else
{
calc_gen(tmp);
gen(op_pop,0);
}
break;
case ast_id: case ast_id:
case ast_vec: case ast_vec:
case ast_hash: case ast_hash:
case ast_call: case ast_call:
case ast_equal:
case ast_addeq: case ast_addeq:
case ast_subeq: case ast_subeq:
case ast_multeq: case ast_multeq:
@ -1074,10 +1184,13 @@ void nasal_codegen::print_op(int index)
// print detail info // print detail info
switch(exec_code[index].op) switch(exec_code[index].op)
{ {
case op_addc:case op_subc:case op_mulc:case op_divc:
case op_addeqc:case op_subeqc:case op_muleqc:case op_diveqc:
case op_pnum:printf(" (%lf)\n",num_res_table[exec_code[index].num]);break; case op_pnum:printf(" (%lf)\n",num_res_table[exec_code[index].num]);break;
case op_callb:printf(" (%s)\n",builtin_func[exec_code[index].num].name);break; case op_callb:printf(" (%s)\n",builtin_func[exec_code[index].num].name);break;
case op_happ: case op_happ:
case op_pstr: case op_pstr:
case op_lnkc:case op_lnkeqc:
case op_callh: case op_callh:
case op_mcallh: case op_mcallh:
case op_para: case op_para:

View File

@ -684,6 +684,8 @@ nasal_ast nasal_parse::call_scalar()
case tok_lbracket: return callv(); break; case tok_lbracket: return callv(); break;
case tok_dot: return callh(); break; case tok_dot: return callh(); break;
} }
// should never run this expression
return nasal_ast(tok_list[ptr].line,ast_nil);
} }
nasal_ast nasal_parse::callh() nasal_ast nasal_parse::callh()
{ {

View File

@ -11,7 +11,7 @@ private:
std::stack<int> ret; // ptr stack stores address for function to return std::stack<int> ret; // ptr stack stores address for function to return
std::stack<int> counter; // iterator stack for forindex/foreach std::stack<int> counter; // iterator stack for forindex/foreach
std::vector<std::string> str_table;// symbols used in process std::vector<std::string> str_table;// symbols used in process
std::vector<uint32_t> imm; // immediate number std::vector<int32_t> imm; // immediate number
nasal_val** mem_addr; // used for mem_call nasal_val** mem_addr; // used for mem_call
nasal_gc gc; // garbage collector nasal_gc gc; // garbage collector
@ -41,11 +41,21 @@ private:
void opr_mul(); void opr_mul();
void opr_div(); void opr_div();
void opr_lnk(); void opr_lnk();
void opr_addc();
void opr_subc();
void opr_mulc();
void opr_divc();
void opr_lnkc();
void opr_addeq(); void opr_addeq();
void opr_subeq(); void opr_subeq();
void opr_muleq(); void opr_muleq();
void opr_diveq(); void opr_diveq();
void opr_lnkeq(); void opr_lnkeq();
void opr_addeqc();
void opr_subeqc();
void opr_muleqc();
void opr_diveqc();
void opr_lnkeqc();
void opr_meq(); void opr_meq();
void opr_eq(); void opr_eq();
void opr_neq(); void opr_neq();
@ -298,6 +308,41 @@ inline void nasal_vm::opr_lnk()
(--stack_top)[0]=new_val; (--stack_top)[0]=new_val;
return; return;
} }
inline void nasal_vm::opr_addc()
{
nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=stack_top[0]->to_number()+gc.num_addrs[imm[pc]]->ptr.num;
stack_top[0]=new_val;
return;
}
inline void nasal_vm::opr_subc()
{
nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=stack_top[0]->to_number()-gc.num_addrs[imm[pc]]->ptr.num;
stack_top[0]=new_val;
return;
}
inline void nasal_vm::opr_mulc()
{
nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=stack_top[0]->to_number()*gc.num_addrs[imm[pc]]->ptr.num;
stack_top[0]=new_val;
return;
}
inline void nasal_vm::opr_divc()
{
nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=stack_top[0]->to_number()/gc.num_addrs[imm[pc]]->ptr.num;
stack_top[0]=new_val;
return;
}
inline void nasal_vm::opr_lnkc()
{
nasal_val* new_val=gc.gc_alloc(vm_str);
*new_val->ptr.str=stack_top[0]->to_string()+str_table[imm[pc]];
stack_top[0]=new_val;
return;
}
inline void nasal_vm::opr_addeq() inline void nasal_vm::opr_addeq()
{ {
nasal_val* new_val=gc.gc_alloc(vm_num); nasal_val* new_val=gc.gc_alloc(vm_num);
@ -333,6 +378,41 @@ inline void nasal_vm::opr_lnkeq()
(--stack_top)[0]=mem_addr[0]=new_val; (--stack_top)[0]=mem_addr[0]=new_val;
return; return;
} }
inline void nasal_vm::opr_addeqc()
{
nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=mem_addr[0]->to_number()+gc.num_addrs[imm[pc]]->ptr.num;
stack_top[0]=mem_addr[0]=new_val;
return;
}
inline void nasal_vm::opr_subeqc()
{
nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=mem_addr[0]->to_number()-gc.num_addrs[imm[pc]]->ptr.num;
stack_top[0]=mem_addr[0]=new_val;
return;
}
inline void nasal_vm::opr_muleqc()
{
nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=mem_addr[0]->to_number()*gc.num_addrs[imm[pc]]->ptr.num;
stack_top[0]=mem_addr[0]=new_val;
return;
}
inline void nasal_vm::opr_diveqc()
{
nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=mem_addr[0]->to_number()/gc.num_addrs[imm[pc]]->ptr.num;
stack_top[0]=mem_addr[0]=new_val;
return;
}
inline void nasal_vm::opr_lnkeqc()
{
nasal_val* new_val=gc.gc_alloc(vm_str);
*new_val->ptr.str=mem_addr[0]->to_string()+str_table[imm[pc]];
stack_top[0]=mem_addr[0]=new_val;
return;
}
inline void nasal_vm::opr_meq() inline void nasal_vm::opr_meq()
{ {
mem_addr[0]=(--stack_top)[0]; mem_addr[0]=(--stack_top)[0];
@ -510,7 +590,7 @@ inline void nasal_vm::opr_callvi()
nasal_val* val=stack_top[0]; nasal_val* val=stack_top[0];
if(val->type!=vm_vec) if(val->type!=vm_vec)
{ {
die("callvi: multi-definition/multi-assignment must use a vector"); die("callvi: must use a vector");
return; return;
} }
// cannot use operator[],because this may cause overflow // cannot use operator[],because this may cause overflow
@ -761,6 +841,7 @@ inline void nasal_vm::opr_ret()
} }
void nasal_vm::run(std::vector<opcode>& exec) void nasal_vm::run(std::vector<opcode>& exec)
{ {
int count[72]={0};
void* opr_table[]= void* opr_table[]=
{ {
&&nop, &&intg, &&intl, &&offset, &&nop, &&intg, &&intl, &&offset,
@ -769,16 +850,18 @@ void nasal_vm::run(std::vector<opcode>& exec)
&&newh, &&newf, &&happ, &&para, &&newh, &&newf, &&happ, &&para,
&&defpara, &&dynpara, &&unot, &&usub, &&defpara, &&dynpara, &&unot, &&usub,
&&add, &&sub, &&mul, &&div, &&add, &&sub, &&mul, &&div,
&&lnk, &&addeq, &&subeq, &&muleq, &&lnk, &&addc, &&subc, &&mulc,
&&diveq, &&lnkeq, &&meq, &&eq, &&divc, &&lnkc, &&addeq, &&subeq,
&&neq, &&less, &&leq, &&grt, &&muleq, &&diveq, &&lnkeq, &&addeqc,
&&geq, &&pop, &&jmp, &&jt, &&subeqc, &&muleqc, &&diveqc, &&lnkeqc,
&&jf, &&counter, &&cntpop, &&findex, &&meq, &&eq, &&neq, &&less,
&&feach, &&callg, &&calll, &&callv, &&leq, &&grt, &&geq, &&pop,
&&callvi, &&callh, &&callfv, &&callfh, &&jmp, &&jt, &&jf, &&counter,
&&callb, &&slcbegin, &&slcend, &&slc, &&cntpop, &&findex, &&feach, &&callg,
&&slc2, &&mcallg, &&mcalll, &&mcallv, &&calll, &&callv, &&callvi, &&callh,
&&mcallh, &&ret &&callfv, &&callfh, &&callb, &&slcbegin,
&&slcend, &&slc, &&slc2, &&mcallg,
&&mcalll, &&mcallv, &&mcallh, &&ret
}; };
std::vector<void*> code; std::vector<void*> code;
for(auto& i:exec) for(auto& i:exec)
@ -795,68 +878,91 @@ nop:
if(gc.val_stack[STACK_MAX_DEPTH-1]&&gc.val_stack[STACK_MAX_DEPTH-1]!=(nasal_val*)0xffff) if(gc.val_stack[STACK_MAX_DEPTH-1]&&gc.val_stack[STACK_MAX_DEPTH-1]!=(nasal_val*)0xffff)
std::cout<<">> [vm] stack overflow.\n"; std::cout<<">> [vm] stack overflow.\n";
std::cout<<">> [vm] process exited after "<<((double)(clock()-begin))/CLOCKS_PER_SEC<<"s.\n"; std::cout<<">> [vm] process exited after "<<((double)(clock()-begin))/CLOCKS_PER_SEC<<"s.\n";
// debug
// for(int i=0;i<15;++i)
// {
// int maxnum=0,index=0;
// for(int j=0;j<62;++j)
// if(count[j]>maxnum)
// {
// index=j;
// maxnum=count[j];
// }
// std::cout<<code_table[index].name<<": "<<maxnum<<"\n";
// count[index]=0;
// }
return; return;
#define exec_operand(op) {op();if(!gc.val_stack[STACK_MAX_DEPTH-1])goto *code[++pc];goto nop;} #define exec_operand(op,num) {op();/*++count[num];*/if(!gc.val_stack[STACK_MAX_DEPTH-1])goto *code[++pc];goto nop;}
intg: exec_operand(opr_intg ); intg: exec_operand(opr_intg ,1);
intl: exec_operand(opr_intl ); intl: exec_operand(opr_intl ,2);
offset: exec_operand(opr_offset ); offset: exec_operand(opr_offset ,3);
loadg: exec_operand(opr_loadg ); loadg: exec_operand(opr_loadg ,4);
loadl: exec_operand(opr_loadl ); loadl: exec_operand(opr_loadl ,5);
pnum: exec_operand(opr_pnum ); pnum: exec_operand(opr_pnum ,6);
pone: exec_operand(opr_pone ); pone: exec_operand(opr_pone ,7);
pzero: exec_operand(opr_pzero ); pzero: exec_operand(opr_pzero ,8);
pnil: exec_operand(opr_pnil ); pnil: exec_operand(opr_pnil ,9);
pstr: exec_operand(opr_pstr ); pstr: exec_operand(opr_pstr ,10);
newv: exec_operand(opr_newv ); newv: exec_operand(opr_newv ,11);
newh: exec_operand(opr_newh ); newh: exec_operand(opr_newh ,12);
newf: exec_operand(opr_newf ); newf: exec_operand(opr_newf ,13);
happ: exec_operand(opr_happ ); happ: exec_operand(opr_happ ,14);
para: exec_operand(opr_para ); para: exec_operand(opr_para ,15);
defpara: exec_operand(opr_defpara ); defpara: exec_operand(opr_defpara ,16);
dynpara: exec_operand(opr_dynpara ); dynpara: exec_operand(opr_dynpara ,17);
unot: exec_operand(opr_unot ); unot: exec_operand(opr_unot ,18);
usub: exec_operand(opr_usub ); usub: exec_operand(opr_usub ,19);
add: exec_operand(opr_add ); add: exec_operand(opr_add ,20);
sub: exec_operand(opr_sub ); sub: exec_operand(opr_sub ,21);
mul: exec_operand(opr_mul ); mul: exec_operand(opr_mul ,22);
div: exec_operand(opr_div ); div: exec_operand(opr_div ,23);
lnk: exec_operand(opr_lnk ); lnk: exec_operand(opr_lnk ,24);
addeq: exec_operand(opr_addeq ); addc: exec_operand(opr_addc ,25);
subeq: exec_operand(opr_subeq ); subc: exec_operand(opr_subc ,26);
muleq: exec_operand(opr_muleq ); mulc: exec_operand(opr_mulc ,27);
diveq: exec_operand(opr_diveq ); divc: exec_operand(opr_divc ,28);
lnkeq: exec_operand(opr_lnkeq ); lnkc: exec_operand(opr_lnkc ,29);
meq: exec_operand(opr_meq ); addeq: exec_operand(opr_addeq ,30);
eq: exec_operand(opr_eq ); subeq: exec_operand(opr_subeq ,31);
neq: exec_operand(opr_neq ); muleq: exec_operand(opr_muleq ,32);
less: exec_operand(opr_less ); diveq: exec_operand(opr_diveq ,33);
leq: exec_operand(opr_leq ); lnkeq: exec_operand(opr_lnkeq ,34);
grt: exec_operand(opr_grt ); addeqc: exec_operand(opr_addeqc ,35);
geq: exec_operand(opr_geq ); subeqc: exec_operand(opr_subeqc ,36);
pop: exec_operand(opr_pop ); muleqc: exec_operand(opr_muleqc ,37);
jmp: exec_operand(opr_jmp ); diveqc: exec_operand(opr_diveqc ,38);
jt: exec_operand(opr_jt ); lnkeqc: exec_operand(opr_lnkeqc ,39);
jf: exec_operand(opr_jf ); meq: exec_operand(opr_meq ,40);
counter: exec_operand(opr_counter ); eq: exec_operand(opr_eq ,41);
cntpop: exec_operand(opr_cntpop ); neq: exec_operand(opr_neq ,42);
findex: exec_operand(opr_findex ); less: exec_operand(opr_less ,43);
feach: exec_operand(opr_feach ); leq: exec_operand(opr_leq ,44);
callg: exec_operand(opr_callg ); grt: exec_operand(opr_grt ,45);
calll: exec_operand(opr_calll ); geq: exec_operand(opr_geq ,46);
callv: exec_operand(opr_callv ); pop: exec_operand(opr_pop ,47);
callvi: exec_operand(opr_callvi ); jmp: exec_operand(opr_jmp ,48);
callh: exec_operand(opr_callh ); jt: exec_operand(opr_jt ,49);
callfv: exec_operand(opr_callfv ); jf: exec_operand(opr_jf ,50);
callfh: exec_operand(opr_callfh ); counter: exec_operand(opr_counter ,51);
callb: exec_operand(opr_callb ); cntpop: exec_operand(opr_cntpop ,52);
slcbegin:exec_operand(opr_slcbegin); findex: exec_operand(opr_findex ,53);
slcend: exec_operand(opr_slcend ); feach: exec_operand(opr_feach ,54);
slc: exec_operand(opr_slc ); callg: exec_operand(opr_callg ,55);
slc2: exec_operand(opr_slc2 ); calll: exec_operand(opr_calll ,56);
mcallg: exec_operand(opr_mcallg ); callv: exec_operand(opr_callv ,57);
mcalll: exec_operand(opr_mcalll ); callvi: exec_operand(opr_callvi ,58);
mcallv: exec_operand(opr_mcallv ); callh: exec_operand(opr_callh ,59);
mcallh: exec_operand(opr_mcallh ); callfv: exec_operand(opr_callfv ,60);
ret: exec_operand(opr_ret ); callfh: exec_operand(opr_callfh ,61);
callb: exec_operand(opr_callb ,62);
slcbegin:exec_operand(opr_slcbegin,63);
slcend: exec_operand(opr_slcend ,64);
slc: exec_operand(opr_slc ,65);
slc2: exec_operand(opr_slc2 ,66);
mcallg: exec_operand(opr_mcallg ,67);
mcalll: exec_operand(opr_mcalll ,68);
mcallv: exec_operand(opr_mcallv ,69);
mcallh: exec_operand(opr_mcallh ,70);
ret: exec_operand(opr_ret ,71);
} }
#endif #endif