🚀 crashed coroutine will not make main thread crash.

This commit is contained in:
ValKmjolnir 2022-10-06 23:11:27 +08:00
parent ae85791f01
commit 405175061a
6 changed files with 80 additions and 72 deletions

View File

@ -31,7 +31,6 @@ test:nasal
@ ./nasal -o -e test/ascii-art.nas
@ ./nasal -o -c test/auto_crash.nas
@ ./nasal -o -a -c test/bf.nas
@ ./nasal -o -a -c test/bfcolored.nas
@ ./nasal -o -a -c test/bfconvertor.nas
@ ./nasal -o -e -d test/bfs.nas
@ ./nasal -o -t test/bigloop.nas

View File

@ -1047,21 +1047,21 @@ nas_ref builtin_cocreate(nas_ref* local,nasal_gc& gc)
if(gc.cort)
return nas_err("coroutine::create","cannot create another coroutine in a coroutine");
nas_ref co=gc.alloc(vm_co);
nas_co& coroutine=co.co();
coroutine.pc=func.func().entry-1;
nas_co& cort=co.co();
cort.pc=func.func().entry-1;
coroutine.top[0]=nil;
coroutine.localr=coroutine.top+1;
coroutine.top=coroutine.localr+func.func().lsize;
coroutine.localr[0]=func.func().local[0];
coroutine.top[0]=nil; // old upvalr
coroutine.top++;
coroutine.top[0]={vm_addr,(nas_ref*)nullptr}; // old localr
coroutine.top++;
coroutine.top[0]={vm_ret,(u32)0}; // old pc, set to zero to make op_ret recognizing this as coroutine function
cort.top[0]=nil;
cort.localr=cort.top+1;
cort.top=cort.localr+func.func().lsize;
cort.localr[0]=func.func().local[0];
cort.top[0]=nil; // old upvalr
cort.top++;
cort.top[0]={vm_addr,(nas_ref*)nullptr}; // old localr
cort.top++;
cort.top[0]={vm_ret,(u32)0}; // old pc, set to zero to make op_ret recognizing this as coroutine function
coroutine.funcr=func; // make sure the coroutine function can use correct upvalues
coroutine.status=nas_co::suspended;
cort.funcr=func; // make sure the coroutine function can use correct upvalues
cort.status=nas_co::suspended;
return co;
}

View File

@ -32,20 +32,20 @@ const u32 ini[gc_tsize]=
128, // vm_str
128, // vm_vec
32, // vm_hash
512, // vm_func
512, // vm_upval
128, // vm_func
0, // vm_upval
0, // vm_obj
0 // vm_co
};
const u32 incr[gc_tsize]=
{
256, // vm_str
512, // vm_vec
512, // vm_hash
512, // vm_func
256, // vm_vec
256, // vm_hash
128, // vm_func
128, // vm_upval
128, // vm_obj
16 // vm_co
32 // vm_co
};
struct nas_vec; // vector

View File

