bug fixed & more efficient callfv
I changed callfv's way of calling a function with arguments in vm_vec. now callfv fetches arguments from val_stack directly,so it runs test/fib.nas from 2.4s to 1.9s. delete operand callf,add operands callfv & callfh. also,i check val_stack's top to make sure there is not a stack overflow.
This commit is contained in:
parent
a68bf85f04
commit
8e29a3ec5b
3
lib.nas
3
lib.nas
|
@ -26,8 +26,7 @@ var setsize=func(vector,size)
|
|||
}
|
||||
var system=func(str)
|
||||
{
|
||||
__builtin_system(str);
|
||||
return;
|
||||
return __builtin_system(str);
|
||||
}
|
||||
var input=func()
|
||||
{
|
||||
|
|
18
main.cpp
18
main.cpp
|
@ -1,10 +1,5 @@
|
|||
#include "nasal.h"
|
||||
|
||||
nasal_lexer lexer;
|
||||
nasal_parse parse;
|
||||
nasal_import import;
|
||||
std::string file="null";
|
||||
nasal_codegen codegen;
|
||||
nasal_vm vm;
|
||||
|
||||
void help()
|
||||
|
@ -39,8 +34,12 @@ void die(std::string stage,std::string filename)
|
|||
return;
|
||||
}
|
||||
|
||||
void execute(std::string& command)
|
||||
void execute(std::string& file,std::string& command)
|
||||
{
|
||||
nasal_lexer lexer;
|
||||
nasal_parse parse;
|
||||
nasal_import import;
|
||||
nasal_codegen codegen;
|
||||
lexer.openfile(file);
|
||||
lexer.scanner();
|
||||
if(lexer.get_error())
|
||||
|
@ -95,12 +94,13 @@ void execute(std::string& command)
|
|||
int main()
|
||||
{
|
||||
std::string command;
|
||||
std::string file="null";
|
||||
#ifdef _WIN32
|
||||
// use chcp 65001 to use unicode io
|
||||
system("chcp 65001");
|
||||
system("cls");
|
||||
#else
|
||||
system("clear");
|
||||
int rs=system("clear");// avoid annoying warning of high version gcc/g++
|
||||
#endif
|
||||
logo();
|
||||
std::cout<<">> Nasal interpreter ver 6.5 efficient gc test .\n";
|
||||
|
@ -120,7 +120,7 @@ int main()
|
|||
#ifdef _WIN32
|
||||
system("cls");
|
||||
#else
|
||||
system("clear");
|
||||
int rs=system("clear");
|
||||
#endif
|
||||
}
|
||||
else if(command=="logo")
|
||||
|
@ -128,7 +128,7 @@ int main()
|
|||
else if(command=="exit")
|
||||
break;
|
||||
else if(command=="lex" || command=="ast" || command=="code" || command=="exec")
|
||||
execute(command);
|
||||
execute(file,command);
|
||||
else
|
||||
file=command;
|
||||
}
|
||||
|
|
|
@ -172,14 +172,15 @@ nasal_val* builtin_setsize(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
|||
|
||||
nasal_val* builtin_system(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_val* ret_addr=gc.gc_alloc(vm_num);
|
||||
nasal_val* str_addr=local_scope[1];
|
||||
if(str_addr->type!=vm_str)
|
||||
{
|
||||
builtin_err("system","\"str\" must be string");
|
||||
return nullptr;
|
||||
}
|
||||
system(str_addr->ptr.str->data());
|
||||
return gc.nil_addr;
|
||||
ret_addr->ptr.num=(double)system(str_addr->ptr.str->data());
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
nasal_val* builtin_input(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||
|
|
|
@ -54,7 +54,8 @@ enum op_code
|
|||
op_callv, // call vec[index]
|
||||
op_callvi, // call vec[immediate] (used in multi-assign/multi-define)
|
||||
op_callh, // call hash.label
|
||||
op_callf, // call function(parameters)
|
||||
op_callfv, // call function(vector as parameters)
|
||||
op_callfh, // call function(hash as parameters)
|
||||
op_callb, // call builtin-function
|
||||
op_slcbegin, // begin of slice like: vec[1,2,3:6,0,-1]
|
||||
op_slcend, // end of slice
|
||||
|
@ -124,7 +125,8 @@ struct
|
|||
{op_callv, "callv "},
|
||||
{op_callvi, "callvi"},
|
||||
{op_callh, "callh "},
|
||||
{op_callf, "callf "},
|
||||
{op_callfv, "callfv"},
|
||||
{op_callfh, "callfh"},
|
||||
{op_callb, "callb "},
|
||||
{op_slcbegin, "slcbeg"},
|
||||
{op_slcend, "slcend"},
|
||||
|
@ -509,12 +511,18 @@ void nasal_codegen::call_vec(nasal_ast& ast)
|
|||
void nasal_codegen::call_func(nasal_ast& ast)
|
||||
{
|
||||
if(!ast.get_children().size())
|
||||
gen(op_newv,0);
|
||||
gen(op_callfv,0);
|
||||
else if(ast.get_children()[0].get_type()==ast_hashmember)
|
||||
{
|
||||
hash_gen(ast);
|
||||
gen(op_callfh,0);
|
||||
}
|
||||
else
|
||||
vec_gen(ast);
|
||||
gen(op_callf,0);
|
||||
{
|
||||
for(auto& node:ast.get_children())
|
||||
calc_gen(node);
|
||||
gen(op_callfv,ast.get_children().size());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
55
nasal_gc.h
55
nasal_gc.h
|
@ -12,21 +12,22 @@ enum nasal_type
|
|||
vm_type_size
|
||||
};
|
||||
|
||||
// change parameters here to make your own efficient gc
|
||||
// better set bigger number on vm_num and vm_vec
|
||||
const int increment[vm_type_size]=
|
||||
{
|
||||
8, // vm_nil,in fact it is not in use
|
||||
0, // vm_nil,in fact it is not in use
|
||||
65536,// vm_num
|
||||
512, // vm_str
|
||||
256, // vm_str
|
||||
16, // vm_func
|
||||
128, // vm_vec
|
||||
16 // vm_hash
|
||||
2048, // vm_vec
|
||||
8 // vm_hash
|
||||
};
|
||||
|
||||
struct nasal_vec;
|
||||
struct nasal_hash;
|
||||
struct nasal_func;
|
||||
struct nasal_scop;
|
||||
struct nasal_val;
|
||||
struct nasal_vec; //24 bytes
|
||||
struct nasal_hash;//56 bytes
|
||||
struct nasal_func;//120 bytes
|
||||
struct nasal_val; // 16 bytes
|
||||
|
||||
struct nasal_vec
|
||||
{
|
||||
|
@ -61,8 +62,10 @@ struct nasal_func
|
|||
|
||||
struct nasal_val
|
||||
{
|
||||
bool collected;
|
||||
bool mark;
|
||||
#define GC_UNCOLLECTED 0
|
||||
#define GC_FOUND 1
|
||||
#define GC_COLLECTED 2
|
||||
uint8_t mark;
|
||||
uint16_t type;
|
||||
union
|
||||
{
|
||||
|
@ -202,15 +205,13 @@ void nasal_func::clear()
|
|||
/*functions of nasal_val*/
|
||||
nasal_val::nasal_val()
|
||||
{
|
||||
collected=true;
|
||||
mark=false;
|
||||
mark=GC_COLLECTED;
|
||||
type=vm_nil;
|
||||
return;
|
||||
}
|
||||
nasal_val::nasal_val(int val_type)
|
||||
{
|
||||
collected=true;
|
||||
mark=false;
|
||||
mark=GC_COLLECTED;
|
||||
type=val_type;
|
||||
switch(type)
|
||||
{
|
||||
|
@ -290,7 +291,7 @@ void nasal_gc::mark()
|
|||
nasal_val* tmp=bfs.front();
|
||||
bfs.pop();
|
||||
if(!tmp || tmp->mark) continue;
|
||||
tmp->mark=true;
|
||||
tmp->mark=GC_FOUND;
|
||||
if(tmp->type==vm_vec)
|
||||
for(auto i:tmp->ptr.vec->elems)
|
||||
bfs.push(i);
|
||||
|
@ -311,21 +312,20 @@ void nasal_gc::sweep()
|
|||
{
|
||||
for(auto i:memory)
|
||||
{
|
||||
if(!i->collected && !i->mark)
|
||||
if(i->mark==GC_UNCOLLECTED)
|
||||
{
|
||||
switch(i->type)
|
||||
{
|
||||
case vm_nil: break;
|
||||
case vm_num: i->ptr.num=0; break;
|
||||
case vm_str: i->ptr.str->clear(); break;
|
||||
case vm_vec: i->ptr.vec->elems.clear(); break;
|
||||
case vm_hash:i->ptr.hash->elems.clear();break;
|
||||
case vm_func:i->ptr.func->clear(); break;
|
||||
}
|
||||
free_list[i->type].push(i);
|
||||
i->collected=true;
|
||||
i->mark=GC_COLLECTED;
|
||||
}
|
||||
i->mark=false;
|
||||
else if(i->mark==GC_FOUND)
|
||||
i->mark=GC_UNCOLLECTED;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -338,6 +338,7 @@ void nasal_gc::gc_init(std::vector<double>& nums,std::vector<std::string>& strs)
|
|||
memory.push_back(tmp);
|
||||
free_list[i].push(tmp);
|
||||
}
|
||||
|
||||
stack_top=val_stack; // set stack_top to val_stack
|
||||
|
||||
zero_addr=new nasal_val(vm_num); // init constant 0
|
||||
|
@ -349,21 +350,21 @@ void nasal_gc::gc_init(std::vector<double>& nums,std::vector<std::string>& strs)
|
|||
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
|
||||
num_addrs.resize(nums.size());
|
||||
for(int i=0;i<nums.size();++i)
|
||||
{
|
||||
nasal_val* tmp=new nasal_val(vm_num);
|
||||
tmp->ptr.num=nums[i];
|
||||
num_addrs.push_back(tmp);
|
||||
num_addrs[i]=tmp;
|
||||
}
|
||||
|
||||
// init constant strings
|
||||
str_addrs.resize(strs.size());
|
||||
for(int i=0;i<strs.size();++i)
|
||||
{
|
||||
nasal_val* tmp=new nasal_val(vm_str);
|
||||
*tmp->ptr.str=strs[i];
|
||||
str_addrs.push_back(tmp);
|
||||
str_addrs[i]=tmp;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -405,7 +406,7 @@ nasal_val* nasal_gc::gc_alloc(int type)
|
|||
free_list[type].push(tmp);
|
||||
}
|
||||
nasal_val* ret=free_list[type].front();
|
||||
ret->collected=false;
|
||||
ret->mark=GC_UNCOLLECTED;
|
||||
free_list[type].pop();
|
||||
return ret;
|
||||
}
|
||||
|
@ -423,7 +424,7 @@ nasal_val* nasal_gc::builtin_alloc(int type)
|
|||
free_list[type].push(tmp);
|
||||
}
|
||||
nasal_val* ret=free_list[type].front();
|
||||
ret->collected=false;
|
||||
ret->mark=GC_UNCOLLECTED;
|
||||
free_list[type].pop();
|
||||
return ret;
|
||||
}
|
||||
|
|
124
nasal_vm.h
124
nasal_vm.h
|
@ -69,7 +69,8 @@ private:
|
|||
void opr_callv();
|
||||
void opr_callvi();
|
||||
void opr_callh();
|
||||
void opr_callf();
|
||||
void opr_callfv();
|
||||
void opr_callfh();
|
||||
void opr_callb();
|
||||
void opr_slcbegin();
|
||||
void opr_slcend();
|
||||
|
@ -101,6 +102,7 @@ void nasal_vm::init(
|
|||
std::vector<opcode>& exec)
|
||||
{
|
||||
gc.gc_init(nums,strs);
|
||||
gc.val_stack[STACK_MAX_DEPTH-1]=nullptr;
|
||||
str_table=strs; // get constant strings & symbols
|
||||
exec_code=exec; // get bytecodes
|
||||
loop_mark=true; // set loop mark to true
|
||||
|
@ -135,7 +137,7 @@ bool nasal_vm::condition(nasal_val* val_addr)
|
|||
std::string& str=*val_addr->ptr.str;
|
||||
double number=str2num(str);
|
||||
if(std::isnan(number))
|
||||
return str.length();
|
||||
return !str.empty();
|
||||
return number;
|
||||
}
|
||||
return false;
|
||||
|
@ -211,19 +213,21 @@ void nasal_vm::opr_newf()
|
|||
{
|
||||
nasal_val* val=gc.gc_alloc(vm_func);
|
||||
val->ptr.func->entry=exec_code[pc].num;
|
||||
if(!gc.local.empty())
|
||||
val->ptr.func->closure=gc.local.back();// local contains 'me'
|
||||
else
|
||||
if(gc.local.empty())
|
||||
val->ptr.func->closure.push_back(gc.nil_addr);// me
|
||||
else
|
||||
val->ptr.func->closure=gc.local.back();// local contains 'me'
|
||||
*(++stack_top)=val;
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_vapp()
|
||||
{
|
||||
nasal_val* vec=*(stack_top-exec_code[pc].num);
|
||||
for(nasal_val** i=stack_top-exec_code[pc].num+1;i<=stack_top;++i)
|
||||
vec->ptr.vec->elems.push_back(*i);
|
||||
stack_top-=exec_code[pc].num;
|
||||
nasal_val** begin=stack_top-exec_code[pc].num+1;
|
||||
auto& vec=begin[-1]->ptr.vec->elems;// stack_top-exec_code[pc].num stores the vector
|
||||
vec.resize(exec_code[pc].num);
|
||||
for(int i=0;i<exec_code[pc].num;++i)
|
||||
vec[i]=begin[i];
|
||||
stack_top=begin-1;
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_happ()
|
||||
|
@ -265,7 +269,7 @@ void nasal_vm::opr_unot()
|
|||
{
|
||||
double number=str2num(*val->ptr.str);
|
||||
if(std::isnan(number))
|
||||
new_val=val->ptr.str->length()?gc.zero_addr:gc.one_addr;
|
||||
new_val=val->ptr.str->empty()?gc.one_addr:gc.zero_addr;
|
||||
else
|
||||
new_val=number?gc.zero_addr:gc.one_addr;
|
||||
}
|
||||
|
@ -526,8 +530,7 @@ void nasal_vm::opr_findex()
|
|||
void nasal_vm::opr_feach()
|
||||
{
|
||||
std::vector<nasal_val*>& ref=(*stack_top)->ptr.vec->elems;
|
||||
++counter.top();
|
||||
if(counter.top()>=ref.size())
|
||||
if(++counter.top()>=ref.size())
|
||||
{
|
||||
pc=exec_code[pc].num-1;
|
||||
return;
|
||||
|
@ -635,73 +638,89 @@ void nasal_vm::opr_callh()
|
|||
*stack_top=res;
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_callf()
|
||||
void nasal_vm::opr_callfv()
|
||||
{
|
||||
// get parameter list and function value
|
||||
nasal_val* para_addr=*stack_top;
|
||||
nasal_val* func_addr=*(stack_top-1);
|
||||
int args_size=exec_code[pc].num;
|
||||
nasal_val** vec=stack_top-args_size+1;
|
||||
nasal_val* func_addr=*(vec-1);
|
||||
if(func_addr->type!=vm_func)
|
||||
{
|
||||
die("callf: called a value that is not a function");
|
||||
die("callfv: called a value that is not a function");
|
||||
return;
|
||||
}
|
||||
// push new local scope
|
||||
gc.local.push_back(func_addr->ptr.func->closure);
|
||||
auto& ref_func=*func_addr->ptr.func;
|
||||
gc.local.push_back(ref_func.closure);
|
||||
// load parameters
|
||||
nasal_func& ref_func=*func_addr->ptr.func;
|
||||
std::vector<nasal_val*>& ref_default=ref_func.default_para;
|
||||
std::vector<nasal_val*>& ref_closure=gc.local.back();
|
||||
std::unordered_map<std::string,int>& ref_keys=ref_func.key_table;
|
||||
auto& ref_default=ref_func.default_para;
|
||||
auto& ref_closure=gc.local.back();
|
||||
auto& ref_keys=ref_func.key_table;
|
||||
|
||||
if(para_addr->type==vm_vec)
|
||||
{
|
||||
std::vector<nasal_val*>& args=para_addr->ptr.vec->elems;
|
||||
int args_size=args.size();
|
||||
int offset=ref_func.offset;
|
||||
int para_size=ref_keys.size();
|
||||
for(int i=0;i<para_size;++i)
|
||||
// load arguments
|
||||
if(args_size<para_size && !ref_default[args_size])
|
||||
{
|
||||
if(i>=args_size)
|
||||
{
|
||||
if(!ref_default[i])
|
||||
{
|
||||
die("callf: lack argument(s)");
|
||||
// if the first default value is not nullptr,then values after it are not nullptr
|
||||
die("callfv: lack argument(s)");
|
||||
return;
|
||||
}
|
||||
ref_closure[i+ref_func.offset]=ref_default[i];
|
||||
}
|
||||
else
|
||||
ref_closure[i+ref_func.offset]=args[i];
|
||||
}
|
||||
// if args_size>para_size,for 0 to args_size will cause corruption
|
||||
for(int i=0;i<para_size;++i)
|
||||
ref_closure[i+offset]=(i>=args_size)?ref_default[i]:vec[i];
|
||||
// load dynamic argument if args_size>=para_size
|
||||
if(ref_func.dynpara>=0)
|
||||
{
|
||||
nasal_val* vec_addr=gc.gc_alloc(vm_vec);
|
||||
for(int i=para_size;i<args_size;++i)
|
||||
vec_addr->ptr.vec->elems.push_back(args[i]);
|
||||
ref_closure[para_size+ref_func.offset]=vec_addr;
|
||||
vec_addr->ptr.vec->elems.push_back(vec[i]);
|
||||
ref_closure[para_size+offset]=vec_addr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unordered_map<std::string,nasal_val*>& ref_hash=para_addr->ptr.hash->elems;
|
||||
if(ref_func.dynpara>=0)
|
||||
{
|
||||
die("callf: special call cannot use dynamic argument");
|
||||
|
||||
stack_top-=args_size;// pop arguments
|
||||
ret.push(pc);
|
||||
pc=ref_func.entry-1;
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_callfh()
|
||||
{
|
||||
// get parameter list and function value
|
||||
std::unordered_map<std::string,nasal_val*>& ref_hash=(*stack_top)->ptr.hash->elems;
|
||||
nasal_val* func_addr=*(stack_top-1);
|
||||
if(func_addr->type!=vm_func)
|
||||
{
|
||||
die("callfh: called a value that is not a function");
|
||||
return;
|
||||
}
|
||||
// push new local scope
|
||||
auto& ref_func=*func_addr->ptr.func;
|
||||
gc.local.push_back(ref_func.closure);
|
||||
// load parameters
|
||||
auto& ref_default=ref_func.default_para;
|
||||
auto& ref_closure=gc.local.back();
|
||||
auto& ref_keys=ref_func.key_table;
|
||||
|
||||
if(ref_func.dynpara>=0)
|
||||
{
|
||||
die("callfh: special call cannot use dynamic argument");
|
||||
return;
|
||||
}
|
||||
int offset=ref_func.offset;
|
||||
for(auto& i:ref_keys)
|
||||
{
|
||||
if(ref_hash.count(i.first))
|
||||
ref_closure[i.second+ref_func.offset]=ref_hash[i.first];
|
||||
ref_closure[i.second+offset]=ref_hash[i.first];
|
||||
else if(ref_default[i.second])
|
||||
ref_closure[i.second+ref_func.offset]=ref_default[i.second];
|
||||
ref_closure[i.second+offset]=ref_default[i.second];
|
||||
else
|
||||
{
|
||||
die("callf: lack argument(s): \""+i.first+"\"");
|
||||
die("callfh: lack argument(s): \""+i.first+"\"");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
--stack_top;
|
||||
|
||||
--stack_top;// pop hash
|
||||
ret.push(pc);
|
||||
pc=ref_func.entry-1;
|
||||
return;
|
||||
|
@ -920,7 +939,8 @@ void nasal_vm::run()
|
|||
&nasal_vm::opr_callv,
|
||||
&nasal_vm::opr_callvi,
|
||||
&nasal_vm::opr_callh,
|
||||
&nasal_vm::opr_callf,
|
||||
&nasal_vm::opr_callfv,
|
||||
&nasal_vm::opr_callfh,
|
||||
&nasal_vm::opr_callb,
|
||||
&nasal_vm::opr_slcbegin,
|
||||
&nasal_vm::opr_slcend,
|
||||
|
@ -934,7 +954,7 @@ void nasal_vm::run()
|
|||
};
|
||||
clock_t begin_time=clock();
|
||||
// main loop
|
||||
for(pc=0;loop_mark;++pc)
|
||||
for(pc=0;loop_mark&&!gc.val_stack[STACK_MAX_DEPTH-1];++pc)
|
||||
(this->*opr_table[exec_code[pc].op])();
|
||||
float total_time=((double)(clock()-begin_time))/CLOCKS_PER_SEC;
|
||||
std::cout<<">> [vm] process exited after "<<total_time<<"s.\n";
|
||||
|
|
|
@ -26,8 +26,7 @@ var setsize=func(vector,size)
|
|||
}
|
||||
var system=func(str)
|
||||
{
|
||||
__builtin_system(str);
|
||||
return;
|
||||
return __builtin_system(str);
|
||||
}
|
||||
var input=func()
|
||||
{
|
||||
|
|
|
@ -137,7 +137,7 @@ while(error>0.0005)
|
|||
}
|
||||
cnt+=1;
|
||||
show+=1;
|
||||
if(show==300)
|
||||
if(show==350)
|
||||
{
|
||||
show=0;
|
||||
print('epoch ',cnt,':',error,'\r');
|
||||
|
|
|
@ -6,3 +6,4 @@ var fib=func(x)
|
|||
}
|
||||
for(var i=0;i<31;i+=1)
|
||||
print(fib(i),'\n');
|
||||
|
Loading…
Reference in New Issue