🎨 improve gc code structure

This commit is contained in:
ValKmjolnir 2023-04-10 00:24:50 +08:00
parent 5519dc7a29
commit db47ab4445
3 changed files with 241 additions and 191 deletions

View File

@ -543,13 +543,13 @@ var builtin_open(var* local,gc& ngc) {
return nas_err("open","failed to open file <"+name.str()+">"); return nas_err("open","failed to open file <"+name.str()+">");
} }
var ret=ngc.alloc(vm_obj); var ret=ngc.alloc(vm_obj);
ret.obj().set(nas_obj::file,res); ret.obj().set(obj_type::file,res);
return ret; return ret;
} }
var builtin_close(var* local,gc& ngc) { var builtin_close(var* local,gc& ngc) {
var fd=local[1]; var fd=local[1];
if (!fd.objchk(nas_obj::file)) { if (!fd.objchk(obj_type::file)) {
return nas_err("close","not a valid filehandle"); return nas_err("close","not a valid filehandle");
} }
fd.obj().clear(); fd.obj().clear();
@ -560,7 +560,7 @@ var builtin_read(var* local,gc& ngc) {
var fd=local[1]; var fd=local[1];
var buf=local[2]; var buf=local[2];
var len=local[3]; var len=local[3];
if (!fd.objchk(nas_obj::file)) { if (!fd.objchk(obj_type::file)) {
return nas_err("read","not a valid filehandle"); return nas_err("read","not a valid filehandle");
} }
if (buf.type!=vm_str || buf.val.gcobj->unmut) { 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 builtin_write(var* local,gc& ngc) {
var fd=local[1]; var fd=local[1];
var str=local[2]; var str=local[2];
if (!fd.objchk(nas_obj::file)) { if (!fd.objchk(obj_type::file)) {
return nas_err("write","not a valid filehandle"); return nas_err("write","not a valid filehandle");
} }
if (str.type!=vm_str) { if (str.type!=vm_str) {
@ -599,7 +599,7 @@ var builtin_seek(var* local,gc& ngc) {
var fd=local[1]; var fd=local[1];
var pos=local[2]; var pos=local[2];
var whence=local[3]; 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 nas_err("seek","not a valid filehandle");
} }
return var::num((f64)fseek((FILE*)fd.obj().ptr,pos.num(),whence.num())); 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 builtin_tell(var* local,gc& ngc) {
var fd=local[1]; 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 nas_err("tell","not a valid filehandle");
} }
return var::num((f64)ftell((FILE*)fd.obj().ptr)); 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 builtin_readln(var* local,gc& ngc) {
var fd=local[1]; 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 nas_err("readln","not a valid filehandle");
} }
var str=ngc.alloc(vm_str); 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 builtin_eof(var* local,gc& ngc) {
var fd=local[1]; 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 nas_err("readln","not a valid filehandle");
} }
return var::num((f64)feof((FILE*)fd.obj().ptr)); return var::num((f64)feof((FILE*)fd.obj().ptr));
@ -842,13 +842,13 @@ var builtin_opendir(var* local,gc& ngc) {
} }
#endif #endif
var ret=ngc.alloc(vm_obj); var ret=ngc.alloc(vm_obj);
ret.obj().set(nas_obj::dir,p); ret.obj().set(obj_type::dir,p);
return ret; return ret;
} }
var builtin_readdir(var* local,gc& ngc) { var builtin_readdir(var* local,gc& ngc) {
var handle=local[1]; 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"); return nas_err("readdir","not a valid dir handle");
} }
#ifdef _MSC_VER #ifdef _MSC_VER
@ -865,7 +865,7 @@ var builtin_readdir(var* local,gc& ngc) {
var builtin_closedir(var* local,gc& ngc) { var builtin_closedir(var* local,gc& ngc) {
var handle=local[1]; 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"); return nas_err("closedir","not a valid dir handle");
} }
handle.obj().clear(); handle.obj().clear();
@ -929,7 +929,7 @@ var builtin_dlopen(var* local,gc& ngc) {
} }
var ret=ngc.temp=ngc.alloc(vm_hash); var ret=ngc.temp=ngc.alloc(vm_hash);
var lib=ngc.alloc(vm_obj); 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; ret.hash().elems["lib"]=lib;
#ifdef _WIN32 #ifdef _WIN32
@ -948,7 +948,7 @@ var builtin_dlopen(var* local,gc& ngc) {
for(u32 i=0;tbl[i].name;++i) { for(u32 i=0;tbl[i].name;++i) {
void* p=(void*)tbl[i].fd; void* p=(void*)tbl[i].fd;
var tmp=ngc.alloc(vm_obj); 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; 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 builtin_dlclose(var* local,gc& ngc) {
var libptr=local[1]; 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"); return nas_err("dlclose","\"lib\" is not a valid dynamic lib");
} }
libptr.obj().clear(); libptr.obj().clear();
@ -968,7 +968,7 @@ var builtin_dlclose(var* local,gc& ngc) {
var builtin_dlcallv(var* local,gc& ngc) { var builtin_dlcallv(var* local,gc& ngc) {
var fp=local[1]; var fp=local[1];
var args=local[2]; 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"); return nas_err("dlcall","\"ptr\" is not a valid function pointer");
} }
auto& vec=args.vec().elems; auto& vec=args.vec().elems;
@ -977,11 +977,18 @@ var builtin_dlcallv(var* local,gc& ngc) {
var builtin_dlcall(var* local,gc& ngc) { var builtin_dlcall(var* local,gc& ngc) {
var fp=local[1]; 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"); 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 // 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) { 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.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.ctx.funcr=func; // make sure the coroutine function can use correct upvalues
cort.status=nas_co::suspended; cort.status=coroutine_status::suspended;
return co; return co;
} }
@ -1136,7 +1143,7 @@ var builtin_coresume(var* local,gc& ngc) {
return nil; return nil;
} }
// cannot resume a dead coroutine // cannot resume a dead coroutine
if (co.co().status==nas_co::dead) { if (co.co().status==coroutine_status::dead) {
return nil; return nil;
} }
@ -1181,9 +1188,9 @@ var builtin_costatus(var* local,gc& ngc) {
return ngc.newstr("error"); return ngc.newstr("error");
} }
switch(co.co().status) { switch(co.co().status) {
case nas_co::suspended: return ngc.newstr("suspended");break; case coroutine_status::suspended: return ngc.newstr("suspended");break;
case nas_co::running: return ngc.newstr("running"); break; case coroutine_status::running: return ngc.newstr("running"); break;
case nas_co::dead: return ngc.newstr("dead"); break; case coroutine_status::dead: return ngc.newstr("dead"); break;
} }
return nil; return nil;
} }

