fix(arc): wire owned-arg-temp release into remaining call paths
Extend EmitOwnedArgReleases coverage to the method-call statement (both the arbitrary-receiver ObjExpr path and the named-receiver path), the method-call expression path, and the standalone function-call expression path. Each now tracks value-argument temps in a parallel list and releases the +1-owned ones after the call, matching the constructor and procedure paths. Avoided `Exit` inside `try/finally`: that shape miscompiles today — the Exit branch fails to pop the exception frame and segfaults in _PopExcFrame at runtime (logged in bugs.txt). Free the temp list explicitly before each Exit instead; leaking it on the fatal-exception path is acceptable. Stage-2 self-compiles, fixpoint clean, 2260 tests pass.
This commit is contained in:
parent
dc2ab8fe37
commit
ddde3c8621
|
|
@ -4340,6 +4340,7 @@ var
|
|||
Par: TMethodParam;
|
||||
ArgTemp: string;
|
||||
ArgLine: string;
|
||||
ArgTemps: TStringList;
|
||||
I: Integer;
|
||||
QType: string;
|
||||
FuncName: string;
|
||||
|
|
@ -4414,15 +4415,20 @@ begin
|
|||
end;
|
||||
SelfTemp := EmitExpr(ACall.ObjExpr);
|
||||
ArgLine := Format('l %s', [SelfTemp]);
|
||||
ArgTemps := TStringList.Create();
|
||||
for I := 0 to ACall.Args.Count - 1 do
|
||||
begin
|
||||
Par := TMethodParam(MDecl.Params.Items[I]);
|
||||
if Par.IsVarParam then
|
||||
begin
|
||||
ArgTemps.Add('');
|
||||
ArgLine := ArgLine + Format(', l %s',
|
||||
[EmitLValueAddr(TASTExpr(ACall.Args.Items[I]))])
|
||||
[EmitLValueAddr(TASTExpr(ACall.Args.Items[I]))]);
|
||||
end
|
||||
else
|
||||
begin
|
||||
ArgTemp := EmitExpr(TASTExpr(ACall.Args.Items[I]));
|
||||
ArgTemps.Add(ArgTemp);
|
||||
QType := QbeTypeOf(Par.ResolvedType);
|
||||
ArgTemp := CoerceArg(ArgTemp, TASTExpr(ACall.Args.Items[I]), QType);
|
||||
ArgLine := ArgLine + Format(', %s %s', [QType, ArgTemp]);
|
||||
|
|
@ -4443,6 +4449,8 @@ begin
|
|||
EmitLine(Format(' %s =l add %s, %d', [ArgTemp, VTblTemp, SlotOff]));
|
||||
EmitLine(Format(' %s =l loadl %s', [FPtrTemp, ArgTemp]));
|
||||
EmitLine(Format(' call %s(%s)', [FPtrTemp, ArgLine]));
|
||||
EmitOwnedArgReleases(ACall.Args, ArgTemps);
|
||||
ArgTemps.Free();
|
||||
{ Receiver was a +1-owned temporary (function/property return) used
|
||||
transiently — release it so the temporary does not leak. }
|
||||
if ExprOwnsRef(ACall.ObjExpr) then
|
||||
|
|
@ -4454,6 +4462,8 @@ begin
|
|||
else
|
||||
FuncName := '$' + MethodEmitName(MDecl, RT.Name, ACall.Name);
|
||||
EmitLine(Format(' call %s(%s)', [FuncName, ArgLine]));
|
||||
EmitOwnedArgReleases(ACall.Args, ArgTemps);
|
||||
ArgTemps.Free();
|
||||
if ExprOwnsRef(ACall.ObjExpr) then
|
||||
EmitLine(Format(' call $_ClassRelease(l %s)', [SelfTemp]));
|
||||
Exit;
|
||||
|
|
@ -4568,42 +4578,52 @@ begin
|
|||
|
||||
{ Build argument string: l Self, then each explicit arg }
|
||||
ArgLine := Format('l %s', [SelfTemp]);
|
||||
for I := 0 to ACall.Args.Count - 1 do
|
||||
begin
|
||||
Par := TMethodParam(MDecl.Params.Items[I]);
|
||||
if Par.IsVarParam then
|
||||
ArgLine := ArgLine + Format(', l %s',
|
||||
[EmitLValueAddr(TASTExpr(ACall.Args.Items[I]))])
|
||||
ArgTemps := TStringList.Create();
|
||||
try
|
||||
for I := 0 to ACall.Args.Count - 1 do
|
||||
begin
|
||||
Par := TMethodParam(MDecl.Params.Items[I]);
|
||||
if Par.IsVarParam then
|
||||
begin
|
||||
ArgTemps.Add('');
|
||||
ArgLine := ArgLine + Format(', l %s',
|
||||
[EmitLValueAddr(TASTExpr(ACall.Args.Items[I]))]);
|
||||
end
|
||||
else
|
||||
begin
|
||||
ArgTemp := EmitExpr(TASTExpr(ACall.Args.Items[I]));
|
||||
ArgTemps.Add(ArgTemp);
|
||||
QType := QbeTypeOf(Par.ResolvedType);
|
||||
ArgTemp := CoerceArg(ArgTemp, TASTExpr(ACall.Args.Items[I]), QType);
|
||||
ArgLine := ArgLine + Format(', %s %s', [QType, ArgTemp]);
|
||||
end;
|
||||
end;
|
||||
|
||||
if MDecl.VTableSlot >= 0 then
|
||||
begin
|
||||
{ Virtual dispatch: load vptr from instance[0], then load fptr from vtable.
|
||||
Slot 0 of vtable is typeinfo, so method N is at offset (N+1)*8. }
|
||||
VTblTemp := AllocTemp;
|
||||
EmitLine(Format(' %s =l loadl %s', [VTblTemp, SelfTemp]));
|
||||
FPtrTemp := AllocTemp;
|
||||
SlotOff := (MDecl.VTableSlot + 1) * 8;
|
||||
ArgTemp := AllocTemp;
|
||||
EmitLine(Format(' %s =l add %s, %d', [ArgTemp, VTblTemp, SlotOff]));
|
||||
EmitLine(Format(' %s =l loadl %s', [FPtrTemp, ArgTemp]));
|
||||
EmitLine(Format(' call %s(%s)', [FPtrTemp, ArgLine]));
|
||||
end
|
||||
else
|
||||
begin
|
||||
ArgTemp := EmitExpr(TASTExpr(ACall.Args.Items[I]));
|
||||
QType := QbeTypeOf(Par.ResolvedType);
|
||||
ArgTemp := CoerceArg(ArgTemp, TASTExpr(ACall.Args.Items[I]), QType);
|
||||
ArgLine := ArgLine + Format(', %s %s', [QType, ArgTemp]);
|
||||
{ Static dispatch }
|
||||
if MDecl.OwnerTypeName <> '' then
|
||||
FuncName := '$' + MethodEmitName(MDecl, MDecl.OwnerTypeName, ACall.Name)
|
||||
else
|
||||
FuncName := '$' + MethodEmitName(MDecl, RT.Name, ACall.Name);
|
||||
EmitLine(Format(' call %s(%s)', [FuncName, ArgLine]));
|
||||
end;
|
||||
end;
|
||||
|
||||
if MDecl.VTableSlot >= 0 then
|
||||
begin
|
||||
{ Virtual dispatch: load vptr from instance[0], then load fptr from vtable.
|
||||
Slot 0 of vtable is typeinfo, so method N is at offset (N+1)*8. }
|
||||
VTblTemp := AllocTemp;
|
||||
EmitLine(Format(' %s =l loadl %s', [VTblTemp, SelfTemp]));
|
||||
FPtrTemp := AllocTemp;
|
||||
SlotOff := (MDecl.VTableSlot + 1) * 8;
|
||||
ArgTemp := AllocTemp;
|
||||
EmitLine(Format(' %s =l add %s, %d', [ArgTemp, VTblTemp, SlotOff]));
|
||||
EmitLine(Format(' %s =l loadl %s', [FPtrTemp, ArgTemp]));
|
||||
EmitLine(Format(' call %s(%s)', [FPtrTemp, ArgLine]));
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ Static dispatch }
|
||||
if MDecl.OwnerTypeName <> '' then
|
||||
FuncName := '$' + MethodEmitName(MDecl, MDecl.OwnerTypeName, ACall.Name)
|
||||
else
|
||||
FuncName := '$' + MethodEmitName(MDecl, RT.Name, ACall.Name);
|
||||
EmitLine(Format(' call %s(%s)', [FuncName, ArgLine]));
|
||||
EmitOwnedArgReleases(ACall.Args, ArgTemps);
|
||||
finally
|
||||
ArgTemps.Free();
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
@ -7664,56 +7684,68 @@ begin
|
|||
else
|
||||
FuncName := '$' + QBEMangle(FC.Name);
|
||||
ArgLine := '';
|
||||
for I := 0 to FC.Args.Count - 1 do
|
||||
begin
|
||||
Par := TMethodParam(MDecl.Params.Items[I]);
|
||||
if ArgLine <> '' then ArgLine := ArgLine + ', ';
|
||||
if Par.IsOpenArray then
|
||||
ArgTemps := TStringList.Create();
|
||||
try
|
||||
for I := 0 to FC.Args.Count - 1 do
|
||||
begin
|
||||
if TASTExpr(FC.Args.Items[I]) is TArrayLiteralExpr then
|
||||
Par := TMethodParam(MDecl.Params.Items[I]);
|
||||
if ArgLine <> '' then ArgLine := ArgLine + ', ';
|
||||
if Par.IsOpenArray then
|
||||
begin
|
||||
ArgTemp := EmitArrayLiteralExpr(TArrayLiteralExpr(TASTExpr(FC.Args.Items[I])));
|
||||
ArgLine := ArgLine + Format('l %s, l %d',
|
||||
[ArgTemp, TArrayLiteralExpr(TASTExpr(FC.Args.Items[I])).Elements.Count - 1]);
|
||||
ArgTemps.Add('');
|
||||
if TASTExpr(FC.Args.Items[I]) is TArrayLiteralExpr then
|
||||
begin
|
||||
ArgTemp := EmitArrayLiteralExpr(TArrayLiteralExpr(TASTExpr(FC.Args.Items[I])));
|
||||
ArgLine := ArgLine + Format('l %s, l %d',
|
||||
[ArgTemp, TArrayLiteralExpr(TASTExpr(FC.Args.Items[I])).Elements.Count - 1]);
|
||||
end
|
||||
else if TASTExpr(FC.Args.Items[I]).ResolvedType.Kind = tyStaticArray then
|
||||
begin
|
||||
{ Static array coerced to open-array: pass base ptr + compile-time high }
|
||||
ArgTemp := EmitExpr(TASTExpr(FC.Args.Items[I]));
|
||||
ArgLine := ArgLine + Format('l %s, l %d', [ArgTemp,
|
||||
TStaticArrayTypeDesc(TASTExpr(FC.Args.Items[I]).ResolvedType).HighBound -
|
||||
TStaticArrayTypeDesc(TASTExpr(FC.Args.Items[I]).ResolvedType).LowBound]);
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ Forward an open-array param variable }
|
||||
ArgTemp := EmitExpr(TASTExpr(FC.Args.Items[I]));
|
||||
ArgTemp2 := AllocTemp;
|
||||
EmitLine(Format(' %s =l loadl %%_var_%s_high',
|
||||
[ArgTemp2, TIdentExpr(TASTExpr(FC.Args.Items[I])).Name]));
|
||||
ArgLine := ArgLine + Format('l %s, l %s', [ArgTemp, ArgTemp2]);
|
||||
end;
|
||||
end
|
||||
else if TASTExpr(FC.Args.Items[I]).ResolvedType.Kind = tyStaticArray then
|
||||
else if Par.IsVarParam then
|
||||
begin
|
||||
{ Static array coerced to open-array: pass base ptr + compile-time high }
|
||||
ArgTemp := EmitExpr(TASTExpr(FC.Args.Items[I]));
|
||||
ArgLine := ArgLine + Format('l %s, l %d', [ArgTemp,
|
||||
TStaticArrayTypeDesc(TASTExpr(FC.Args.Items[I]).ResolvedType).HighBound -
|
||||
TStaticArrayTypeDesc(TASTExpr(FC.Args.Items[I]).ResolvedType).LowBound]);
|
||||
ArgTemps.Add('');
|
||||
ArgLine := ArgLine + Format('l %s',
|
||||
[EmitLValueAddr(TASTExpr(FC.Args.Items[I]))]);
|
||||
end
|
||||
else if (Par.ResolvedType <> nil) and
|
||||
(Par.ResolvedType.Kind = tyInterface) then
|
||||
begin
|
||||
ArgTemps.Add('');
|
||||
EmitInterfaceExprPair(TASTExpr(FC.Args.Items[I]),
|
||||
ArgTemp, ArgTemp2);
|
||||
ArgLine := ArgLine + Format('l %s, l %s', [ArgTemp, ArgTemp2]);
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ Forward an open-array param variable }
|
||||
ArgTemp := EmitExpr(TASTExpr(FC.Args.Items[I]));
|
||||
ArgTemp2 := AllocTemp;
|
||||
EmitLine(Format(' %s =l loadl %%_var_%s_high',
|
||||
[ArgTemp2, TIdentExpr(TASTExpr(FC.Args.Items[I])).Name]));
|
||||
ArgLine := ArgLine + Format('l %s, l %s', [ArgTemp, ArgTemp2]);
|
||||
ArgTemp := EmitExpr(TASTExpr(FC.Args.Items[I]));
|
||||
ArgTemps.Add(ArgTemp);
|
||||
ArgTemp := CoerceArg(ArgTemp, TASTExpr(FC.Args.Items[I]), QbeTypeOf(Par.ResolvedType));
|
||||
ArgLine := ArgLine + Format('%s %s', [QbeTypeOf(Par.ResolvedType), ArgTemp]);
|
||||
end;
|
||||
end
|
||||
else if Par.IsVarParam then
|
||||
ArgLine := ArgLine + Format('l %s',
|
||||
[EmitLValueAddr(TASTExpr(FC.Args.Items[I]))])
|
||||
else if (Par.ResolvedType <> nil) and
|
||||
(Par.ResolvedType.Kind = tyInterface) then
|
||||
begin
|
||||
EmitInterfaceExprPair(TASTExpr(FC.Args.Items[I]),
|
||||
ArgTemp, ArgTemp2);
|
||||
ArgLine := ArgLine + Format('l %s, l %s', [ArgTemp, ArgTemp2]);
|
||||
end
|
||||
else
|
||||
begin
|
||||
ArgTemp := EmitExpr(TASTExpr(FC.Args.Items[I]));
|
||||
ArgTemp := CoerceArg(ArgTemp, TASTExpr(FC.Args.Items[I]), QbeTypeOf(Par.ResolvedType));
|
||||
ArgLine := ArgLine + Format('%s %s', [QbeTypeOf(Par.ResolvedType), ArgTemp]);
|
||||
end;
|
||||
T := AllocTemp;
|
||||
EmitLine(Format(' %s =%s call %s(%s)', [T, QType, FuncName, ArgLine]));
|
||||
EmitOwnedArgReleases(FC.Args, ArgTemps);
|
||||
Result := T;
|
||||
finally
|
||||
ArgTemps.Free();
|
||||
end;
|
||||
T := AllocTemp;
|
||||
EmitLine(Format(' %s =%s call %s(%s)', [T, QType, FuncName, ArgLine]));
|
||||
Result := T;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
|
|
@ -7944,15 +7976,20 @@ begin
|
|||
|
||||
{ Build argument string }
|
||||
ArgLine := Format('l %s', [SelfTemp]);
|
||||
ArgTemps := TStringList.Create();
|
||||
for I := 0 to MCallExpr.Args.Count - 1 do
|
||||
begin
|
||||
Par := TMethodParam(MDecl.Params.Items[I]);
|
||||
if Par.IsVarParam then
|
||||
begin
|
||||
ArgTemps.Add('');
|
||||
ArgLine := ArgLine + Format(', l %s',
|
||||
[EmitLValueAddr(TASTExpr(MCallExpr.Args.Items[I]))])
|
||||
[EmitLValueAddr(TASTExpr(MCallExpr.Args.Items[I]))]);
|
||||
end
|
||||
else
|
||||
begin
|
||||
ArgTemp := EmitExpr(TASTExpr(MCallExpr.Args.Items[I]));
|
||||
ArgTemps.Add(ArgTemp);
|
||||
ArgTemp := CoerceArg(ArgTemp, TASTExpr(MCallExpr.Args.Items[I]),
|
||||
QbeTypeOf(Par.ResolvedType));
|
||||
ArgLine := ArgLine + Format(', %s %s', [QbeTypeOf(Par.ResolvedType), ArgTemp]);
|
||||
|
|
@ -7974,6 +8011,8 @@ begin
|
|||
end
|
||||
else
|
||||
EmitLine(Format(' %s =%s call %s(%s)', [T, QType, FuncName, ArgLine]));
|
||||
EmitOwnedArgReleases(MCallExpr.Args, ArgTemps);
|
||||
ArgTemps.Free();
|
||||
{ Receiver was a +1-owned temporary (function/property return) used as
|
||||
the call target — release it so the temporary does not leak. The
|
||||
method's return value (T) is independent and already owns its own ref. }
|
||||
|
|
|
|||
Loading…
Reference in a new issue