кстати, передача неоктрытых массивов без `IN` делает копии тоже по месту вызова, причём делается это уже силами кодогена, выделяя место на стеке через `ADD ESP, -size`. конечно, почистить это потом все забыли. ну ёлы-палы, ну… вот засунуть такое в длиииинный цикл — и офигеть от того, что внезапно, на пустом месте, закончится стек. какого чёрта это не делается в вызываемой процедуре?
отсюда запомните правило хорошего тона: никогда не вызывайте в цикле процедуру, которая принимает неоткрытый массив без `IN`.
короче, иллюстрация:
Код:
TYPE S10 = ARRAY 10 OF CHAR;
PROCEDURE Str2Proc (a: S10);
PROCEDURE TestStr12;
VAR b: S10;
BEGIN
Str2Proc(b); (* тут мы делаем копию b на стеке через ADD ESP *)
Str2Proc(b); (* а тут ещё раз, забыв убрать старую копию, снова через ADD ESP *)
END TestStr12;
делается две копии `b`. будет цикл — будет овердофига копий, место на стеке выделяется каждый раз. по-моему, это тупо баг, ребята забыли подкорректировать ESP в финале.
но.
Код:
PROCEDURE Str0Proc (a: ARRAY OF CHAR);
PROCEDURE TestStr13;
VAR b: S10;
BEGIN
Str0Proc(b);
Str0Proc(b);
END TestStr13;
копии `b` делаются внутри `Str0Proc`, так что такой вызов из цикла безопасен.
Код:
PROCEDURE Str1Proc (IN a: S10);
PROCEDURE TestStr13;
VAR b: S10;
BEGIN
Str1Proc(b);
Str1Proc(b);
END TestStr13;
никаких копий.
Код:
PROCEDURE Str1Proc (IN a: S10);
PROCEDURE TestStr14;
VAR b: S10;
BEGIN
Str1Proc(b$);
Str1Proc(b$);
END TestStr14;
а вот тут всё происходит уровнем выше: заводятся две скрытые локальные перменные (по количеству вызовов). такая ерунда в цикле безопасна. то есть, место на стеке выделяется один раз, по визуальному счёту вызовов. собственно, реальный AST:
Код:
PROCEDURE TestStr14
VAR @str0: ARRAY 10 OF CHAR
VAR @str1: ARRAY 10 OF CHAR
VAR b: S10
BEGIN
COMPOUND
@str0 := b$;
CALL Str1Proc(@str0$);
END COMPOUND;
COMPOUND
@str1 := b$;
CALL Str1Proc(@str1$);
END COMPOUND;
END TestStr14