[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