🎨 improve gc code structure
This commit is contained in:
parent
5519dc7a29
commit
db47ab4445
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
338
nasal_gc.h
338
nasal_gc.h
|
@ -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,8 +272,10 @@ 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) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
for(auto& i:val.vec().elems) {
|
for(auto& i:val.vec().elems) {
|
||||||
if (i.type==vm_hash) {
|
if (i.type==vm_hash) {
|
||||||
ret=i.hash().get_val(key);
|
ret=i.hash().get_val(key);
|
||||||
|
@ -309,7 +285,6 @@ var nas_hash::get_val(const string& key) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return var::none();
|
return var::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,8 +293,10 @@ 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) {
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
for(auto& i:val.vec().elems) {
|
for(auto& i:val.vec().elems) {
|
||||||
if (i.type==vm_hash) {
|
if (i.type==vm_hash) {
|
||||||
addr=i.hash().get_mem(key);
|
addr=i.hash().get_mem(key);
|
||||||
|
@ -329,7 +306,6 @@ var* nas_hash::get_mem(const string& key) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case vm_hash:
|
|
||||||
for(auto& i:tmp.hash().elems) {
|
|
||||||
bfs.push_back(i.second);
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case vm_func:
|
void gc::mark_context(std::vector<var>& bfs_queue) {
|
||||||
for(auto& i:tmp.func().local) {
|
|
||||||
bfs.push_back(i);
|
// 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);
|
||||||
}
|
}
|
||||||
for(auto& i:tmp.func().upval) {
|
bfs_queue.push_back(rctx->funcr);
|
||||||
bfs.push_back(i);
|
bfs_queue.push_back(rctx->upvalr);
|
||||||
|
bfs_queue.push_back(temp);
|
||||||
|
|
||||||
|
if (!cort) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case vm_upval:
|
// coroutine is running, so scan main process stack from mctx
|
||||||
for(auto& i:tmp.upval().elems) {
|
for(var* i=mctx.stack;i<=mctx.top;++i) {
|
||||||
bfs.push_back(i);
|
bfs_queue.push_back(*i);
|
||||||
}
|
}
|
||||||
break;
|
bfs_queue.push_back(mctx.funcr);
|
||||||
case vm_co:
|
bfs_queue.push_back(mctx.upvalr);
|
||||||
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;
|
|
||||||
|
void gc::mark_var(std::vector<var>& 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<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
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in New Issue