*polished sample script; *fixed a memory leak with gc caused by reference cycle; *finished internal class development.

This commit is contained in:
paladin-t 2015-12-11 17:25:21 +08:00
parent a426e150ae
commit ef79101296
7 changed files with 203 additions and 72 deletions

View File

@ -1,6 +1,8 @@
Dec. 11 2015
Added an IS statement to detect type equality of a value
Added support to store a routine in a variable by CALL statement
Fixed a memory leak with GC caused by reference cycle
Finished internal class development
Dec. 10 2015
Developing class, added a NEW statement to duplicate a class instance

View File

@ -82,7 +82,7 @@ extern "C" {
/** Macros */
#define _VER_MAJOR 1
#define _VER_MINOR 1
#define _VER_REVISION 105
#define _VER_REVISION 106
#define _VER_SUFFIX
#define _MB_VERSION ((_VER_MAJOR * 0x01000000) + (_VER_MINOR * 0x00010000) + (_VER_REVISION))
#define _STRINGIZE(A) _MAKE_STRINGIZE(A)
@ -312,6 +312,8 @@ typedef short _lock_t;
#ifdef MB_ENABLE_GC
typedef struct _gc_t {
_ht_node_t* table;
_ht_node_t* recursive_table;
_ht_node_t* collected_table;
int_t collecting;
} _gc_t;
#endif /* MB_ENABLE_GC */
@ -1072,6 +1074,10 @@ static char* _extract_string(_object_t* obj);
case _DT_USERTYPE_REF: \
_unref(&(__o)->data.usertype_ref->ref, (__o)->data.usertype_ref); \
break;
#define _ADDGC_USERTYPE_REF(__o, __g) \
case _DT_USERTYPE_REF: \
_gc_add(&(__o)->data.usertype_ref->ref, (__o)->data.usertype_ref, (__g)); \
break;
#define _REF_ARRAY(__o) \
case _DT_ARRAY: \
if(!(__o)->ref) \
@ -1082,6 +1088,11 @@ static char* _extract_string(_object_t* obj);
if(!(__o)->ref) \
_unref(&(__o)->data.array->ref, (__o)->data.array); \
break;
#define _ADDGC_ARRAY(__o, __g) \
case _DT_ARRAY: \
if(!(__o)->ref) \
_gc_add(&(__o)->data.array->ref, (__o)->data.array, (__g)); \
break;
#ifdef MB_ENABLE_COLLECTION_LIB
# define _REF_COLL(__o) \
case _DT_LIST: \
@ -1097,6 +1108,13 @@ static char* _extract_string(_object_t* obj);
case _DT_DICT: \
_unref(&(__o)->data.dict->ref, (__o)->data.dict); \
break;
# define _ADDGC_COLL(__o, __g) \
case _DT_LIST: \
_gc_add(&(__o)->data.list->ref, (__o)->data.list, (__g)); \
break; \
case _DT_DICT: \
_gc_add(&(__o)->data.dict->ref, (__o)->data.dict, (__g)); \
break;
#else /* MB_ENABLE_COLLECTION_LIB */
# define _REF_COLL(__o) ((void)(__o));
# define _UNREF_COLL(__o) ((void)(__o));
@ -1111,9 +1129,15 @@ static char* _extract_string(_object_t* obj);
if(!(__o)->ref) \
_unref(&(__o)->data.instance->ref, (__o)->data.instance); \
break;
# define _ADDGC_CLASS(__o, __g) \
case _DT_CLASS: \
if(!(__o)->ref) \
_gc_add(&(__o)->data.instance->ref, (__o)->data.instance, (__g)); \
break;
#else /* MB_ENABLE_CLASS */
# define _REF_CLASS(__o) ((void)(__o));
# define _UNREF_CLASS(__o) ((void)(__o));
# define _ADDGC_CLASS(__o, __g) ((void)(__o)); ((void)(__g));
#endif /* MB_ENABLE_CLASS */
#define _REF(__o) \
switch((__o)->type) { \
@ -1131,6 +1155,14 @@ static char* _extract_string(_object_t* obj);
_UNREF_CLASS(__o) \
default: break; \
}
#define _ADDGC(__o, __g) \
switch((__o)->type) { \
_ADDGC_USERTYPE_REF(__o, __g) \
_ADDGC_ARRAY(__o, __g) \
_ADDGC_COLL(__o, __g) \
_ADDGC_CLASS(__o, __g) \
default: break; \
}
static bool_t _lock_ref_object(_lock_t* lk, _ref_t* ref, void* obj);
static bool_t _unlock_ref_object(_lock_t* lk, _ref_t* ref, void* obj);
@ -1142,10 +1174,12 @@ static void _create_ref(_ref_t* ref, _unref_func_t dtor, _data_e t, mb_interpret
static void _destroy_ref(_ref_t* ref);
#ifdef MB_ENABLE_GC
static void _gc_add(_ref_t* ref, void* data);
static void _gc_add(_ref_t* ref, void* data, _gc_t* gc);
static void _gc_remove(_ref_t* ref, void* data);
static int _gc_add_reachable(void* data, void* extra, void* ht);
static void _gc_get_reachable(mb_interpreter_t* s, _ht_node_t* ht);
static int _gc_destroy_garbage_in_list(void* data, void* extra, _gc_t* gc);
static int _gc_destroy_garbage_in_dict(void* data, void* extra, _gc_t* gc);
static int _gc_destroy_garbage(void* data, void* extra);
static void _gc_try_trigger(mb_interpreter_t* s);
static void _gc_collect_garbage(mb_interpreter_t* s);
@ -1265,6 +1299,7 @@ static void _swap_public_value(mb_value_t* tgt, mb_value_t* src);
static int _clear_scope_chain(mb_interpreter_t* s);
static int _dispose_scope_chain(mb_interpreter_t* s);
static void _tidy_scope_chain(mb_interpreter_t* s);
static void _tidy_intermediate_value(_ref_t* ref, void* data);
static void _stepped(mb_interpreter_t* s, _ls_node_t* ast);
static int _execute_statement(mb_interpreter_t* s, _ls_node_t** l);
@ -4115,7 +4150,9 @@ unsigned _unref(_ref_t* ref, void* data) {
result = --(*(ref->count));
#ifdef MB_ENABLE_GC
_gc_add(ref, data);
_gc_add(ref, data, 0);
if(ref->count && !(*ref->count))
_tidy_intermediate_value(ref, data);
ref->on_unref(ref, data);
if(!ref->count)
_gc_remove(ref, data);
@ -4148,23 +4185,33 @@ void _destroy_ref(_ref_t* ref) {
}
#ifdef MB_ENABLE_GC
void _gc_add(_ref_t* ref, void* data) {
void _gc_add(_ref_t* ref, void* data, _gc_t* gc) {
/* Add a referenced object to GC */
_ht_node_t* table = 0;
mb_assert(ref && data);
if(gc && _ht_find(gc->collected_table, ref))
return;
if(ref->type == _DT_ARRAY)
return;
if(!ref->s->gc.table)
return;
if(ref->s->gc.collecting)
if(ref->s->gc.collecting > 1)
return;
if(ref->count && *ref->count)
_ht_set_or_insert(ref->s->gc.table, ref, data);
if(ref->s->gc.collecting)
table = ref->s->gc.recursive_table;
else
_ht_remove(ref->s->gc.table, ref, 0);
table = ref->s->gc.table;
if(ref->count && *ref->count)
_ht_set_or_insert(table, ref, data);
else
_ht_remove(table, ref, 0);
}
void _gc_remove(_ref_t* ref, void* data) {
@ -4251,27 +4298,9 @@ void _gc_get_reachable(mb_interpreter_t* s, _ht_node_t* ht) {
/* Get all reachable referenced objects */
_running_context_t* running = 0;
_ht_node_t* global_scope = 0;
_object_t tmp;
mb_assert(s && ht);
_MAKE_NIL(&tmp);
_public_value_to_internal_object(&s->running_context->intermediate_value, &tmp);
switch(tmp.type) {
case _DT_ARRAY: /* Fall through */
#ifdef MB_ENABLE_COLLECTION_LIB
case _DT_LIST: /* Fall through */
case _DT_DICT: /* Fall through */
#endif /* MB_ENABLE_COLLECTION_LIB */
#ifdef MB_ENABLE_CLASS
case _DT_CLASS: /* Fall through */
#endif /* MB_ENABLE_CLASS */
case _DT_USERTYPE_REF:
_gc_add_reachable(&tmp, 0, ht);
break;
}
running = s->running_context;
while(running) {
global_scope = running->var_dict;
@ -4283,10 +4312,50 @@ void _gc_get_reachable(mb_interpreter_t* s, _ht_node_t* ht) {
}
}
int _gc_destroy_garbage_in_list(void* data, void* extra, _gc_t* gc) {
/* Destroy only the capsule (wrapper) of an object, leave the data behind, and add it to GC if possible */
int result = _OP_RESULT_NORMAL;
_object_t* obj = 0;
mb_unrefvar(extra);
mb_assert(data);
obj = (_object_t*)data;
_ADDGC(obj, gc);
safe_free(obj);
result = _OP_RESULT_DEL_NODE;
return result;
}
int _gc_destroy_garbage_in_dict(void* data, void* extra, _gc_t* gc) {
/* Destroy only the capsule (wrapper) of an object, leave the data behind, deal with extra as well, and add it to GC if possible */
int result = _OP_RESULT_NORMAL;
_object_t* obj = 0;
mb_unrefvar(extra);
mb_assert(data);
obj = (_object_t*)data;
_ADDGC(obj, gc);
safe_free(obj);
obj = (_object_t*)extra;
_ADDGC(obj, gc);
safe_free(obj);
result = _OP_RESULT_DEL_NODE;
return result;
}
int _gc_destroy_garbage(void* data, void* extra) {
/* Destroy a garbage */
int result = _OP_RESULT_NORMAL;
_gc_t* gc = 0;
_ref_t* ref = 0;
bool_t cld = false;
#ifdef MB_ENABLE_COLLECTION_LIB
_list_t* lst = 0;
_dict_t* dct = 0;
@ -4295,18 +4364,27 @@ int _gc_destroy_garbage(void* data, void* extra) {
mb_assert(data && extra);
ref = (_ref_t*)extra;
gc = &ref->s->gc;
switch(ref->type) {
#ifdef MB_ENABLE_COLLECTION_LIB
case _DT_LIST:
lst = (_list_t*)data;
_ls_foreach(lst->list, _destroy_object_capsule_only);
if(gc->collecting <= 1 && !_ht_find(gc->recursive_table, ref)) {
_LS_FOREACH(lst->list, _do_nothing_on_object, _gc_destroy_garbage_in_list, gc);
} else {
_ls_foreach(lst->list, _destroy_object_capsule_only);
}
_ls_clear(lst->list);
lst->count = 0;
break;
case _DT_DICT:
dct = (_dict_t*)data;
_ht_foreach(dct->dict, _destroy_object_capsule_only_with_extra);
if(gc->collecting <= 1 && !_ht_find(gc->recursive_table, ref)) {
_HT_FOREACH(dct->dict, _do_nothing_on_object, _gc_destroy_garbage_in_dict, gc);
} else {
_ht_foreach(dct->dict, _destroy_object_capsule_only_with_extra);
}
_ht_clear(dct->dict);
break;
@ -4314,7 +4392,12 @@ int _gc_destroy_garbage(void* data, void* extra) {
default:
break;
}
_unref(ref, data);
if(ref->count) {
cld = (*(ref->count)) == 1;
_unref(ref, data);
if(cld)
_ht_set_or_insert(gc->collected_table, ref, data);
}
result = _OP_RESULT_DEL_NODE;
@ -4345,8 +4428,14 @@ void _gc_collect_garbage(mb_interpreter_t* s) {
_HT_FOREACH(valid, _do_nothing_on_object, _ht_remove_exist, s->gc.table);
/* Collect garbage */
_ht_foreach(s->gc.table, _gc_destroy_garbage);
/* Tidy */
_ht_clear(s->gc.table);
if(s->gc.recursive_table->count) {
s->gc.collecting++;
_ht_foreach(s->gc.recursive_table, _gc_destroy_garbage);
_ht_clear(s->gc.recursive_table);
s->gc.collecting--;
}
/* Tidy */
_ht_clear(valid);
_ht_destroy(valid);
s->gc.collecting--;
@ -6629,6 +6718,7 @@ int _dispose_scope_chain(mb_interpreter_t* s) {
result++;
running = prev;
}
s->running_context = 0;
return result;
}
@ -6654,6 +6744,35 @@ void _tidy_scope_chain(mb_interpreter_t* s) {
#endif /* MB_ENABLE_CLASS */
}
void _tidy_intermediate_value(_ref_t* ref, void* data) {
/* Tidy the intermediate value */
_object_t tmp;
mb_assert(ref && data);
if(!ref->s->running_context)
return;
_MAKE_NIL(&tmp);
_public_value_to_internal_object(&ref->s->running_context->intermediate_value, &tmp);
if(tmp.data.usertype == data) {
switch(tmp.type) {
case _DT_ARRAY: /* Fall through */
#ifdef MB_ENABLE_COLLECTION_LIB
case _DT_LIST: /* Fall through */
case _DT_DICT: /* Fall through */
#endif /* MB_ENABLE_COLLECTION_LIB */
#ifdef MB_ENABLE_CLASS
case _DT_CLASS: /* Fall through */
#endif /* MB_ENABLE_CLASS */
case _DT_USERTYPE_REF:
mb_make_nil(ref->s->running_context->intermediate_value);
break;
}
}
}
void _stepped(mb_interpreter_t* s, _ls_node_t* ast) {
/* Called each step */
_object_t* obj = 0;
@ -7405,6 +7524,8 @@ int mb_open(struct mb_interpreter_t** s) {
#ifdef MB_ENABLE_GC
(*s)->gc.table = _ht_create(0, _ht_cmp_ref, _ht_hash_ref, _do_nothing_on_object);
(*s)->gc.recursive_table = _ht_create(0, _ht_cmp_ref, _ht_hash_ref, _do_nothing_on_object);
(*s)->gc.collected_table = _ht_create(0, _ht_cmp_ref, _ht_hash_ref, _do_nothing_on_object);
#endif /* MB_ENABLE_GC */
(*s)->sub_stack = _ls_create();
@ -7446,13 +7567,21 @@ int mb_close(struct mb_interpreter_t** s) {
#ifdef MB_ENABLE_GC
_gc_collect_garbage(*s);
_ht_destroy((*s)->gc.table);
(*s)->gc.table = 0;
#endif /* MB_ENABLE_GC */
_tidy_scope_chain(*s);
_dispose_scope_chain(*s);
#ifdef MB_ENABLE_GC
_gc_collect_garbage(*s);
_ht_destroy((*s)->gc.table);
_ht_destroy((*s)->gc.recursive_table);
_ht_destroy((*s)->gc.collected_table);
(*s)->gc.table = 0;
(*s)->gc.recursive_table = 0;
(*s)->gc.collected_table = 0;
#endif /* MB_ENABLE_GC */
_ls_foreach((*s)->temp_values, _destroy_object);
_ls_destroy((*s)->temp_values);
_ls_foreach((*s)->lazy_destroy_objects, _destroy_object);

View File

@ -4,4 +4,4 @@
s$ = "hello "
s$ = s$ + "world"
PRINT s$ + "!"
print s$ + "!"

View File

@ -4,14 +4,14 @@
e = 50
PRINT "Primes in ", e, ": ", 2, ", "
print "Primes in ", e, ": ", 2, ", "
FOR n = 3 TO e
m = 2
is = 1
WHILE m < n
IF n MOD m = 0 THEN is = 0 ELSE m = m + 1
IF is = 0 THEN EXIT
WEND
IF is = 1 THEN PRINT n, ", "
NEXT n
for n = 3 to e
m = 2
isp = 1
while m < n
if n mod m = 0 then isp = 0 else m = m + 1
if isp = 0 then exit
wend
if isp = 1 then print n, ", "
next n

View File

@ -2,21 +2,21 @@
' Copyright (c) 2011 - 2015 Wang Renxin. All rights reserved.
' For more information, see https://github.com/paladin-t/my_basic/
PRINT "Input: "
INPUT ns$
n = VAL(ns$)
print "Input: "
input ns$
n = val(ns$)
x = n * 2 - 1
a = 1 - 1 / 3
w = (x - 5) / 2 + 1
v = 100 / w
FOR y = 5 TO x STEP 2
for y = 5 to x step 2
iy = (y - 1) / 4
iy = FLOOR(iy)
IF iy = (y - 1) / 4 THEN a = a + 1 / y ELSE a = a - 1 / y
iy = floor(iy)
if iy = (y - 1) / 4 then a = a + 1 / y else a = a - 1 / y
u = u + v
NEXT
next
a = a * 4
PRINT "PI = ", a
print "Pi = ", a

View File

@ -2,22 +2,22 @@
' Copyright (c) 2011 - 2015 Wang Renxin. All rights reserved.
' For more information, see https://github.com/paladin-t/my_basic/
BEGIN:
begin:
n = 10
DIM arr(n)
GOSUB CALC
GOSUB SHOW
END
dim arr(n)
gosub calc
gosub show
end
CALC:
calc:
arr(0) = 1
FOR i = 1 TO n - 1
IF i = 1 THEN arr(i) = 1 ELSE arr(i) = arr(i - 1) + arr(i - 2)
NEXT
RETURN
for i = 1 to n - 1
if i = 1 then arr(i) = 1 else arr(i) = arr(i - 1) + arr(i - 2)
next
return
SHOW:
FOR i = 0 TO n - 1
PRINT arr(i), ", "
NEXT
RETURN
show:
for i = 0 to n - 1
print arr(i), ", "
next
return

View File

@ -2,14 +2,14 @@
' Copyright (c) 2011 - 2015 Wang Renxin. All rights reserved.
' For more information, see https://github.com/paladin-t/my_basic/
DEF AREA(a, b)
RETURN CALL MUL(a, b)
ENDDEF
def area(a, b)
return call mul(a, b)
enddef
DEF MUL(a, b)
def mul(a, b)
return a * b
ENDDEF
enddef
a = 3
b = 4
PRINT a; b; AREA(a, b);
print a; b; area(a, b);