View File

@ -40,7 +40,27 @@ enum vm_type:u8 {
vm_co 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_vec; // vector
struct nas_hash; // hashmap(dict) struct nas_hash; // hashmap(dict)
@ -64,12 +84,12 @@ struct var {
var(const var&) = default; 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;}
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 // number and string can be translated to each other
f64 tonum(); f64 tonum();
string tostr(); string tostr();
friend std::ostream& operator<<(std::ostream&,var&); bool objchk(obj_type);
bool objchk(u32);
// create new var object // create new var object
static var none(); static var none();
@ -132,12 +152,12 @@ struct nas_func {
}; };
struct nas_upval { struct nas_upval {
// if on stack, use these three variables /* on stack, use these variables */
bool onstk; bool onstk;
u32 size; u32 size;
var* stk; var* stk;
// if not on stack, use this /* not on stack, use this */
std::vector<var> elems; std::vector<var> elems;
nas_upval() {onstk=true;stk=nullptr;size=0;} nas_upval() {onstk=true;stk=nullptr;size=0;}
@ -146,18 +166,11 @@ struct nas_upval {
}; };
struct nas_obj { struct nas_obj {
enum obj:u32 { obj_type type;
file=1,
dir,
dylib,
faddr,
unsafe
};
/* RAII constructor */
/* new object is initialized when creating */
u32 type;
void* ptr; void* ptr;
private: private:
/* RAII constructor, new object is initialized when creating */
void file_dtor() { void file_dtor() {
fclose((FILE*)ptr); fclose((FILE*)ptr);
} }
@ -176,24 +189,10 @@ private:
#endif #endif
} }
public: public:
nas_obj():type(0),ptr(nullptr) {} nas_obj():type(obj_type::null),ptr(nullptr) {}
~nas_obj() {clear();} ~nas_obj() {clear();}
void set(u32 t=0,void* p=nullptr) { void set(obj_type,void*);
type=t; void clear();
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;
}
}; };
struct context { struct context {
@ -208,43 +207,18 @@ struct context {
}; };
struct nas_co { struct nas_co {
enum costat:u32{
suspended,
running,
dead
};
// calculation stack
var stack[STACK_DEPTH]; var stack[STACK_DEPTH];
context ctx; context ctx;
coroutine_status status;
u32 status;
nas_co() {clear();} nas_co() {clear();}
void clear() { void clear();
for(u32 i=0;i<STACK_DEPTH;++i) {
stack[i]=var::nil();
}
ctx.pc=0;
ctx.localr=nullptr;
ctx.memr=nullptr;
ctx.canary=stack+STACK_DEPTH-1;
ctx.top=stack;
ctx.funcr=var::nil();
ctx.upvalr=var::nil();
ctx.stack=stack;
status=nas_co::suspended;
}
}; };
struct nas_val { struct nas_val {
enum status:u8 {
uncollected=0,
collected,
found
};
u8 mark; // mark if it is visited by gc or collected by gc gc_status mark;
u8 type; // value type u8 type; // value type
u8 unmut; // used to mark if a string is unmutable u8 unmut; // used to mark if a string is unmutable
union { union {
@ -298,15 +272,16 @@ var nas_hash::get_val(const string& key) {
return elems.at(key); return elems.at(key);
} else if (elems.count("parents")) { } else if (elems.count("parents")) {
var ret=var::none(); var ret=var::none();
var val=elems["parents"]; var val=elems.at("parents");
if (val.type==vm_vec) { if (val.type!=vm_vec) {
for(auto& i:val.vec().elems) { return ret;
if (i.type==vm_hash) { }
ret=i.hash().get_val(key); for(auto& i:val.vec().elems) {
} if (i.type==vm_hash) {
if (ret.type!=vm_none) { ret=i.hash().get_val(key);
return ret; }
} if (ret.type!=vm_none) {
return ret;
} }
} }
} }
@ -318,15 +293,16 @@ var* nas_hash::get_mem(const string& key) {
return &elems.at(key); return &elems.at(key);
} else if (elems.count("parents")) { } else if (elems.count("parents")) {
var* addr=nullptr; var* addr=nullptr;
var val=elems["parents"]; var val=elems.at("parents");
if (val.type==vm_vec) { if (val.type!=vm_vec) {
for(auto& i:val.vec().elems) { return addr;
if (i.type==vm_hash) { }
addr=i.hash().get_mem(key); for(auto& i:val.vec().elems) {
} if (i.type==vm_hash) {
if (addr) { addr=i.hash().get_mem(key);
return addr; }
} if (addr) {
return addr;
} }
} }
} }
@ -355,8 +331,42 @@ void nas_func::clear() {
keys.clear(); keys.clear();
} }
void nas_obj::set(obj_type t,void* p) {
type=t;
ptr=p;
}
void nas_obj::clear() {
if (!ptr) {
return;
}
switch(type) {
case obj_type::file: file_dtor(); break;
case obj_type::dir: dir_dtor(); break;
case obj_type::dylib: dylib_dtor();break;
default: break;
}
ptr=nullptr;
}
void nas_co::clear() {
for(u32 i=0;i<STACK_DEPTH;++i) {
stack[i]=var::nil();
}
ctx.pc=0;
ctx.localr=nullptr;
ctx.memr=nullptr;
ctx.canary=stack+STACK_DEPTH-1;
ctx.top=stack;
ctx.funcr=var::nil();
ctx.upvalr=var::nil();
ctx.stack=stack;
status=coroutine_status::suspended;
}
nas_val::nas_val(u8 val_type) { nas_val::nas_val(u8 val_type) {
mark=status::collected; mark=gc_status::collected;
type=val_type; type=val_type;
unmut=0; unmut=0;
switch(val_type) { switch(val_type) {
@ -426,28 +436,20 @@ std::ostream& operator<<(std::ostream& out,var& ref) {
return out; return out;
} }
bool var::objchk(u32 objtype) { bool var::objchk(obj_type objtype) {
return type==vm_obj && obj().type==objtype && obj().ptr; return type==vm_obj && obj().type==objtype && obj().ptr;
} }
var var::none() { var var::none() {
var t; return {vm_none,0};
t.type=vm_none;
return t;
} }
var var::nil() { var var::nil() {
var t; return {vm_nil,0};
t.type=vm_nil;
t.val.num=0;
return t;
} }
var var::ret(u32 pc) { var var::ret(u32 pc) {
var t; return {vm_ret,pc};
t.type=vm_ret;
t.val.ret=pc;
return t;
} }
var var::cnt(i64 n) { var var::cnt(i64 n) {
@ -495,24 +497,24 @@ const var one =var::num(1);
const var nil =var::nil(); const var nil =var::nil();
struct gc { struct gc {
/* main context */ /* main context temporary storage */
context mctx; context mctx;
/* runtime context */ /* runtime context */
context* rctx; context* rctx;
nas_co* cort=nullptr; // running coroutine nas_co* cort=nullptr; // running coroutine
/* native function used */ /* temporary space used in builtin/module functions */
var temp=nil; // temporary place used in builtin/module functions var temp=nil;
/* constants and memory pool */ /* constants and memory pool */
std::vector<var> strs; // reserved address for const vm_str std::vector<var> strs; // reserved address for const vm_str
std::vector<var> env_argv; // command line arguments std::vector<var> env_argv; // command line arguments
std::vector<nas_val*> memory; // gc memory std::vector<nas_val*> memory; // gc memory
std::vector<nas_val*> unused[gc_tsize]; // gc free list std::vector<nas_val*> unused[gc_type_size]; // gc free list
// heap increase size /* heap increase size */
u32 incr[gc_tsize]={ u32 incr[gc_type_size]={
128, // vm_str 128, // vm_str
128, // vm_vec 128, // vm_vec
64, // vm_hash 64, // vm_hash
@ -523,14 +525,26 @@ struct gc {
}; };
/* values for analysis */ /* values for analysis */
u64 size[gc_tsize]; u64 size[gc_type_size];
u64 gcnt[gc_tsize]; u64 gcnt[gc_type_size];
u64 acnt[gc_tsize]; u64 acnt[gc_type_size];
i64 worktime=0; i64 worktime=0;
gc(context* _ctx): rctx(_ctx) {} gc(context* _ctx): rctx(_ctx) {}
private:
/* gc functions */
void mark(); void mark();
void mark_context(std::vector<var>&);
void mark_var(std::vector<var>&,var&);
inline void mark_vec(std::vector<var>&,nas_vec&);
inline void mark_hash(std::vector<var>&,nas_hash&);
inline void mark_func(std::vector<var>&,nas_func&);
inline void mark_upval(std::vector<var>&,nas_upval&);
inline void mark_co(std::vector<var>&,nas_co&);
void sweep(); void sweep();
public:
void extend(u8); void extend(u8);
void init(const std::vector<string>&,const std::vector<string>&); void init(const std::vector<string>&,const std::vector<string>&);
void clear(); void clear();
@ -543,79 +557,98 @@ struct gc {
void ctxreserve(); void ctxreserve();
}; };
/* gc functions */
void gc::mark() { void gc::mark() {
std::vector<var> bfs; std::vector<var> bfs;
// scan coroutine process stack when coroutine ptr is not null mark_context(bfs);
// 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);
}
while(!bfs.empty()) { while(!bfs.empty()) {
var tmp=bfs.back(); var value=bfs.back();
bfs.pop_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; continue;
} }
tmp.val.gcobj->mark=nas_val::status::found; mark_var(bfs,value);
switch(tmp.type) { }
case vm_vec: }
for(auto& i:tmp.vec().elems) {
bfs.push_back(i); void gc::mark_context(std::vector<var>& bfs_queue) {
}
break; // scan now running context, this context maybe related to coroutine or main
case vm_hash: for(var* i=rctx->stack;i<=rctx->top;++i) {
for(auto& i:tmp.hash().elems) { bfs_queue.push_back(*i);
bfs.push_back(i.second); }
} bfs_queue.push_back(rctx->funcr);
break; bfs_queue.push_back(rctx->upvalr);
case vm_func: bfs_queue.push_back(temp);
for(auto& i:tmp.func().local) {
bfs.push_back(i); if (!cort) {
} return;
for(auto& i:tmp.func().upval) { }
bfs.push_back(i);
} // coroutine is running, so scan main process stack from mctx
break; for(var* i=mctx.stack;i<=mctx.top;++i) {
case vm_upval: bfs_queue.push_back(*i);
for(auto& i:tmp.upval().elems) { }
bfs.push_back(i); bfs_queue.push_back(mctx.funcr);
} bfs_queue.push_back(mctx.upvalr);
break; }
case vm_co:
bfs.push_back(tmp.co().ctx.funcr); void gc::mark_var(std::vector<var>& bfs_queue,var& value) {
bfs.push_back(tmp.co().ctx.upvalr); value.val.gcobj->mark=gc_status::found;
for(var* i=tmp.co().stack;i<=tmp.co().ctx.top;++i) { switch(value.type) {
bfs.push_back(*i); case vm_vec: mark_vec(bfs_queue,value.vec()); break;
} case vm_hash: mark_hash(bfs_queue,value.hash()); break;
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<var>& bfs_queue,nas_vec& vec) {
for(auto& i:vec.elems) {
bfs_queue.push_back(i);
}
}
void gc::mark_hash(std::vector<var>& bfs_queue,nas_hash& hash) {
for(auto& i:hash.elems) {
bfs_queue.push_back(i.second);
}
}
void gc::mark_func(std::vector<var>& 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<var>& bfs_queue,nas_upval& upval) {
for(auto& i:upval.elems) {
bfs_queue.push_back(i);
}
}
void gc::mark_co(std::vector<var>& 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() { void gc::sweep() {
for(auto i:memory) { for(auto i:memory) {
if (i->mark==nas_val::status::uncollected) { if (i->mark==gc_status::uncollected) {
i->clear(); i->clear();
unused[i->type-vm_str].push_back(i); unused[i->type-vm_str].push_back(i);
i->mark=nas_val::status::collected; i->mark=gc_status::collected;
} else if (i->mark==nas_val::status::found) { } else if (i->mark==gc_status::found) {
i->mark=nas_val::status::uncollected; i->mark=gc_status::uncollected;
} }
} }
} }
@ -623,11 +656,12 @@ void gc::sweep() {
void gc::extend(u8 type) { void gc::extend(u8 type) {
u8 index=type-vm_str; u8 index=type-vm_str;
size[index]+=incr[index]; size[index]+=incr[index];
for(u32 i=0;i<incr[index];++i) { for(u32 i=0;i<incr[index];++i) {
nas_val* tmp=new nas_val(type); nas_val* tmp=new nas_val(type);
// failed to allocate new memory
if (!tmp) { if (!tmp) {
std::cerr<<"failed to allocate new memory\n";
std::exit(-1); std::exit(-1);
} }
@ -635,6 +669,7 @@ void gc::extend(u8 type) {
memory.push_back(tmp); memory.push_back(tmp);
unused[index].push_back(tmp); unused[index].push_back(tmp);
} }
incr[index]*=2; incr[index]*=2;
} }
@ -644,7 +679,7 @@ void gc::init(const std::vector<string>& s,const std::vector<string>& argv) {
worktime=0; worktime=0;
// initialize counters // initialize counters
for(u8 i=0;i<gc_tsize;++i) { for(u8 i=0;i<gc_type_size;++i) {
size[i]=gcnt[i]=acnt[i]=0; size[i]=gcnt[i]=acnt[i]=0;
} }
@ -673,7 +708,7 @@ void gc::clear() {
delete i; delete i;
} }
memory.clear(); memory.clear();
for(u8 i=0;i<gc_tsize;++i) { for(u8 i=0;i<gc_type_size;++i) {
unused[i].clear(); unused[i].clear();
} }
for(auto& i:strs) { for(auto& i:strs) {
@ -686,8 +721,9 @@ void gc::clear() {
void gc::info() { void gc::info() {
const char* name[]={"str ","vec ","hash ","func ","upval","obj ","co "}; const char* name[]={"str ","vec ","hash ","func ","upval","obj ","co "};
std::clog<<"\ngarbage collector info (gc count|alloc count|memory size)\n"; std::clog<<"\ngarbage collector info (gc count|alloc count|memory size)\n";
u32 maxlen=0; u32 maxlen=0;
for(u8 i=0;i<gc_tsize;++i) { for(u8 i=0;i<gc_type_size;++i) {
u32 len=std::to_string(gcnt[i]).length(); u32 len=std::to_string(gcnt[i]).length();
maxlen=maxlen<len?len:maxlen; maxlen=maxlen<len?len:maxlen;
len=std::to_string(acnt[i]).length(); len=std::to_string(acnt[i]).length();
@ -695,8 +731,9 @@ void gc::info() {
len=std::to_string(size[i]).length(); len=std::to_string(size[i]).length();
maxlen=maxlen<len?len:maxlen; maxlen=maxlen<len?len:maxlen;
} }
double total=0; double total=0;
for(u8 i=0;i<gc_tsize;++i) { for(u8 i=0;i<gc_type_size;++i) {
if (gcnt[i] || acnt[i] || size[i]) { if (gcnt[i] || acnt[i] || size[i]) {
total+=gcnt[i]; total+=gcnt[i];
std::clog<<" "<<name[i]<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<gcnt[i]; std::clog<<" "<<name[i]<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<gcnt[i];
@ -704,6 +741,7 @@ void gc::info() {
std::clog<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<size[i]<<"\n"; std::clog<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<size[i]<<"\n";
} }
} }
double sec=worktime*1.0/1000000000; // seconds double sec=worktime*1.0/1000000000; // seconds
std::clog<<" time | "<<(sec<0.1? sec*1000:sec)<<(sec<0.1? " ms\n":" s\n"); std::clog<<" time | "<<(sec<0.1? sec*1000:sec)<<(sec<0.1? " ms\n":" s\n");
if (total) { if (total) {
@ -726,7 +764,7 @@ var gc::alloc(u8 type) {
extend(type); extend(type);
} }
var ret=var::gcobj(unused[index].back()); var ret=var::gcobj(unused[index].back());
ret.val.gcobj->mark=nas_val::status::uncollected; ret.val.gcobj->mark=gc_status::uncollected;
unused[index].pop_back(); unused[index].pop_back();
return ret; return ret;
} }
@ -760,12 +798,14 @@ void gc::ctxchg(nas_co& co) {
cort=&co; cort=&co;
// set coroutine state to running // set coroutine state to running
cort->status=nas_co::running; cort->status=coroutine_status::running;
} }
void gc::ctxreserve() { void gc::ctxreserve() {
// pc=0 means this coroutine is finished // 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 // store running state to coroutine
cort->ctx=*rctx; 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 var (*mod)(var*,usize,gc*); // module function type
typedef struct { typedef struct {
const char* name; const char* name;
mod fd; mod fd;
} mod_func; // module function stores in tables with this type, end with {nullptr,nullptr} } mod_func; // module function stores in tables with this type, end with {nullptr,nullptr}
typedef mod_func* (*getptr)(); // module function "get" type typedef mod_func* (*getptr)(); // module function "get" type

View File

@ -148,7 +148,8 @@ public:
const codegen&, const codegen&,
const linker&, const linker&,
const std::vector<string>&, const std::vector<string>&,
const bool); const bool
);
}; };
void vm::init( void vm::init(