@ -45,7 +45,8 @@ protected:
void lstate();
void ustate();
void detail();
[[noreturn]] void die(const string&);
void die(const string&);
#define vm_error(info) {die(info);return;}
/* vm calculation functions*/
bool condition(nas_ref);
/* vm operands */
@ -306,8 +307,6 @@ void nasal_vm::detail()
lstate();
ustate();
}
[[noreturn]]
void nasal_vm::die(const string& str)
{
std::cout<<"[vm] error: "<<str<<"\n";
@ -315,7 +314,13 @@ void nasal_vm::die(const string& str)
stackinfo();
if(detail_info)
detail();
std::exit(1);
if(gc.stack==stack){
std::exit(1);
}else{
pc=0; // mark coroutine 'dead'
gc.ctxreserve();
top[0]=nil;
}
}
inline bool nasal_vm::condition(nas_ref val)
{
@ -436,7 +441,7 @@ inline void nasal_vm::o_unot()
else
top[0]=num?zero:one;
}break;
default:die("incorrect value type");break;
default:vm_error("incorrect value type");break;
}
}
inline void nasal_vm::o_usub()
@ -581,7 +586,7 @@ inline void nasal_vm::o_jf()
inline void nasal_vm::o_cnt()
{
if(top[0].type!=vm_vec)
die("must use vector in forindex/foreach");
vm_error("must use vector in forindex/foreach");
(++top)[0]={vm_cnt,(i64)-1};
}
inline void nasal_vm::o_findex()
@ -626,15 +631,15 @@ inline void nasal_vm::o_callv()
{
top[0]=vec.vec().get_val(val.tonum());
if(top[0].type==vm_none)
die("index out of range:"+std::to_string(val.tonum()));
vm_error("index out of range:"+std::to_string(val.tonum()));
}
else if(vec.type==vm_hash)
{
if(val.type!=vm_str)
die("must use string as the key");
vm_error("must use string as the key");
top[0]=vec.hash().get_val(val.str());
if(top[0].type==vm_none)
die("cannot find member \""+val.str()+"\"");
vm_error("cannot find member \""+val.str()+"\"");
if(top[0].type==vm_func)
top[0].func().local[0]=val;// 'me'
}
@ -644,33 +649,30 @@ inline void nasal_vm::o_callv()
i32 num=val.tonum();
i32 len=str.length();
if(num<-len || num>=len)
die("index out of range:"+std::to_string(val.tonum()));
vm_error("index out of range:"+std::to_string(val.tonum()));
top[0]={vm_num,f64((u8)str[num>=0? num:num+len])};
}
else
die("must call a vector/hash/string");
vm_error("must call a vector/hash/string");
}
inline void nasal_vm::o_callvi()
{
nas_ref val=top[0];
if(val.type!=vm_vec)
die("must use a vector");
vm_error("must use a vector");
// cannot use operator[],because this may cause overflow
(++top)[0]=val.vec().get_val(imm[pc]);
if(top[0].type==vm_none)
die("index out of range:"+std::to_string(imm[pc]));
vm_error("index out of range:"+std::to_string(imm[pc]));
}
inline void nasal_vm::o_callh()
{
nas_ref val=top[0];
if(val.type!=vm_hash)
die("must call a hash");
vm_error("must call a hash");
top[0]=val.hash().get_val(str_table[imm[pc]]);
if(top[0].type==vm_none)
die("member \""+str_table[imm[pc]]+"\" does not exist");
vm_error("member \""+str_table[imm[pc]]+"\" does not exist");
if(top[0].type==vm_func)
top[0].func().local[0]=val;// 'me'
}
@ -679,19 +681,18 @@ inline void nasal_vm::o_callfv()
u32 argc=imm[pc]; // arguments counter
nas_ref* local=top-argc+1; // arguments begin address
if(local[-1].type!=vm_func)
die("must call a function");
vm_error("must call a function");
auto& func=local[-1].func();
nas_ref tmp=local[-1];
local[-1]=funcr;
funcr=tmp;
// top-argc+lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
if(top-argc+func.lsize+3>=canary)
die("stack overflow");
vm_error("stack overflow");
// parameter size is func->psize-1, 1 is reserved for "me"
u32 psize=func.psize-1;
if(argc<psize && func.local[argc+1].type==vm_none)
die("lack argument(s)");
vm_error("lack argument(s)");
nas_ref dynamic=nil;
top=local+func.lsize;
@ -726,17 +727,16 @@ inline void nasal_vm::o_callfh()
{
auto& hash=top[0].hash().elems;
if(top[-1].type!=vm_func)
die("must call a function");
vm_error("must call a function");
auto& func=top[-1].func();
nas_ref tmp=top[-1];
top[-1]=funcr;
funcr=tmp;
// top -1(hash) +lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
if(top+func.lsize+2>=canary)
die("stack overflow");
vm_error("stack overflow");
if(func.dpara>=0)
die("special call cannot use dynamic argument");
vm_error("special call cannot use dynamic argument");
nas_ref* local=top;
top+=func.lsize;
@ -749,7 +749,7 @@ inline void nasal_vm::o_callfh()
if(hash.count(key))
local[i.second]=hash[key];
else if(local[i.second].type==vm_none)
die("lack argument(s): \""+key+"\"");
vm_error("lack argument(s): \""+key+"\"");
}
top[0]=upvalr;
@ -769,7 +769,7 @@ inline void nasal_vm::o_callb()
// (top) will be set to another context.top, instead of main_context.top
top[0]=(*builtin[imm[pc]].func)(localr,gc);
if(top[0].type==vm_none)
die("native function error");
vm_error("native function error");
}
inline void nasal_vm::o_slcbeg()
{
@ -780,7 +780,7 @@ inline void nasal_vm::o_slcbeg()
// +--------------+
(++top)[0]=gc.alloc(vm_vec);
if(top[-1].type!=vm_vec)
die("must slice a vector");
vm_error("must slice a vector");
}
inline void nasal_vm::o_slcend()
{
@ -792,7 +792,7 @@ inline void nasal_vm::o_slc()
nas_ref val=(top--)[0];
nas_ref res=top[-1].vec().get_val(val.tonum());
if(res.type==vm_none)
die("index out of range:"+std::to_string(val.tonum()));
vm_error("index out of range:"+std::to_string(val.tonum()));
top[0].vec().elems.push_back(res);
}
inline void nasal_vm::o_slc2()
@ -816,15 +816,12 @@ inline void nasal_vm::o_slc2()
else if(type1!=vm_nil && type2==vm_nil)
num2=num1<0? -1:size-1;
if(num1>num2)
die("begin index must be less than or equal to end index");
else if(num1<-size || num1>=size)
die("begin index out of range: "+std::to_string(num1));
else if(num2<-size || num2>=size)
die("end index out of range: "+std::to_string(num2));
else
if(num1<-size || num1>=size || num2<-size || num2>=size){
vm_error("index "+std::to_string(num1)+":"+std::to_string(num2)+" out of range.");
}else if(num1<=num2){
for(i32 i=num1;i<=num2;++i)
aim.push_back(i>=0?ref[i]:ref[i+size]);
}
}
inline void nasal_vm::o_mcallg()
{
@ -855,12 +852,11 @@ inline void nasal_vm::o_mcallv()
{
memr=vec.vec().get_mem(val.tonum());
if(!memr)
die("index out of range:"+std::to_string(val.tonum()));
}
else if(vec.type==vm_hash) // do mcallh but use the mcallv way
vm_error("index out of range:"+std::to_string(val.tonum()));
}else if(vec.type==vm_hash) // do mcallh but use the mcallv way
{
if(val.type!=vm_str)
die("must use string as the key");
vm_error("must use string as the key");
nas_hash& ref=vec.hash();
string& str=val.str();
memr=ref.get_mem(str);
@ -869,15 +865,14 @@ inline void nasal_vm::o_mcallv()
ref.elems[str]=nil;
memr=ref.get_mem(str);
}
}
else
die("cannot get memory space in this type");
}else
vm_error("cannot get memory space in this type");
}
inline void nasal_vm::o_mcallh()
{
nas_ref hash=top[0]; // mcall hash, reserved on stack to avoid gc
if(hash.type!=vm_hash)
die("must call a hash");
vm_error("must call a hash");
nas_hash& ref=hash.hash();
const string& str=str_table[imm[pc]];
memr=ref.get_mem(str);
@ -1021,14 +1016,12 @@ void nasal_vm::run(
while(code[pc]){
(this->*code[pc])();
if(top>=canary)
break;
die("stack overflow");
++pc;
}
#endif
vmexit:
if(top>=canary)
die("stack overflow");
if(detail)
gc.info();
gc.clear();
@ -1041,7 +1034,7 @@ vmexit:
op();\
if(top<canary)\
goto *code[++pc];\
goto vmexit;\
die("stack overflow");\
}
// do not cause stackoverflow
#define exec_nodie(op) {op();goto *code[++pc];}

View File

@ -44,8 +44,10 @@ var total=1000; # ms
var co=coroutine.create(productor);
var tm=maketimestamp();
if(os.platform()=="windows")
if(os.platform()=="windows"){
system("chcp 65001");
system("color");
}
var counter=0;
var bar=process_bar.high_resolution_bar(40);
var consumer=func(){
@ -59,4 +61,18 @@ var consumer=func(){
tm.stamp();
while(tm.elapsedMSec()<total)
consumer();
println("\nexecute ",counter," tasks during ",total," ms, avg ",counter/total," tasks/ms.")
println("\nexecute ",counter," tasks during ",total," ms, avg ",counter/total," tasks/ms.");
var co=coroutine.create(func{
var b=func(){b()}
coroutine.yield(b);
b();
coroutine.yield(0);
});
println("coroutine yield: ",coroutine.resume(co));
println("coroutine state:\e[32m ",coroutine.status(co),"\e[0m");
println("coroutine error: ",coroutine.resume(co));
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
println("coroutine yield: ",coroutine.resume(co));
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");

View File

@ -119,6 +119,6 @@ func(diff){
print("\n");
diff(
io.fin("test/bf.nas"),
io.fin("test/bfcolored.nas")
io.fin("test/bfconvertor.nas")
);
}(myers);