From 8faa144d04389286890668fe8db2122b5d324a24 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Thu, 25 Nov 2021 19:46:02 +0100 Subject: [PATCH] Berry static methods --- lib/libesp32/Berry/src/be_bytecode.c | 4 +-- lib/libesp32/Berry/src/be_class.c | 5 +++- lib/libesp32/Berry/src/be_class.h | 2 +- lib/libesp32/Berry/src/be_constobj.h | 20 +++++++++++++++ lib/libesp32/Berry/src/be_gc.c | 2 +- lib/libesp32/Berry/src/be_map.c | 4 ++- lib/libesp32/Berry/src/be_object.h | 31 ++++++++++++---------- lib/libesp32/Berry/src/be_parser.c | 34 +++++++++++++------------ lib/libesp32/Berry/src/be_solidifylib.c | 14 +++++++--- lib/libesp32/Berry/src/be_string.c | 10 ++++++-- lib/libesp32/Berry/src/be_vm.c | 28 ++++++++++++++++---- 11 files changed, 108 insertions(+), 46 deletions(-) diff --git a/lib/libesp32/Berry/src/be_bytecode.c b/lib/libesp32/Berry/src/be_bytecode.c index 521317e63..9f9283fbe 100644 --- a/lib/libesp32/Berry/src/be_bytecode.c +++ b/lib/libesp32/Berry/src/be_bytecode.c @@ -23,7 +23,7 @@ #define MAGIC_NUMBER1 0xBE #define MAGIC_NUMBER2 0xCD #define MAGIC_NUMBER3 0xFE -#define BYTECODE_VERSION 2 +#define BYTECODE_VERSION 3 #define USE_64BIT_INT (BE_INTGER_TYPE == 2 \ || BE_INTGER_TYPE == 1 && LONG_MAX == 9223372036854775807L) @@ -425,7 +425,7 @@ static void load_class(bvm *vm, void *fp, bvalue *v, int version) be_incrtop(vm); if (load_proto(vm, fp, (bproto**)&var_toobj(value), -3, version)) { /* actual method */ - be_method_bind(vm, c, name, var_toobj(value)); + be_method_bind(vm, c, name, var_toobj(value), bfalse); } else { /* no proto, static member set to nil */ be_member_bind(vm, c, name, bfalse); diff --git a/lib/libesp32/Berry/src/be_class.c b/lib/libesp32/Berry/src/be_class.c index c8c826371..a960d4b24 100644 --- a/lib/libesp32/Berry/src/be_class.c +++ b/lib/libesp32/Berry/src/be_class.c @@ -75,7 +75,7 @@ void be_member_bind(bvm *vm, bclass *c, bstring *name, bbool var) } } -void be_method_bind(bvm *vm, bclass *c, bstring *name, bproto *p) +void be_method_bind(bvm *vm, bclass *c, bstring *name, bproto *p, bbool is_static) { bclosure *cl; bvalue *attr; @@ -87,6 +87,9 @@ void be_method_bind(bvm *vm, bclass *c, bstring *name, bproto *p) cl = be_newclosure(vm, p->nupvals); cl->proto = p; var_setclosure(attr, cl); + if (is_static) { + func_setstatic(attr); + } } void be_prim_method_bind(bvm *vm, bclass *c, bstring *name, bntvfunc f) diff --git a/lib/libesp32/Berry/src/be_class.h b/lib/libesp32/Berry/src/be_class.h index 8bc0a6af7..59abbab30 100644 --- a/lib/libesp32/Berry/src/be_class.h +++ b/lib/libesp32/Berry/src/be_class.h @@ -53,7 +53,7 @@ bclass* be_newclass(bvm *vm, bstring *name, bclass *super); void be_class_compress(bvm *vm, bclass *c); int be_class_attribute(bvm *vm, bclass *c, bstring *attr); void be_member_bind(bvm *vm, bclass *c, bstring *name, bbool var); -void be_method_bind(bvm *vm, bclass *c, bstring *name, bproto *p); +void be_method_bind(bvm *vm, bclass *c, bstring *name, bproto *p, bbool is_static); void be_prim_method_bind(bvm *vm, bclass *c, bstring *name, bntvfunc f); void be_closure_method_bind(bvm *vm, bclass *c, bstring *name, bclosure *cl); int be_class_closure_count(bclass *c); diff --git a/lib/libesp32/Berry/src/be_constobj.h b/lib/libesp32/Berry/src/be_constobj.h index 0e8f1081c..d3f1f5764 100644 --- a/lib/libesp32/Berry/src/be_constobj.h +++ b/lib/libesp32/Berry/src/be_constobj.h @@ -38,6 +38,11 @@ extern "C" { .type = BE_FUNCTION \ } +#define be_const_static_func(_func) { \ + .v.nf = (_func), \ + .type = BE_FUNCTION | BE_FUNC_STATIC \ +} + #define be_const_nil() { \ .v.i = 0, \ .type = BE_NIL \ @@ -88,6 +93,11 @@ extern "C" { .type = BE_CLOSURE \ } +#define be_const_static_closure(_closure) { \ + .v.c = &(_closure), \ + .type = BE_CLOSURE | BE_FUNC_STATIC \ +} + #define be_const_module(_module) { \ .v.c = &(_module), \ .type = BE_MODULE \ @@ -251,6 +261,11 @@ const bntvmodule be_native_module(_module) = { \ BE_FUNCTION \ } +#define be_const_static_func(_func) { \ + bvaldata(_func), \ + BE_FUNCTION | BE_FUNC_STATIC \ +} + #define be_const_nil() { \ bvaldata(0), \ BE_NIL \ @@ -301,6 +316,11 @@ const bntvmodule be_native_module(_module) = { \ BE_CLOSURE \ } +#define be_const_static_closure(_closure) { \ + bvaldata(&(_closure)), \ + BE_CLOSURE | BE_FUNC_STATIC \ +} + #define be_const_module(_module) { \ bvaldata(&(_module)), \ BE_MODULE \ diff --git a/lib/libesp32/Berry/src/be_gc.c b/lib/libesp32/Berry/src/be_gc.c index c0bcf0c5a..b3cf7ab98 100644 --- a/lib/libesp32/Berry/src/be_gc.c +++ b/lib/libesp32/Berry/src/be_gc.c @@ -348,7 +348,7 @@ static void free_instance(bvm *vm, bgcobject *obj) static void free_object(bvm *vm, bgcobject *obj) { - switch (obj->type) { + switch (var_type(obj)) { case BE_STRING: free_lstring(vm, obj); break; /* long string */ case BE_CLASS: be_free(vm, obj, sizeof(bclass)); break; case BE_INSTANCE: free_instance(vm, obj); break; diff --git a/lib/libesp32/Berry/src/be_map.c b/lib/libesp32/Berry/src/be_map.c index a11614680..004406f46 100644 --- a/lib/libesp32/Berry/src/be_map.c +++ b/lib/libesp32/Berry/src/be_map.c @@ -346,5 +346,7 @@ bmapnode* be_map_val2node(bvalue *value) void be_map_release(bvm *vm, bmap *map) { (void)vm; - resize(vm, map, map->count ? map->count : 1); + if (!gc_isconst(map)) { + resize(vm, map, map->count ? map->count : 1); + } } diff --git a/lib/libesp32/Berry/src/be_object.h b/lib/libesp32/Berry/src/be_object.h index f5b878531..4c8cbf1ab 100644 --- a/lib/libesp32/Berry/src/be_object.h +++ b/lib/libesp32/Berry/src/be_object.h @@ -11,25 +11,30 @@ #include "berry.h" /* basic types, do not change value */ -#define BE_NONE (-1) /* unknown type */ -#define BE_COMPTR (-2) /* common pointer */ -#define BE_INDEX (-3) /* index for instance variable, previously BE_INT */ #define BE_NIL 0 #define BE_INT 1 #define BE_REAL 2 #define BE_BOOL 3 -#define BE_FUNCTION 4 -#define BE_STRING 5 /* from this type can be gced, see BE_GCOBJECT */ -#define BE_CLASS 6 -#define BE_INSTANCE 7 -#define BE_PROTO 8 -#define BE_LIST 9 -#define BE_MAP 10 -#define BE_MODULE 11 -#define BE_COMOBJ 12 /* common object */ +#define BE_NONE 4 /* unknown type */ +#define BE_COMPTR 5 /* common pointer */ +#define BE_INDEX 6 /* index for instance variable, previously BE_INT */ +#define BE_FUNCTION 7 +#define BE_STRING 8 /* from this type can be gced, see BE_GCOBJECT */ +#define BE_CLASS 9 +#define BE_INSTANCE 10 +#define BE_PROTO 11 +#define BE_LIST 12 +#define BE_MAP 13 +#define BE_MODULE 14 +#define BE_COMOBJ 15 /* common object */ #define BE_NTVFUNC ((0 << 5) | BE_FUNCTION) #define BE_CLOSURE ((1 << 5) | BE_FUNCTION) #define BE_NTVCLOS ((2 << 5) | BE_FUNCTION) +#define BE_FUNC_STATIC (1 << 7) + +#define func_isstatic(o) (((o)->type & BE_FUNC_STATIC) != 0) +#define func_setstatic(o) ((o)->type |= BE_FUNC_STATIC) +#define func_clearstatic(o) ((o)->type &= ~BE_FUNC_STATIC) #define array_count(a) (sizeof(a) / sizeof((a)[0])) @@ -187,7 +192,7 @@ typedef const char* (*breader)(void*, size_t*); #define cast_bool(_v) cast(bbool, _v) #define basetype(_t) ((_t) & 0x1F) -#define var_type(_v) ((_v)->type) +#define var_type(_v) ((_v)->type & 0x7F) #define var_basetype(_v) basetype((_v)->type) #define var_istype(_v, _t) (var_type(_v) == _t) #define var_settype(_v, _t) ((_v)->type = _t) diff --git a/lib/libesp32/Berry/src/be_parser.c b/lib/libesp32/Berry/src/be_parser.c index 664f24b92..d2f2d7af5 100644 --- a/lib/libesp32/Berry/src/be_parser.c +++ b/lib/libesp32/Berry/src/be_parser.c @@ -1422,12 +1422,28 @@ static void class_static_assignment_expr(bparser *parser, bexpdesc *e, bstring * } } +static void classdef_stmt(bparser *parser, bclass *c, bbool is_static) +{ + bexpdesc e; + bstring *name; + bproto *proto; + /* 'def' ID '(' varlist ')' block 'end' */ + scan_next_token(parser); /* skip 'def' */ + name = func_name(parser, &e, 1); + check_class_attr(parser, c, name); + proto = funcbody(parser, name, is_static ? 0 : FUNC_METHOD); + be_method_bind(parser->vm, c, proto->name, proto, is_static); + be_stackpop(parser->vm, 1); +} + static void classstatic_stmt(bparser *parser, bclass *c, bexpdesc *e) { bstring *name; /* 'static' ID ['=' expr] {',' ID ['=' expr] } */ scan_next_token(parser); /* skip 'static' */ - if (match_id(parser, name) != NULL) { + if (next_type(parser) == KeyDef) { /* 'static' 'def' ... */ + classdef_stmt(parser, c, btrue); + } else if (match_id(parser, name) != NULL) { check_class_attr(parser, c, name); be_member_bind(parser->vm, c, name, bfalse); class_static_assignment_expr(parser, e, name); @@ -1446,20 +1462,6 @@ static void classstatic_stmt(bparser *parser, bclass *c, bexpdesc *e) } } -static void classdef_stmt(bparser *parser, bclass *c) -{ - bexpdesc e; - bstring *name; - bproto *proto; - /* 'def' ID '(' varlist ')' block 'end' */ - scan_next_token(parser); /* skip 'def' */ - name = func_name(parser, &e, 1); - check_class_attr(parser, c, name); - proto = funcbody(parser, name, FUNC_METHOD); - be_method_bind(parser->vm, c, proto->name, proto); - be_stackpop(parser->vm, 1); -} - static void class_inherit(bparser *parser, bexpdesc *e) { if (next_type(parser) == OptColon) { /* ':' */ @@ -1479,7 +1481,7 @@ static void class_block(bparser *parser, bclass *c, bexpdesc *e) switch (next_type(parser)) { case KeyVar: classvar_stmt(parser, c); break; case KeyStatic: classstatic_stmt(parser, c, e); break; - case KeyDef: classdef_stmt(parser, c); break; + case KeyDef: classdef_stmt(parser, c, bfalse); break; case OptSemic: scan_next_token(parser); break; default: push_error(parser, "unexpected token '%s'", token2str(parser)); diff --git a/lib/libesp32/Berry/src/be_solidifylib.c b/lib/libesp32/Berry/src/be_solidifylib.c index ec0b60ca1..3dba26768 100644 --- a/lib/libesp32/Berry/src/be_solidifylib.c +++ b/lib/libesp32/Berry/src/be_solidifylib.c @@ -41,6 +41,9 @@ static void m_solidify_bvalue(bvm *vm, bvalue * value, const char *classname, co static void m_solidify_map(bvm *vm, bmap * map, const char *class_name) { + // compact first + be_map_release(vm, map); + logfmt(" be_nested_map(%i,\n", map->count); logfmt(" ( (struct bmapnode*) &(const bmapnode[]) {\n"); @@ -128,7 +131,8 @@ static void m_solidify_bvalue(bvm *vm, bvalue * value, const char *classname, co } break; case BE_CLOSURE: - logfmt("be_const_closure(%s%s%s_closure)", + logfmt("be_const_%sclosure(%s%s%s_closure)", + func_isstatic(value) ? "static_" : "", classname ? classname : "", classname ? "_" : "", str(((bclosure*) var_toobj(value))->proto->name)); break; @@ -139,7 +143,9 @@ static void m_solidify_bvalue(bvm *vm, bvalue * value, const char *classname, co logfmt("be_const_comptr(&be_ntv_%s_%s)", classname ? classname : "unknown", key ? key : "unknown"); break; case BE_NTVFUNC: - logfmt("be_const_func(be_ntv_%s_%s)", classname ? classname : "unknown", key ? key : "unknown"); + logfmt("be_const_%sfunc(be_ntv_%s_%s)", + func_isstatic(value) ? "static_" : "", + classname ? classname : "unknown", key ? key : "unknown"); break; case BE_INSTANCE: { @@ -199,7 +205,7 @@ static void m_solidify_proto_inner_class(bvm *vm, bproto *pr, int builtins) static void m_solidify_proto(bvm *vm, bproto *pr, const char * func_name, int builtins, int indent) { // const char * func_name = str(pr->name); - const char * func_source = str(pr->source); + // const char * func_source = str(pr->source); logfmt("%*sbe_nested_proto(\n", indent, ""); indent += 2; @@ -345,7 +351,7 @@ static void m_solidify_subclass(bvm *vm, bclass *cl, int builtins) logfmt(" NULL,\n"); } - logfmt(" (be_nested_const_str(\"%s\", %i, %i))\n", class_name, be_strhash(cl->name), str_len(cl->name)); + logfmt(" (be_nested_str_literal(\"%s\"))\n", class_name); logfmt(");\n"); } diff --git a/lib/libesp32/Berry/src/be_string.c b/lib/libesp32/Berry/src/be_string.c index b6890a937..798437420 100644 --- a/lib/libesp32/Berry/src/be_string.c +++ b/lib/libesp32/Berry/src/be_string.c @@ -57,12 +57,18 @@ int be_eqstr(bstring *s1, bstring *s2) } /* const short strings */ if (gc_isconst(s1) || gc_isconst(s2)) { /* one of the two string is short const */ - if (cast(bcstring*, s1)->hash && cast(bcstring*, s2)->hash) { - return 0; /* if they both have a hash, then we know they are different */ + uint32_t hash1 = cast(bcstring*, s1)->hash; + uint32_t hash2 = cast(bcstring*, s2)->hash; + if (hash1 && hash2 && hash1 != hash2) { + return 0; /* if hash differ, since we know both are non-null */ } + /* if hash are equals, there might be a chance that they are different */ + /* This can happen with solidified code that a same string is present more than once */ + /* so just considering that two strings with the same hash must be same pointer, this is no more true */ return !strcmp(str(s1), str(s2)); } + /* if both strings are in-memory, they can't be equal without having the same pointer */ return 0; } diff --git a/lib/libesp32/Berry/src/be_vm.c b/lib/libesp32/Berry/src/be_vm.c index 39ae6521e..f00cc128a 100644 --- a/lib/libesp32/Berry/src/be_vm.c +++ b/lib/libesp32/Berry/src/be_vm.c @@ -854,16 +854,29 @@ newframe: /* a new call frame */ bvalue *a = RA(); *a = a_temp; if (basetype(type) == BE_FUNCTION) { - /* check if the object is a superinstance, if so get the lowest possible subclass */ - while (obj->sub) { - obj = obj->sub; + if (func_isstatic(a)) { + /* static method, don't bother with the instance */ + a[1] = a_temp; + var_settype(a, NOT_METHOD); + } else { + /* this is a real method (i.e. non-static) */ + /* check if the object is a superinstance, if so get the lowest possible subclass */ + while (obj->sub) { + obj = obj->sub; + } + var_setinstance(&a[1], obj); /* replace superinstance by lowest subinstance */ } - var_setinstance(&a[1], obj); /* replace superinstance by lowest subinstance */ } else { vm_error(vm, "attribute_error", "class '%s' has no method '%s'", str(be_instance_name(obj)), str(var_tostr(c))); } + } else if (var_isclass(b) && var_isstr(c)) { + class_attribute(vm, b, c, &a_temp); + reg = vm->reg; + bvalue *a = RA(); + a[1] = a_temp; + var_settype(a, NOT_METHOD); } else if (var_ismodule(b) && var_isstr(c)) { module_attribute(vm, b, c, &a_temp); reg = vm->reg; @@ -893,9 +906,14 @@ newframe: /* a new call frame */ dispatch(); } if (var_isclass(a) && var_isstr(b)) { + /* if value is a function, we mark it as a static to distinguish from methods */ bclass *obj = var_toobj(a); bstring *attr = var_tostr(b); - if (!be_class_setmember(vm, obj, attr, c)) { + bvalue c_static = *c; + if (var_isfunction(&c_static)) { + c_static.type = func_setstatic(&c_static); + } + if (!be_class_setmember(vm, obj, attr, &c_static)) { reg = vm->reg; vm_error(vm, "attribute_error", "class '%s' cannot assign to static attribute '%s'",