change instruction dispatch to computed-goto

bug fixed
prepare for version 7.0
This commit is contained in:
ValKmjolnir 2021-06-26 14:53:10 +08:00
parent 3c9a10d710
commit 706659ba3d
7 changed files with 212 additions and 194 deletions

View File

@ -199,7 +199,7 @@ for(var i=0;i<4000000;i+=1);
0x0000000c: nop 0x00000000 0x0000000c: nop 0x00000000
``` ```
### Version 6.5(latest) ### 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,6 +329,16 @@ 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)
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.
This version uses gcc 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).
## Test data ## Test data
### version 6.5(i5-8250U windows10 2021/6/19) ### version 6.5(i5-8250U windows10 2021/6/19)
@ -378,6 +388,23 @@ 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)
running time:
|file|total time|info|
|:----|:----|:----|
|pi.nas|0.17s|great improvement|
|fib.nas|0.75s|great improvement|
|bp.nas|0.32s(5467 epoch)|good improvement|
|bigloop.nas|0.11s|great improvement|
|mandelbrot.nas|0.04s|great improvment|
|life.nas|8.80s(windows) 1.34(ubuntu WSL)|little improvement|
|ascii-art.nas|0.015s|little improvement|
|calc.nas|0.0625s|little improvement|
|quick_sort.nas|0s|great improvement|
|bfs.nas|0.0156s|great improvement|
## How to Use Nasal to Program ## How to Use Nasal to Program
### basic value type ### basic value type
@ -660,7 +687,7 @@ Use import("") to get the nasal file including your built-in functions,then you
version 6.5 update: version 6.5 update:
Use nasal_gc::builtin_alloc in builtin function if this function uses alloc more then one time. Use nasal_gc::builtin_alloc in builtin function if this function uses alloc more than one time.
When running a builtin function,alloc will run more than one time,this may cause mark-sweep in gc_alloc. When running a builtin function,alloc will run more than one time,this may cause mark-sweep in gc_alloc.

View File

@ -29,7 +29,6 @@ void help_cmd()
void info() void info()
{ {
std::cout std::cout
<<">> Nasal interpreter ver 6.5.\n"
<<">> Thanks to https://github.com/andyross/nasal\n" <<">> Thanks to https://github.com/andyross/nasal\n"
<<">> Code: https://github.com/ValKmjolnir/Nasal-Interpreter\n" <<">> Code: https://github.com/ValKmjolnir/Nasal-Interpreter\n"
<<">> Code: https://gitee.com/valkmjolnir/Nasal-Interpreter\n" <<">> Code: https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
@ -44,7 +43,8 @@ void logo()
<<" /\\ \\ \\__ _ ___ __ _| | \n" <<" /\\ \\ \\__ _ ___ __ _| | \n"
<<" / \\/ / _` / __|/ _` | | \n" <<" / \\/ / _` / __|/ _` | | \n"
<<" / /\\ / (_| \\__ \\ (_| | | \n" <<" / /\\ / (_| \\__ \\ (_| | | \n"
<<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n"; <<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
<<">> Nasal interpreter ver 7.0 \n";
return; return;
} }
void die(const char* stage,std::string& filename) void die(const char* stage,std::string& filename)
@ -104,10 +104,9 @@ void execute(std::string& file,std::string& command)
} }
vm.init( vm.init(
codegen.get_str_table(), codegen.get_str_table(),
codegen.get_num_table(), codegen.get_num_table()
codegen.get_exec_code()
); );
vm.run(); vm.run(codegen.get_exec_code());
vm.clear(); vm.clear();
return; return;
} }
@ -150,10 +149,7 @@ int main(int argc,const char* argv[])
if(argc==1) if(argc==1)
interact(); interact();
else if(argc==2 && (!strcmp(argv[1],"-v") || !strcmp(argv[1],"-version"))) else if(argc==2 && (!strcmp(argv[1],"-v") || !strcmp(argv[1],"-version")))
{
logo(); logo();
std::cout<<"Nasal interpreter ver 6.5\n";
}
else if(argc==2 && (!strcmp(argv[1],"-h") || !strcmp(argv[1],"-help"))) else if(argc==2 && (!strcmp(argv[1],"-h") || !strcmp(argv[1],"-help")))
help_cmd(); help_cmd();
else if(argc==2 && argv[1][0]!='-') else if(argc==2 && argv[1][0]!='-')

View File

