mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-10 22:29:23 +02:00
+ 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:
parent
fdab7122dd
commit
125c0cf225
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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%
|
||||
|
||||
|
@ -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
64
tests/test/jvm/tw20212.pp
Normal 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.
|
||||
|
Loading…
Reference in New Issue
Block a user