mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2026-01-06 04:10:36 +01:00
+ support for procedural variables for the JVM target
o every porocedural variable type is represented by a class with one
public "invoke" method whose signature matches the signature of the
procvar
o internally, dispatching happens via java.lang.reflect.Method.invoke().
WARNING: while this allows calling private/protected or other methods
that are normally not accessible from another context, a security
manger can override this. If such a security manager is installed,
most procvars will cause security exceptions
o such dispatching also requires that all arguments are wrapped, but
that's done in the compiler-generated body of the invoke method,
so that procvars can also be called conveniently from Java code
o typecasting between a procedure of object and tmethod is supported,
as well as Delphi-style replacing of only the method pointer via
@procvar1=@procvar2.
o nested procvars are not yet supported, but most of the basic
infrastructure for them is already present
* all units/programs now get an internal __FPC_JVM_Module_Class_Alias$
type when compiled for the JVM target, which is an "external" class
that maps to the unit name. This is required to look up the
JLRMethod instances for regular functions/procedures
+ new tabstractprocdef.copyas() method that allows to create a procvar
from a procdef and vice versa
git-svn-id: branches/jvmbackend@18690 -
This commit is contained in:
parent
b526505bbf
commit
979f55e1db
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -7364,6 +7364,8 @@ rtl/java/jdk15.pas svneol=native#text/plain
|
||||
rtl/java/jdynarrh.inc svneol=native#text/plain
|
||||
rtl/java/jint64.inc svneol=native#text/plain
|
||||
rtl/java/jmathh.inc svneol=native#text/plain
|
||||
rtl/java/jpvar.inc svneol=native#text/plain
|
||||
rtl/java/jpvarh.inc svneol=native#text/plain
|
||||
rtl/java/jrec.inc svneol=native#text/plain
|
||||
rtl/java/jrech.inc svneol=native#text/plain
|
||||
rtl/java/jset.inc svneol=native#text/plain
|
||||
|
||||
@ -648,7 +648,9 @@ implementation
|
||||
for i:=1 to pred(initdim) do
|
||||
elemdef:=tarraydef(elemdef).elementdef;
|
||||
if (elemdef.typ in [recorddef,setdef]) or
|
||||
is_shortstring(elemdef) then
|
||||
is_shortstring(elemdef) or
|
||||
((elemdef.typ=procvardef) and
|
||||
not tprocvardef(elemdef).is_addressonly) then
|
||||
begin
|
||||
{ duplicate array/string/set instance }
|
||||
list.concat(taicpu.op_none(a_dup));
|
||||
@ -667,7 +669,9 @@ implementation
|
||||
g_call_system_proc(list,'fpc_initialize_array_enumset')
|
||||
else
|
||||
g_call_system_proc(list,'fpc_initialize_array_bitset')
|
||||
end
|
||||
end;
|
||||
procvardef:
|
||||
g_call_system_proc(list,'fpc_initialize_array_procvar');
|
||||
end;
|
||||
tg.ungettemp(list,recref);
|
||||
end
|
||||
@ -1170,6 +1174,11 @@ implementation
|
||||
end;
|
||||
recorddef:
|
||||
procname:='FPC_COPY_JRECORD_ARRAY';
|
||||
procvardef:
|
||||
if tprocvardef(eledef).is_addressonly then
|
||||
procname:='FPC_COPY_SHALLOW_ARRAY'
|
||||
else
|
||||
procname:='FPC_COPY_JPROCVAR_ARRAY';
|
||||
setdef:
|
||||
if tsetdef(eledef).elementdef.typ=enumdef then
|
||||
procname:='FPC_COPY_JENUMSET_ARRAY'
|
||||
@ -1229,7 +1238,7 @@ implementation
|
||||
srsym:=search_struct_member(tabstractrecorddef(size),'FPCDEEPCOPY');
|
||||
if not assigned(srsym) or
|
||||
(srsym.typ<>procsym) then
|
||||
Message1(cg_f_unknown_compilerproc,'FpcRecordBaseType.fpcDeepCopy');
|
||||
Message1(cg_f_unknown_compilerproc,size.typename+'.fpcDeepCopy');
|
||||
pd:=tprocdef(tprocsym(srsym).procdeflist[0]);
|
||||
a_call_name(list,pd,pd.mangledname,false);
|
||||
{ both parameters are removed, no function result }
|
||||
@ -1304,6 +1313,14 @@ implementation
|
||||
handled:=true;
|
||||
end;
|
||||
end;
|
||||
procvardef:
|
||||
begin
|
||||
if not tprocvardef(size).is_addressonly then
|
||||
begin
|
||||
concatcopy_record(list,tprocvardef(size).classdef,source,dest);
|
||||
handled:=true;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
if not handled then
|
||||
inherited;
|
||||
|
||||
@ -28,7 +28,7 @@ interface
|
||||
uses
|
||||
cgbase,
|
||||
symtype,symdef,
|
||||
ncgcal;
|
||||
node,ncgcal;
|
||||
|
||||
type
|
||||
tjvmcallparanode = class(tcgcallparanode)
|
||||
@ -50,6 +50,9 @@ interface
|
||||
procedure set_result_location(realresdef: tstoreddef); override;
|
||||
procedure do_release_unused_return_value;override;
|
||||
procedure extra_post_call_code; override;
|
||||
function dispatch_procvar: tnode;
|
||||
public
|
||||
function pass_1: tnode; override;
|
||||
end;
|
||||
|
||||
|
||||
@ -61,7 +64,7 @@ implementation
|
||||
cgutils,tgobj,procinfo,
|
||||
cpubase,aasmdata,aasmcpu,
|
||||
hlcgobj,hlcgcpu,
|
||||
pass_1,node,nutils,nbas,ncnv,ncon,ninl,nld,nmem,
|
||||
pass_1,nutils,nbas,ncnv,ncon,ninl,nld,nmem,
|
||||
jvmdef;
|
||||
|
||||
{*****************************************************************************
|
||||
@ -418,36 +421,11 @@ implementation
|
||||
realresdef: tdef;
|
||||
ppn: tjvmcallparanode;
|
||||
pararef: treference;
|
||||
{$ifndef nounsupported}
|
||||
i: longint;
|
||||
{$endif}
|
||||
begin
|
||||
if not assigned(typedef) then
|
||||
realresdef:=tstoreddef(resultdef)
|
||||
else
|
||||
realresdef:=tstoreddef(typedef);
|
||||
{$ifndef nounsupported}
|
||||
if assigned(right) then
|
||||
begin
|
||||
for i:=1 to pushedparasize do
|
||||
current_asmdata.CurrAsmList.concat(taicpu.op_none(a_pop));
|
||||
if (tabstractprocdef(procdefinition).proctypeoption<>potype_constructor) and
|
||||
(realresdef<>voidtype) then
|
||||
begin
|
||||
case hlcg.def2regtyp(realresdef) of
|
||||
R_INTREGISTER,
|
||||
R_ADDRESSREGISTER:
|
||||
begin
|
||||
thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,realresdef,0,hlcg.def2regtyp(realresdef));
|
||||
end;
|
||||
R_FPUREGISTER:
|
||||
thlcgjvm(hlcg).a_loadfpu_const_stack(current_asmdata.CurrAsmList,realresdef,0.0);
|
||||
end;
|
||||
{ calling code assumes this result was already put on the stack by the callee }
|
||||
thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,align(realresdef.size,4) shr 2);
|
||||
end;
|
||||
end;
|
||||
{$endif}
|
||||
{ a constructor doesn't actually return a value in the jvm }
|
||||
if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) then
|
||||
totalremovesize:=pushedparasize
|
||||
@ -504,6 +482,64 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function tjvmcallnode.dispatch_procvar: tnode;
|
||||
var
|
||||
pdclass: tobjectdef;
|
||||
prevpara, para, nextpara: tcallparanode;
|
||||
begin
|
||||
pdclass:=tprocvardef(right.resultdef).classdef;
|
||||
{ convert procvar type into corresponding class }
|
||||
if not tprocvardef(right.resultdef).is_addressonly then
|
||||
begin
|
||||
right:=caddrnode.create_internal(right);
|
||||
include(right.flags,nf_typedaddr);
|
||||
end;
|
||||
right:=ctypeconvnode.create_explicit(right,pdclass);
|
||||
include(right.flags,nf_load_procvar);
|
||||
typecheckpass(right);
|
||||
|
||||
{ call the invoke method with these parameters. It will take care of the
|
||||
wrapping and typeconversions; first filter out the automatically added
|
||||
hidden parameters though }
|
||||
prevpara:=nil;
|
||||
para:=tcallparanode(left);
|
||||
while assigned(para) do
|
||||
begin
|
||||
nextpara:=tcallparanode(para.right);
|
||||
if vo_is_hidden_para in para.parasym.varoptions then
|
||||
begin
|
||||
if assigned(prevpara) then
|
||||
prevpara.right:=nextpara
|
||||
else
|
||||
left:=nextpara;
|
||||
para.right:=nil;
|
||||
para.free;
|
||||
end
|
||||
else
|
||||
prevpara:=para;
|
||||
para:=nextpara;
|
||||
end;
|
||||
result:=ccallnode.createinternmethod(right,'INVOKE',left);
|
||||
{ reused }
|
||||
left:=nil;
|
||||
right:=nil;
|
||||
end;
|
||||
|
||||
|
||||
function tjvmcallnode.pass_1: tnode;
|
||||
begin
|
||||
{ transform procvar calls }
|
||||
if assigned(right) then
|
||||
result:=dispatch_procvar
|
||||
else
|
||||
begin
|
||||
result:=inherited pass_1;
|
||||
if assigned(result) then
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
begin
|
||||
ccallnode:=tjvmcallnode;
|
||||
ccallparanode:=tjvmcallparanode;
|
||||
|
||||
@ -33,9 +33,12 @@ interface
|
||||
function typecheck_dynarray_to_openarray: tnode; override;
|
||||
function typecheck_string_to_chararray: tnode; override;
|
||||
function typecheck_char_to_string: tnode; override;
|
||||
function typecheck_proc_to_procvar: tnode; override;
|
||||
function pass_1: tnode; override;
|
||||
function simplify(forinline: boolean): tnode; override;
|
||||
function first_set_to_set : tnode;override;
|
||||
function first_nil_to_methodprocvar: tnode; override;
|
||||
function first_proc_to_procvar: tnode; override;
|
||||
|
||||
procedure second_int_to_int;override;
|
||||
{ procedure second_string_to_string;override; }
|
||||
@ -49,7 +52,7 @@ interface
|
||||
procedure second_int_to_real;override;
|
||||
{ procedure second_real_to_real;override; }
|
||||
{ procedure second_cord_to_pointer;override; }
|
||||
{ procedure second_proc_to_procvar;override; }
|
||||
procedure second_proc_to_procvar;override;
|
||||
procedure second_bool_to_int;override;
|
||||
procedure second_int_to_bool;override;
|
||||
{ procedure second_load_smallset;override; }
|
||||
@ -90,11 +93,11 @@ implementation
|
||||
|
||||
uses
|
||||
verbose,globals,globtype,constexp,
|
||||
symconst,symdef,symsym,symtable,aasmbase,aasmdata,
|
||||
symbase,symconst,symdef,symsym,symtable,aasmbase,aasmdata,
|
||||
defutil,defcmp,jvmdef,
|
||||
cgbase,cgutils,pass_1,pass_2,
|
||||
nbas,ncon,ncal,ninl,nld,nmem,procinfo,
|
||||
nutils,
|
||||
nutils,paramgr,
|
||||
cpubase,aasmcpu,
|
||||
tgobj,hlcgobj,hlcgcpu;
|
||||
|
||||
@ -113,18 +116,25 @@ implementation
|
||||
result:=false;
|
||||
if def1.typ<>procvardef then
|
||||
exit;
|
||||
{ is_addressonly procvars are treated like regular pointer-sized data,
|
||||
po_methodpointer procvars like implicit pointers to a struct }
|
||||
if tprocvardef(def1).is_addressonly then
|
||||
result:=
|
||||
((def2.typ=procvardef) and
|
||||
tprocvardef(def2).is_addressonly) or
|
||||
(def2=java_jlobject) or
|
||||
(def2=voidpointertype)
|
||||
else
|
||||
else if po_methodpointer in tprocvardef(def1).procoptions then
|
||||
begin
|
||||
if not assigned(tmethoddef) then
|
||||
tmethoddef:=search_system_type('TMETHOD').typedef;
|
||||
result:=
|
||||
(def2=methodpointertype) or
|
||||
(def2=tmethoddef);
|
||||
(def2=tmethoddef) or
|
||||
((def2.typ=procvardef) and
|
||||
(po_methodpointer in tprocvardef(def2).procoptions));
|
||||
end;
|
||||
{ can't typecast nested procvars, they need 3 data pointers }
|
||||
end;
|
||||
|
||||
begin
|
||||
@ -186,6 +196,26 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function tjvmtypeconvnode.typecheck_proc_to_procvar: tnode;
|
||||
begin
|
||||
result:=inherited typecheck_proc_to_procvar;
|
||||
if not assigned(totypedef) then
|
||||
begin
|
||||
if assigned(tprocvardef(resultdef).classdef) then
|
||||
internalerror(2011072405);
|
||||
{ associate generic classdef; this is the result of an @proc
|
||||
expression, and such expressions can never result in a direct call
|
||||
-> no invoke() method required (which only exists in custom
|
||||
constructed descendents created for defined procvar types) }
|
||||
if is_nested_pd(tabstractprocdef(resultdef)) then
|
||||
{ todo }
|
||||
internalerror(2011072406)
|
||||
else
|
||||
tprocvardef(resultdef).classdef:=java_procvarbase;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{*****************************************************************************
|
||||
FirstTypeConv
|
||||
*****************************************************************************}
|
||||
@ -295,6 +325,127 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function tjvmtypeconvnode.first_nil_to_methodprocvar: tnode;
|
||||
begin
|
||||
result:=inherited first_nil_to_methodprocvar;
|
||||
if assigned(result) then
|
||||
exit;
|
||||
if not assigned(tprocvardef(resultdef).classdef) then
|
||||
tprocvardef(resultdef).classdef:=java_procvarbase;
|
||||
result:=ccallnode.createinternmethod(
|
||||
cloadvmtaddrnode.create(ctypenode.create(tprocvardef(resultdef).classdef)),'CREATE',nil);
|
||||
{ method pointer is an implicit pointer type }
|
||||
result:=ctypeconvnode.create_explicit(result,getpointerdef(resultdef));
|
||||
result:=cderefnode.create(result);
|
||||
end;
|
||||
|
||||
|
||||
function tjvmtypeconvnode.first_proc_to_procvar: tnode;
|
||||
var
|
||||
constrparas: tcallparanode;
|
||||
newpara: tnode;
|
||||
procdefparas: tarrayconstructornode;
|
||||
pvs: tparavarsym;
|
||||
fvs: tsym;
|
||||
i: longint;
|
||||
corrclass: tdef;
|
||||
jlclass: tobjectdef;
|
||||
encodedtype: tsymstr;
|
||||
procload: tnode;
|
||||
procdef: tprocdef;
|
||||
st: tsymtable;
|
||||
pushaddr: boolean;
|
||||
begin
|
||||
result:=inherited first_proc_to_procvar;
|
||||
if assigned(result) then
|
||||
exit;
|
||||
procdef:=tloadnode(left).procdef;
|
||||
procload:=tloadnode(left).left;
|
||||
if not assigned(procload) then
|
||||
begin
|
||||
{ nested or regular routine -> figure out whether unit-level or
|
||||
nested, and if nested whether it's nested in a method or in a
|
||||
regular routine }
|
||||
st:=procdef.owner;
|
||||
while st.symtabletype=localsymtable do
|
||||
st:=st.defowner.owner;
|
||||
if st.symtabletype in [objectsymtable,recordsymtable] then
|
||||
{ nested routine in method -> part of encloding class }
|
||||
procload:=cloadvmtaddrnode.create(ctypenode.create(tdef(st.defowner)))
|
||||
else
|
||||
begin
|
||||
{ regular procedure/function -> get type representing unit
|
||||
class }
|
||||
while not(st.symtabletype in [staticsymtable,globalsymtable]) do
|
||||
st:=st.defowner.owner;
|
||||
corrclass:=search_named_unit_globaltype(st.realname^,'__FPC_JVM_MODULE_CLASS_ALIAS$',true).typedef;
|
||||
procload:=cloadvmtaddrnode.create(ctypenode.create(tdef(corrclass)));
|
||||
end;
|
||||
end;
|
||||
{ todo: support nested procvars }
|
||||
if is_nested_pd(procdef) then
|
||||
internalerror(2011072607);
|
||||
{ constructor FpcBaseProcVarType.create(inst: jlobject; const method: unicodestring; const argTypes: array of JLClass); }
|
||||
constrparas:=ccallparanode.create(ctypeconvnode.create_explicit(procload,java_jlobject),nil);
|
||||
constrparas:=ccallparanode.create(cstringconstnode.createstr(procdef.procsym.realname),constrparas);
|
||||
procdefparas:=nil;
|
||||
jlclass:=tobjectdef(search_system_type('JLCLASS').typedef);
|
||||
{ in reverse to make it easier to build the arrayconstructorn }
|
||||
for i:=procdef.paras.count-1 downto 0 do
|
||||
begin
|
||||
pvs:=tparavarsym(procdef.paras[i]);
|
||||
{ self is deal with via the "inst" parameter }
|
||||
if vo_is_self in pvs.varoptions then
|
||||
continue;
|
||||
{ in case of an arraydef, pass by jlclass.forName() to get the classdef
|
||||
(could be optimized by adding support to loadvmtaddrnode to also deal
|
||||
with arrays, although we'd have to create specific arraydefs for var/
|
||||
out/constref parameters }
|
||||
pushaddr:=paramanager.push_copyout_param(pvs.varspez,pvs.vardef,procdef.proccalloption);
|
||||
if pushaddr or
|
||||
(pvs.vardef.typ=arraydef) then
|
||||
begin
|
||||
encodedtype:=jvmencodetype(pvs.vardef,false);
|
||||
if pushaddr then
|
||||
encodedtype:='['+encodedtype;
|
||||
newpara:=ccallnode.createinternmethod(cloadvmtaddrnode.create(ctypenode.create(jlclass)),'FORNAME',
|
||||
ccallparanode.create(cstringconstnode.createstr(encodedtype),nil));
|
||||
end
|
||||
else
|
||||
begin
|
||||
corrclass:=jvmgetcorrespondingclassdef(pvs.vardef);
|
||||
if pvs.vardef.typ in [orddef,floatdef] then
|
||||
begin
|
||||
{ get the class representing the primitive type }
|
||||
fvs:=search_struct_member(tobjectdef(corrclass),'FTYPE');
|
||||
if not assigned(fvs) or
|
||||
(fvs.typ<>staticvarsym) then
|
||||
internalerror(2011072417);
|
||||
newpara:=cloadnode.create(fvs,fvs.owner);
|
||||
end
|
||||
else
|
||||
newpara:=cloadvmtaddrnode.create(ctypenode.create(corrclass));
|
||||
newpara:=ctypeconvnode.create_explicit(newpara,jlclass);
|
||||
end;
|
||||
procdefparas:=carrayconstructornode.create(newpara,procdefparas);
|
||||
end;
|
||||
if not assigned(procdefparas) then
|
||||
procdefparas:=carrayconstructornode.create(nil,nil);
|
||||
constrparas:=ccallparanode.create(procdefparas,constrparas);
|
||||
result:=ccallnode.createinternmethod(cloadvmtaddrnode.create(ctypenode.create(tprocvardef(resultdef).classdef)),'CREATE',constrparas);
|
||||
{ typecast to the procvar type }
|
||||
if tprocvardef(resultdef).is_addressonly then
|
||||
result:=ctypeconvnode.create_explicit(result,resultdef)
|
||||
else
|
||||
begin
|
||||
result:=ctypeconvnode.create_explicit(result,getpointerdef(resultdef));
|
||||
result:=cderefnode.create(result)
|
||||
end;
|
||||
{ reused }
|
||||
tloadnode(left).left:=nil;
|
||||
end;
|
||||
|
||||
|
||||
{*****************************************************************************
|
||||
SecondTypeConv
|
||||
*****************************************************************************}
|
||||
@ -433,6 +584,12 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
procedure tjvmtypeconvnode.second_proc_to_procvar;
|
||||
begin
|
||||
internalerror(2011072506);
|
||||
end;
|
||||
|
||||
|
||||
procedure tjvmtypeconvnode.second_bool_to_int;
|
||||
var
|
||||
newsize: tcgsize;
|
||||
@ -714,6 +871,61 @@ implementation
|
||||
end;
|
||||
end;
|
||||
|
||||
function procvar_to_procvar(fromdef, todef: tdef): tnode;
|
||||
var
|
||||
fsym: tsym;
|
||||
begin
|
||||
result:=nil;
|
||||
if fromdef=todef then
|
||||
exit;
|
||||
fsym:=tfieldvarsym(search_struct_member(tprocvardef(fromdef).classdef,'METHOD'));
|
||||
if not assigned(fsym) or
|
||||
(fsym.typ<>fieldvarsym) then
|
||||
internalerror(2011072414);
|
||||
{ can either be a procvar or a procvarclass }
|
||||
if fromdef.typ=procvardef then
|
||||
begin
|
||||
left:=ctypeconvnode.create_explicit(left,tprocvardef(fromdef).classdef);
|
||||
include(left.flags,nf_load_procvar);
|
||||
typecheckpass(left);
|
||||
end;
|
||||
result:=csubscriptnode.create(fsym,left);
|
||||
{ create destination procvartype with info from source }
|
||||
result:=ccallnode.createinternmethod(
|
||||
cloadvmtaddrnode.create(ctypenode.create(tprocvardef(todef).classdef)),
|
||||
'CREATE',ccallparanode.create(result,nil));
|
||||
left:=nil;
|
||||
end;
|
||||
|
||||
function procvar_to_tmethod(fromdef, todef: tdef): tnode;
|
||||
var
|
||||
fsym: tsym;
|
||||
begin
|
||||
{ must be procedure-of-object -> implicit pointer type -> get address
|
||||
before typecasting to corresponding classdef }
|
||||
left:=caddrnode.create_internal(left);
|
||||
inserttypeconv_explicit(left,tprocvardef(fromdef).classdef);
|
||||
fsym:=tfieldvarsym(search_struct_member(tprocvardef(fromdef).classdef,'METHOD'));
|
||||
if not assigned(fsym) or
|
||||
(fsym.typ<>fieldvarsym) then
|
||||
internalerror(2011072414);
|
||||
result:=csubscriptnode.create(fsym,left);
|
||||
left:=nil;
|
||||
end;
|
||||
|
||||
function tmethod_to_procvar(fromdef, todef: tdef): tnode;
|
||||
var
|
||||
fsym: tsym;
|
||||
begin
|
||||
fsym:=tfieldvarsym(search_struct_member(tprocvardef(todef).classdef,'METHOD'));
|
||||
if not assigned(fsym) or
|
||||
(fsym.typ<>fieldvarsym) then
|
||||
internalerror(2011072415);
|
||||
result:=ccallnode.createinternmethod(cloadvmtaddrnode.create(ctypenode.create(tprocvardef(todef).classdef)),
|
||||
'CREATE',ccallparanode.create(left,nil));
|
||||
left:=nil;
|
||||
end;
|
||||
|
||||
function ptr_no_typecheck_required(fromdef, todef: tdef): boolean;
|
||||
|
||||
function check_type_equality(def1,def2: tdef): boolean;
|
||||
@ -762,6 +974,11 @@ implementation
|
||||
|
||||
begin
|
||||
result:=true;
|
||||
{ check procvar conversion compatibility via their classes }
|
||||
if fromdef.typ=procvardef then
|
||||
fromdef:=tprocvardef(fromdef).classdef;
|
||||
if todef.typ=procvardef then
|
||||
todef:=tprocvardef(todef).classdef;
|
||||
if (todef=java_jlobject) or
|
||||
(todef=voidpointertype) then
|
||||
exit;
|
||||
@ -809,8 +1026,7 @@ implementation
|
||||
|
||||
var
|
||||
fromclasscompatible,
|
||||
toclasscompatible,
|
||||
procvarconv: boolean;
|
||||
toclasscompatible: boolean;
|
||||
fromdef,
|
||||
todef: tdef;
|
||||
fromarrtype,
|
||||
@ -832,7 +1048,6 @@ implementation
|
||||
|
||||
{ don't allow conversions between object-based and non-object-based
|
||||
types }
|
||||
procvarconv:=isvalidprocvartypeconv(left.resultdef,resultdef);
|
||||
fromclasscompatible:=
|
||||
(left.resultdef.typ=formaldef) or
|
||||
(left.resultdef.typ=pointerdef) or
|
||||
@ -841,7 +1056,10 @@ implementation
|
||||
((left.resultdef.typ in [stringdef,classrefdef]) and
|
||||
not is_shortstring(left.resultdef)) or
|
||||
(left.resultdef.typ=enumdef) or
|
||||
procvarconv;
|
||||
{ procvar2procvar needs special handling }
|
||||
((left.resultdef.typ=procvardef) and
|
||||
tprocvardef(left.resultdef).is_addressonly and
|
||||
(resultdef.typ<>procvardef));
|
||||
toclasscompatible:=
|
||||
(resultdef.typ=pointerdef) or
|
||||
is_java_class_or_interface(resultdef) or
|
||||
@ -849,7 +1067,8 @@ implementation
|
||||
((resultdef.typ in [stringdef,classrefdef]) and
|
||||
not is_shortstring(resultdef)) or
|
||||
(resultdef.typ=enumdef) or
|
||||
procvarconv;
|
||||
((resultdef.typ=procvardef) and
|
||||
tprocvardef(resultdef).is_addressonly);
|
||||
{ typescasts from void (the result of untyped_ptr^) to an implicit
|
||||
pointertype (record, array, ...) also needs a typecheck }
|
||||
if is_void(left.resultdef) and
|
||||
@ -884,7 +1103,7 @@ implementation
|
||||
toarrtype:=jvmarrtype_setlength(todef);
|
||||
if not ptr_no_typecheck_required(fromdef,todef) then
|
||||
begin
|
||||
if (fromarrtype in ['A','R','T','E','L']) or
|
||||
if (fromarrtype in ['A','R','T','E','L','P']) or
|
||||
(fromarrtype<>toarrtype) then
|
||||
begin
|
||||
if not check_only and
|
||||
@ -942,6 +1161,23 @@ implementation
|
||||
exit;
|
||||
end;
|
||||
|
||||
{ procvar to tmethod and vice versa, and procvar to procvar }
|
||||
if isvalidprocvartypeconv(left.resultdef,resultdef) then
|
||||
begin
|
||||
if not check_only then
|
||||
begin
|
||||
if (left.resultdef.typ=procvardef) and
|
||||
(resultdef.typ=procvardef) then
|
||||
resnode:=procvar_to_procvar(left.resultdef,resultdef)
|
||||
else if left.resultdef.typ=procvardef then
|
||||
resnode:=procvar_to_tmethod(left.resultdef,resultdef)
|
||||
else
|
||||
resnode:=tmethod_to_procvar(left.resultdef,resultdef);
|
||||
end;
|
||||
result:=true;
|
||||
exit;
|
||||
end;
|
||||
|
||||
{ don't allow conversions between different classes of primitive types,
|
||||
except for a few special cases }
|
||||
|
||||
@ -1102,20 +1338,6 @@ implementation
|
||||
(left.resultdef.typ=enumdef) and
|
||||
(resultdef.typ=objectdef) then
|
||||
firstpass(left);
|
||||
{$ifndef nounsupported}
|
||||
{ generated in nmem; replace voidpointertype with java_jlobject }
|
||||
if nf_load_procvar in flags then
|
||||
begin
|
||||
self.totypedef:=java_jlobject;
|
||||
resultdef:=java_jlobject;
|
||||
end;
|
||||
if isvalidprocvartypeconv(left.resultdef,resultdef) then
|
||||
begin
|
||||
convtype:=tc_equal;
|
||||
result:=true;
|
||||
exit;
|
||||
end;
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
|
||||
@ -1234,13 +1456,10 @@ implementation
|
||||
checkdef:=java_juenumset
|
||||
else
|
||||
checkdef:=java_jubitset;
|
||||
end;
|
||||
{$ifndef nounsupported}
|
||||
if checkdef.typ=procvardef then
|
||||
checkdef:=java_jlobject
|
||||
else
|
||||
{$endif}
|
||||
if is_wide_or_unicode_string(checkdef) then
|
||||
end
|
||||
else if checkdef.typ=procvardef then
|
||||
checkdef:=tprocvardef(checkdef).classdef
|
||||
else if is_wide_or_unicode_string(checkdef) then
|
||||
checkdef:=java_jlstring
|
||||
else if is_ansistring(checkdef) then
|
||||
checkdef:=java_ansistring
|
||||
|
||||
@ -55,7 +55,7 @@ implementation
|
||||
uses
|
||||
verbose,
|
||||
aasmdata,
|
||||
nbas,nld,ncal,ninl,nmem,ncnv,
|
||||
nbas,nld,ncal,ncon,ninl,nmem,ncnv,
|
||||
symconst,symsym,symdef,symtable,defutil,jvmdef,
|
||||
paramgr,
|
||||
pass_1,
|
||||
@ -187,6 +187,9 @@ procedure tjvmloadnode.pass_generate_code;
|
||||
else
|
||||
hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,java_jlobject,java_jlobject,tparavarsym(symtableentry).localloc,location.reference.base);
|
||||
end
|
||||
else if symtableentry.typ=procsym then
|
||||
{ handled in tjvmcnvnode.first_proc_to_procvar }
|
||||
internalerror(2011072408)
|
||||
else
|
||||
inherited pass_generate_code;
|
||||
end;
|
||||
|
||||
@ -120,6 +120,8 @@ implementation
|
||||
*****************************************************************************}
|
||||
|
||||
function tjvmaddrnode.pass_typecheck: tnode;
|
||||
var
|
||||
fsym: tsym;
|
||||
begin
|
||||
result:=nil;
|
||||
typecheckpass(left);
|
||||
@ -128,12 +130,73 @@ implementation
|
||||
|
||||
make_not_regable(left,[ra_addr_regable,ra_addr_taken]);
|
||||
|
||||
if (left.resultdef.typ=procdef) or
|
||||
(
|
||||
(left.resultdef.typ=procvardef) and
|
||||
((m_tp_procvar in current_settings.modeswitches) or
|
||||
(m_mac_procvar in current_settings.modeswitches))
|
||||
) then
|
||||
{ in TP/Delphi, @procvar = contents of procvar and @@procvar =
|
||||
address of procvar. In case of a procedure of object, this works
|
||||
by letting the first addrnode typecast the procvar into a tmethod
|
||||
record followed by subscripting its "code" field (= first field),
|
||||
and if there's a second addrnode then it takes the address of
|
||||
this code field (which is hence also the address of the procvar).
|
||||
|
||||
In Java, such ugly hacks don't work -> replace first addrnode
|
||||
with getting procvar.method.code, and second addrnode with
|
||||
the class for procedure of object}
|
||||
if not(nf_internal in flags) and
|
||||
((m_tp_procvar in current_settings.modeswitches) or
|
||||
(m_mac_procvar in current_settings.modeswitches)) and
|
||||
(((left.nodetype=addrn) and
|
||||
(taddrnode(left).left.resultdef.typ=procvardef)) or
|
||||
(left.resultdef.typ=procvardef)) then
|
||||
begin
|
||||
if (left.nodetype=addrn) and
|
||||
(taddrnode(left).left.resultdef.typ=procvardef) then
|
||||
begin
|
||||
{ double address -> pointer that is the address of the
|
||||
procvardef (don't allow for non-object procvars, as they
|
||||
aren't implicitpointerdefs) }
|
||||
if not jvmimplicitpointertype(taddrnode(left).left.resultdef) then
|
||||
CGMessage(parser_e_illegal_expression)
|
||||
else
|
||||
begin
|
||||
{ an internal address node will observe "normal" address
|
||||
operator semantics (= take the actual address!) }
|
||||
result:=caddrnode.create_internal(taddrnode(left).left);
|
||||
result:=ctypeconvnode.create_explicit(result,tprocvardef(taddrnode(left).left.resultdef).classdef);
|
||||
taddrnode(left).left:=nil;
|
||||
end;
|
||||
end
|
||||
else if left.resultdef.typ=procvardef then
|
||||
begin
|
||||
if not tprocvardef(left.resultdef).is_addressonly then
|
||||
begin
|
||||
{ the "code" field from the procvar }
|
||||
result:=caddrnode.create_internal(left);
|
||||
result:=ctypeconvnode.create_explicit(result,tprocvardef(left.resultdef).classdef);
|
||||
{ procvarclass.method }
|
||||
fsym:=search_struct_member(tprocvardef(left.resultdef).classdef,'METHOD');
|
||||
if not assigned(fsym) or
|
||||
(fsym.typ<>fieldvarsym) then
|
||||
internalerror(2011072501);
|
||||
result:=csubscriptnode.create(fsym,result);
|
||||
{ procvarclass.method.code }
|
||||
fsym:=search_struct_member(trecorddef(tfieldvarsym(fsym).vardef),'CODE');
|
||||
if not assigned(fsym) or
|
||||
(fsym.typ<>fieldvarsym) then
|
||||
internalerror(2011072502);
|
||||
result:=csubscriptnode.create(fsym,result);
|
||||
left:=nil
|
||||
end
|
||||
else
|
||||
{ convert contents to plain pointer }
|
||||
begin
|
||||
result:=ctypeconvnode.create_explicit(left,java_jlobject);
|
||||
include(result.flags,nf_load_procvar);
|
||||
left:=nil;
|
||||
end;
|
||||
end
|
||||
else
|
||||
internalerror(2011072506);
|
||||
end
|
||||
else if (left.resultdef.typ=procdef) then
|
||||
begin
|
||||
result:=inherited;
|
||||
exit;
|
||||
@ -181,14 +244,7 @@ implementation
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ procvar }
|
||||
{$ifndef nounsupported}
|
||||
location_reset(location,LOC_REGISTER,OS_ADDR);
|
||||
location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,java_jlobject);
|
||||
hlcg.a_load_const_reg(current_asmdata.CurrAsmList,java_jlobject,0,location.register);
|
||||
{$else}
|
||||
internalerror(2011051601);
|
||||
{$endif}
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -199,7 +255,7 @@ implementation
|
||||
procedure tjvmloadvmtaddrnode.pass_generate_code;
|
||||
begin
|
||||
current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_ldc,current_asmdata.RefAsmSymbol(
|
||||
tobjectdef(tclassrefdef(resultdef).pointeddef).jvm_full_typename(true))));
|
||||
tabstractrecorddef(tclassrefdef(resultdef).pointeddef).jvm_full_typename(true))));
|
||||
thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,1);
|
||||
location_reset(location,LOC_REGISTER,OS_ADDR);
|
||||
location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef);
|
||||
|
||||
@ -40,6 +40,7 @@ unit tgcpu;
|
||||
|
||||
ttgjvm = class(ttgobj)
|
||||
protected
|
||||
procedure getimplicitobjtemp(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference);
|
||||
function getifspecialtemp(list: TAsmList; def: tdef; forcesize: aint; temptype: ttemptype; out ref: treference): boolean;
|
||||
function alloctemp(list: TAsmList; size, alignment: longint; temptype: ttemptype; def: tdef): longint; override;
|
||||
public
|
||||
@ -61,6 +62,36 @@ unit tgcpu;
|
||||
|
||||
{ ttgjvm }
|
||||
|
||||
procedure ttgjvm.getimplicitobjtemp(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference);
|
||||
var
|
||||
sym: tsym;
|
||||
pd: tprocdef;
|
||||
begin
|
||||
gettemp(list,java_jlobject.size,java_jlobject.alignment,temptype,ref);
|
||||
list.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(tabstractrecorddef(def).jvm_full_typename(true))));
|
||||
{ the constructor doesn't return anything, so put a duplicate of the
|
||||
self pointer on the evaluation stack for use as function result
|
||||
after the constructor has run }
|
||||
list.concat(taicpu.op_none(a_dup));
|
||||
thlcgjvm(hlcg).incstack(list,2);
|
||||
{ call the constructor }
|
||||
sym:=tsym(tabstractrecorddef(def).symtable.find('CREATE'));
|
||||
if assigned(sym) and
|
||||
(sym.typ=procsym) then
|
||||
begin
|
||||
pd:=tprocsym(sym).find_bytype_parameterless(potype_constructor);
|
||||
if not assigned(pd) then
|
||||
internalerror(2011032701);
|
||||
end
|
||||
else
|
||||
internalerror(2011060301);
|
||||
hlcg.a_call_name(list,pd,pd.mangledname,false);
|
||||
thlcgjvm(hlcg).decstack(list,1);
|
||||
{ store reference to instance }
|
||||
thlcgjvm(hlcg).a_load_stack_ref(list,java_jlobject,ref,0);
|
||||
end;
|
||||
|
||||
|
||||
function ttgjvm.getifspecialtemp(list: TAsmList; def: tdef; forcesize: aint; temptype: ttemptype; out ref: treference): boolean;
|
||||
var
|
||||
eledef: tdef;
|
||||
@ -99,28 +130,7 @@ unit tgcpu;
|
||||
end;
|
||||
recorddef:
|
||||
begin
|
||||
gettemp(list,java_jlobject.size,java_jlobject.alignment,temptype,ref);
|
||||
list.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(trecorddef(def).jvm_full_typename(true))));
|
||||
{ the constructor doesn't return anything, so put a duplicate of the
|
||||
self pointer on the evaluation stack for use as function result
|
||||
after the constructor has run }
|
||||
list.concat(taicpu.op_none(a_dup));
|
||||
thlcgjvm(hlcg).incstack(list,2);
|
||||
{ call the constructor }
|
||||
sym:=tsym(trecorddef(def).symtable.find('CREATE'));
|
||||
if assigned(sym) and
|
||||
(sym.typ=procsym) then
|
||||
begin
|
||||
pd:=tprocsym(sym).find_bytype_parameterless(potype_constructor);
|
||||
if not assigned(pd) then
|
||||
internalerror(2011032701);
|
||||
end
|
||||
else
|
||||
internalerror(2011060301);
|
||||
hlcg.a_call_name(list,pd,pd.mangledname,false);
|
||||
thlcgjvm(hlcg).decstack(list,1);
|
||||
{ store reference to instance }
|
||||
thlcgjvm(hlcg).a_load_stack_ref(list,java_jlobject,ref,0);
|
||||
getimplicitobjtemp(list,def,temptype,ref);
|
||||
result:=true;
|
||||
end;
|
||||
setdef:
|
||||
@ -171,6 +181,14 @@ unit tgcpu;
|
||||
thlcgjvm(hlcg).a_load_stack_ref(list,java_jlobject,ref,0);
|
||||
result:=true;
|
||||
end;
|
||||
procvardef:
|
||||
begin
|
||||
if not tprocvardef(def).is_addressonly then
|
||||
begin
|
||||
getimplicitobjtemp(list,tprocvardef(def).classdef,temptype,ref);
|
||||
result:=true;
|
||||
end;
|
||||
end;
|
||||
stringdef:
|
||||
begin
|
||||
if is_shortstring(def) then
|
||||
|
||||
@ -79,6 +79,8 @@ interface
|
||||
procedure jvmgetboxtype(def: tdef; out objdef, paradef: tdef; mergeints: boolean);
|
||||
function jvmgetunboxmethod(def: tdef): string;
|
||||
|
||||
function jvmgetcorrespondingclassdef(def: tdef): tdef;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
@ -338,13 +340,7 @@ implementation
|
||||
end;
|
||||
procvardef :
|
||||
begin
|
||||
{$ifndef nounsupported}
|
||||
result:=jvmaddencodedtype(java_jlobject,false,encodedstr,forcesignature,founderror);
|
||||
{$else}
|
||||
{ will be hanlded via wrapping later, although wrapping may
|
||||
happen at higher level }
|
||||
result:=false;
|
||||
{$endif}
|
||||
result:=jvmaddencodedtype(tprocvardef(def).classdef,false,encodedstr,forcesignature,founderror);
|
||||
end;
|
||||
objectdef :
|
||||
case tobjectdef(def).objecttype of
|
||||
@ -471,6 +467,9 @@ implementation
|
||||
else
|
||||
result:='L'
|
||||
end
|
||||
else if (def.typ=procvardef) and
|
||||
not tprocvardef(def).is_addressonly then
|
||||
result:='P'
|
||||
else
|
||||
begin
|
||||
if not jvmtryencodetype(def,res,false,errdef) then
|
||||
@ -643,6 +642,90 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function jvmgetcorrespondingclassdef(def: tdef): tdef;
|
||||
var
|
||||
paradef: tdef;
|
||||
begin
|
||||
if def.typ in [orddef,floatdef] then
|
||||
jvmgetboxtype(def,result,paradef,false)
|
||||
else
|
||||
begin
|
||||
case def.typ of
|
||||
stringdef :
|
||||
begin
|
||||
case tstringdef(def).stringtype of
|
||||
{ translated into java.lang.String }
|
||||
st_widestring,
|
||||
st_unicodestring:
|
||||
result:=java_jlstring;
|
||||
st_ansistring:
|
||||
result:=java_ansistring;
|
||||
st_shortstring:
|
||||
result:=java_shortstring;
|
||||
else
|
||||
internalerror(2011072409);
|
||||
end;
|
||||
end;
|
||||
enumdef:
|
||||
begin
|
||||
result:=tenumdef(def).classdef;
|
||||
end;
|
||||
pointerdef :
|
||||
begin
|
||||
if def=voidpointertype then
|
||||
result:=java_jlobject
|
||||
else if jvmimplicitpointertype(tpointerdef(def).pointeddef) then
|
||||
result:=tpointerdef(def).pointeddef
|
||||
else
|
||||
internalerror(2011072410);
|
||||
end;
|
||||
recorddef :
|
||||
begin
|
||||
result:=def;
|
||||
end;
|
||||
variantdef :
|
||||
begin
|
||||
result:=cvarianttype;
|
||||
end;
|
||||
classrefdef :
|
||||
begin
|
||||
result:=search_system_type('JLCLASS').typedef;
|
||||
end;
|
||||
setdef :
|
||||
begin
|
||||
if tsetdef(def).elementdef.typ=enumdef then
|
||||
result:=java_juenumset
|
||||
else
|
||||
result:=java_jubitset;
|
||||
end;
|
||||
formaldef :
|
||||
begin
|
||||
result:=java_jlobject;
|
||||
end;
|
||||
arraydef :
|
||||
begin
|
||||
{ cannot represent statically }
|
||||
internalerror(2011072411);
|
||||
end;
|
||||
procvardef :
|
||||
begin
|
||||
result:=tprocvardef(def).classdef;
|
||||
end;
|
||||
objectdef :
|
||||
case tobjectdef(def).objecttype of
|
||||
odt_javaclass,
|
||||
odt_interfacejava:
|
||||
result:=def
|
||||
else
|
||||
internalerror(2011072412);
|
||||
end;
|
||||
else
|
||||
internalerror(2011072413);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function jvmmangledbasename(sym: tsym; const usesymname: TSymStr; withsignature: boolean): TSymStr;
|
||||
var
|
||||
container: tsymtable;
|
||||
|
||||
@ -480,14 +480,6 @@ interface
|
||||
var
|
||||
tmpreg: tregister;
|
||||
begin
|
||||
{$ifdef jvm}
|
||||
{$ifndef nounsupported}
|
||||
location_reset(location,LOC_REGISTER,OS_ADDR);
|
||||
location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,java_jlobject);
|
||||
hlcg.a_load_const_reg(current_asmdata.CurrAsmList,java_jlobject,0,location.register);
|
||||
exit;
|
||||
{$endif nounsupported}
|
||||
{$endif jvm}
|
||||
if tabstractprocdef(resultdef).is_addressonly then
|
||||
begin
|
||||
location_reset(location,LOC_REGISTER,OS_ADDR);
|
||||
|
||||
@ -467,14 +467,6 @@ implementation
|
||||
end;
|
||||
procsym:
|
||||
begin
|
||||
{$ifdef jvm}
|
||||
{$ifndef nounsupported}
|
||||
location_reset(location,LOC_REGISTER,OS_ADDR);
|
||||
location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,java_jlobject);
|
||||
hlcg.a_load_const_reg(current_asmdata.CurrAsmList,java_jlobject,0,location.register);
|
||||
exit;
|
||||
{$endif nounsupported}
|
||||
{$endif jvm}
|
||||
if not assigned(procdef) then
|
||||
internalerror(200312011);
|
||||
if assigned(left) then
|
||||
@ -1083,8 +1075,11 @@ implementation
|
||||
fillchar(paraloc,sizeof(paraloc),0);
|
||||
{ Allocate always a temp, also if no elements are required, to
|
||||
be sure that location is valid (PFV) }
|
||||
{ on the JVM platform, an array can have 0 elements; since the length
|
||||
of the array is part of the array itself, make sure we allocate one
|
||||
of the proper length to avoid getting unexpected results later }
|
||||
if tarraydef(resultdef).highrange=-1 then
|
||||
tg.gethltemp(current_asmdata.CurrAsmList,resultdef,elesize,tt_normal,location.reference)
|
||||
tg.gethltemp(current_asmdata.CurrAsmList,resultdef,{$ifdef jvm}0{$else}elesize{$endif},tt_normal,location.reference)
|
||||
else
|
||||
tg.gethltemp(current_asmdata.CurrAsmList,resultdef,(tarraydef(resultdef).highrange+1)*elesize,tt_normal,location.reference);
|
||||
href:=location.reference;
|
||||
|
||||
@ -1823,22 +1823,6 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
procedure copyparasym(p:TObject;arg:pointer);
|
||||
var
|
||||
newparast : TSymtable absolute arg;
|
||||
vs : tparavarsym;
|
||||
begin
|
||||
if tsym(p).typ<>paravarsym then
|
||||
exit;
|
||||
with tparavarsym(p) do
|
||||
begin
|
||||
vs:=tparavarsym.create(realname,paranr,varspez,vardef,varoptions);
|
||||
vs.defaultconstsym:=defaultconstsym;
|
||||
newparast.insert(vs);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function ttypeconvnode.typecheck_proc_to_procvar : tnode;
|
||||
var
|
||||
pd : tabstractprocdef;
|
||||
@ -1856,15 +1840,7 @@ implementation
|
||||
resultdef:=totypedef
|
||||
else
|
||||
begin
|
||||
nestinglevel:=pd.parast.symtablelevel;
|
||||
resultdef:=tprocvardef.create(nestinglevel);
|
||||
tprocvardef(resultdef).proctypeoption:=pd.proctypeoption;
|
||||
tprocvardef(resultdef).proccalloption:=pd.proccalloption;
|
||||
tprocvardef(resultdef).procoptions:=pd.procoptions;
|
||||
tprocvardef(resultdef).returndef:=pd.returndef;
|
||||
{ method ? then set the methodpointer flag }
|
||||
if (pd.owner.symtabletype=ObjectSymtable) then
|
||||
include(tprocvardef(resultdef).procoptions,po_methodpointer);
|
||||
resultdef:=pd.getcopyas(procvardef,pc_normal);
|
||||
{ only need the address of the method? this is needed
|
||||
for @tobject.create. In this case there will be a loadn without
|
||||
a methodpointer. }
|
||||
@ -1873,11 +1849,7 @@ implementation
|
||||
(not(m_nested_procvars in current_settings.modeswitches) or
|
||||
not is_nested_pd(tprocvardef(resultdef))) then
|
||||
include(tprocvardef(resultdef).procoptions,po_addressonly);
|
||||
|
||||
{ Add parameters use only references, we don't need to keep the
|
||||
parast. We use the parast from the original function to calculate
|
||||
our parameter data and reset it afterwards }
|
||||
pd.parast.SymList.ForEachCall(@copyparasym,tprocvardef(resultdef).parast);
|
||||
{ calculate parameter list & order }
|
||||
tprocvardef(resultdef).calcparas;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -491,6 +491,9 @@ implementation
|
||||
special handling }
|
||||
if (left.resultdef.typ=procdef) or
|
||||
(
|
||||
{ in case of nf_internal, follow the normal FPC semantics so that
|
||||
we can easily get the actual address of a procvar }
|
||||
not(nf_internal in flags) and
|
||||
(left.resultdef.typ=procvardef) and
|
||||
((m_tp_procvar in current_settings.modeswitches) or
|
||||
(m_mac_procvar in current_settings.modeswitches))
|
||||
|
||||
@ -1288,6 +1288,9 @@ implementation
|
||||
fsym:=tfieldvarsym.create('$proc',vs_value,java_jlobject,[]);
|
||||
hrecst.insert(fsym);
|
||||
hrecst.addfield(fsym,vis_hidden);
|
||||
fsym:=tfieldvarsym.create('$data',vs_value,java_jlobject,[]);
|
||||
hrecst.insert(fsym);
|
||||
hrecst.addfield(fsym,vis_hidden);
|
||||
methodpointertype:=trecorddef.create('',hrecst);
|
||||
systemunit.insert(ttypesym.create('$methodpointer',methodpointertype));
|
||||
end
|
||||
@ -1307,6 +1310,8 @@ implementation
|
||||
java_juenumset:=current_objectdef
|
||||
else if (current_objectdef.objname^='FPCBITSET') then
|
||||
java_jubitset:=current_objectdef
|
||||
else if (current_objectdef.objname^='FPCBASEPROCVARTYPE') then
|
||||
java_procvarbase:=current_objectdef;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -93,6 +93,9 @@ implementation
|
||||
{ parser }
|
||||
scanner,
|
||||
pbase,pexpr,ptype,pdecl,pparautl
|
||||
{$ifdef jvm}
|
||||
,pjvm
|
||||
{$endif}
|
||||
;
|
||||
|
||||
const
|
||||
@ -311,6 +314,10 @@ implementation
|
||||
end;
|
||||
{ Add implicit hidden parameters and function result }
|
||||
handle_calling_convention(pv);
|
||||
{$ifdef jvm}
|
||||
{ anonymous -> no name }
|
||||
jvm_create_procvar_class('',pv);
|
||||
{$endif}
|
||||
end
|
||||
else
|
||||
{ read type declaration, force reading for value paras }
|
||||
|
||||
@ -40,6 +40,7 @@ interface
|
||||
procedure add_java_default_record_methods_intf(def: trecorddef);
|
||||
|
||||
procedure jvm_maybe_create_enum_class(const name: TIDString; def: tdef);
|
||||
procedure jvm_create_procvar_class(const name: TIDString; def: tdef);
|
||||
|
||||
function jvm_add_typed_const_initializer(csym: tconstsym): tstaticvarsym;
|
||||
|
||||
@ -53,7 +54,7 @@ implementation
|
||||
verbose,systems,
|
||||
fmodule,
|
||||
parabase,aasmdata,
|
||||
pdecsub,ngenutil,
|
||||
pdecsub,ngenutil,pparautl,
|
||||
symtable,symcreat,defcmp,jvmdef,
|
||||
defutil,paramgr;
|
||||
|
||||
@ -208,6 +209,36 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
procedure setup_for_new_class(const scannername: string; out sstate: tscannerstate; out islocal: boolean; out oldsymtablestack: TSymtablestack);
|
||||
begin
|
||||
replace_scanner(scannername,sstate);
|
||||
oldsymtablestack:=symtablestack;
|
||||
islocal:=symtablestack.top.symtablelevel>=normal_function_level;
|
||||
if islocal then
|
||||
begin
|
||||
{ we cannot add a class local to a procedure -> insert it in the
|
||||
static symtable. This is not ideal because this means that it will
|
||||
be saved to the ppu file for no good reason, and loaded again
|
||||
even though it contains a reference to a type that was never
|
||||
saved to the ppu file (the locally defined enum type). Since this
|
||||
alias for the locally defined enumtype is only used while
|
||||
implementing the class' methods, this is however no problem. }
|
||||
symtablestack:=symtablestack.getcopyuntil(current_module.localsymtable);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure restore_after_new_class(const sstate: tscannerstate; const islocal: boolean; const oldsymtablestack: TSymtablestack);
|
||||
begin
|
||||
if islocal then
|
||||
begin
|
||||
symtablestack.free;
|
||||
symtablestack:=oldsymtablestack;
|
||||
end;
|
||||
restore_scanner(sstate);
|
||||
end;
|
||||
|
||||
|
||||
procedure jvm_maybe_create_enum_class(const name: TIDString; def: tdef);
|
||||
var
|
||||
arrdef: tarraydef;
|
||||
@ -228,20 +259,8 @@ implementation
|
||||
{ if it's a subrange type, don't create a new class }
|
||||
if assigned(tenumdef(def).basedef) then
|
||||
exit;
|
||||
replace_scanner('jvm_enum_class',sstate);
|
||||
oldsymtablestack:=symtablestack;
|
||||
islocal:=symtablestack.top.symtablelevel>=normal_function_level;
|
||||
if islocal then
|
||||
begin
|
||||
{ we cannot add a class local to a procedure -> insert it in the
|
||||
static symtable. This is not ideal because this means that it will
|
||||
be saved to the ppu file for no good reason, and loaded again
|
||||
even though it contains a reference to a type that was never
|
||||
saved to the ppu file (the locally defined enum type). Since this
|
||||
alias for the locally defined enumtype is only used while
|
||||
implementing the class' methods, this is however no problem. }
|
||||
symtablestack:=symtablestack.getcopyuntil(current_module.localsymtable);
|
||||
end;
|
||||
|
||||
setup_for_new_class('jvm_enum_class',sstate,islocal,oldsymtablestack);
|
||||
|
||||
{ create new class (different internal name than enum to prevent name
|
||||
clash; at unit level because we don't want its methods to be nested
|
||||
@ -396,13 +415,65 @@ implementation
|
||||
pd.synthetickind:=tsk_jvm_enum_classconstr;
|
||||
|
||||
symtablestack.pop(enumclass.symtable);
|
||||
if islocal then
|
||||
begin
|
||||
symtablestack.free;
|
||||
symtablestack:=oldsymtablestack;
|
||||
end;
|
||||
restore_after_new_class(sstate,islocal,oldsymtablestack);
|
||||
current_structdef:=old_current_structdef;
|
||||
restore_scanner(sstate);
|
||||
end;
|
||||
|
||||
|
||||
procedure jvm_create_procvar_class(const name: TIDString; def: tdef);
|
||||
var
|
||||
oldsymtablestack: tsymtablestack;
|
||||
pvclass: tobjectdef;
|
||||
temptypesym: ttypesym;
|
||||
sstate: tscannerstate;
|
||||
methoddef: tprocdef;
|
||||
islocal: boolean;
|
||||
begin
|
||||
{ inlined definition of procvar -> generate name, derive from
|
||||
FpcBaseNestedProcVarType, pass nestedfpstruct to constructor and
|
||||
copy it }
|
||||
if name='' then
|
||||
internalerror(2011071901);
|
||||
|
||||
setup_for_new_class('jvm_pvar_class',sstate,islocal,oldsymtablestack);
|
||||
|
||||
{ create new class (different internal name than pvar to prevent name
|
||||
clash; at unit level because we don't want its methods to be nested
|
||||
inside a function in case its a local type) }
|
||||
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);
|
||||
{ associate typesym }
|
||||
pvclass.symtable.insert(ttypesym.create('__FPC_TProcVarClassAlias',pvclass));
|
||||
{ set external name to match procvar type name }
|
||||
if not islocal then
|
||||
pvclass.objextname:=stringdup(name)
|
||||
else
|
||||
pvclass.objextname:=stringdup(pvclass.objrealname^);
|
||||
|
||||
symtablestack.push(pvclass.symtable);
|
||||
|
||||
{ inherit constructor and keep public }
|
||||
add_missing_parent_constructors_intf(pvclass,vis_public);
|
||||
|
||||
{ add a method to call the procvar using unwrapped arguments, which
|
||||
then wraps them and calls through to JLRMethod.invoke }
|
||||
methoddef:=tprocdef(tprocvardef(def).getcopyas(procdef,pc_procvar2bareproc));
|
||||
finish_copied_procdef(methoddef,'invoke',pvclass.symtable,pvclass);
|
||||
insert_self_and_vmt_para(methoddef);
|
||||
methoddef.synthetickind:=tsk_jvm_procvar_invoke;
|
||||
methoddef.calcparas;
|
||||
|
||||
{ add local alias for the procvartype that we can use when implementing
|
||||
the invoke method }
|
||||
temptypesym:=ttypesym.create('__FPC_ProcVarAlias',nil);
|
||||
{ don't pass def to the ttypesym constructor, because then it
|
||||
will replace the current (real) typesym of that def with the alias }
|
||||
temptypesym.typedef:=def;
|
||||
pvclass.symtable.insert(temptypesym);
|
||||
|
||||
symtablestack.pop(pvclass.symtable);
|
||||
restore_after_new_class(sstate,islocal,oldsymtablestack);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
@ -684,6 +684,24 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
{$ifdef jvm}
|
||||
procedure addmoduleclass;
|
||||
var
|
||||
def: tobjectdef;
|
||||
typesym: ttypesym;
|
||||
begin
|
||||
{ java_jlobject may not have been parsed yet (system unit); in any
|
||||
case, we only use this to refer to the class type, so inheritance
|
||||
does not matter }
|
||||
def:=tobjectdef.create(odt_javaclass,'__FPC_JVM_Module_Class_Alias$',nil);
|
||||
include(def.objectoptions,oo_is_external);
|
||||
include(def.objectoptions,oo_is_sealed);
|
||||
def.objextname:=stringdup(current_module.realmodulename^);
|
||||
typesym:=ttypesym.create('__FPC_JVM_Module_Class_Alias$',def);
|
||||
symtablestack.top.insert(typesym);
|
||||
end;
|
||||
{$endif jvm}
|
||||
|
||||
procedure proc_unit;
|
||||
|
||||
function is_assembler_generated:boolean;
|
||||
@ -835,6 +853,10 @@ implementation
|
||||
{ ... parse the declarations }
|
||||
Message1(parser_u_parsing_interface,current_module.realmodulename^);
|
||||
symtablestack.push(current_module.globalsymtable);
|
||||
{$ifdef jvm}
|
||||
{ fake classdef to represent the class corresponding to the unit }
|
||||
addmoduleclass;
|
||||
{$endif}
|
||||
read_interface_declarations;
|
||||
symtablestack.pop(current_module.globalsymtable);
|
||||
|
||||
@ -1813,6 +1835,11 @@ implementation
|
||||
|
||||
symtablestack.push(current_module.localsymtable);
|
||||
|
||||
{$ifdef jvm}
|
||||
{ fake classdef to represent the class corresponding to the unit }
|
||||
addmoduleclass;
|
||||
{$endif}
|
||||
|
||||
{ Insert _GLOBAL_OFFSET_TABLE_ symbol if system uses it }
|
||||
maybe_load_got;
|
||||
|
||||
|
||||
@ -1724,6 +1724,9 @@ implementation
|
||||
_FUNCTION:
|
||||
begin
|
||||
def:=procvar_dec(genericdef,genericlist);
|
||||
{$ifdef jvm}
|
||||
jvm_create_procvar_class(name,def);
|
||||
{$endif}
|
||||
end;
|
||||
else
|
||||
if (token=_KLAMMERAFFE) and (m_iso in current_settings.modeswitches) then
|
||||
|
||||
@ -113,7 +113,7 @@ implementation
|
||||
symtable,defutil,
|
||||
pbase,pdecobj,pdecsub,psub,ptconst,
|
||||
{$ifdef jvm}
|
||||
pjvm,
|
||||
pjvm,jvmdef,
|
||||
{$endif jvm}
|
||||
node,nbas,nld,nmem,
|
||||
defcmp,
|
||||
@ -623,12 +623,114 @@ implementation
|
||||
'ele:=FpcEnumValueObtainable(it.next);'+
|
||||
'i:=ele.fpcOrdinal-__fromsetbase;'+
|
||||
'result.add(fpcValueOf(i+__tosetbase));'+
|
||||
'end '+
|
||||
'end '+
|
||||
'end;',
|
||||
pd,true);
|
||||
end;
|
||||
|
||||
|
||||
procedure implement_jvm_procvar_invoke(pd: tprocdef);
|
||||
{$ifdef jvm}
|
||||
var
|
||||
pvclass: tobjectdef;
|
||||
procvar: tprocvardef;
|
||||
paraname,str,endstr: ansistring;
|
||||
pvs: tparavarsym;
|
||||
paradef,boxdef,boxargdef: tdef;
|
||||
i: longint;
|
||||
firstpara: boolean;
|
||||
{$endif jvm}
|
||||
begin
|
||||
{$ifndef jvm}
|
||||
internalerror(2011072401);
|
||||
{$else not jvm}
|
||||
pvclass:=tobjectdef(pd.owner.defowner);
|
||||
procvar:=tprocvardef(ttypesym(search_struct_member(pvclass,'__FPC_PROCVARALIAS')).typedef);
|
||||
{ the procvar wrapper class has a tmethod member called "method", whose
|
||||
"code" field is a JLRMethod, and whose "data" field is the self pointer
|
||||
if any (if none is required, it's ignored by the JVM, so there's no
|
||||
problem with always passing it) }
|
||||
|
||||
{ force extended syntax to allow calling invokeObjectFunc() without using
|
||||
its result }
|
||||
str:='';
|
||||
endstr:='';
|
||||
{ create local pointer to result type for typecasting in case of an
|
||||
implicit pointer type }
|
||||
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
|
||||
begin
|
||||
str:=str+'invoke:=';
|
||||
if procvar.returndef.typ in [orddef,floatdef] then
|
||||
begin
|
||||
{ primitivetype(boxtype(..).unboxmethod) }
|
||||
jvmgetboxtype(procvar.returndef,boxdef,boxargdef,false);
|
||||
str:=str+procvar.returndef.typename+'('+boxdef.typename+'(';
|
||||
endstr:=').'+jvmgetunboxmethod(procvar.returndef)+')';
|
||||
end
|
||||
else if jvmimplicitpointertype(procvar.returndef) then
|
||||
begin
|
||||
str:=str+'__FPC_returnptrtype(';
|
||||
{ dereference }
|
||||
endstr:=')^';
|
||||
end
|
||||
else
|
||||
begin
|
||||
str:=str+procvar.returndef.typename+'(';
|
||||
endstr:=')';
|
||||
end;
|
||||
end;
|
||||
str:=str+'invokeObjectFunc([';
|
||||
{ parameters are a constant array of jlobject }
|
||||
firstpara:=true;
|
||||
for i:=0 to procvar.paras.count-1 do
|
||||
begin
|
||||
{ skip self/vmt/parentfp, passed separately }
|
||||
pvs:=tparavarsym(procvar.paras[i]);
|
||||
if ([vo_is_self,vo_is_vmt,vo_is_parentfp]*pvs.varoptions)<>[] then
|
||||
continue;
|
||||
if not firstpara then
|
||||
str:=str+',';
|
||||
firstpara:=false;
|
||||
paraname:=pvs.realname;
|
||||
paradef:=pvs.vardef;
|
||||
{ Pascalize hidden high parameter }
|
||||
if vo_is_high_para in pvs.varoptions then
|
||||
paraname:='high('+tparavarsym(procvar.paras[i-1]).realname+')'
|
||||
else if vo_is_hidden_para in pvs.varoptions then
|
||||
begin
|
||||
if ([vo_is_range_check,vo_is_overflow_check]*pvs.varoptions)<>[] then
|
||||
{ ok, simple boolean parameters }
|
||||
else
|
||||
internalerror(2011072403);
|
||||
end;
|
||||
{ var/out/constref parameters -> pass address through (same for
|
||||
implicit pointer types) }
|
||||
if paramanager.push_addr_param(pvs.varspez,paradef,procvar.proccalloption) or
|
||||
jvmimplicitpointertype(paradef) then
|
||||
begin
|
||||
paraname:='@'+paraname;
|
||||
paradef:=java_jlobject;
|
||||
end;
|
||||
if paradef.typ in [orddef,floatdef] then
|
||||
begin
|
||||
{ box primitive types; use valueOf() rather than create because it
|
||||
can give better performance }
|
||||
jvmgetboxtype(paradef,boxdef,boxargdef,false);
|
||||
str:=str+boxdef.typename+'.valueOf('+boxargdef.typename+'('+paraname+'))'
|
||||
end
|
||||
else
|
||||
str:=str+'JLObject('+paraname+')';
|
||||
end;
|
||||
str:=str+'])'+endstr+' end;';
|
||||
str_parse_method_impl(str,pd,false)
|
||||
{$endif not jvm}
|
||||
end;
|
||||
|
||||
|
||||
procedure add_synthetic_method_implementations_for_struct(struct: tabstractrecorddef);
|
||||
var
|
||||
i : longint;
|
||||
@ -676,6 +778,8 @@ implementation
|
||||
implement_jvm_enum_bitset2set(pd);
|
||||
tsk_jvm_enum_set2set:
|
||||
implement_jvm_enum_set2set(pd);
|
||||
tsk_jvm_procvar_invoke:
|
||||
implement_jvm_procvar_invoke(pd);
|
||||
else
|
||||
internalerror(2011032801);
|
||||
end;
|
||||
@ -747,22 +851,27 @@ implementation
|
||||
if assigned(newstruct) then
|
||||
begin
|
||||
symtablestack.push(pd.parast);
|
||||
for i:=0 to pd.paras.count-1 do
|
||||
{ may not be assigned in case we converted a procvar into a procdef }
|
||||
if assigned(pd.paras) then
|
||||
begin
|
||||
parasym:=tparavarsym(pd.paras[i]);
|
||||
if vo_is_self in parasym.varoptions then
|
||||
for i:=0 to pd.paras.count-1 do
|
||||
begin
|
||||
if parasym.vardef.typ=classrefdef then
|
||||
parasym.vardef:=tclassrefdef.create(newstruct)
|
||||
else
|
||||
parasym.vardef:=newstruct;
|
||||
end
|
||||
parasym:=tparavarsym(pd.paras[i]);
|
||||
if vo_is_self in parasym.varoptions then
|
||||
begin
|
||||
if parasym.vardef.typ=classrefdef then
|
||||
parasym.vardef:=tclassrefdef.create(newstruct)
|
||||
else
|
||||
parasym.vardef:=newstruct;
|
||||
end
|
||||
end;
|
||||
end;
|
||||
{ also fix returndef in case of a constructor }
|
||||
if pd.proctypeoption=potype_constructor then
|
||||
pd.returndef:=newstruct;
|
||||
symtablestack.pop(pd.parast);
|
||||
end;
|
||||
pd.calcparas;
|
||||
proc_add_definition(pd);
|
||||
end;
|
||||
|
||||
|
||||
@ -427,6 +427,10 @@ interface
|
||||
tprocnameoption = (pno_showhidden, pno_proctypeoption, pno_paranames,
|
||||
pno_ownername, pno_noclassmarker, pno_noleadingdollar);
|
||||
tprocnameoptions = set of tprocnameoption;
|
||||
tproccopytyp = (pc_normal,
|
||||
{ always creates a top-level function, removes all
|
||||
special parameters (self, vmt, parentfp, ...) }
|
||||
pc_procvar2bareproc);
|
||||
|
||||
tabstractprocdef = class(tstoreddef)
|
||||
{ saves a definition to the return type }
|
||||
@ -458,6 +462,8 @@ interface
|
||||
function is_methodpointer:boolean;virtual;
|
||||
function is_addressonly:boolean;virtual;
|
||||
function no_self_node:boolean;
|
||||
{ get either a copy as a procdef or procvardef }
|
||||
function getcopyas(newtyp:tdeftyp;copytyp:tproccopytyp): tstoreddef;
|
||||
procedure check_mark_as_nested;
|
||||
procedure init_paraloc_info(side: tcallercallee);
|
||||
function stack_tainting_parameter(side: tcallercallee): boolean;
|
||||
@ -467,10 +473,19 @@ interface
|
||||
end;
|
||||
|
||||
tprocvardef = class(tabstractprocdef)
|
||||
{$ifdef jvm}
|
||||
{ class representing this procvar on the Java side }
|
||||
classdef : tobjectdef;
|
||||
classdefderef : tderef;
|
||||
{$endif}
|
||||
constructor create(level:byte);
|
||||
constructor ppuload(ppufile:tcompilerppufile);
|
||||
function getcopy : tstoreddef;override;
|
||||
procedure ppuwrite(ppufile:tcompilerppufile);override;
|
||||
{$ifdef jvm}
|
||||
procedure buildderef;override;
|
||||
procedure deref;override;
|
||||
{$endif}
|
||||
function GetSymtable(t:tGetSymtable):TSymtable;override;
|
||||
function size : asizeint;override;
|
||||
function GetTypeName:string;override;
|
||||
@ -511,7 +526,8 @@ interface
|
||||
tsk_jvm_enum_fpcvalueof, // Java FPCValueOf function that returns the enum instance corresponding to an ordinal from an FPC POV
|
||||
tsk_jvm_enum_long2set, // Java fpcLongToEnumSet function that returns an enumset corresponding to a bit pattern in a jlong
|
||||
tsk_jvm_enum_bitset2set, // Java fpcBitSetToEnumSet function that returns an enumset corresponding to a BitSet
|
||||
tsk_jvm_enum_set2Set // Java fpcEnumSetToEnumSet function that returns an enumset corresponding to another enumset (different enum kind)
|
||||
tsk_jvm_enum_set2Set, // Java fpcEnumSetToEnumSet function that returns an enumset corresponding to another enumset (different enum kind)
|
||||
tsk_jvm_procvar_invoke // Java invoke method that calls a wrapped procvar
|
||||
);
|
||||
|
||||
{$ifdef oldregvars}
|
||||
@ -853,6 +869,8 @@ interface
|
||||
java_ansistring : tobjectdef;
|
||||
{ FPC java implementation of shortstrings }
|
||||
java_shortstring : tobjectdef;
|
||||
{ FPC java procvar base class }
|
||||
java_procvarbase : tobjectdef;
|
||||
|
||||
const
|
||||
{$ifdef i386}
|
||||
@ -3663,6 +3681,81 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function tabstractprocdef.getcopyas(newtyp:tdeftyp;copytyp:tproccopytyp): tstoreddef;
|
||||
var
|
||||
j, nestinglevel: longint;
|
||||
pvs, npvs: tparavarsym;
|
||||
csym, ncsym: tconstsym;
|
||||
begin
|
||||
nestinglevel:=parast.symtablelevel;
|
||||
if newtyp=procdef then
|
||||
begin
|
||||
if (typ=procdef) or
|
||||
(copytyp<>pc_procvar2bareproc) then
|
||||
result:=tprocdef.create(nestinglevel)
|
||||
else
|
||||
result:=tprocdef.create(normal_function_level);
|
||||
tprocdef(result).visibility:=vis_public;
|
||||
end
|
||||
else
|
||||
begin
|
||||
result:=tprocvardef.create(nestinglevel);
|
||||
end;
|
||||
tabstractprocdef(result).returndef:=returndef;
|
||||
tabstractprocdef(result).returndefderef:=returndefderef;
|
||||
tabstractprocdef(result).parast:=tparasymtable.create(tabstractprocdef(result),parast.symtablelevel);
|
||||
pvs:=nil;
|
||||
npvs:=nil;
|
||||
for j:=0 to parast.symlist.count-1 do
|
||||
begin
|
||||
case tsym(parast.symlist[j]).typ of
|
||||
paravarsym:
|
||||
begin
|
||||
pvs:=tparavarsym(parast.symlist[j]);
|
||||
{ in case of bare proc, don't copy self, vmt or framepointer
|
||||
parameters }
|
||||
if (copytyp=pc_procvar2bareproc) and
|
||||
(([vo_is_self,vo_is_vmt,vo_is_parentfp,vo_is_result]*pvs.varoptions)<>[]) then
|
||||
continue;
|
||||
npvs:=tparavarsym.create(pvs.realname,pvs.paranr,pvs.varspez,
|
||||
pvs.vardef,pvs.varoptions);
|
||||
npvs.defaultconstsym:=pvs.defaultconstsym;
|
||||
tabstractprocdef(result).parast.insert(npvs);
|
||||
end;
|
||||
constsym:
|
||||
begin
|
||||
// ignore, reuse original constym. Should also be duplicated
|
||||
// be safe though
|
||||
end
|
||||
else
|
||||
internalerror(201160604);
|
||||
end;
|
||||
end;
|
||||
tabstractprocdef(result).savesize:=savesize;
|
||||
|
||||
tabstractprocdef(result).proctypeoption:=proctypeoption;
|
||||
tabstractprocdef(result).proccalloption:=proccalloption;
|
||||
tabstractprocdef(result).procoptions:=procoptions;
|
||||
if (copytyp=pc_procvar2bareproc) then
|
||||
tabstractprocdef(result).procoptions:=tabstractprocdef(result).procoptions*[po_explicitparaloc,po_hascallingconvention,po_varargs,po_iocheck];
|
||||
tabstractprocdef(result).callerargareasize:=callerargareasize;
|
||||
tabstractprocdef(result).calleeargareasize:=calleeargareasize;
|
||||
tabstractprocdef(result).maxparacount:=maxparacount;
|
||||
tabstractprocdef(result).minparacount:=minparacount;
|
||||
if po_explicitparaloc in procoptions then
|
||||
tabstractprocdef(result).funcretloc[callerside]:=funcretloc[callerside].getcopy;
|
||||
{ recalculate parameter info }
|
||||
tabstractprocdef(result).has_paraloc_info:=callnoside;
|
||||
{$ifdef m68k}
|
||||
tabstractprocdef(result).exp_funcretloc:=exp_funcretloc;
|
||||
{$endif}
|
||||
if (typ=procdef) and
|
||||
(newtyp=procvardef) and
|
||||
(owner.symtabletype=ObjectSymtable) then
|
||||
include(tprocvardef(result).procoptions,po_methodpointer);
|
||||
end;
|
||||
|
||||
|
||||
procedure tabstractprocdef.check_mark_as_nested;
|
||||
begin
|
||||
{ nested procvars require that nested functions use the Delphi-style
|
||||
@ -4143,42 +4236,10 @@ implementation
|
||||
j : longint;
|
||||
pvs : tparavarsym;
|
||||
begin
|
||||
result:=tprocdef.create(parast.symtablelevel);
|
||||
tprocdef(result).dispid:=dispid;
|
||||
tprocdef(result).returndef:=returndef;
|
||||
tprocdef(result).returndefderef:=returndefderef;
|
||||
tprocdef(result).parast:=tparasymtable.create(tprocdef(result),parast.symtablelevel);
|
||||
for j:=0 to parast.symlist.count-1 do
|
||||
begin
|
||||
case tsym(parast.symlist[j]).typ of
|
||||
paravarsym:
|
||||
begin
|
||||
pvs:=tparavarsym(parast.symlist[j]);
|
||||
tprocdef(result).parast.insert(tparavarsym.create(
|
||||
pvs.realname,pvs.paranr,pvs.varspez,pvs.vardef,pvs.varoptions));
|
||||
end;
|
||||
else
|
||||
internalerror(201160604);
|
||||
end;
|
||||
end;
|
||||
tprocdef(result).savesize:=savesize;
|
||||
|
||||
tprocdef(result).proctypeoption:=proctypeoption;
|
||||
tprocdef(result).proccalloption:=proccalloption;
|
||||
tprocdef(result).procoptions:=procoptions;
|
||||
tprocdef(result).callerargareasize:=callerargareasize;
|
||||
tprocdef(result).calleeargareasize:=calleeargareasize;
|
||||
tprocdef(result).maxparacount:=maxparacount;
|
||||
tprocdef(result).minparacount:=minparacount;
|
||||
if po_explicitparaloc in procoptions then
|
||||
tprocdef(result).funcretloc[callerside]:=funcretloc[callerside].getcopy;
|
||||
{ recalculate parameter info }
|
||||
tprocdef(result).has_paraloc_info:=callnoside;
|
||||
{$ifdef m68k}
|
||||
tprocdef(result).exp_funcretloc:=exp_funcretloc;
|
||||
{$endif}
|
||||
result:=inherited getcopyas(procdef,pc_normal);
|
||||
{ don't copy mangled name, can be different }
|
||||
tprocdef(result).messageinf:=messageinf;
|
||||
tprocdef(result).dispid:=dispid;
|
||||
if po_msgstr in procoptions then
|
||||
tprocdef(result).messageinf.str:=stringdup(messageinf.str^);
|
||||
tprocdef(result).symoptions:=symoptions;
|
||||
@ -4741,6 +4802,9 @@ implementation
|
||||
inherited ppuload(procvardef,ppufile);
|
||||
{ load para symtable }
|
||||
parast:=tparasymtable.create(self,ppufile.getbyte);
|
||||
{$ifdef jvm}
|
||||
ppufile.getderef(classdefderef);
|
||||
{$endif}
|
||||
tparasymtable(parast).ppuload(ppufile);
|
||||
end;
|
||||
|
||||
@ -4774,6 +4838,9 @@ implementation
|
||||
tprocvardef(result).has_paraloc_info:=has_paraloc_info;
|
||||
{$ifdef m68k}
|
||||
tprocvardef(result).exp_funcretloc:=exp_funcretloc;
|
||||
{$endif}
|
||||
{$ifdef jvm}
|
||||
tprocvardef(result).classdef:=classdef;
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
@ -4786,6 +4853,9 @@ implementation
|
||||
procvars) }
|
||||
ppufile.putbyte(parast.symtablelevel);
|
||||
|
||||
{$ifdef jvm}
|
||||
ppufile.putderef(classdefderef);
|
||||
{$endif}
|
||||
{ Write this entry }
|
||||
ppufile.writeentry(ibprocvardef);
|
||||
|
||||
@ -4793,6 +4863,20 @@ implementation
|
||||
tparasymtable(parast).ppuwrite(ppufile);
|
||||
end;
|
||||
|
||||
{$ifdef jvm}
|
||||
procedure tprocvardef.buildderef;
|
||||
begin
|
||||
inherited buildderef;
|
||||
classdefderef.build(classdef);
|
||||
end;
|
||||
|
||||
procedure tprocvardef.deref;
|
||||
begin
|
||||
inherited deref;
|
||||
classdef:=tobjectdef(classdefderef.resolve);
|
||||
end;
|
||||
{$endif}
|
||||
|
||||
|
||||
function tprocvardef.GetSymtable(t:tGetSymtable):TSymtable;
|
||||
begin
|
||||
@ -5014,6 +5098,8 @@ implementation
|
||||
java_juenumset:=self
|
||||
else if (objname^='FPCBITSET') then
|
||||
java_jubitset:=self
|
||||
else if (objname^='FPCBASEPROCVARTYPE') then
|
||||
java_procvarbase:=self;
|
||||
end;
|
||||
writing_class_record_dbginfo:=false;
|
||||
end;
|
||||
|
||||
@ -628,6 +628,7 @@ procedure fpc_initialize_array_ansistring(arr: TJObjectArray; normalarrdim: long
|
||||
level elements types of the array) }
|
||||
procedure fpc_initialize_array_dynarr(arr: TJObjectArray; normalarrdim: longint);compilerproc;
|
||||
procedure fpc_initialize_array_record(arr: TJObjectArray; normalarrdim: longint; inst: FpcBaseRecordType);compilerproc;
|
||||
procedure fpc_initialize_array_procvar(arr: TJObjectArray; normalarrdim: longint; inst: FpcBaseProcVarType);compilerproc;
|
||||
procedure fpc_initialize_array_bitset(arr: TJObjectArray; normalarrdim: longint; inst: FpcBitSet);compilerproc;
|
||||
procedure fpc_initialize_array_enumset(arr: TJObjectArray; normalarrdim: longint; inst: JUEnumSet);compilerproc;
|
||||
procedure fpc_initialize_array_shortstring(arr: TJObjectArray; normalarrdim: longint; maxlen: byte);compilerproc;
|
||||
|
||||
@ -116,6 +116,16 @@
|
||||
function getTypeParameters(): Arr1JLRTypeVariable; overload;
|
||||
end;
|
||||
|
||||
JLRMember = interface external 'java.lang.reflect' name 'Member'
|
||||
const
|
||||
&PUBLIC = 0;
|
||||
DECLARED = 1;
|
||||
function getDeclaringClass(): JLClass; overload;
|
||||
function getName(): JLString; overload;
|
||||
function getModifiers(): jint; overload;
|
||||
function isSynthetic(): jboolean; overload;
|
||||
end;
|
||||
|
||||
JLRType = interface external 'java.lang.reflect' name 'Type'
|
||||
end;
|
||||
|
||||
@ -1011,6 +1021,21 @@
|
||||
function hashCode(): jint; overload;
|
||||
end;
|
||||
|
||||
JLRAccessibleObject = class external 'java.lang.reflect' name 'AccessibleObject' (JLObject, JLRAnnotatedElement)
|
||||
public
|
||||
class procedure setAccessible(para1: Arr1JLRAccessibleObject; para2: jboolean); static; overload; // throws java.lang.SecurityException
|
||||
class procedure setAccessible(var para1: array of JLRAccessibleObject; para2: jboolean); static; overload; // throws java.lang.SecurityException
|
||||
procedure setAccessible(para1: jboolean); overload; virtual; // throws java.lang.SecurityException
|
||||
function isAccessible(): jboolean; overload; virtual;
|
||||
strict protected
|
||||
constructor create(); overload;
|
||||
public
|
||||
function getAnnotation(para1: JLClass): JLAAnnotation; overload; virtual;
|
||||
function isAnnotationPresent(para1: JLClass): jboolean; overload; virtual;
|
||||
function getAnnotations(): Arr1JLAAnnotation; overload; virtual;
|
||||
function getDeclaredAnnotations(): Arr1JLAAnnotation; overload; virtual;
|
||||
end;
|
||||
|
||||
JLClass = class sealed external 'java.lang' name 'Class' (JLObject, JISerializable, JLRGenericDeclaration, JLRType, JLRAnnotatedElement)
|
||||
public
|
||||
type
|
||||
@ -1739,6 +1764,33 @@
|
||||
function hashCode(): jint; overload;
|
||||
end;
|
||||
|
||||
JLRMethod = class sealed external 'java.lang.reflect' name 'Method' (JLRAccessibleObject, JLRGenericDeclaration, JLRMember)
|
||||
public
|
||||
function getDeclaringClass(): JLClass; overload; virtual;
|
||||
function getName(): JLString; overload; virtual;
|
||||
function getModifiers(): jint; overload; virtual;
|
||||
function getTypeParameters(): Arr1JLRTypeVariable; overload; virtual;
|
||||
function getReturnType(): JLClass; overload; virtual;
|
||||
function getGenericReturnType(): JLRType; overload; virtual;
|
||||
function getParameterTypes(): Arr1JLClass; overload; virtual;
|
||||
function getGenericParameterTypes(): Arr1JLRType; overload; virtual;
|
||||
function getExceptionTypes(): Arr1JLClass; overload; virtual;
|
||||
function getGenericExceptionTypes(): Arr1JLRType; overload; virtual;
|
||||
function equals(para1: JLObject): jboolean; overload; virtual;
|
||||
function hashCode(): jint; overload; virtual;
|
||||
function toString(): JLString; overload; virtual;
|
||||
function toGenericString(): JLString; overload; virtual;
|
||||
function invoke(para1: JLObject; para2: Arr1JLObject): JLObject; overload; virtual; // throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException
|
||||
function invoke(para1: JLObject; const para2: array of JLObject): JLObject; overload; virtual; // throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException
|
||||
function isBridge(): jboolean; overload; virtual;
|
||||
function isVarArgs(): jboolean; overload; virtual;
|
||||
function isSynthetic(): jboolean; overload; virtual;
|
||||
function getAnnotation(para1: JLClass): JLAAnnotation; overload; virtual;
|
||||
function getDeclaredAnnotations(): Arr1JLAAnnotation; overload; virtual;
|
||||
function getDefaultValue(): JLObject; overload; virtual;
|
||||
function getParameterAnnotations(): Arr2JLAAnnotation; overload; virtual;
|
||||
end;
|
||||
|
||||
JUHashMap = class external 'java.util' name 'HashMap' (JUAbstractMap, JUMap, JLCloneable, JISerializable)
|
||||
public
|
||||
type
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{ Imports for Java packages/classes: java.io.Serializable, java.lang.AbstractStringBuilder, java.lang.Appendable, java.lang.Boolean, java.lang.Byte, java.lang.CharSequence, java.lang.Character, java.lang.Class, java.lang.Cloneable, java.lang.Comparable, java.lang.Double, java.lang.Enum, java.lang.Error, java.lang.Exception, java.lang.Float, java.lang.IllegalArgumentException, java.lang.IndexOutOfBoundsException, java.lang.Integer, java.lang.Iterable, java.lang.LinkageError, java.lang.Long, java.lang.Number, java.lang.Object, java.lang.RuntimeException, java.lang.Short, java.lang.String, java.lang.StringBuffer, java.lang.StringBuilder, java.lang.System, java.lang.Throwable, java.lang.reflect.AnnotatedElement, java.lang.reflect.Array, java.lang.reflect.GenericDeclaration, java.lang.reflect.Type, java.text.Collator, java.util.AbstractCollection, java.util.AbstractMap, java.util.AbstractSet, java.util.Arrays, java.util.BitSet, java.util.Collection, java.util.Comparator, java.util.EnumSet, java.util.HashMap, java.util.Iterator, java.util.Map, java.util.Set }
|
||||
{ Imports for Java packages/classes: java.io.Serializable, java.lang.AbstractStringBuilder, java.lang.Appendable, java.lang.Boolean, java.lang.Byte, java.lang.CharSequence, java.lang.Character, java.lang.Class, java.lang.Cloneable, java.lang.Comparable, java.lang.Double, java.lang.Enum, java.lang.Error, java.lang.Exception, java.lang.Float, java.lang.IllegalArgumentException, java.lang.IndexOutOfBoundsException, java.lang.Integer, java.lang.Iterable, java.lang.LinkageError, java.lang.Long, java.lang.Number, java.lang.Object, java.lang.RuntimeException, java.lang.Short, java.lang.String, java.lang.StringBuffer, java.lang.StringBuilder, java.lang.System, java.lang.Throwable, java.lang.reflect.AccessibleObject, java.lang.reflect.AnnotatedElement, java.lang.reflect.Array, java.lang.reflect.GenericDeclaration, java.lang.reflect.Member, java.lang.reflect.Method, java.lang.reflect.Type, java.text.Collator, java.util.AbstractCollection, java.util.AbstractMap, java.util.AbstractSet, java.util.Arrays, java.util.BitSet, java.util.Collection, java.util.Comparator, java.util.EnumSet, java.util.HashMap, java.util.Iterator, java.util.Map, java.util.Set }
|
||||
type
|
||||
JLStringBuffer = class;
|
||||
Arr1JLStringBuffer = array of JLStringBuffer;
|
||||
@ -35,6 +35,11 @@ type
|
||||
Arr2JLNumber = array of Arr1JLNumber;
|
||||
Arr3JLNumber = array of Arr2JLNumber;
|
||||
|
||||
JLRMethod = class;
|
||||
Arr1JLRMethod = array of JLRMethod;
|
||||
Arr2JLRMethod = array of Arr1JLRMethod;
|
||||
Arr3JLRMethod = array of Arr2JLRMethod;
|
||||
|
||||
JLCharacter = class;
|
||||
Arr1JLCharacter = array of JLCharacter;
|
||||
Arr2JLCharacter = array of Arr1JLCharacter;
|
||||
@ -165,6 +170,11 @@ type
|
||||
Arr2JLRuntimeException = array of Arr1JLRuntimeException;
|
||||
Arr3JLRuntimeException = array of Arr2JLRuntimeException;
|
||||
|
||||
JLRAccessibleObject = class;
|
||||
Arr1JLRAccessibleObject = array of JLRAccessibleObject;
|
||||
Arr2JLRAccessibleObject = array of Arr1JLRAccessibleObject;
|
||||
Arr3JLRAccessibleObject = array of Arr2JLRAccessibleObject;
|
||||
|
||||
JLIterable = interface;
|
||||
Arr1JLIterable = array of JLIterable;
|
||||
Arr2JLIterable = array of Arr1JLIterable;
|
||||
@ -210,6 +220,11 @@ type
|
||||
Arr2JLComparable = array of Arr1JLComparable;
|
||||
Arr3JLComparable = array of Arr2JLComparable;
|
||||
|
||||
JLRMember = interface;
|
||||
Arr1JLRMember = array of JLRMember;
|
||||
Arr2JLRMember = array of Arr1JLRMember;
|
||||
Arr3JLRMember = array of Arr2JLRMember;
|
||||
|
||||
JLCharSequence = interface;
|
||||
Arr1JLCharSequence = array of JLCharSequence;
|
||||
Arr2JLCharSequence = array of Arr1JLCharSequence;
|
||||
@ -265,20 +280,15 @@ type
|
||||
Arr2JSProtectionDomain = array of Arr1JSProtectionDomain;
|
||||
Arr3JSProtectionDomain = array of Arr2JSProtectionDomain;
|
||||
|
||||
JLRField = class external 'java.lang.reflect' name 'Field';
|
||||
Arr1JLRField = array of JLRField;
|
||||
Arr2JLRField = array of Arr1JLRField;
|
||||
Arr3JLRField = array of Arr2JLRField;
|
||||
|
||||
JIPrintStream = class external 'java.io' name 'PrintStream';
|
||||
Arr1JIPrintStream = array of JIPrintStream;
|
||||
Arr2JIPrintStream = array of Arr1JIPrintStream;
|
||||
Arr3JIPrintStream = array of Arr2JIPrintStream;
|
||||
|
||||
JLRMethod = class external 'java.lang.reflect' name 'Method';
|
||||
Arr1JLRMethod = array of JLRMethod;
|
||||
Arr2JLRMethod = array of Arr1JLRMethod;
|
||||
Arr3JLRMethod = array of Arr2JLRMethod;
|
||||
JLRField = class external 'java.lang.reflect' name 'Field';
|
||||
Arr1JLRField = array of JLRField;
|
||||
Arr2JLRField = array of Arr1JLRField;
|
||||
Arr3JLRField = array of Arr2JLRField;
|
||||
|
||||
JTCollationKey = class external 'java.text' name 'CollationKey';
|
||||
Arr1JTCollationKey = array of JTCollationKey;
|
||||
|
||||
@ -27,6 +27,7 @@ type
|
||||
TJRecordArray = array of FpcBaseRecordType;
|
||||
TJEnumSetArray = array of JUEnumSet;
|
||||
TJBitSetArray = array of JUBitSet;
|
||||
TJProcVarArray = array of FpcBaseProcVarType;
|
||||
TShortstringArray = array of ShortstringClass;
|
||||
TJStringArray = array of unicodestring;
|
||||
|
||||
@ -42,6 +43,7 @@ const
|
||||
FPCJDynArrTypeRecord = 'R';
|
||||
FPCJDynArrTypeEnumSet = 'E';
|
||||
FPCJDynArrTypeBitSet = 'L';
|
||||
FPCJDynArrTypeProcVar = 'P';
|
||||
FPCJDynArrTypeShortstring = 'T';
|
||||
|
||||
{ 1-dimensional setlength routines
|
||||
@ -60,6 +62,7 @@ procedure fpc_copy_shallow_array(src, dst: JLObject; srcstart: jint = -1; srccop
|
||||
procedure fpc_copy_jrecord_array(src, dst: TJRecordArray; srcstart: jint = -1; srccopylen: jint = -1);
|
||||
procedure fpc_copy_jenumset_array(src, dst: TJEnumSetArray; srcstart: jint = -1; srccopylen: jint = -1);
|
||||
procedure fpc_copy_jbitset_array(src, dst: TJBitSetArray; srcstart: jint = -1; srccopylen: jint = -1);
|
||||
procedure fpc_copy_jprocvar_array(src, dst: TJProcVarArray; srcstart: jint = -1; srccopylen: jint = -1);
|
||||
procedure fpc_copy_jshortstring_array(src, dst: TShortstringArray; srcstart: jint = -1; srccopylen: jint = -1);
|
||||
|
||||
{ multi-dimendional setlength routine: all intermediate dimensions are arrays
|
||||
|
||||
218
rtl/java/jpvar.inc
Normal file
218
rtl/java/jpvar.inc
Normal file
@ -0,0 +1,218 @@
|
||||
{
|
||||
This file is part of the Free Pascal run time library.
|
||||
Copyright (c) 2011 by Jonas Maebe,
|
||||
members of the Free Pascal development team.
|
||||
|
||||
This file implements support infrastructure for procvars under the JVM
|
||||
|
||||
See the file COPYING.FPC, included in this distribution,
|
||||
for details about the copyright.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
**********************************************************************}
|
||||
|
||||
|
||||
constructor FpcBaseProcVarType.create(inst: jlobject; const methodName: unicodestring; const argTypes: array of JLClass);
|
||||
begin
|
||||
method.data:=inst;
|
||||
setFpcBaseProcVarTypeBySignature(methodName,argtypes);
|
||||
end;
|
||||
|
||||
|
||||
constructor FpcBaseProcVarType.create(const meth: tmethod);
|
||||
begin
|
||||
method:=meth;
|
||||
end;
|
||||
|
||||
|
||||
procedure FpcBaseProcVarType.setFpcBaseProcVarTypeBySignature(const methodName: unicodestring; const argTypes: array of JLClass);
|
||||
var
|
||||
owningClass: JLClass;
|
||||
begin
|
||||
{ class method or instance method }
|
||||
if method.data is JLClass then
|
||||
owningClass:=JLClass(method.data)
|
||||
else
|
||||
owningClass:=method.data.getClass;
|
||||
method.code:=owningClass.getDeclaredMethod(methodName,argTypes);
|
||||
{ required to enable calling private methods in one class from another
|
||||
class -- can cause security exceptions if the security manager doesn't
|
||||
allow this though... }
|
||||
if not method.code.isAccessible then
|
||||
method.code.setAccessible(true);
|
||||
end;
|
||||
|
||||
|
||||
procedure FpcBaseProcVarType.fpcDeepCopy(result: FpcBaseProcVarType);
|
||||
begin
|
||||
result.method:=method;
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseProcVarType.clone: JLObject;
|
||||
begin
|
||||
result:=inherited;
|
||||
FpcBaseProcVarType(result).method:=method;
|
||||
end;
|
||||
|
||||
|
||||
procedure FpcBaseProcVarType.invokeProc(const args: array of jlobject);
|
||||
begin
|
||||
method.code.invoke(method.data,args);
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseProcVarType.invokeBooleanFunc(const args: array of jlobject): jboolean;
|
||||
begin
|
||||
result:=JLBoolean(method.code.invoke(method.data,args)).booleanValue;
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseProcVarType.invokeCharFunc(const args: array of jlobject): jchar;
|
||||
begin
|
||||
result:=JLCharacter(method.code.invoke(method.data,args)).charValue;
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseProcVarType.invokeByteFunc(const args: array of jlobject): jbyte;
|
||||
begin
|
||||
result:=JLByte(method.code.invoke(method.data,args)).byteValue;
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseProcVarType.invokeShortFunc(const args: array of jlobject): jshort;
|
||||
begin
|
||||
result:=JLShort(method.code.invoke(method.data,args)).shortValue;
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseProcVarType.invokeIntFunc(const args: array of jlobject): jint;
|
||||
begin
|
||||
result:=JLInteger(method.code.invoke(method.data,args)).intValue;
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseProcVarType.invokeLongFunc(const args: array of jlobject): jlong;
|
||||
begin
|
||||
result:=JLLong(method.code.invoke(method.data,args)).longValue;
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseProcVarType.invokeSingleFunc(const args: array of jlobject): jfloat;
|
||||
begin
|
||||
result:=JLFloat(method.code.invoke(method.data,args)).floatValue;
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseProcVarType.invokeDoubleFunc(const args: array of jlobject): jdouble;
|
||||
begin
|
||||
result:=JLDouble(method.code.invoke(method.data,args)).doubleValue;
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseProcVarType.invokeObjectFunc(const args: array of jlobject): jlobject;
|
||||
begin
|
||||
result:=method.code.invoke(method.data,args);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
function FpcBaseNestedProcVarType.getNestedArgs(const args: array of jlobject): TJLObjectDynArray;
|
||||
var
|
||||
arglen: longint;
|
||||
begin
|
||||
{ add the parentfp struct pointer as last argument (delphi nested cc
|
||||
"calling convention") }
|
||||
arglen:=length(args);
|
||||
setlength(result,arglen+1);
|
||||
JLSystem.ArrayCopy(JLObject(@args),0,JLObject(result),0,arglen);
|
||||
result[arglen]:=nestedfpstruct;
|
||||
end;
|
||||
|
||||
|
||||
constructor FpcBaseNestedProcVarType.create(inst, context: jlobject; const methodName: unicodestring; const argTypes: array of JLClass);
|
||||
begin
|
||||
inherited create(inst,methodName,argTypes);
|
||||
nestedfpstruct:=context;
|
||||
end;
|
||||
|
||||
|
||||
procedure FpcBaseNestedProcVarType.fpcDeepCopy(result: FpcBaseProcVarType);
|
||||
begin
|
||||
inherited fpcDeepCopy(result);
|
||||
FpcBaseNestedProcVarType(result).nestedfpstruct:=nestedfpstruct;
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseNestedProcVarType.clone: JLObject;
|
||||
begin
|
||||
result:=inherited;
|
||||
FpcBaseNestedProcVarType(result).nestedfpstruct:=nestedfpstruct;
|
||||
end;
|
||||
|
||||
|
||||
procedure FpcBaseNestedProcVarType.invokeProc(const args: array of jlobject);
|
||||
begin
|
||||
inherited invokeProc(getNestedArgs(args));
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseNestedProcVarType.invokeBooleanFunc(const args: array of jlobject): jboolean;
|
||||
begin
|
||||
result:=inherited invokeBooleanFunc(getNestedArgs(args));
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseNestedProcVarType.invokeCharFunc(const args: array of jlobject): jchar;
|
||||
begin
|
||||
result:=inherited invokeCharFunc(getNestedArgs(args));
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseNestedProcVarType.invokeByteFunc(const args: array of jlobject): jbyte;
|
||||
begin
|
||||
result:=inherited invokeByteFunc(getNestedArgs(args));
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseNestedProcVarType.invokeShortFunc(const args: array of jlobject): jshort;
|
||||
begin
|
||||
result:=inherited invokeShortFunc(getNestedArgs(args));
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseNestedProcVarType.invokeIntFunc(const args: array of jlobject): jint;
|
||||
begin
|
||||
result:=inherited invokeIntFunc(getNestedArgs(args));
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseNestedProcVarType.invokeLongFunc(const args: array of jlobject): jlong;
|
||||
begin
|
||||
result:=inherited invokeLongFunc(getNestedArgs(args));
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseNestedProcVarType.invokeSingleFunc(const args: array of jlobject): jfloat;
|
||||
begin
|
||||
result:=inherited invokeSingleFunc(getNestedArgs(args));
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseNestedProcVarType.invokeDoubleFunc(const args: array of jlobject): jdouble;
|
||||
begin
|
||||
result:=inherited invokeDoubleFunc(getNestedArgs(args));
|
||||
end;
|
||||
|
||||
|
||||
function FpcBaseNestedProcVarType.invokeObjectFunc(const args: array of jlobject): jlobject;
|
||||
begin
|
||||
result:=inherited invokeObjectFunc(getNestedArgs(args));
|
||||
end;
|
||||
|
||||
|
||||
|
||||
75
rtl/java/jpvarh.inc
Normal file
75
rtl/java/jpvarh.inc
Normal file
@ -0,0 +1,75 @@
|
||||
{
|
||||
This file is part of the Free Pascal run time library.
|
||||
Copyright (c) 2011 by Jonas Maebe,
|
||||
members of the Free Pascal development team.
|
||||
|
||||
This file declares support infrastructure for procvars under the JVM
|
||||
|
||||
See the file COPYING.FPC, included in this distribution,
|
||||
for details about the copyright.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
**********************************************************************}
|
||||
|
||||
type
|
||||
{ tmethod record }
|
||||
TMethod = record
|
||||
code: JLRMethod;
|
||||
data: jlobject;
|
||||
end;
|
||||
|
||||
|
||||
{ base type for procedure variables }
|
||||
FpcBaseProcVarType = class(jlobject,jlcloneable)
|
||||
method: TMethod;
|
||||
|
||||
constructor create(inst: jlobject; const methodName: unicodestring; const argTypes: array of JLClass);
|
||||
constructor create(const meth: tmethod);
|
||||
|
||||
procedure setFpcBaseProcVarTypeBySignature(const methodName: unicodestring; const argTypes: array of JLClass); virtual;
|
||||
procedure fpcDeepCopy(result: FpcBaseProcVarType); virtual;
|
||||
function clone: JLObject; override;
|
||||
|
||||
strict protected
|
||||
procedure invokeProc(const args: array of jlobject); virtual;
|
||||
function invokeBooleanFunc(const args: array of jlobject): jboolean; virtual;
|
||||
function invokeCharFunc(const args: array of jlobject): jchar; virtual;
|
||||
function invokeByteFunc(const args: array of jlobject): jbyte; virtual;
|
||||
function invokeShortFunc(const args: array of jlobject): jshort; virtual;
|
||||
function invokeIntFunc(const args: array of jlobject): jint; virtual;
|
||||
function invokeLongFunc(const args: array of jlobject): jlong; virtual;
|
||||
function invokeSingleFunc(const args: array of jlobject): jfloat; virtual;
|
||||
function invokeDoubleFunc(const args: array of jlobject): jdouble; virtual;
|
||||
function invokeObjectFunc(const args: array of jlobject): jlobject; virtual;
|
||||
end;
|
||||
|
||||
FpcBaseNestedProcVarType = class(FpcBaseProcVarType)
|
||||
strict protected
|
||||
type
|
||||
{ TJObjectArray isn't declared here yet }
|
||||
TJLObjectDynArray = array of JLObject;
|
||||
{ add the nestedfpstruct to the list of parameters }
|
||||
function getNestedArgs(const args: array of jlobject): TJLObjectDynArray; virtual;
|
||||
public
|
||||
nestedfpstruct: jlobject;
|
||||
|
||||
constructor create(inst, context: jlobject; const methodName: unicodestring; const argTypes: array of JLClass);
|
||||
procedure fpcDeepCopy(result: FpcBaseProcVarType); override;
|
||||
function clone: JLObject; override;
|
||||
|
||||
strict protected
|
||||
procedure invokeProc(const args: array of jlobject); override;
|
||||
function invokeBooleanFunc(const args: array of jlobject): jboolean; override;
|
||||
function invokeCharFunc(const args: array of jlobject): jchar; override;
|
||||
function invokeByteFunc(const args: array of jlobject): jbyte; override;
|
||||
function invokeShortFunc(const args: array of jlobject): jshort; override;
|
||||
function invokeIntFunc(const args: array of jlobject): jint; override;
|
||||
function invokeLongFunc(const args: array of jlobject): jlong; override;
|
||||
function invokeSingleFunc(const args: array of jlobject): jfloat; override;
|
||||
function invokeDoubleFunc(const args: array of jlobject): jdouble; override;
|
||||
function invokeObjectFunc(const args: array of jlobject): jlobject; override;
|
||||
end;
|
||||
|
||||
@ -87,6 +87,25 @@ procedure fpc_initialize_array_record(arr: TJObjectArray; normalarrdim: longint;
|
||||
end;
|
||||
|
||||
|
||||
procedure fpc_initialize_array_procvar_intern(arr: TJObjectArray; normalarrdim: longint; inst: FpcBaseProcVarType); external name 'fpc_initialize_array_procvar';
|
||||
|
||||
procedure fpc_initialize_array_procvar(arr: TJObjectArray; normalarrdim: longint; inst: FpcBaseProcVarType);compilerproc;
|
||||
var
|
||||
i: longint;
|
||||
begin
|
||||
if normalarrdim > 0 then
|
||||
begin
|
||||
for i:=low(arr) to high(arr) do
|
||||
fpc_initialize_array_procvar_intern(TJObjectArray(arr[i]),normalarrdim-1,inst);
|
||||
end
|
||||
else
|
||||
begin
|
||||
for i:=low(arr) to high(arr) do
|
||||
arr[i]:=inst.clone;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{ exactly the same as fpc_initialize_array_record, but can't use generic
|
||||
routine because of Java clonable design :( (except by rtti/invoke, but that's
|
||||
not particularly fast either) }
|
||||
|
||||
@ -131,15 +131,12 @@ type
|
||||
{$i jrech.inc}
|
||||
{$i jseth.inc}
|
||||
{$i sstringh.inc}
|
||||
{$i jpvarh.inc}
|
||||
{$i jdynarrh.inc}
|
||||
{$i astringh.inc}
|
||||
|
||||
{$ifndef nounsupported}
|
||||
type
|
||||
tmethod = record
|
||||
code: jlobject;
|
||||
end;
|
||||
|
||||
{$ifndef nounsupported}
|
||||
const
|
||||
vtInteger = 0;
|
||||
vtBoolean = 1;
|
||||
@ -290,6 +287,7 @@ function min(a,b : longint) : longint;
|
||||
{$i jrec.inc}
|
||||
{$i jset.inc}
|
||||
{$i jint64.inc}
|
||||
{$i jpvar.inc}
|
||||
|
||||
{ copying helpers }
|
||||
|
||||
@ -384,6 +382,27 @@ procedure fpc_copy_jbitset_array(src, dst: TJBitSetArray; srcstart: jint = -1; s
|
||||
end;
|
||||
|
||||
|
||||
procedure fpc_copy_jprocvar_array(src, dst: TJProcVarArray; srcstart: jint = -1; srccopylen: jint = -1);
|
||||
var
|
||||
i: longint;
|
||||
srclen, dstlen: jint;
|
||||
begin
|
||||
srclen:=length(src);
|
||||
dstlen:=length(dst);
|
||||
if srcstart=-1 then
|
||||
srcstart:=0
|
||||
else if srcstart>=srclen then
|
||||
exit;
|
||||
if srccopylen=-1 then
|
||||
srccopylen:=srclen
|
||||
else if srcstart+srccopylen>srclen then
|
||||
srccopylen:=srclen-srcstart;
|
||||
{ no arraycopy, have to clone each element }
|
||||
for i:=0 to min(srccopylen,dstlen)-1 do
|
||||
dst[i]:=FpcBaseProcVarType(src[srcstart+i].clone);
|
||||
end;
|
||||
|
||||
|
||||
procedure fpc_copy_jshortstring_array(src, dst: TShortstringArray; srcstart: jint = -1; srccopylen: jint = -1);
|
||||
var
|
||||
i: longint;
|
||||
@ -475,6 +494,18 @@ function fpc_setlength_dynarr_jbitset(aorg, anew: TJBitSetArray; deepcopy: boole
|
||||
end;
|
||||
|
||||
|
||||
function fpc_setlength_dynarr_jprocvar(aorg, anew: TJProcVarArray; deepcopy: boolean): TJProcVarArray;
|
||||
begin
|
||||
if deepcopy or
|
||||
(length(aorg)<>length(anew)) then
|
||||
begin
|
||||
fpc_copy_jprocvar_array(aorg,anew);
|
||||
result:=anew
|
||||
end
|
||||
else
|
||||
result:=aorg;
|
||||
end;
|
||||
|
||||
|
||||
function fpc_setlength_dynarr_jshortstring(aorg, anew: TShortstringArray; deepcopy: boolean): TShortstringArray;
|
||||
begin
|
||||
@ -536,6 +567,13 @@ function fpc_setlength_dynarr_multidim(aorg, anew: TJObjectArray; deepcopy: bool
|
||||
for i:=succ(partdone) to high(result) do
|
||||
result[i]:=JLObject(fpc_setlength_dynarr_jbitset(nil,TJBitSetArray(anew[i]),deepcopy));
|
||||
end;
|
||||
FPCJDynArrTypeProcVar:
|
||||
begin
|
||||
for i:=low(result) to partdone do
|
||||
result[i]:=JLObject(fpc_setlength_dynarr_jprocvar(TJProcVarArray(aorg[i]),TJProcVarArray(anew[i]),deepcopy));
|
||||
for i:=succ(partdone) to high(result) do
|
||||
result[i]:=JLObject(fpc_setlength_dynarr_jprocvar(nil,TJProcVarArray(anew[i]),deepcopy));
|
||||
end;
|
||||
FPCJDynArrTypeShortstring:
|
||||
begin
|
||||
for i:=low(result) to partdone do
|
||||
@ -592,6 +630,8 @@ function fpc_dynarray_copy(src: JLObject; start, len: longint; ndim: longint; el
|
||||
fpc_copy_jenumset_array(TJEnumSetArray(src),TJEnumSetArray(result),start,len);
|
||||
FPCJDynArrTypeBitSet:
|
||||
fpc_copy_jbitset_array(TJBitSetArray(src),TJBitSetArray(result),start,len);
|
||||
FPCJDynArrTypeProcvar:
|
||||
fpc_copy_jprocvar_array(TJProcVarArray(src),TJProcVarArray(result),start,len);
|
||||
FPCJDynArrTypeShortstring:
|
||||
fpc_copy_jshortstring_array(TShortstringArray(src),TShortstringArray(result),start,len);
|
||||
else
|
||||
|
||||
Loading…
Reference in New Issue
Block a user