+ support for generics on the JVM target:

o don't try to create .class files for generic types
   o still generate all JVM-specific wrappers for generic types even though they
     won't be written out, because when specializing all the defid's have to
     match exactly
   o add synthetic routine implementations after generating the specializations,
     so that the synthetic routines for those specializations are also generated
     (we don't specialize generic versions of the synthetic generic routines
      because it's not easy or even always possible to create valid generic
      versions of synthetic routines)
   o Note: these are Pascal-style generics, not Java-style generics. The generic
     types nor their specializations are usable from Java code (specializations
     may become usable in the future)

git-svn-id: branches/jvmbackend@19047 -
This commit is contained in:
Jonas Maebe 2011-09-11 11:54:37 +00:00
parent fdab7122dd
commit 125c0cf225
10 changed files with 120 additions and 16 deletions

1
.gitattributes vendored
View File

@ -9821,6 +9821,7 @@ tests/test/jvm/tval5.pp svneol=native#text/plain
tests/test/jvm/tvalc.pp svneol=native#text/plain
tests/test/jvm/tvarpara.pp svneol=native#text/plain
tests/test/jvm/tvirtclmeth.pp svneol=native#text/plain
tests/test/jvm/tw20212.pp svneol=native#text/plain
tests/test/jvm/twith.pp svneol=native#text/plain
tests/test/jvm/uenum.pp svneol=native#text/plain
tests/test/jvm/unsupported.pp svneol=native#text/plain

View File

@ -624,10 +624,11 @@ implementation
{ in case of nested class: relation to parent class }
if obj.owner.symtabletype in [objectsymtable,recordsymtable] then
AsmWriteln(InnerStructDef(obj));
{ all all nested classes }
{ add all nested classes }
for i:=0 to obj.symtable.deflist.count-1 do
if is_java_class_or_interface(tdef(obj.symtable.deflist[i])) or
(tdef(obj.symtable.deflist[i]).typ=recorddef) then
if (is_java_class_or_interface(tdef(obj.symtable.deflist[i])) or
(tdef(obj.symtable.deflist[i]).typ=recorddef)) and
not(df_generic in tdef(obj.symtable.deflist[i]).defoptions) then
AsmWriteln(InnerStructDef(tabstractrecorddef(obj.symtable.deflist[i])));
end;
AsmLn;
@ -966,7 +967,8 @@ implementation
procsym:
begin
for j:=0 to tprocsym(sym).procdeflist.count-1 do
WriteSymtableVarSyms(tprocdef(tprocsym(sym).procdeflist[j]).localst);
if not(df_generic in tprocdef(tprocsym(sym).procdeflist[j]).defoptions) then
WriteSymtableVarSyms(tprocdef(tprocsym(sym).procdeflist[j]).localst);
end;
end;
end;
@ -989,8 +991,9 @@ implementation
{ methods are also in the static/globalsymtable of the unit
-> make sure they are only written for the objectdefs that
own them }
if not(st.symtabletype in [staticsymtable,globalsymtable]) or
(def.owner=st) then
if (not(st.symtabletype in [staticsymtable,globalsymtable]) or
(def.owner=st)) and
not(df_generic in def.defoptions) then
begin
WriteProcDef(tprocdef(def));
if assigned(tprocdef(def).localst) then
@ -1014,6 +1017,8 @@ implementation
for i:=0 to st.DefList.Count-1 do
begin
def:=tdef(st.DefList[i]);
if df_generic in def.defoptions then
continue;
case def.typ of
objectdef:
if not(oo_is_external in tobjectdef(def).objectoptions) then

View File

