+ support for virtual constructors for the JVM platform. We simply

create a virtual class (factory) method that calls the constructor,
    and then let the existing support for virtual class methods handle
    everything

git-svn-id: branches/jvmbackend@18710 -
This commit is contained in:
Jonas Maebe 2011-08-20 08:26:40 +00:00
parent e38cfc307b
commit 1d0388d40a
2 changed files with 63 additions and 5 deletions

View File

@ -538,26 +538,36 @@ implementation
function tjvmcallnode.pass_1: tnode;
var
sym: tsym;
wrappername: shortstring;
begin
{ transform procvar calls }
if assigned(right) then
result:=dispatch_procvar
else
begin
{ replace virtual class method calls in case they may be indirect }
{ replace virtual class method and constructor calls in case they may
be indirect; make sure we don't replace the callthrough to the
original constructor with another call to the wrapper }
if (procdefinition.typ=procdef) and
([po_classmethod,po_virtualmethod]<=procdefinition.procoptions) and
(current_procinfo.procdef.synthetickind<>tsk_callthrough) and
((procdefinition.proctypeoption=potype_constructor) or
(po_classmethod in procdefinition.procoptions)) and
(po_virtualmethod in procdefinition.procoptions) and
(methodpointer.nodetype<>loadvmtaddrn) then
begin
wrappername:=symtableprocentry.name+'__FPCVIRTUALCLASSMETHOD__';
sym:=
search_struct_member(tobjectdef(procdefinition.owner.defowner),
upper(tprocdef(procdefinition).import_name^));
wrappername);
if not assigned(sym) or
(sym.typ<>procsym) then
internalerror(2011072801);
{ check whether we can simply replace the symtableprocentry, or
whether we have to reresolve overloads }
if symtableprocentry.ProcdefList.count=1 then
whether we have to reresolve overloads -- can never simply
replace in case of constructor -> class method call, because
constructors have a vmt parameter and class methods don't }
if (procdefinition.proctypeoption<>potype_constructor) and
(symtableprocentry.ProcdefList.count=1) then
begin
symtableprocentry:=tprocsym(sym);
procdefinition:=tprocdef(symtableprocentry.ProcdefList[0]);

View File

@ -545,11 +545,56 @@ implementation
end;
procedure jvm_wrap_virtual_constructor(pd: tprocdef);
var
wrapperpd: tprocdef;
begin
{ to avoid having to implement procvar-like support for dynamically
invoking constructors, call the constructors from virtual class
methods and replace calls to the constructors with calls to the
virtual class methods -> we can reuse lots of infrastructure }
if (po_external in pd.procoptions) or
(oo_is_external in pd.struct.objectoptions) then
exit;
{ wrapper is part of the same symtable as the original procdef }
symtablestack.push(pd.owner);
{ get a copy of the constructor }
wrapperpd:=tprocdef(pd.getcopyas(procdef,pc_bareproc));
{ this one is is a class method rather than a constructor }
include(wrapperpd.procoptions,po_classmethod);
wrapperpd.proctypeoption:=potype_function;
wrapperpd.returndef:=tobjectdef(pd.owner.defowner);
{ import/external name = name of original constructor (since
constructors don't have names in Java, this won't conflict with the
original constructor definition) }
stringdispose(wrapperpd.import_name);
wrapperpd.import_name:=stringdup(pd.procsym.realname);
{ associate with wrapper procsym (Pascal-level name = wrapper name ->
in callnodes, we will have to replace the calls to virtual
constructors with calls to the wrappers) }
finish_copied_procdef(wrapperpd,pd.procsym.realname+'__fpcvirtconstrwrapper__',pd.owner,tabstractrecorddef(pd.owner.defowner));
{ since it was a bare copy, insert the self parameter (we can't just
copy the vmt parameter from the constructor, that's different) }
insert_self_and_vmt_para(wrapperpd);
wrapperpd.calcparas;
{ implementation: call through to the constructor }
wrapperpd.synthetickind:=tsk_callthrough;
wrapperpd.skpara:=pd;
symtablestack.pop(pd.owner);
{ and now wrap this generated virtual static method itself as well}
jvm_wrap_virtual_class_method(wrapperpd);
end;
procedure jvm_wrap_virtual_class_methods(obj: tobjectdef);
var
i: longint;
def: tdef;
begin
{ new methods will be inserted while we do this, but since
symtable.deflist.count is evaluated at the start of the loop that
doesn't matter }
for i:=0 to obj.symtable.deflist.count-1 do
begin
def:=tdef(obj.symtable.deflist[i]);
@ -557,6 +602,9 @@ implementation
continue;
if [po_classmethod,po_virtualmethod]<=tprocdef(def).procoptions then
jvm_wrap_virtual_class_method(tprocdef(def))
else if (tprocdef(def).proctypeoption=potype_constructor) and
(po_virtualmethod in tprocdef(def).procoptions) then
jvm_wrap_virtual_constructor(tprocdef(def));
end;
end;