123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- {
- Copyright (c) 20011 by Jonas Maebe
- JVM version of some node tree helper routines
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- 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. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ****************************************************************************
- }
- unit njvmutil;
- {$i fpcdefs.inc}
- interface
- uses
- node,
- ngenutil,
- symtype,symconst,symsym;
- type
- tjvmnodeutils = class(tnodeutils)
- class function initialize_data_node(p:tnode; force: boolean):tnode; override;
- class function finalize_data_node(p:tnode):tnode; override;
- class function force_init: boolean; override;
- class procedure insertbssdata(sym: tstaticvarsym); override;
- class function create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef; override;
- class procedure InsertInitFinalTable; override;
- class procedure InsertThreadvarTablesTable; override;
- class procedure InsertThreadvars; override;
- class procedure InsertWideInitsTablesTable; override;
- class procedure InsertWideInits; override;
- class procedure InsertResourceTablesTable; override;
- class procedure InsertResourceInfo(ResourcesUsed : boolean); override;
- class procedure InsertMemorySizes; override;
- strict protected
- class procedure add_main_procdef_paras(pd: tdef); override;
- end;
- implementation
- uses
- verbose,cutils,globtype,globals,constexp,fmodule,
- aasmdata,aasmtai,cpubase,aasmcpu,
- symdef,symbase,symtable,defutil,jvmdef,
- nbas,ncnv,ncon,ninl,ncal,nld,nmem,
- ppu,
- pass_1;
- class function tjvmnodeutils.initialize_data_node(p:tnode; force: boolean):tnode;
- var
- normaldim: longint;
- temp: ttempcreatenode;
- stat: tstatementnode;
- def: tdef;
- paras: tcallparanode;
- proc: string;
- begin
- if not assigned(p.resultdef) then
- typecheckpass(p);
- if ((p.resultdef.typ=stringdef) and
- not is_shortstring(p.resultdef) and
- not is_longstring(p.resultdef)) or
- is_dynamic_array(p.resultdef) then
- begin
- { Always initialise with empty string/array rather than nil. Java
- makes a distinction between an empty string/array and a null
- string/array, but we don't. We therefore have to pick which one we
- use to represent empty strings/arrays. I've chosen empty rather than
- null structures, because otherwise it becomes impossible to return
- an empty string to Java code (it would return null).
- On the consumer side, we do interpret both null and empty as the same
- thing, so Java code can pass in null strings/arrays and we'll
- interpret them correctly.
- }
- result:=cinlinenode.create(in_setlength_x,false,
- ccallparanode.create(genintconstnode(0),
- ccallparanode.create(p,nil)));
- end
- else if force then
- begin
- { an explicit call to initialize() }
- if p.resultdef.typ=recorddef then
- result:=ccallnode.createinternmethod(p,'FPCINITIALIZEREC',nil)
- else if p.resultdef.typ=arraydef then
- begin
- stat:=nil;
- { in case it's an open array whose elements are regular arrays, put the
- dimension of the regular arrays on the stack (otherwise pass 0) }
- normaldim:=0;
- def:=tarraydef(p.resultdef).elementdef;
- while (def.typ=arraydef) and
- not is_dynamic_array(def) do
- begin
- inc(normaldim);
- def:=tarraydef(def).elementdef;
- end;
- if jvmimplicitpointertype(p.resultdef) then
- begin
- p:=caddrnode.create(p);
- include(p.flags,nf_typedaddr);
- end;
- paras:=ccallparanode.create(ctypeconvnode.create_explicit(p,
- search_system_type('TJOBJECTARRAY').typedef),nil);
- paras:=ccallparanode.create(genintconstnode(normaldim),paras);
- if is_wide_or_unicode_string(def) then
- proc:='fpc_initialize_array_unicodestring'
- else if is_ansistring(def) then
- proc:='fpc_initialize_array_ansistring'
- else if is_dynamic_array(def) then
- proc:='fpc_initialize_array_dynarr'
- else if is_record(def) then
- begin
- result:=internalstatements(stat);
- temp:=ctempcreatenode.create(def,def.size,tt_persistent,true);
- addstatement(stat,temp);
- paras:=ccallparanode.create(ctemprefnode.create(temp),paras);
- proc:='fpc_initialize_array_record'
- end;
- if assigned(stat) then
- begin
- addstatement(stat,ccallnode.createintern(proc,paras));
- addstatement(stat,ctempdeletenode.create(temp));
- end
- else
- result:=ccallnode.createintern(proc,paras);
- end
- else
- result:=cassignmentnode.create(p,cnilnode.create);
- end
- else
- begin
- p.free;
- { records/arrays/... are automatically initialised }
- result:=cnothingnode.create;
- end;
- end;
- class function tjvmnodeutils.finalize_data_node(p:tnode):tnode;
- begin
- // do nothing
- p.free;
- result:=cnothingnode.create;
- end;
- class function tjvmnodeutils.force_init: boolean;
- begin
- { we need an initialisation in case the al_globals list is not empty
- (that's where the initialisation for global records etc is added) }
- { problem: some bss symbols are only registered while processing the main
- program (e.g. constant sets) -> cannot predict whether or not we'll
- need it in advance }
- result:=true;
- end;
- class procedure tjvmnodeutils.insertbssdata(sym: tstaticvarsym);
- var
- enuminitsym,
- vs: tstaticvarsym;
- block: tblocknode;
- stat: tstatementnode;
- temp: ttempcreatenode;
- initnode: tnode;
- eledef: tdef;
- ndim: longint;
- initnodefinished: boolean;
- begin
- { handled while generating the unit/program init code, or class
- constructor; add something to al_globals to indicate that we need to
- insert an init section though }
- if current_asmdata.asmlists[al_globals].empty and
- jvmimplicitpointertype(sym.vardef) then
- current_asmdata.asmlists[al_globals].concat(cai_align.Create(1));
- { in case of a threadvar, allocate a separate sym that's a subtype of the
- java.lang.ThreadLocal class which will wrap the actual variable value }
- if vo_is_thread_var in sym.varoptions then
- begin
- vs:=tstaticvarsym.create(sym.realname+'$threadvar',sym.varspez,
- jvmgetthreadvardef(sym.vardef),
- sym.varoptions - [vo_is_thread_var]);
- sym.owner.insert(vs);
- { make sure that the new sym does not get allocated (we will allocate
- it when encountering the original sym, because only then we know
- that it's a threadvar) }
- include(vs.symoptions,sp_static);
- { switch around the mangled names of sym and vs, since the wrapper
- should map to the declared name }
- sym.set_mangledbasename(vs.realname);
- vs.set_mangledbasename(sym.realname);
- { add initialization code for the wrapper }
- block:=internalstatements(stat);
- if assigned(current_module.tcinitcode) then
- addstatement(stat,tnode(current_module.tcinitcode));
- current_module.tcinitcode:=block;
- { create initialization value if necessary }
- initnode:=nil;
- initnodefinished:=false;
- temp:=nil;
- { in case of enum type, initialize with enum(0) if it exists }
- if sym.vardef.typ=enumdef then
- begin
- enuminitsym:=tstaticvarsym(tenumdef(sym.vardef).getbasedef.classdef.symtable.Find('__FPC_ZERO_INITIALIZER'));
- if assigned(enuminitsym) then
- initnode:=cloadnode.create(enuminitsym,enuminitsym.owner);
- end
- { normal array -> include dimensions and element type so we can
- create a deep copy }
- else if (sym.vardef.typ=arraydef) and
- not is_dynamic_array(sym.vardef) then
- begin
- temp:=ctempcreatenode.create(sym.vardef,sym.vardef.size,tt_persistent,true);
- addstatement(stat,temp);
- initnode:=ccallparanode.create(
- ctypeconvnode.create_explicit(
- caddrnode.create_internal(ctemprefnode.create(temp)),
- java_jlobject),
- nil);
- jvmgetarraydimdef(sym.vardef,eledef,ndim);
- initnode:=ccallparanode.create(genintconstnode(ndim),initnode);
- initnode:=ccallparanode.create(
- cordconstnode.create(ord(jvmarrtype_setlength(eledef)),
- cwidechartype,false),
- initnode);
- initnodefinished:=true;
- end
- { implicitpointertype -> allocate (get temp and assign address) }
- else if jvmimplicitpointertype(sym.vardef) then
- begin
- temp:=ctempcreatenode.create(sym.vardef,sym.vardef.size,tt_persistent,true);
- addstatement(stat,temp);
- initnode:=caddrnode.create_internal(ctemprefnode.create(temp));
- end
- { unicodestring/ansistring -> empty string }
- else if is_wide_or_unicode_string(sym.vardef) or
- is_ansistring(sym.vardef) then
- begin
- temp:=ctempcreatenode.create(sym.vardef,sym.vardef.size,tt_persistent,true);
- addstatement(stat,temp);
- addstatement(stat,cassignmentnode.create(
- ctemprefnode.create(temp),
- cstringconstnode.createstr('')));
- initnode:=ctemprefnode.create(temp);
- end
- { dynamic array -> empty array }
- else if is_dynamic_array(sym.vardef) then
- begin
- temp:=ctempcreatenode.create(sym.vardef,sym.vardef.size,tt_persistent,true);
- addstatement(stat,temp);
- addstatement(stat,cinlinenode.create(in_setlength_x,false,
- ccallparanode.create(genintconstnode(0),
- ccallparanode.create(ctemprefnode.create(temp),nil))
- )
- );
- initnode:=ctemprefnode.create(temp);
- end;
- if assigned(initnode) and
- not initnodefinished then
- initnode:=ccallparanode.create(ctypeconvnode.create_explicit(initnode,java_jlobject),nil);
- addstatement(stat,cassignmentnode.create(
- cloadnode.create(vs,vs.owner),
- ccallnode.createinternmethod(
- cloadvmtaddrnode.create(ctypenode.create(vs.vardef)),
- 'CREATE',initnode)));
- { deallocate the temp if we allocated one }
- if assigned(temp) then
- addstatement(stat,ctempdeletenode.create(temp));
- end;
- end;
- class function tjvmnodeutils.create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef;
- begin
- if (potype=potype_proginit) then
- begin
- result:=inherited create_main_procdef('main', potype, ps);
- include(tprocdef(result).procoptions,po_global);
- tprocdef(result).visibility:=vis_public;
- end
- else
- result:=inherited create_main_procdef(name, potype, ps);
- end;
- class procedure tjvmnodeutils.InsertInitFinalTable;
- var
- hp : tused_unit;
- unitinits : TAsmList;
- unitclassname: string;
- mainpsym: tsym;
- mainpd: tprocdef;
- begin
- unitinits:=TAsmList.Create;
- hp:=tused_unit(usedunits.first);
- while assigned(hp) do
- begin
- { class constructors are automatically handled by the JVM }
- { call the unit init code and make it external }
- if (hp.u.flags and (uf_init or uf_finalize))<>0 then
- begin
- { trigger init code by referencing the class representing the
- unit; if necessary, it will register the fini code to run on
- exit}
- unitclassname:='';
- if assigned(hp.u.namespace) then
- begin
- unitclassname:=hp.u.namespace^+'/';
- replace(unitclassname,'.','/');
- end;
- unitclassname:=unitclassname+hp.u.realmodulename^;
- unitinits.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(unitclassname)));
- unitinits.concat(taicpu.op_none(a_pop));
- end;
- hp:=tused_unit(hp.next);
- end;
- { insert in main program routine }
- mainpsym:=tsym(current_module.localsymtable.find(mainaliasname));
- if not assigned(mainpsym) or
- (mainpsym.typ<>procsym) then
- internalerror(2011041901);
- mainpd:=tprocsym(mainpsym).find_procdef_bytype(potype_proginit);
- if not assigned(mainpd) then
- internalerror(2011041902);
- mainpd.exprasmlist.insertList(unitinits);
- unitinits.free;
- end;
- class procedure tjvmnodeutils.InsertThreadvarTablesTable;
- begin
- { not yet supported }
- end;
- class procedure tjvmnodeutils.InsertThreadvars;
- begin
- { not yet supported }
- end;
- class procedure tjvmnodeutils.InsertWideInitsTablesTable;
- begin
- { not required }
- end;
- class procedure tjvmnodeutils.InsertWideInits;
- begin
- { not required }
- end;
- class procedure tjvmnodeutils.InsertResourceTablesTable;
- begin
- { not supported }
- end;
- class procedure tjvmnodeutils.InsertResourceInfo(ResourcesUsed: boolean);
- begin
- { not supported }
- end;
- class procedure tjvmnodeutils.InsertMemorySizes;
- begin
- { not required }
- end;
- class procedure tjvmnodeutils.add_main_procdef_paras(pd: tdef);
- var
- pvs: tparavarsym;
- begin
- if (tprocdef(pd).proctypeoption=potype_proginit) then
- begin
- { add the args parameter }
- pvs:=tparavarsym.create('$args',1,vs_const,search_system_type('TJSTRINGARRAY').typedef,[]);
- tprocdef(pd).parast.insert(pvs);
- tprocdef(pd).calcparas;
- end;
- end;
- begin
- cnodeutils:=tjvmnodeutils;
- end.
|