@ -139,6 +139,8 @@ implementation
topowner:=topowner.owner.defowner;
{ create procdef }
pd:=tprocdef.create(topowner.owner.symtablelevel+1);
if df_generic in obj.defoptions then
include(pd.defoptions,df_generic);
{ method of this objectdef }
pd.struct:=obj;
{ associated procsym }
@ -474,6 +476,8 @@ implementation
pvclass:=tobjectdef.create(odt_javaclass,'$'+current_module.realmodulename^+'$'+name+'$InternProcvar$'+tostr(def.defid),java_procvarbase);
tprocvardef(def).classdef:=pvclass;
include(pvclass.objectoptions,oo_is_sealed);
if df_generic in def.defoptions then
include(pvclass.defoptions,df_generic);
{ associate typesym }
pvclass.symtable.insert(ttypesym.create('__FPC_TProcVarClassAlias',pvclass));
{ set external name to match procvar type name }
@ -825,6 +829,8 @@ implementation
{ create procdef }
pd:=tprocdef.create(normal_function_level);
if df_generic in obj.defoptions then
include(pd.defoptions,df_generic);
{ construct procsym name (unique for this access; reusing the same
helper for multiple accesses to the same field is hard because the

View File

@ -936,15 +936,16 @@ implementation
init_procinfo.parse_body;
{ save file pos for debuginfo }
current_module.mainfilepos:=init_procinfo.entrypos;
{ add implementations for synthetic method declarations added by
the compiler }
add_synthetic_method_implementations(current_module.globalsymtable);
add_synthetic_method_implementations(current_module.localsymtable);
end;
{ Generate specializations of objectdefs methods }
generate_specialization_procs;
{ add implementations for synthetic method declarations added by
the compiler }
add_synthetic_method_implementations(current_module.globalsymtable);
add_synthetic_method_implementations(current_module.localsymtable);
{ if the unit contains ansi/widestrings, initialization and
finalization code must be forced }
force_init_final:=tglobalsymtable(current_module.globalsymtable).needs_init_final or
@ -1874,11 +1875,13 @@ implementation
{ save file pos for debuginfo }
current_module.mainfilepos:=main_procinfo.entrypos;
add_synthetic_method_implementations(current_module.localsymtable);
{ Generate specializations of objectdefs methods }
generate_specialization_procs;
{ add implementations for synthetic method declarations added by
the compiler }
add_synthetic_method_implementations(current_module.localsymtable);
{ should we force unit initialization? }
force_init_final:=tstaticsymtable(current_module.localsymtable).needs_init_final;
if force_init_final or cnodeutils.force_init then

View File

@ -2066,7 +2066,7 @@ implementation
{ Setup symtablestack a definition time }
specobj:=tabstractrecorddef(ttypesym(p).typedef);
if not (is_class_or_object(specobj) or is_record(specobj)) then
if not (is_class_or_object(specobj) or is_record(specobj) or is_javaclass(specobj)) then
exit;
oldsymtablestack:=symtablestack;
@ -2110,7 +2110,8 @@ implementation
read_proc_body(nil,tprocdef(hp));
current_filepos:=oldcurrent_filepos;
end
else
{ synthetic routines will be implemented afterwards }
else if tprocdef(hp).synthetickind=tsk_none then
MessagePos1(tprocdef(hp).fileinfo,sym_e_forward_not_resolved,tprocdef(hp).fullprocname(false));
end;
end;

View File

@ -699,8 +699,10 @@ implementation
if jvmimplicitpointertype(procvar.returndef) then
str:=str+'type __FPC_returnptrtype = ^'+procvar.returndef.typename+';';
str:=str+'begin ';
{ result handling }
if not is_void(procvar.returndef) then
{ result handling (skip for generic definitions, we'll generate a new
version for the specialized definition) ) }
if not is_void(procvar.returndef) and
(procvar.returndef.typ<>undefineddef) then
begin
str:=str+'invoke:=';
if procvar.returndef.typ in [orddef,floatdef] then
@ -915,6 +917,9 @@ implementation
stname: string;
i: longint;
begin
{ add generic flag if required }
if df_generic in newstruct.defoptions then
include(pd.defoptions,df_generic);
{ associate the procdef with a procsym in the owner }
if not(pd.proctypeoption in [potype_class_constructor,potype_class_destructor]) then
stname:=upper(realname)

View File

@ -3211,6 +3211,11 @@ implementation
else
internalerror(2011032601);
{ in case of specializations, add some extras to prevent name conflicts
with nested classes }
if df_specialization in defoptions then
result:='$'+result+'$specialization$';
st:=owner;
while assigned(st) and
(st.symtabletype in [objectsymtable,recordsymtable,localsymtable]) do
@ -3758,6 +3763,10 @@ implementation
begin
// ignore, reuse original constym. Should also be duplicated
// be safe though
end;
symconst.typesym:
begin
// reuse original, part of generic declaration
end
else
internalerror(201160604);

View File

@ -208,4 +208,12 @@ ppcjvm -O2 -g -B tstring9
if %errorlevel% neq 0 exit /b %errorlevel%
java -Dfile.encoding=UTF-8 -cp ..\..\..\rtl\units\jvm-java;. tstring9
if %errorlevel% neq 0 exit /b %errorlevel%
ppcjvm -O2 -g -B tstr
if %errorlevel% neq 0 exit /b %errorlevel%
java -Dfile.encoding=UTF-8 -cp ..\..\..\rtl\units\jvm-java;. tstr
if %errorlevel% neq 0 exit /b %errorlevel%
ppcjvm -O2 -g -B tw20212
if %errorlevel% neq 0 exit /b %errorlevel%
java -Dfile.encoding=UTF-8 -cp ..\..\..\rtl\units\jvm-java;. tw20212
if %errorlevel% neq 0 exit /b %errorlevel%

View File

@ -116,3 +116,5 @@ $PPC -O2 -g -B tstring9
java -Dfile.encoding=UTF-8 -cp ../../../rtl/units/jvm-java:. tstring9
$PPC -O2 -g -B tstr
java -Dfile.encoding=UTF-8 -cp ../../../rtl/units/jvm-java:. tstr
$PPC -O2 -g -B tw20212
java -Dfile.encoding=UTF-8 -cp ../../../rtl/units/jvm-java:. tw20212

64
tests/test/jvm/tw20212.pp Normal file
View File

@ -0,0 +1,64 @@
program tw20212;
{$mode objfpc}{$H+}
{$ifdef cpujvm}
uses
jdk15;
{$macro on}
{$define writeln:=JLSystem.fout.println}
{$endif}
type
generic TLinkedList<T> = class
private
FData: T;
FNext: TLinkedList;
public
property Data: T read FData write FData;
property Next: TLinkedList read FNext write FNext;
constructor Create(const AData: T);
procedure Append(const AData: T);
end;
constructor TLinkedList.Create(const AData: T);
begin
FData := AData;
FNext := nil;
end;
procedure TLinkedList.Append(const AData: T);
var
tmp: TLinkedList;
begin
tmp:=FNext;
while Assigned(tmp) and Assigned(tmp.Next) do
tmp := tmp.Next;
if Assigned(tmp) then
tmp.Next := TLinkedList.Create(AData)
else
FNext := TLinkedList.Create(AData);
end;
type
TIntegerLinkedList = specialize TLinkedList<Integer>;
var
L, it: TIntegerLinkedList;
begin
L := TIntegerLinkedList.Create(1);
L.Append(1);
L.Append(2);
L.Append(3);
L.Append(5);
L.Append(8);
L.Append(11);
it:=l;
while assigned(it) do
begin
writeln(it.data);
it:=it.next;
end;
end.