[Fortran] PR37336 - FIINAL patch [1/n]: Implement the finalization wrapper subroutine
Tobias Burnus
burnus@net-b.de
Mon Aug 13 20:06:00 GMT 2012
Dear all,
Attached is the first part of a patch which will implement finalization
support and polymorphic freeing in gfortran.
It addresses two needs:
a) For polymorphic ("CLASS") variables, allocatable components have to
be freed; however, at compile time only the allocatable components of
the declared type are known â and the dynamic type might have more
b) Fortran 2003 allows finalization subroutines ("FINAL", destructors),
which can be elemental, scalar or for a given rank (any array type is
allowed). Those should be called for DEALLOCATE, leaving the scope
(unless saved), intrinsic assignment and with intent(out).
The finalization is done as follows (F2008, "4.5.6.2 The finalization
process")
"(1) If the dynamic type of the entity has a final subroutine whose
dummy argument has the same kind type parameters and rank as the entity
being finalized, it is called with the entity as an actual argument.
Otherwise, if there is an elemental final subroutine whose dummy
argument has the same kind type parameters as the entity being
finalized, it is called with the entity as an actual argument.
Otherwise, no subroutine is called at this point.
"(2) All finalizable components that appear in the type definition are
finalized in a processor-dependent order. If the entity being finalized
is an array, each finalizable component of each element of that entity
is finalized separately.
"(3) If the entity is of extended type and the parent type is
finalizable, the parent component is finalized."
The idea is to create a wrapper function which handles those steps - and
attach a reference to the dynamic type (i.e. add it via proc-pointer to
the vtable). Additionally, the wrapper can be directly called for TYPE.
The attached patch implements the generation of the wrapper subroutine;
it does not yet implement the actual calls. The wrapper is generated on
Fortran AST level and creates code similar to
subroutine final_wrapper_for_type_t (array)
type(t), intent(inout) :: array(..)
integer, pointer :: ptr
integer(c_intptr_t) :: i, addr
select case (rank (array))
case (3)
call final_rank3 (array)
case default:
do i = 0, size (array)-1
addr = transfer (c_loc (array), addr) + i * STORAGE_SIZE (array)
call c_f_pointer (transfer (addr, c_ptr), ptr)
call elemental_final (ptr)
end do
end select
! For all noninherited allocatable components, call
! DEALLOCATE(array(:)%comp, stat=ignore)
! scalarized as above
call final_wrapper_of_parent (array(...)%parent)
end subroutine final_wrapper_for_type_t
Note 1: The call to the parent type requires packing support for
assumed-rank arrays, which has not yet been implemented (also required
for TS29113, though not for this usage). That is, without further
patches, the wrapper will only work for scalars or if the parent has no
wrapper subroutine.
Note 2: The next step will be to add the calls to the wrapper, starting
with an explicit DEALLOCATE.
I intent to commit the patch, when approved, without allowing FINAL at
resolution time; that way there is no false impression that finalization
actually works.
Build and regtested on x86-64-gnu-linux.
OK for the trunk?
* * *
Note: The patch will break gfortran's OOP ABI. It does so by adding
"_final" to the virtual table (vtab).
I think breaking the ABI for this functionality is unavoidable. The ABI
change only affects code which uses the CLASS (polymorphic variables)
and the issue only raises if one mixes old with new code for the same
derived type. However, if one does so (e.g. by incomplete
recompilation), segfaults and similar issues will occur. Hence, I am
considering to bump the .mod version; that will effectively force a
recompilation and thus avoid the issue. The down side is that it will
also break packages (e.g. of Linux distributions) which ship .mod files
(sorry!). What do you think?
I think it could then be combined with Janus' proc-pointer patch, which
changes the assembler name of (non-Bind(C)) procedure pointers, declared
at module level. Again, by forcing recompilation, the .mod version bump
should ensure that users don't see the ABI breakage. His patch is at
http://gcc.gnu.org/ml/fortran/2012-04/msg00033.html (I think is okay,
but I believe it has not yet been reviewed.)
Tobias
PS: I used the following test case to test whether the wrapper
generation and scalarization works; it properly prints 11,22,33,44,55,66
and also the dump looks okay for various versions.
The scalarization code should work relatively well; there is only one
call to an external function: For SIZE gfortran - for what ever reason -
doesn't generate inline code, but calls libgfortran.
But now the test code:
module m
type tt
end type tt
type t
! type(tt), allocatable :: comp1
integer :: val
contains
final bar1
end type t
type t1t
! type(tt), allocatable :: comp1
integer :: val
!contains
! final bar1
end type t1t
type, extends(t) :: t2
type(tt), allocatable :: comp2
contains
final bar2
end type t2
class(t), allocatable, save :: a
class(t2), allocatable, save :: b
contains
impure elemental subroutine bar1(x)
! subroutine bar1(x)
type(t), intent(inout) :: x!(:)
print *, 'bar1, ....'
print *, '..........', x%val
end subroutine bar1
subroutine bar2(y)
type(t2),intent(inout) :: y(:,:)
end subroutine bar2
end
use m
use iso_c_binding
type(t1t) ::x(3,2)
interface
subroutine fini(x) bind(C,name="__m_MOD___final_m_T")
type(*) :: x(..)
end subroutine
end interface
x%val = reshape([11,22,33,44,55,66],shape(x))
print *, storage_size(x)
call fini(x)
end
And one example for a dump:
__final_m_T (struct array7_t & restrict array)
{
integer(kind=8) idx;
integer(kind=8) nelem;
struct t * ptr;
{
struct array7_t * D.1977;
D.1977 = (struct array7_t *) array;
nelem = (integer(kind=8)) (integer(kind=4)) _gfortran_size0 (D.1977) + -1;
}
switch ((integer(kind=4)) array->dtype & 7)
{
default:;
{
integer(kind=8) D.1981;
D.1981 = nelem;
idx = 0;
if (idx <= D.1981)
{
while (1)
{
{
logical(kind=4) D.1991;
{
integer(kind=8) transfer.3;
integer(kind=8) D.1989;
integer(kind=8) D.1988;
static integer(kind=8) C.1987 = 0;
void * D.1986;
void * D.1985;
integer(kind=8) D.1984;
D.1985 = (void *) array->data;
D.1986 = D.1985;
D.1984 = 8;
D.1988 = 8;
__builtin_memcpy ((void *) &transfer.3, (void *) &D.1986, MAX_EXPR
<MIN_EXPR <D.1988, D.1984>, 0>);
ptr = (struct t *) (idx * 4 + transfer.3);
}
bar1 (ptr);
L.11:;
D.1991 = idx == D.1981;
idx = idx + 1;
if (D.1991) goto L.12;
}
}
}
L.12:;
}
goto L.9;
}
L.9:;
L.8:;
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: final-wrapper.diff
Type: text/x-patch
Size: 31943 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/fortran/attachments/20120813/15bd4bde/attachment.bin>
More information about the Fortran
mailing list