Berry remove reuse of methods for interface-like code reuse #21500 (#22055)

This commit is contained in:
s-hadinger 2024-08-29 22:00:20 +02:00 committed by GitHub
parent 71f0a06356
commit 1ab9bee312
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 30 additions and 82 deletions

View File

@ -25,6 +25,7 @@ All notable changes to this project will be documented in this file.
- Matter fix Waterleak broken after Berry solidification optimisation #21885 - Matter fix Waterleak broken after Berry solidification optimisation #21885
### Removed ### Removed
- Berry remove reuse of methods for interface-like code reuse #21500
## [14.2.0.2] 20240823 ## [14.2.0.2] 20240823
### Changed ### Changed

View File

@ -695,7 +695,7 @@ static void setsfxvar(bfuncinfo *finfo, bopcode op, bexpdesc *e1, int src)
/* e1 must be in a register and have a valid idx */ /* e1 must be in a register and have a valid idx */
/* if `keep_reg` is true, do not release register */ /* if `keep_reg` is true, do not release register */
/* return 1 if assignment was possible, 0 if type is not compatible */ /* return 1 if assignment was possible, 0 if type is not compatible */
int be_code_setvar(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2, bbool keep_reg, bbool ismethod) int be_code_setvar(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2, bbool keep_reg)
{ {
/* free_e2 indicates special case where ETINDEX or ETMEMBER need to be freed if top of registers */ /* free_e2 indicates special case where ETINDEX or ETMEMBER need to be freed if top of registers */
bbool free_e2 = (e2->type == ETINDEX || e2->type == ETMEMBER) && (e2->v.ss.idx != e1->v.idx) && (e2->v.ss.idx == finfo->freereg - 1); bbool free_e2 = (e2->type == ETINDEX || e2->type == ETMEMBER) && (e2->v.ss.idx != e1->v.idx) && (e2->v.ss.idx == finfo->freereg - 1);
@ -729,7 +729,7 @@ int be_code_setvar(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2, bbool keep_reg,
break; break;
case ETMEMBER: /* store to member R(A).RK(B) <- RK(C) */ case ETMEMBER: /* store to member R(A).RK(B) <- RK(C) */
case ETINDEX: /* store to member R(A)[RK(B)] <- RK(C) */ case ETINDEX: /* store to member R(A)[RK(B)] <- RK(C) */
setsfxvar(finfo, (e1->type == ETMEMBER) ? (ismethod ? OP_SETMET : OP_SETMBR) : OP_SETIDX, e1, src); setsfxvar(finfo, (e1->type == ETMEMBER) ? OP_SETMBR : OP_SETIDX, e1, src);
if (keep_reg && e2->type == ETREG && e1->v.ss.obj >= be_list_count(finfo->local)) { if (keep_reg && e2->type == ETREG && e1->v.ss.obj >= be_list_count(finfo->local)) {
/* special case of walrus assignemnt when we need to recreate an ETREG */ /* special case of walrus assignemnt when we need to recreate an ETREG */
code_move(finfo, e1->v.ss.obj, src); /* move from ETREG to MEMBER instance*/ code_move(finfo, e1->v.ss.obj, src); /* move from ETREG to MEMBER instance*/
@ -923,7 +923,7 @@ void be_code_import(bfuncinfo *finfo, bexpdesc *m, bexpdesc *v)
codeABC(finfo, OP_IMPORT, dst, src, 0); codeABC(finfo, OP_IMPORT, dst, src, 0);
m->type = ETREG; m->type = ETREG;
m->v.idx = dst; m->v.idx = dst;
be_code_setvar(finfo, v, m, bfalse, bfalse); be_code_setvar(finfo, v, m, bfalse);
} }
} }

View File

@ -16,7 +16,7 @@ int be_code_allocregs(bfuncinfo *finfo, int count);
void be_code_prebinop(bfuncinfo *finfo, int op, bexpdesc *e); void be_code_prebinop(bfuncinfo *finfo, int op, bexpdesc *e);
void be_code_binop(bfuncinfo *finfo, int op, bexpdesc *e1, bexpdesc *e2, int dst); void be_code_binop(bfuncinfo *finfo, int op, bexpdesc *e1, bexpdesc *e2, int dst);
int be_code_unop(bfuncinfo *finfo, int op, bexpdesc *e); int be_code_unop(bfuncinfo *finfo, int op, bexpdesc *e);
int be_code_setvar(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2, bbool keep_reg, bbool ismethod); int be_code_setvar(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2, bbool keep_reg);
int be_code_nextreg(bfuncinfo *finfo, bexpdesc *e); int be_code_nextreg(bfuncinfo *finfo, bexpdesc *e);
int be_code_jump(bfuncinfo *finfo); int be_code_jump(bfuncinfo *finfo);
void be_code_jumpto(bfuncinfo *finfo, int dst); void be_code_jumpto(bfuncinfo *finfo, int dst);

View File

@ -62,7 +62,7 @@ void be_print_inst(binstruction ins, int pc, void* fout)
case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV:
case OP_MOD: case OP_LT: case OP_LE: case OP_EQ: case OP_MOD: case OP_LT: case OP_LE: case OP_EQ:
case OP_NE: case OP_GT: case OP_GE: case OP_CONNECT: case OP_NE: case OP_GT: case OP_GE: case OP_CONNECT:
case OP_GETMBR: case OP_SETMBR: case OP_GETMET: case OP_SETMET: case OP_GETMBR: case OP_SETMBR: case OP_GETMET:
case OP_GETIDX: case OP_SETIDX: case OP_AND: case OP_GETIDX: case OP_SETIDX: case OP_AND:
case OP_OR: case OP_XOR: case OP_SHL: case OP_SHR: case OP_OR: case OP_XOR: case OP_SHL: case OP_SHR:
logbuf("%s\tR%d\t%c%d\t%c%d", opc2str(op), IGET_RA(ins), logbuf("%s\tR%d\t%c%d\t%c%d", opc2str(op), IGET_RA(ins),

View File

@ -54,5 +54,4 @@ OPCODE(CATCH), /* A, B, C | ... */
OPCODE(RAISE), /* A, B, C | RAISE(B,C) B is code, C is description. A==0 only B provided, A==1 B and C are provided, A==2 rethrow with both parameters already on stack */ OPCODE(RAISE), /* A, B, C | RAISE(B,C) B is code, C is description. A==0 only B provided, A==1 B and C are provided, A==2 rethrow with both parameters already on stack */
OPCODE(CLASS), /* Bx | init class in K[Bx] */ OPCODE(CLASS), /* Bx | init class in K[Bx] */
OPCODE(GETNGBL), /* A, B | R(A) <- GLOBAL[RK(B)] by name */ OPCODE(GETNGBL), /* A, B | R(A) <- GLOBAL[RK(B)] by name */
OPCODE(SETNGBL), /* A, B | R(A) -> GLOBAL[RK(B)] by name */ OPCODE(SETNGBL) /* A, B | R(A) -> GLOBAL[RK(B)] by name */
OPCODE(SETMET), /* A, B, C | R(A).RK(B) <- RK(C) only if R(A) is a class, and RK(C) is marked as non-static */

View File

@ -634,7 +634,7 @@ static bproto* funcbody(bparser *parser, bstring *name, bclass *c, int type)
new_var(parser, parser_newstr(parser, "_class"), &e1); /* new implicit variable '_class' */ new_var(parser, parser_newstr(parser, "_class"), &e1); /* new implicit variable '_class' */
init_exp(&e2, ETCONST, 0); init_exp(&e2, ETCONST, 0);
be_code_implicit_class(parser->finfo, &e2, c); be_code_implicit_class(parser->finfo, &e2, c);
be_code_setvar(parser->finfo, &e1, &e2, bfalse, bfalse); be_code_setvar(parser->finfo, &e1, &e2, bfalse);
finfo.proto->varg |= BE_VA_STATICMETHOD; finfo.proto->varg |= BE_VA_STATICMETHOD;
} }
stmtlist(parser); /* parse statement without final `end` */ stmtlist(parser); /* parse statement without final `end` */
@ -738,7 +738,7 @@ static void map_nextmember(bparser *parser, bexpdesc *l)
match_token(parser, OptColon); /* ':' */ match_token(parser, OptColon); /* ':' */
expr(parser, &e); /* value in `e` */ expr(parser, &e); /* value in `e` */
check_var(parser, &e); /* check if value is correct */ check_var(parser, &e); /* check if value is correct */
be_code_setvar(finfo, &v, &e, bfalse, bfalse); /* set suffi INDEX value to e */ be_code_setvar(finfo, &v, &e, bfalse); /* set suffi INDEX value to e */
} }
static void list_expr(bparser *parser, bexpdesc *e) static void list_expr(bparser *parser, bexpdesc *e)
@ -1018,7 +1018,7 @@ static void assign_expr(bparser *parser)
if (check_newvar(parser, &e)) { /* new variable */ if (check_newvar(parser, &e)) { /* new variable */
new_var(parser, e.v.s, &e); new_var(parser, e.v.s, &e);
} }
if (be_code_setvar(parser->finfo, &e, &e1, bfalse, bfalse)) { if (be_code_setvar(parser->finfo, &e, &e1, bfalse)) {
parser->lexer.linenumber = line; parser->lexer.linenumber = line;
parser_error(parser, parser_error(parser,
"try to assign constant expressions."); "try to assign constant expressions.");
@ -1121,7 +1121,7 @@ static void walrus_expr(bparser *parser, bexpdesc *e)
if (check_newvar(parser, &e1)) { /* new variable */ if (check_newvar(parser, &e1)) { /* new variable */
new_var(parser, e1.v.s, &e1); new_var(parser, e1.v.s, &e1);
} }
if (be_code_setvar(parser->finfo, &e1, e, btrue /* do not release register */, bfalse)) { if (be_code_setvar(parser->finfo, &e1, e, btrue /* do not release register */ )) {
parser->lexer.linenumber = line; parser->lexer.linenumber = line;
parser_error(parser, parser_error(parser,
"try to assign constant expressions."); "try to assign constant expressions.");
@ -1254,7 +1254,7 @@ static void for_iter(bparser *parser, bstring *var, bexpdesc *it)
finfo->binfo->beginpc = finfo->pc; finfo->binfo->beginpc = finfo->pc;
/* itvar = .it() */ /* itvar = .it() */
init_exp(&e, ETLOCAL, new_localvar(parser, var)); /* new itvar */ init_exp(&e, ETLOCAL, new_localvar(parser, var)); /* new itvar */
be_code_setvar(finfo, &e, it, bfalse, bfalse); /* code function to variable '.it' */ be_code_setvar(finfo, &e, it, bfalse); /* code function to variable '.it' */
be_code_call(finfo, e.v.idx, 0); /* itvar <- call .it() */ be_code_call(finfo, e.v.idx, 0); /* itvar <- call .it() */
stmtlist(parser); stmtlist(parser);
} }
@ -1435,7 +1435,7 @@ static void classvar_stmt(bparser *parser, bclass *c)
} }
} }
static void class_static_assignment_expr(bparser *parser, bexpdesc *e, bstring *name, bbool ismethod) static void class_static_assignment_expr(bparser *parser, bexpdesc *e, bstring *name)
{ {
if (match_skip(parser, OptAssign)) { /* '=' */ if (match_skip(parser, OptAssign)) { /* '=' */
bexpdesc e1, e2; bexpdesc e1, e2;
@ -1448,32 +1448,22 @@ static void class_static_assignment_expr(bparser *parser, bexpdesc *e, bstring *
key.v.s = name; key.v.s = name;
be_code_member(parser->finfo, &e1, &key); /* compute member accessor */ be_code_member(parser->finfo, &e1, &key); /* compute member accessor */
be_code_setvar(parser->finfo, &e1, &e2, bfalse, ismethod); /* set member */ be_code_setvar(parser->finfo, &e1, &e2, bfalse); /* set member */
} }
} }
static void classdef_stmt(bparser *parser, bclass *c, bexpdesc *e, bbool is_static) static void classdef_stmt(bparser *parser, bclass *c, bbool is_static)
{ {
bexpdesc e1; bexpdesc e;
bstring *name; bstring *name;
bproto *proto; bproto *proto;
/* 'def' ID '(' varlist ')' block 'end' */ /* 'def' ID '(' varlist ')' block 'end' */
/* 'def' ID = funcname */
/* 'def' ID = classname '.' method */
scan_next_token(parser); /* skip 'def' */ scan_next_token(parser); /* skip 'def' */
name = func_name(parser, &e1, 1); name = func_name(parser, &e, 1);
check_class_attr(parser, c, name); /* check that we don't redefine an existing name within the class */ check_class_attr(parser, c, name);
if (next_type(parser) == OptAssign) { proto = funcbody(parser, name, c, is_static ? FUNC_STATIC : FUNC_METHOD);
/* 'def' ID = funcname */ be_class_method_bind(parser->vm, c, proto->name, proto, is_static);
/* 'def' ID = classname '.' method */ be_stackpop(parser->vm, 1);
be_class_member_bind(parser->vm, c, name, bfalse);
class_static_assignment_expr(parser, e, name, !is_static);
} else {
/* 'def' ID '(' varlist ')' block 'end' */
proto = funcbody(parser, name, c, is_static ? FUNC_STATIC : FUNC_METHOD);
be_class_method_bind(parser->vm, c, proto->name, proto, is_static);
be_stackpop(parser->vm, 1);
}
} }
static void classstaticclass_stmt(bparser *parser, bclass *c_out, bexpdesc *e_out); static void classstaticclass_stmt(bparser *parser, bclass *c_out, bexpdesc *e_out);
@ -1483,10 +1473,9 @@ static void classstatic_stmt(bparser *parser, bclass *c, bexpdesc *e)
bstring *name; bstring *name;
/* 'static' ['var'] ID ['=' expr] {',' ID ['=' expr] } */ /* 'static' ['var'] ID ['=' expr] {',' ID ['=' expr] } */
/* 'static' 'def' ID '(' varlist ')' block 'end' */ /* 'static' 'def' ID '(' varlist ')' block 'end' */
/* 'static' 'def' ID '=' func */
scan_next_token(parser); /* skip 'static' */ scan_next_token(parser); /* skip 'static' */
if (next_type(parser) == KeyDef) { /* 'static' 'def' ... */ if (next_type(parser) == KeyDef) { /* 'static' 'def' ... */
classdef_stmt(parser, c, e, btrue); classdef_stmt(parser, c, btrue);
} else if (next_type(parser) == KeyClass) { /* 'static' 'class' ... */ } else if (next_type(parser) == KeyClass) { /* 'static' 'class' ... */
classstaticclass_stmt(parser, c, e); classstaticclass_stmt(parser, c, e);
} else { } else {
@ -1496,13 +1485,13 @@ static void classstatic_stmt(bparser *parser, bclass *c, bexpdesc *e)
if (match_id(parser, name) != NULL) { if (match_id(parser, name) != NULL) {
check_class_attr(parser, c, name); check_class_attr(parser, c, name);
be_class_member_bind(parser->vm, c, name, bfalse); be_class_member_bind(parser->vm, c, name, bfalse);
class_static_assignment_expr(parser, e, name, bfalse); class_static_assignment_expr(parser, e, name);
while (match_skip(parser, OptComma)) { /* ',' */ while (match_skip(parser, OptComma)) { /* ',' */
if (match_id(parser, name) != NULL) { if (match_id(parser, name) != NULL) {
check_class_attr(parser, c, name); check_class_attr(parser, c, name);
be_class_member_bind(parser->vm, c, name, bfalse); be_class_member_bind(parser->vm, c, name, bfalse);
class_static_assignment_expr(parser, e, name, bfalse); class_static_assignment_expr(parser, e, name);
} else { } else {
parser_error(parser, "class static error"); parser_error(parser, "class static error");
} }
@ -1532,7 +1521,7 @@ static void class_block(bparser *parser, bclass *c, bexpdesc *e)
switch (next_type(parser)) { switch (next_type(parser)) {
case KeyVar: classvar_stmt(parser, c); break; case KeyVar: classvar_stmt(parser, c); break;
case KeyStatic: classstatic_stmt(parser, c, e); break; case KeyStatic: classstatic_stmt(parser, c, e); break;
case KeyDef: classdef_stmt(parser, c, e, bfalse); break; case KeyDef: classdef_stmt(parser, c, bfalse); break;
case OptSemic: scan_next_token(parser); break; case OptSemic: scan_next_token(parser); break;
default: push_error(parser, default: push_error(parser,
"unexpected token '%s'", token2str(parser)); "unexpected token '%s'", token2str(parser));
@ -1559,7 +1548,7 @@ static void class_stmt(bparser *parser)
bexpdesc e1; /* if inline class, we add a second local variable for _class */ bexpdesc e1; /* if inline class, we add a second local variable for _class */
init_exp(&e1, ETLOCAL, 0); init_exp(&e1, ETLOCAL, 0);
e1.v.idx = new_localvar(parser, class_str); e1.v.idx = new_localvar(parser, class_str);
be_code_setvar(parser->finfo, &e1, &e, btrue, bfalse); be_code_setvar(parser->finfo, &e1, &e, btrue);
begin_varinfo(parser, class_str); begin_varinfo(parser, class_str);
@ -1597,7 +1586,7 @@ static void classstaticclass_stmt(bparser *parser, bclass *c_out, bexpdesc *e_ou
key.v.s = name; key.v.s = name;
/* assign the class to the static member */ /* assign the class to the static member */
be_code_member(parser->finfo, &e1, &key); /* compute member accessor */ be_code_member(parser->finfo, &e1, &key); /* compute member accessor */
be_code_setvar(parser->finfo, &e1, &e_class, bfalse, bfalse); /* set member */ be_code_setvar(parser->finfo, &e1, &e_class, bfalse); /* set member */
} else { } else {
parser_error(parser, "class name error"); parser_error(parser, "class name error");
} }
@ -1649,7 +1638,7 @@ static void var_field(bparser *parser)
init_exp(&e2, ETNIL, 0); init_exp(&e2, ETNIL, 0);
} }
new_var(parser, name, &e1); /* new variable */ new_var(parser, name, &e1); /* new variable */
be_code_setvar(parser->finfo, &e1, &e2, bfalse, bfalse); be_code_setvar(parser->finfo, &e1, &e2, bfalse);
} }
static void var_stmt(bparser *parser) static void var_stmt(bparser *parser)

View File

@ -699,7 +699,7 @@ static void m_compact_class(bvm *vm, bbool str_literal, const bclass *cla, void*
case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV:
case OP_MOD: case OP_LT: case OP_LE: case OP_EQ: case OP_MOD: case OP_LT: case OP_LE: case OP_EQ:
case OP_NE: case OP_GT: case OP_GE: case OP_CONNECT: case OP_NE: case OP_GT: case OP_GE: case OP_CONNECT:
case OP_GETMBR: case OP_SETMBR: case OP_GETMET: case OP_SETMET: case OP_GETMBR: case OP_SETMBR: case OP_GETMET:
case OP_GETIDX: case OP_SETIDX: case OP_AND: case OP_GETIDX: case OP_SETIDX: case OP_AND:
case OP_OR: case OP_XOR: case OP_SHL: case OP_SHR: case OP_OR: case OP_XOR: case OP_SHL: case OP_SHR:
case OP_RAISE: case OP_RAISE:

View File

@ -994,7 +994,6 @@ newframe: /* a new call frame */
} }
dispatch(); dispatch();
} }
opcase(SETMET):
opcase(SETMBR): { opcase(SETMBR): {
#if BE_USE_PERF_COUNTERS #if BE_USE_PERF_COUNTERS
vm->counter_set++; vm->counter_set++;
@ -1021,7 +1020,7 @@ newframe: /* a new call frame */
bclass *obj = var_toobj(a); bclass *obj = var_toobj(a);
bstring *attr = var_tostr(b); bstring *attr = var_tostr(b);
bvalue result = *c; bvalue result = *c;
if (var_isfunction(&result) && (IGET_OP(ins) == OP_SETMBR)) { /* don't mark as static if SETMET was used */ if (var_isfunction(&result)) {
var_markstatic(&result); var_markstatic(&result);
} }
if (!be_class_setmember(vm, obj, attr, &result)) { if (!be_class_setmember(vm, obj, attr, &result)) {

View File

@ -1,40 +0,0 @@
# test setting methods as an external class
class A
var a
def init(a)
self.a = a
end
def f0(x) return self end
def f1(x) return x end
def f2(x) return self.a end
static def ff0(x) return _class end
static def ff1(x) return x end
end
class B
var b
def init(b)
self.b = b
end
end
class C : B
var a
def init(a)
self.a = a
end
def fc0 = A.f0
def fc1 = A.f1
def fc2 = A.f2
static def ffc0 = A.ff0
static def ffc1 = A.ff1
end
c = C(10)
assert(c.fc0(1) == c)
assert(c.fc1(1) == 1)
assert(c.fc2(1) == 10)
assert(c.ffc0(1) == A)
assert(c.ffc1(1) == 1)