@ -722,7 +722,7 @@ nasal_val* builtin_substr(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
std::string& str=*str_addr->ptr.str; std::string& str=*str_addr->ptr.str;
int beg=(int)beg_addr->ptr.num; int beg=(int)beg_addr->ptr.num;
int len=(int)len_addr->ptr.num; int len=(int)len_addr->ptr.num;
if(beg>=str.length() || beg+len>=str.length()) if(beg>=str.length() || beg+len-1>=str.length())
{ {
builtin_err("susbtr","index out of range"); builtin_err("susbtr","index out of range");
return nullptr; return nullptr;

View File

@ -245,7 +245,6 @@ struct nasal_gc
std::vector<nasal_val*> slice_stack; // slice stack for vec[val,val,val:val] std::vector<nasal_val*> slice_stack; // slice stack for vec[val,val,val:val]
std::vector<nasal_val*> memory; // gc memory std::vector<nasal_val*> memory; // gc memory
std::queue <nasal_val*> free_list[vm_type_size]; // gc free list std::queue <nasal_val*> free_list[vm_type_size]; // gc free list
std::vector<nasal_val*> global;
std::list<std::vector<nasal_val*>> local; std::list<std::vector<nasal_val*>> local;
void mark(); void mark();
void sweep(); void sweep();
@ -259,8 +258,6 @@ struct nasal_gc
void nasal_gc::mark() void nasal_gc::mark()
{ {
std::queue<nasal_val*> bfs; std::queue<nasal_val*> bfs;
for(auto i:global)
bfs.push(i);
for(auto& i:local) for(auto& i:local)
for(auto j:i) for(auto j:i)
bfs.push(j); bfs.push(j);
@ -332,7 +329,6 @@ void nasal_gc::gc_init(std::vector<double>& nums,std::vector<std::string>& strs)
nil_addr=new nasal_val(vm_nil); // init nil nil_addr=new nasal_val(vm_nil); // init nil
*val_stack=nil_addr; // the first space will not store any values,but gc checks
// init constant numbers // init constant numbers
num_addrs.resize(nums.size()); num_addrs.resize(nums.size());
for(int i=0;i<nums.size();++i) for(int i=0;i<nums.size();++i)
@ -357,7 +353,7 @@ void nasal_gc::gc_clear()
for(int i=0;i<vm_type_size;++i) for(int i=0;i<vm_type_size;++i)
while(!free_list[i].empty()) while(!free_list[i].empty())
free_list[i].pop(); free_list[i].pop();
global.clear(); //global.clear();
local.clear(); local.clear();
slice_stack.clear(); slice_stack.clear();

View File

@ -8,19 +8,15 @@ private:
nasal_val**& stack_top;// stack top nasal_val**& stack_top;// stack top
/* values of nasal_vm */ /* values of nasal_vm */
uint32_t pc; // program counter uint32_t pc; // program counter
bool loop_mark;// when mark is false,break the main loop
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<void (nasal_vm::*)()>
exec_code;//function pointer
std::vector<uint32_t> imm; // immediate number std::vector<uint32_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
void die(std::string); void die(std::string);
bool condition(nasal_val*); bool condition(nasal_val*);
void opr_nop();
void opr_intg(); void opr_intg();
void opr_intl(); void opr_intl();
void opr_offset(); void opr_offset();
@ -86,91 +82,18 @@ public:
nasal_vm():stack_top(gc.stack_top){}; nasal_vm():stack_top(gc.stack_top){};
void init( void init(
std::vector<std::string>&, std::vector<std::string>&,
std::vector<double>&, std::vector<double>&);
std::vector<opcode>&);
void clear(); void clear();
void run(); void run(std::vector<opcode>&);
}; };
void nasal_vm::init( void nasal_vm::init(
std::vector<std::string>& strs, std::vector<std::string>& strs,
std::vector<double>& nums, std::vector<double>& nums)
std::vector<opcode>& exec)
{ {
gc.gc_init(nums,strs); gc.gc_init(nums,strs);
gc.val_stack[STACK_MAX_DEPTH-1]=nullptr; gc.val_stack[STACK_MAX_DEPTH-1]=nullptr;
str_table=strs; // get constant strings & symbols str_table=strs; // get constant strings & symbols
void (nasal_vm::*opr_table[])()=
{
&nasal_vm::opr_nop,
&nasal_vm::opr_intg,
&nasal_vm::opr_intl,
&nasal_vm::opr_offset,
&nasal_vm::opr_loadg,
&nasal_vm::opr_loadl,
&nasal_vm::opr_pnum,
&nasal_vm::opr_pone,
&nasal_vm::opr_pzero,
&nasal_vm::opr_pnil,
&nasal_vm::opr_pstr,
&nasal_vm::opr_newv,
&nasal_vm::opr_newh,
&nasal_vm::opr_newf,
&nasal_vm::opr_happ,
&nasal_vm::opr_para,
&nasal_vm::opr_defpara,
&nasal_vm::opr_dynpara,
&nasal_vm::opr_unot,
&nasal_vm::opr_usub,
&nasal_vm::opr_add,
&nasal_vm::opr_sub,
&nasal_vm::opr_mul,
&nasal_vm::opr_div,
&nasal_vm::opr_lnk,
&nasal_vm::opr_addeq,
&nasal_vm::opr_subeq,
&nasal_vm::opr_muleq,
&nasal_vm::opr_diveq,
&nasal_vm::opr_lnkeq,
&nasal_vm::opr_meq,
&nasal_vm::opr_eq,
&nasal_vm::opr_neq,
&nasal_vm::opr_less,
&nasal_vm::opr_leq,
&nasal_vm::opr_grt,
&nasal_vm::opr_geq,
&nasal_vm::opr_pop,
&nasal_vm::opr_jmp,
&nasal_vm::opr_jt,
&nasal_vm::opr_jf,
&nasal_vm::opr_counter,
&nasal_vm::opr_cntpop,
&nasal_vm::opr_findex,
&nasal_vm::opr_feach,
&nasal_vm::opr_callg,
&nasal_vm::opr_calll,
&nasal_vm::opr_callv,
&nasal_vm::opr_callvi,
&nasal_vm::opr_callh,
&nasal_vm::opr_callfv,
&nasal_vm::opr_callfh,
&nasal_vm::opr_callb,
&nasal_vm::opr_slcbegin,
&nasal_vm::opr_slcend,
&nasal_vm::opr_slc,
&nasal_vm::opr_slc2,
&nasal_vm::opr_mcallg,
&nasal_vm::opr_mcalll,
&nasal_vm::opr_mcallv,
&nasal_vm::opr_mcallh,
&nasal_vm::opr_ret
};
for(auto& i:exec)
{
exec_code.push_back(opr_table[i.op]);
imm.push_back(i.num);
}
loop_mark=true; // set loop mark to true
return; return;
} }
void nasal_vm::clear() void nasal_vm::clear()
@ -181,13 +104,13 @@ void nasal_vm::clear()
while(!counter.empty()) while(!counter.empty())
counter.pop(); counter.pop();
str_table.clear(); str_table.clear();
exec_code.clear(); imm.clear();
return; return;
} }
void nasal_vm::die(std::string str) void nasal_vm::die(std::string str)
{ {
printf(">> [vm] 0x%.8x: %s\n",pc,str.c_str()); printf(">> [vm] 0x%.8x: %s\n",pc,str.c_str());
loop_mark=false; gc.val_stack[STACK_MAX_DEPTH-1]=(nasal_val*)0xffff;
return; return;
} }
bool nasal_vm::condition(nasal_val* val_addr) bool nasal_vm::condition(nasal_val* val_addr)
@ -204,62 +127,60 @@ bool nasal_vm::condition(nasal_val* val_addr)
} }
return false; return false;
} }
void nasal_vm::opr_nop() inline void nasal_vm::opr_intg()
{ {
loop_mark=false; // global values store on stack
for(int i=0;i<imm[pc];++i)
(stack_top++)[0]=gc.nil_addr;
--stack_top;// point to the top
return; return;
} }
void nasal_vm::opr_intg() inline void nasal_vm::opr_intl()
{
gc.global.resize(imm[pc],gc.nil_addr);
return;
}
void nasal_vm::opr_intl()
{ {
stack_top[0]->ptr.func->closure.resize(imm[pc],gc.nil_addr); stack_top[0]->ptr.func->closure.resize(imm[pc],gc.nil_addr);
return; return;
} }
void nasal_vm::opr_offset() inline void nasal_vm::opr_offset()
{ {
stack_top[0]->ptr.func->offset=imm[pc]; stack_top[0]->ptr.func->offset=imm[pc];
return; return;
} }
void nasal_vm::opr_loadg() inline void nasal_vm::opr_loadg()
{ {
gc.global[imm[pc]]=(stack_top--)[0]; gc.val_stack[imm[pc]]=(stack_top--)[0];
return; return;
} }
void nasal_vm::opr_loadl() inline void nasal_vm::opr_loadl()
{ {
gc.local.back()[imm[pc]]=(stack_top--)[0]; gc.local.back()[imm[pc]]=(stack_top--)[0];
return; return;
} }
void nasal_vm::opr_pnum() inline void nasal_vm::opr_pnum()
{ {
(++stack_top)[0]=gc.num_addrs[imm[pc]]; (++stack_top)[0]=gc.num_addrs[imm[pc]];
return; return;
} }
void nasal_vm::opr_pone() inline void nasal_vm::opr_pone()
{ {
(++stack_top)[0]=gc.one_addr; (++stack_top)[0]=gc.one_addr;
return; return;
} }
void nasal_vm::opr_pzero() inline void nasal_vm::opr_pzero()
{ {
(++stack_top)[0]=gc.zero_addr; (++stack_top)[0]=gc.zero_addr;
return; return;
} }
void nasal_vm::opr_pnil() inline void nasal_vm::opr_pnil()
{ {
(++stack_top)[0]=gc.nil_addr; (++stack_top)[0]=gc.nil_addr;
return; return;
} }
void nasal_vm::opr_pstr() inline void nasal_vm::opr_pstr()
{ {
(++stack_top)[0]=gc.str_addrs[imm[pc]]; (++stack_top)[0]=gc.str_addrs[imm[pc]];
return; return;
} }
void nasal_vm::opr_newv() inline void nasal_vm::opr_newv()
{ {
nasal_val* vec_addr=gc.gc_alloc(vm_vec); nasal_val* vec_addr=gc.gc_alloc(vm_vec);
nasal_val** begin=stack_top-imm[pc]+1; nasal_val** begin=stack_top-imm[pc]+1;
@ -271,12 +192,12 @@ void nasal_vm::opr_newv()
stack_top=begin; stack_top=begin;
return; return;
} }
void nasal_vm::opr_newh() inline void nasal_vm::opr_newh()
{ {
(++stack_top)[0]=gc.gc_alloc(vm_hash); (++stack_top)[0]=gc.gc_alloc(vm_hash);
return; return;
} }
void nasal_vm::opr_newf() inline void nasal_vm::opr_newf()
{ {
nasal_val* val=gc.gc_alloc(vm_func); nasal_val* val=gc.gc_alloc(vm_func);
val->ptr.func->entry=imm[pc]; val->ptr.func->entry=imm[pc];
@ -287,13 +208,13 @@ void nasal_vm::opr_newf()
(++stack_top)[0]=val; (++stack_top)[0]=val;
return; return;
} }
void nasal_vm::opr_happ() inline void nasal_vm::opr_happ()
{ {
nasal_val* val=stack_top[0]; nasal_val* val=stack_top[0];
(--stack_top)[0]->ptr.hash->elems[str_table[imm[pc]]]=val; (--stack_top)[0]->ptr.hash->elems[str_table[imm[pc]]]=val;
return; return;
} }
void nasal_vm::opr_para() inline void nasal_vm::opr_para()
{ {
nasal_func* func=stack_top[0]->ptr.func; nasal_func* func=stack_top[0]->ptr.func;
int size=func->key_table.size(); int size=func->key_table.size();
@ -301,7 +222,7 @@ void nasal_vm::opr_para()
func->default_para.push_back(nullptr); func->default_para.push_back(nullptr);
return; return;
} }
void nasal_vm::opr_defpara() inline void nasal_vm::opr_defpara()
{ {
nasal_val* def_val=stack_top[0]; nasal_val* def_val=stack_top[0];
nasal_func* func=(--stack_top)[0]->ptr.func; nasal_func* func=(--stack_top)[0]->ptr.func;
@ -310,12 +231,12 @@ void nasal_vm::opr_defpara()
func->default_para.push_back(def_val); func->default_para.push_back(def_val);
return; return;
} }
void nasal_vm::opr_dynpara() inline void nasal_vm::opr_dynpara()
{ {
stack_top[0]->ptr.func->dynpara=imm[pc]; stack_top[0]->ptr.func->dynpara=imm[pc];
return; return;
} }
void nasal_vm::opr_unot() inline void nasal_vm::opr_unot()
{ {
nasal_val* val=stack_top[0]; nasal_val* val=stack_top[0];
int type=val->type; int type=val->type;
@ -335,89 +256,89 @@ void nasal_vm::opr_unot()
die("unot: incorrect value type"); die("unot: incorrect value type");
return; return;
} }
void nasal_vm::opr_usub() inline void nasal_vm::opr_usub()
{ {
nasal_val* new_val=gc.gc_alloc(vm_num); nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=-stack_top[0]->to_number(); new_val->ptr.num=-stack_top[0]->to_number();
stack_top[0]=new_val; stack_top[0]=new_val;
return; return;
} }
void nasal_vm::opr_add() inline void nasal_vm::opr_add()
{ {
nasal_val* new_val=gc.gc_alloc(vm_num); nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=stack_top[-1]->to_number()+stack_top[0]->to_number(); new_val->ptr.num=stack_top[-1]->to_number()+stack_top[0]->to_number();
(--stack_top)[0]=new_val; (--stack_top)[0]=new_val;
return; return;
} }
void nasal_vm::opr_sub() inline void nasal_vm::opr_sub()
{ {
nasal_val* new_val=gc.gc_alloc(vm_num); nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=stack_top[-1]->to_number()-stack_top[0]->to_number(); new_val->ptr.num=stack_top[-1]->to_number()-stack_top[0]->to_number();
(--stack_top)[0]=new_val; (--stack_top)[0]=new_val;
return; return;
} }
void nasal_vm::opr_mul() inline void nasal_vm::opr_mul()
{ {
nasal_val* new_val=gc.gc_alloc(vm_num); nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=stack_top[-1]->to_number()*stack_top[0]->to_number(); new_val->ptr.num=stack_top[-1]->to_number()*stack_top[0]->to_number();
(--stack_top)[0]=new_val; (--stack_top)[0]=new_val;
return; return;
} }
void nasal_vm::opr_div() inline void nasal_vm::opr_div()
{ {
nasal_val* new_val=gc.gc_alloc(vm_num); nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=stack_top[-1]->to_number()/stack_top[0]->to_number(); new_val->ptr.num=stack_top[-1]->to_number()/stack_top[0]->to_number();
(--stack_top)[0]=new_val; (--stack_top)[0]=new_val;
return; return;
} }
void nasal_vm::opr_lnk() inline void nasal_vm::opr_lnk()
{ {
nasal_val* new_val=gc.gc_alloc(vm_str); nasal_val* new_val=gc.gc_alloc(vm_str);
*new_val->ptr.str=stack_top[-1]->to_string()+stack_top[0]->to_string(); *new_val->ptr.str=stack_top[-1]->to_string()+stack_top[0]->to_string();
(--stack_top)[0]=new_val; (--stack_top)[0]=new_val;
return; return;
} }
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);
new_val->ptr.num=mem_addr[0]->to_number()+stack_top[-1]->to_number(); new_val->ptr.num=mem_addr[0]->to_number()+stack_top[-1]->to_number();
(--stack_top)[0]=mem_addr[0]=new_val; (--stack_top)[0]=mem_addr[0]=new_val;
return; return;
} }
void nasal_vm::opr_subeq() inline void nasal_vm::opr_subeq()
{ {
nasal_val* new_val=gc.gc_alloc(vm_num); nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=mem_addr[0]->to_number()-stack_top[-1]->to_number(); new_val->ptr.num=mem_addr[0]->to_number()-stack_top[-1]->to_number();
(--stack_top)[0]=mem_addr[0]=new_val; (--stack_top)[0]=mem_addr[0]=new_val;
return; return;
} }
void nasal_vm::opr_muleq() inline void nasal_vm::opr_muleq()
{ {
nasal_val* new_val=gc.gc_alloc(vm_num); nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=mem_addr[0]->to_number()*stack_top[-1]->to_number(); new_val->ptr.num=mem_addr[0]->to_number()*stack_top[-1]->to_number();
(--stack_top)[0]=mem_addr[0]=new_val; (--stack_top)[0]=mem_addr[0]=new_val;
return; return;
} }
void nasal_vm::opr_diveq() inline void nasal_vm::opr_diveq()
{ {
nasal_val* new_val=gc.gc_alloc(vm_num); nasal_val* new_val=gc.gc_alloc(vm_num);
new_val->ptr.num=mem_addr[0]->to_number()/stack_top[-1]->to_number(); new_val->ptr.num=mem_addr[0]->to_number()/stack_top[-1]->to_number();
(--stack_top)[0]=mem_addr[0]=new_val; (--stack_top)[0]=mem_addr[0]=new_val;
return; return;
} }
void nasal_vm::opr_lnkeq() inline void nasal_vm::opr_lnkeq()
{ {
nasal_val* new_val=gc.gc_alloc(vm_str); nasal_val* new_val=gc.gc_alloc(vm_str);
*new_val->ptr.str=mem_addr[0]->to_string()+stack_top[-1]->to_string(); *new_val->ptr.str=mem_addr[0]->to_string()+stack_top[-1]->to_string();
(--stack_top)[0]=mem_addr[0]=new_val; (--stack_top)[0]=mem_addr[0]=new_val;
return; return;
} }
void nasal_vm::opr_meq() inline void nasal_vm::opr_meq()
{ {
mem_addr[0]=(--stack_top)[0]; mem_addr[0]=(--stack_top)[0];
return; return;
} }
void nasal_vm::opr_eq() inline void nasal_vm::opr_eq()
{ {
nasal_val* val2=stack_top[0]; nasal_val* val2=stack_top[0];
nasal_val* val1=(--stack_top)[0]; nasal_val* val1=(--stack_top)[0];
@ -433,7 +354,7 @@ void nasal_vm::opr_eq()
stack_top[0]=(val1==val2)?gc.one_addr:gc.zero_addr; stack_top[0]=(val1==val2)?gc.one_addr:gc.zero_addr;
return; return;
} }
void nasal_vm::opr_neq() inline void nasal_vm::opr_neq()
{ {
nasal_val* val2=stack_top[0]; nasal_val* val2=stack_top[0];
nasal_val* val1=(--stack_top)[0]; nasal_val* val1=(--stack_top)[0];
@ -449,66 +370,66 @@ void nasal_vm::opr_neq()
stack_top[0]=(val1!=val2)?gc.one_addr:gc.zero_addr; stack_top[0]=(val1!=val2)?gc.one_addr:gc.zero_addr;
return; return;
} }
void nasal_vm::opr_less() inline void nasal_vm::opr_less()
{ {
--stack_top; --stack_top;
stack_top[0]=(stack_top[0]->to_number()<stack_top[1]->to_number())?gc.one_addr:gc.zero_addr; stack_top[0]=(stack_top[0]->to_number()<stack_top[1]->to_number())?gc.one_addr:gc.zero_addr;
return; return;
} }
void nasal_vm::opr_leq() inline void nasal_vm::opr_leq()
{ {
--stack_top; --stack_top;
stack_top[0]=(stack_top[0]->to_number()<=stack_top[1]->to_number())?gc.one_addr:gc.zero_addr; stack_top[0]=(stack_top[0]->to_number()<=stack_top[1]->to_number())?gc.one_addr:gc.zero_addr;
return; return;
} }
void nasal_vm::opr_grt() inline void nasal_vm::opr_grt()
{ {
--stack_top; --stack_top;
stack_top[0]=(stack_top[0]->to_number()>stack_top[1]->to_number())?gc.one_addr:gc.zero_addr; stack_top[0]=(stack_top[0]->to_number()>stack_top[1]->to_number())?gc.one_addr:gc.zero_addr;
return; return;
} }
void nasal_vm::opr_geq() inline void nasal_vm::opr_geq()
{ {
--stack_top; --stack_top;
stack_top[0]=(stack_top[0]->to_number()>=stack_top[1]->to_number())?gc.one_addr:gc.zero_addr; stack_top[0]=(stack_top[0]->to_number()>=stack_top[1]->to_number())?gc.one_addr:gc.zero_addr;
return; return;
} }
void nasal_vm::opr_pop() inline void nasal_vm::opr_pop()
{ {
--stack_top; --stack_top;
return; return;
} }
void nasal_vm::opr_jmp() inline void nasal_vm::opr_jmp()
{ {
pc=imm[pc]-1; pc=imm[pc]-1;
return; return;
} }
void nasal_vm::opr_jt() inline void nasal_vm::opr_jt()
{ {
if(condition(stack_top[0])) if(condition(stack_top[0]))
pc=imm[pc]-1; pc=imm[pc]-1;
return; return;
} }
void nasal_vm::opr_jf() inline void nasal_vm::opr_jf()
{ {
if(!condition(stack_top[0])) if(!condition(stack_top[0]))
pc=imm[pc]-1; pc=imm[pc]-1;
--stack_top; --stack_top;
return; return;
} }
void nasal_vm::opr_counter() inline void nasal_vm::opr_counter()
{ {
counter.push(-1); counter.push(-1);
if(stack_top[0]->type!=vm_vec) if(stack_top[0]->type!=vm_vec)
die("cnt: must use vector in forindex/foreach"); die("cnt: must use vector in forindex/foreach");
return; return;
} }
void nasal_vm::opr_cntpop() inline void nasal_vm::opr_cntpop()
{ {
counter.pop(); counter.pop();
return; return;
} }
void nasal_vm::opr_findex() inline void nasal_vm::opr_findex()
{ {
if(++counter.top()>=stack_top[0]->ptr.vec->elems.size()) if(++counter.top()>=stack_top[0]->ptr.vec->elems.size())
{ {
@ -519,7 +440,7 @@ void nasal_vm::opr_findex()
stack_top[0]->ptr.num=counter.top(); stack_top[0]->ptr.num=counter.top();
return; return;
} }
void nasal_vm::opr_feach() inline void nasal_vm::opr_feach()
{ {
std::vector<nasal_val*>& ref=stack_top[0]->ptr.vec->elems; std::vector<nasal_val*>& ref=stack_top[0]->ptr.vec->elems;
if(++counter.top()>=ref.size()) if(++counter.top()>=ref.size())
@ -530,17 +451,17 @@ void nasal_vm::opr_feach()
(++stack_top)[0]=ref[counter.top()]; (++stack_top)[0]=ref[counter.top()];
return; return;
} }
void nasal_vm::opr_callg() inline void nasal_vm::opr_callg()
{ {
(++stack_top)[0]=gc.global[imm[pc]]; (++stack_top)[0]=gc.val_stack[imm[pc]];
return; return;
} }
void nasal_vm::opr_calll() inline void nasal_vm::opr_calll()
{ {
(++stack_top)[0]=gc.local.back()[imm[pc]]; (++stack_top)[0]=gc.local.back()[imm[pc]];
return; return;
} }
void nasal_vm::opr_callv() inline void nasal_vm::opr_callv()
{ {
nasal_val* val=stack_top[0]; nasal_val* val=stack_top[0];
nasal_val* vec_addr=(--stack_top)[0]; nasal_val* vec_addr=(--stack_top)[0];
@ -584,7 +505,7 @@ void nasal_vm::opr_callv()
die("callv: must call a vector/hash/string"); die("callv: must call a vector/hash/string");
return; return;
} }
void nasal_vm::opr_callvi() 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)
@ -598,7 +519,7 @@ void nasal_vm::opr_callvi()
die("callvi: index out of range:"+num2str(imm[pc])); die("callvi: index out of range:"+num2str(imm[pc]));
return; return;
} }
void nasal_vm::opr_callh() inline void nasal_vm::opr_callh()
{ {
nasal_val* val=stack_top[0]; nasal_val* val=stack_top[0];
if(val->type!=vm_hash) if(val->type!=vm_hash)
@ -616,7 +537,7 @@ void nasal_vm::opr_callh()
stack_top[0]->ptr.func->closure[0]=val;// me stack_top[0]->ptr.func->closure[0]=val;// me
return; return;
} }
void nasal_vm::opr_callfv() inline void nasal_vm::opr_callfv()
{ {
// get parameter list and function value // get parameter list and function value
int args_size=imm[pc]; int args_size=imm[pc];
@ -660,7 +581,7 @@ void nasal_vm::opr_callfv()
pc=ref_func.entry-1; pc=ref_func.entry-1;
return; return;
} }
void nasal_vm::opr_callfh() inline void nasal_vm::opr_callfh()
{ {
// get parameter list and function value // get parameter list and function value
auto& ref_hash=stack_top[0]->ptr.hash->elems; auto& ref_hash=stack_top[0]->ptr.hash->elems;
@ -701,25 +622,26 @@ void nasal_vm::opr_callfh()
pc=ref_func.entry-1; pc=ref_func.entry-1;
return; return;
} }
void nasal_vm::opr_callb() inline void nasal_vm::opr_callb()
{ {
loop_mark=(++stack_top)[0]=(*builtin_func[imm[pc]].func)(gc.local.back(),gc); (++stack_top)[0]=(*builtin_func[imm[pc]].func)(gc.local.back(),gc);
gc.val_stack[STACK_MAX_DEPTH-1]=(stack_top[0]?nullptr:(nasal_val*)0xffff);
return; return;
} }
void nasal_vm::opr_slcbegin() inline void nasal_vm::opr_slcbegin()
{ {
gc.slice_stack.push_back(gc.gc_alloc(vm_vec)); gc.slice_stack.push_back(gc.gc_alloc(vm_vec));
if(stack_top[0]->type!=vm_vec) if(stack_top[0]->type!=vm_vec)
die("slcbegin: must slice a vector"); die("slcbegin: must slice a vector");
return; return;
} }
void nasal_vm::opr_slcend() inline void nasal_vm::opr_slcend()
{ {
stack_top[0]=gc.slice_stack.back(); stack_top[0]=gc.slice_stack.back();
gc.slice_stack.pop_back(); gc.slice_stack.pop_back();
return; return;
} }
void nasal_vm::opr_slc() inline void nasal_vm::opr_slc()
{ {
nasal_val* val=(stack_top--)[0]; nasal_val* val=(stack_top--)[0];
nasal_val* res=stack_top[0]->ptr.vec->get_val(val->to_number()); nasal_val* res=stack_top[0]->ptr.vec->get_val(val->to_number());
@ -728,7 +650,7 @@ void nasal_vm::opr_slc()
gc.slice_stack.back()->ptr.vec->elems.push_back(res); gc.slice_stack.back()->ptr.vec->elems.push_back(res);
return; return;
} }
void nasal_vm::opr_slc2() inline void nasal_vm::opr_slc2()
{ {
nasal_val* val2=(stack_top--)[0]; nasal_val* val2=(stack_top--)[0];
nasal_val* val1=(stack_top--)[0]; nasal_val* val1=(stack_top--)[0];
@ -768,19 +690,19 @@ void nasal_vm::opr_slc2()
aim.push_back(i>=0?ref[i]:ref[i+ref_size]); aim.push_back(i>=0?ref[i]:ref[i+ref_size]);
return; return;
} }
void nasal_vm::opr_mcallg() inline void nasal_vm::opr_mcallg()
{ {
mem_addr=&gc.global[imm[pc]]; mem_addr=gc.val_stack+imm[pc];
(++stack_top)[0]=mem_addr[0]; (++stack_top)[0]=mem_addr[0];
return; return;
} }
void nasal_vm::opr_mcalll() inline void nasal_vm::opr_mcalll()
{ {
mem_addr=&gc.local.back()[imm[pc]]; mem_addr=&gc.local.back()[imm[pc]];
(++stack_top)[0]=mem_addr[0]; (++stack_top)[0]=mem_addr[0];
return; return;
} }
void nasal_vm::opr_mcallv() inline void nasal_vm::opr_mcallv()
{ {
nasal_val* val=stack_top[0]; nasal_val* val=stack_top[0];
nasal_val* vec_addr=(--stack_top)[0]; nasal_val* vec_addr=(--stack_top)[0];
@ -811,7 +733,7 @@ void nasal_vm::opr_mcallv()
die("mcallv: cannot get memory space in other types"); die("mcallv: cannot get memory space in other types");
return; return;
} }
void nasal_vm::opr_mcallh() inline void nasal_vm::opr_mcallh()
{ {
nasal_val* hash_addr=stack_top[0]; nasal_val* hash_addr=stack_top[0];
if(hash_addr->type!=vm_hash) if(hash_addr->type!=vm_hash)
@ -829,7 +751,7 @@ void nasal_vm::opr_mcallh()
} }
return; return;
} }
void nasal_vm::opr_ret() inline void nasal_vm::opr_ret()
{ {
gc.local.pop_back();// delete local scope gc.local.pop_back();// delete local scope
pc=ret.top();ret.pop();// fetch pc pc=ret.top();ret.pop();// fetch pc
@ -837,14 +759,104 @@ void nasal_vm::opr_ret()
stack_top[0]=stack_top[1];// rewrite nasal_func with returned value stack_top[0]=stack_top[1];// rewrite nasal_func with returned value
return; return;
} }
void nasal_vm::run() void nasal_vm::run(std::vector<opcode>& exec)
{ {
clock_t begin_time=clock(); void* opr_table[]=
for(pc=0;loop_mark&&!gc.val_stack[STACK_MAX_DEPTH-1];++pc) {
(this->*exec_code[pc])(); &&nop, &&intg, &&intl, &&offset,
if(gc.val_stack[STACK_MAX_DEPTH-1]) &&loadg, &&loadl, &&pnum, &&pone,
die("stack overflow"); &&pzero, &&pnil, &&pstr, &&newv,
std::cout<<">> [vm] process exited after "<<((double)(clock()-begin_time))/CLOCKS_PER_SEC<<"s.\n"; &&newh, &&newf, &&happ, &&para,
&&defpara, &&dynpara, &&unot, &&usub,
&&add, &&sub, &&mul, &&div,
&&lnk, &&addeq, &&subeq, &&muleq,
&&diveq, &&lnkeq, &&meq, &&eq,
&&neq, &&less, &&leq, &&grt,
&&geq, &&pop, &&jmp, &&jt,
&&jf, &&counter, &&cntpop, &&findex,
&&feach, &&callg, &&calll, &&callv,
&&callvi, &&callh, &&callfv, &&callfh,
&&callb, &&slcbegin, &&slcend, &&slc,
&&slc2, &&mcallg, &&mcalll, &&mcallv,
&&mcallh, &&ret
};
std::vector<void*> code;
for(auto& i:exec)
{
code.push_back(opr_table[i.op]);
imm.push_back(i.num);
}
clock_t begin=clock();
pc=0;
goto *code[pc];
nop:
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] process exited after "<<((double)(clock()-begin))/CLOCKS_PER_SEC<<"s.\n";
return; return;
#define exec_operand(op) {op();if(!gc.val_stack[STACK_MAX_DEPTH-1])goto *code[++pc];goto nop;}
intg: exec_operand(opr_intg );
intl: exec_operand(opr_intl );
offset: exec_operand(opr_offset );
loadg: exec_operand(opr_loadg );
loadl: exec_operand(opr_loadl );
pnum: exec_operand(opr_pnum );
pone: exec_operand(opr_pone );
pzero: exec_operand(opr_pzero );
pnil: exec_operand(opr_pnil );
pstr: exec_operand(opr_pstr );
newv: exec_operand(opr_newv );
newh: exec_operand(opr_newh );
newf: exec_operand(opr_newf );
happ: exec_operand(opr_happ );
para: exec_operand(opr_para );
defpara: exec_operand(opr_defpara );
dynpara: exec_operand(opr_dynpara );
unot: exec_operand(opr_unot );
usub: exec_operand(opr_usub );
add: exec_operand(opr_add );
sub: exec_operand(opr_sub );
mul: exec_operand(opr_mul );
div: exec_operand(opr_div );
lnk: exec_operand(opr_lnk );
addeq: exec_operand(opr_addeq );
subeq: exec_operand(opr_subeq );
muleq: exec_operand(opr_muleq );
diveq: exec_operand(opr_diveq );
lnkeq: exec_operand(opr_lnkeq );
meq: exec_operand(opr_meq );
eq: exec_operand(opr_eq );
neq: exec_operand(opr_neq );
less: exec_operand(opr_less );
leq: exec_operand(opr_leq );
grt: exec_operand(opr_grt );
geq: exec_operand(opr_geq );
pop: exec_operand(opr_pop );
jmp: exec_operand(opr_jmp );
jt: exec_operand(opr_jt );
jf: exec_operand(opr_jf );
counter: exec_operand(opr_counter );
cntpop: exec_operand(opr_cntpop );
findex: exec_operand(opr_findex );
feach: exec_operand(opr_feach );
callg: exec_operand(opr_callg );
calll: exec_operand(opr_calll );
callv: exec_operand(opr_callv );
callvi: exec_operand(opr_callvi );
callh: exec_operand(opr_callh );
callfv: exec_operand(opr_callfv );
callfh: exec_operand(opr_callfh );
callb: exec_operand(opr_callb );
slcbegin:exec_operand(opr_slcbegin);
slcend: exec_operand(opr_slcend );
slc: exec_operand(opr_slc );
slc2: exec_operand(opr_slc2 );
mcallg: exec_operand(opr_mcallg );
mcalll: exec_operand(opr_mcalll );
mcallv: exec_operand(opr_mcallv );
mcallh: exec_operand(opr_mcallh );
ret: exec_operand(opr_ret );
} }
#endif #endif

