diff --git a/nasal_builtin.h b/nasal_builtin.h index bd37eff..508858e 100644 --- a/nasal_builtin.h +++ b/nasal_builtin.h @@ -543,13 +543,13 @@ var builtin_open(var* local,gc& ngc) { return nas_err("open","failed to open file <"+name.str()+">"); } var ret=ngc.alloc(vm_obj); - ret.obj().set(nas_obj::file,res); + ret.obj().set(obj_type::file,res); return ret; } var builtin_close(var* local,gc& ngc) { var fd=local[1]; - if (!fd.objchk(nas_obj::file)) { + if (!fd.objchk(obj_type::file)) { return nas_err("close","not a valid filehandle"); } fd.obj().clear(); @@ -560,7 +560,7 @@ var builtin_read(var* local,gc& ngc) { var fd=local[1]; var buf=local[2]; var len=local[3]; - if (!fd.objchk(nas_obj::file)) { + if (!fd.objchk(obj_type::file)) { return nas_err("read","not a valid filehandle"); } if (buf.type!=vm_str || buf.val.gcobj->unmut) { @@ -586,7 +586,7 @@ var builtin_read(var* local,gc& ngc) { var builtin_write(var* local,gc& ngc) { var fd=local[1]; var str=local[2]; - if (!fd.objchk(nas_obj::file)) { + if (!fd.objchk(obj_type::file)) { return nas_err("write","not a valid filehandle"); } if (str.type!=vm_str) { @@ -599,7 +599,7 @@ var builtin_seek(var* local,gc& ngc) { var fd=local[1]; var pos=local[2]; var whence=local[3]; - if (!fd.objchk(nas_obj::file)) { + if (!fd.objchk(obj_type::file)) { return nas_err("seek","not a valid filehandle"); } return var::num((f64)fseek((FILE*)fd.obj().ptr,pos.num(),whence.num())); @@ -607,7 +607,7 @@ var builtin_seek(var* local,gc& ngc) { var builtin_tell(var* local,gc& ngc) { var fd=local[1]; - if (!fd.objchk(nas_obj::file)) { + if (!fd.objchk(obj_type::file)) { return nas_err("tell","not a valid filehandle"); } return var::num((f64)ftell((FILE*)fd.obj().ptr)); @@ -615,7 +615,7 @@ var builtin_tell(var* local,gc& ngc) { var builtin_readln(var* local,gc& ngc) { var fd=local[1]; - if (!fd.objchk(nas_obj::file)) { + if (!fd.objchk(obj_type::file)) { return nas_err("readln","not a valid filehandle"); } var str=ngc.alloc(vm_str); @@ -663,7 +663,7 @@ var builtin_stat(var* local,gc& ngc) { var builtin_eof(var* local,gc& ngc) { var fd=local[1]; - if (!fd.objchk(nas_obj::file)) { + if (!fd.objchk(obj_type::file)) { return nas_err("readln","not a valid filehandle"); } return var::num((f64)feof((FILE*)fd.obj().ptr)); @@ -842,13 +842,13 @@ var builtin_opendir(var* local,gc& ngc) { } #endif var ret=ngc.alloc(vm_obj); - ret.obj().set(nas_obj::dir,p); + ret.obj().set(obj_type::dir,p); return ret; } var builtin_readdir(var* local,gc& ngc) { var handle=local[1]; - if (!handle.objchk(nas_obj::dir)) { + if (!handle.objchk(obj_type::dir)) { return nas_err("readdir","not a valid dir handle"); } #ifdef _MSC_VER @@ -865,7 +865,7 @@ var builtin_readdir(var* local,gc& ngc) { var builtin_closedir(var* local,gc& ngc) { var handle=local[1]; - if (!handle.objchk(nas_obj::dir)) { + if (!handle.objchk(obj_type::dir)) { return nas_err("closedir","not a valid dir handle"); } handle.obj().clear(); @@ -929,7 +929,7 @@ var builtin_dlopen(var* local,gc& ngc) { } var ret=ngc.temp=ngc.alloc(vm_hash); var lib=ngc.alloc(vm_obj); - lib.obj().set(nas_obj::dylib,ptr); + lib.obj().set(obj_type::dylib,ptr); ret.hash().elems["lib"]=lib; #ifdef _WIN32 @@ -948,7 +948,7 @@ var builtin_dlopen(var* local,gc& ngc) { for(u32 i=0;tbl[i].name;++i) { void* p=(void*)tbl[i].fd; var tmp=ngc.alloc(vm_obj); - tmp.obj().set(nas_obj::faddr,p); + tmp.obj().set(obj_type::faddr,p); ret.hash().elems[tbl[i].name]=tmp; } @@ -958,7 +958,7 @@ var builtin_dlopen(var* local,gc& ngc) { var builtin_dlclose(var* local,gc& ngc) { var libptr=local[1]; - if (!libptr.objchk(nas_obj::dylib)) { + if (!libptr.objchk(obj_type::dylib)) { return nas_err("dlclose","\"lib\" is not a valid dynamic lib"); } libptr.obj().clear(); @@ -968,7 +968,7 @@ var builtin_dlclose(var* local,gc& ngc) { var builtin_dlcallv(var* local,gc& ngc) { var fp=local[1]; var args=local[2]; - if (!fp.objchk(nas_obj::faddr)) { + if (!fp.objchk(obj_type::faddr)) { return nas_err("dlcall","\"ptr\" is not a valid function pointer"); } auto& vec=args.vec().elems; @@ -977,11 +977,18 @@ var builtin_dlcallv(var* local,gc& ngc) { var builtin_dlcall(var* local,gc& ngc) { var fp=local[1]; - if (!fp.objchk(nas_obj::faddr)) { + if (!fp.objchk(obj_type::faddr)) { return nas_err("dlcall","\"ptr\" is not a valid function pointer"); } + + var* local_frame_start=local+2; + usize local_frame_size=ngc.rctx->top-local_frame_start; // arguments' stored place begins at local +2 - return ((mod)fp.obj().ptr)(local+2,ngc.rctx->top-local-2,&ngc); + return ((mod)fp.obj().ptr)( + local_frame_start, + local_frame_size, + &ngc + ); } var builtin_platform(var* local,gc& ngc) { @@ -1121,7 +1128,7 @@ var builtin_cocreate(var* local,gc& ngc) { cort.ctx.top[0]=var::ret(0); // old pc, set to zero to make op_ret recognizing this as coroutine function cort.ctx.funcr=func; // make sure the coroutine function can use correct upvalues - cort.status=nas_co::suspended; + cort.status=coroutine_status::suspended; return co; } @@ -1136,7 +1143,7 @@ var builtin_coresume(var* local,gc& ngc) { return nil; } // cannot resume a dead coroutine - if (co.co().status==nas_co::dead) { + if (co.co().status==coroutine_status::dead) { return nil; } @@ -1181,9 +1188,9 @@ var builtin_costatus(var* local,gc& ngc) { return ngc.newstr("error"); } switch(co.co().status) { - case nas_co::suspended: return ngc.newstr("suspended");break; - case nas_co::running: return ngc.newstr("running"); break; - case nas_co::dead: return ngc.newstr("dead"); break; + case coroutine_status::suspended: return ngc.newstr("suspended");break; + case coroutine_status::running: return ngc.newstr("running"); break; + case coroutine_status::dead: return ngc.newstr("dead"); break; } return nil; } diff --git a/nasal_gc.h b/nasal_gc.h index d6da08c..9f2c154 100644 --- a/nasal_gc.h +++ b/nasal_gc.h @@ -40,7 +40,27 @@ enum vm_type:u8 { vm_co }; -const u32 gc_tsize=vm_co-vm_str+1; +const u32 gc_type_size=vm_co-vm_str+1; + +enum class obj_type:u32 { + null=0, + file=1, + dir, + dylib, + faddr +}; + +enum class coroutine_status:u32 { + suspended, + running, + dead +}; + +enum class gc_status:u8 { + uncollected=0, + collected, + found +}; struct nas_vec; // vector struct nas_hash; // hashmap(dict) @@ -64,12 +84,12 @@ struct var { var(const var&) = default; bool operator==(const var& nr) const {return type==nr.type && val.gcobj==nr.val.gcobj;} bool operator!=(const var& nr) const {return type!=nr.type || val.gcobj!=nr.val.gcobj;} + friend std::ostream& operator<<(std::ostream&,var&); // number and string can be translated to each other f64 tonum(); string tostr(); - friend std::ostream& operator<<(std::ostream&,var&); - bool objchk(u32); + bool objchk(obj_type); // create new var object static var none(); @@ -132,12 +152,12 @@ struct nas_func { }; struct nas_upval { - // if on stack, use these three variables + /* on stack, use these variables */ bool onstk; u32 size; var* stk; - // if not on stack, use this + /* not on stack, use this */ std::vector elems; nas_upval() {onstk=true;stk=nullptr;size=0;} @@ -146,18 +166,11 @@ struct nas_upval { }; struct nas_obj { - enum obj:u32 { - file=1, - dir, - dylib, - faddr, - unsafe - }; - /* RAII constructor */ - /* new object is initialized when creating */ - u32 type; + obj_type type; void* ptr; + private: + /* RAII constructor, new object is initialized when creating */ void file_dtor() { fclose((FILE*)ptr); } @@ -176,24 +189,10 @@ private: #endif } public: - nas_obj():type(0),ptr(nullptr) {} + nas_obj():type(obj_type::null),ptr(nullptr) {} ~nas_obj() {clear();} - void set(u32 t=0,void* p=nullptr) { - type=t; - ptr=p; - } - void clear() { - if (!ptr) { - return; - } - switch(type) { - case obj::file: file_dtor(); break; - case obj::dir: dir_dtor(); break; - case obj::dylib: dylib_dtor();break; - default: break; - } - ptr=nullptr; - } + void set(obj_type,void*); + void clear(); }; struct context { @@ -208,43 +207,18 @@ struct context { }; struct nas_co { - enum costat:u32{ - suspended, - running, - dead - }; - // calculation stack var stack[STACK_DEPTH]; context ctx; + coroutine_status status; - u32 status; nas_co() {clear();} - void clear() { - for(u32 i=0;i strs; // reserved address for const vm_str std::vector env_argv; // command line arguments std::vector memory; // gc memory - std::vector unused[gc_tsize]; // gc free list + std::vector unused[gc_type_size]; // gc free list - // heap increase size - u32 incr[gc_tsize]={ + /* heap increase size */ + u32 incr[gc_type_size]={ 128, // vm_str 128, // vm_vec 64, // vm_hash @@ -523,14 +525,26 @@ struct gc { }; /* values for analysis */ - u64 size[gc_tsize]; - u64 gcnt[gc_tsize]; - u64 acnt[gc_tsize]; + u64 size[gc_type_size]; + u64 gcnt[gc_type_size]; + u64 acnt[gc_type_size]; i64 worktime=0; gc(context* _ctx): rctx(_ctx) {} + +private: + /* gc functions */ void mark(); + void mark_context(std::vector&); + void mark_var(std::vector&,var&); + inline void mark_vec(std::vector&,nas_vec&); + inline void mark_hash(std::vector&,nas_hash&); + inline void mark_func(std::vector&,nas_func&); + inline void mark_upval(std::vector&,nas_upval&); + inline void mark_co(std::vector&,nas_co&); void sweep(); + +public: void extend(u8); void init(const std::vector&,const std::vector&); void clear(); @@ -543,79 +557,98 @@ struct gc { void ctxreserve(); }; -/* gc functions */ void gc::mark() { std::vector bfs; - // scan coroutine process stack when coroutine ptr is not null - // scan main process stack when coroutine ptr is null - // this scan process must execute because when running coroutine, - // the nas_co related to it will not update it's context(like `top`) until the coroutine suspends or exits. - for(var* i=rctx->stack;i<=rctx->top;++i) { - bfs.push_back(*i); - } - bfs.push_back(rctx->funcr); - bfs.push_back(rctx->upvalr); - bfs.push_back(temp); - - // if coroutine is running, scan main process stack from mctx - if (cort) { - for(var* i=mctx.stack;i<=mctx.top;++i) { - bfs.push_back(*i); - } - bfs.push_back(mctx.funcr); - bfs.push_back(mctx.upvalr); - } + mark_context(bfs); while(!bfs.empty()) { - var tmp=bfs.back(); + var value=bfs.back(); bfs.pop_back(); - if (tmp.type<=vm_num || tmp.val.gcobj->mark) { + if (value.type<=vm_num || + value.val.gcobj->mark!=gc_status::uncollected) { continue; } - tmp.val.gcobj->mark=nas_val::status::found; - switch(tmp.type) { - case vm_vec: - for(auto& i:tmp.vec().elems) { - bfs.push_back(i); - } - break; - case vm_hash: - for(auto& i:tmp.hash().elems) { - bfs.push_back(i.second); - } - break; - case vm_func: - for(auto& i:tmp.func().local) { - bfs.push_back(i); - } - for(auto& i:tmp.func().upval) { - bfs.push_back(i); - } - break; - case vm_upval: - for(auto& i:tmp.upval().elems) { - bfs.push_back(i); - } - break; - case vm_co: - bfs.push_back(tmp.co().ctx.funcr); - bfs.push_back(tmp.co().ctx.upvalr); - for(var* i=tmp.co().stack;i<=tmp.co().ctx.top;++i) { - bfs.push_back(*i); - } - break; - } + mark_var(bfs,value); + } +} + +void gc::mark_context(std::vector& bfs_queue) { + + // scan now running context, this context maybe related to coroutine or main + for(var* i=rctx->stack;i<=rctx->top;++i) { + bfs_queue.push_back(*i); + } + bfs_queue.push_back(rctx->funcr); + bfs_queue.push_back(rctx->upvalr); + bfs_queue.push_back(temp); + + if (!cort) { + return; + } + + // coroutine is running, so scan main process stack from mctx + for(var* i=mctx.stack;i<=mctx.top;++i) { + bfs_queue.push_back(*i); + } + bfs_queue.push_back(mctx.funcr); + bfs_queue.push_back(mctx.upvalr); +} + +void gc::mark_var(std::vector& bfs_queue,var& value) { + value.val.gcobj->mark=gc_status::found; + switch(value.type) { + case vm_vec: mark_vec(bfs_queue,value.vec()); break; + case vm_hash: mark_hash(bfs_queue,value.hash()); break; + case vm_func: mark_func(bfs_queue,value.func()); break; + case vm_upval: mark_upval(bfs_queue,value.upval()); break; + case vm_co: mark_co(bfs_queue,value.co()); break; + default: break; + } +} + +void gc::mark_vec(std::vector& bfs_queue,nas_vec& vec) { + for(auto& i:vec.elems) { + bfs_queue.push_back(i); + } +} + +void gc::mark_hash(std::vector& bfs_queue,nas_hash& hash) { + for(auto& i:hash.elems) { + bfs_queue.push_back(i.second); + } +} + +void gc::mark_func(std::vector& bfs_queue,nas_func& function) { + for(auto& i:function.local) { + bfs_queue.push_back(i); + } + for(auto& i:function.upval) { + bfs_queue.push_back(i); + } +} + +void gc::mark_upval(std::vector& bfs_queue,nas_upval& upval) { + for(auto& i:upval.elems) { + bfs_queue.push_back(i); + } +} + +void gc::mark_co(std::vector& bfs_queue,nas_co& co) { + bfs_queue.push_back(co.ctx.funcr); + bfs_queue.push_back(co.ctx.upvalr); + for(var* i=co.stack;i<=co.ctx.top;++i) { + bfs_queue.push_back(*i); } } void gc::sweep() { for(auto i:memory) { - if (i->mark==nas_val::status::uncollected) { + if (i->mark==gc_status::uncollected) { i->clear(); unused[i->type-vm_str].push_back(i); - i->mark=nas_val::status::collected; - } else if (i->mark==nas_val::status::found) { - i->mark=nas_val::status::uncollected; + i->mark=gc_status::collected; + } else if (i->mark==gc_status::found) { + i->mark=gc_status::uncollected; } } } @@ -623,11 +656,12 @@ void gc::sweep() { void gc::extend(u8 type) { u8 index=type-vm_str; size[index]+=incr[index]; + for(u32 i=0;i& s,const std::vector& argv) { worktime=0; // initialize counters - for(u8 i=0;imark=nas_val::status::uncollected; + ret.val.gcobj->mark=gc_status::uncollected; unused[index].pop_back(); return ret; } @@ -760,12 +798,14 @@ void gc::ctxchg(nas_co& co) { cort=&co; // set coroutine state to running - cort->status=nas_co::running; + cort->status=coroutine_status::running; } void gc::ctxreserve() { // pc=0 means this coroutine is finished - cort->status=rctx->pc? nas_co::suspended:nas_co::dead; + cort->status=rctx->pc? + coroutine_status::suspended: + coroutine_status::dead; // store running state to coroutine cort->ctx=*rctx; @@ -784,8 +824,10 @@ var nas_err(const string& err_f,const string& info) { } typedef var (*mod)(var*,usize,gc*); // module function type + typedef struct { const char* name; mod fd; } mod_func; // module function stores in tables with this type, end with {nullptr,nullptr} + typedef mod_func* (*getptr)(); // module function "get" type diff --git a/nasal_vm.h b/nasal_vm.h index b743ddf..6bc32d5 100644 --- a/nasal_vm.h +++ b/nasal_vm.h @@ -148,7 +148,8 @@ public: const codegen&, const linker&, const std::vector&, - const bool); + const bool + ); }; void vm::init(