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:
Valk Richard Li 2021-06-03 21:49:31 +08:00
parent a68bf85f04
commit 8e29a3ec5b
9 changed files with 164 additions and 135 deletions

View File

@ -26,8 +26,7 @@ var setsize=func(vector,size)
}
var system=func(str)
{
__builtin_system(str);
return;
return __builtin_system(str);
}
var input=func()
{

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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";

View File

@ -26,8 +26,7 @@ var setsize=func(vector,size)
}
var system=func(str)
{
__builtin_system(str);
return;
return __builtin_system(str);
}
var input=func()
{

View File

@ -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');

View File

@ -6,3 +6,4 @@ var fib=func(x)
}
for(var i=0;i<31;i+=1)
print(fib(i),'\n');