View File

@ -15,10 +15,7 @@ var list=func()
_.end=tmp; _.end=tmp;
} }
else else
{ _.begin=_.end=tmp;
_.begin=tmp;
_.end=tmp;
}
return; return;
}, },
push_front:func(elem) push_front:func(elem)
@ -31,10 +28,7 @@ var list=func()
_.begin=tmp; _.begin=tmp;
} }
else else
{ _.begin=_.end=tmp;
_.begin=tmp;
_.end=tmp;
}
return; return;
}, },
pop_back:func() pop_back:func()

View File

@ -3,9 +3,7 @@
var sort=func(vec,left,right,cmp=func(a,b){return a<=b;}) var sort=func(vec,left,right,cmp=func(a,b){return a<=b;})
{ {
if(left>=right) return nil; if(left>=right) return nil;
var L=left; var (L,R,tmp)=(left,right,vec[left]);
var R=right;
var tmp=vec[L];
while(left<right) while(left<right)
{ {
while(left<right and cmp(tmp,vec[right])) while(left<right and cmp(tmp,vec[right]))
@ -13,14 +11,9 @@ var sort=func(vec,left,right,cmp=func(a,b){return a<=b;})
while(left<right and cmp(vec[left],tmp)) while(left<right and cmp(vec[left],tmp))
left+=1; left+=1;
if(left!=right) if(left!=right)
{ (vec[left],vec[right])=(vec[right],vec[left]);
var t=vec[left];
vec[left]=vec[right];
vec[right]=t;
}
} }
vec[L]=vec[left]; (vec[L],vec[left])=(vec[left],tmp);
vec[left]=tmp;
sort(vec,L,left-1,cmp); sort(vec,L,left-1,cmp);
sort(vec,left+1,R,cmp); sort(vec,left+1,R,cmp);
return nil; return nil;