| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 | {    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,nbas,    ngenutil,    symtype,symconst,symsym,symdef;  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 function check_insert_trashing(pd: tprocdef): boolean; override;      class function  trashable_sym(p: tsym): boolean; override;      class procedure maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode); 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,      symbase,symcpu,symtable,defutil,jvmdef,      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      result:=nil;      proc:='';      temp:=nil;      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:=cstaticvarsym.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(tcpuenumdef(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 function tjvmnodeutils.check_insert_trashing(pd: tprocdef): boolean;    begin      { initialise locals with 0 }      if ts_init_locals in current_settings.targetswitches then        localvartrashing:=high(trashintvalues);      result:=inherited;    end;  class function tjvmnodeutils.trashable_sym(p: tsym): boolean;    begin      result:=        inherited and        not jvmimplicitpointertype(tabstractnormalvarsym(p).vardef);    end;  class procedure tjvmnodeutils.maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode);    var      enumdef: tenumdef;      trashintval: int64;      trashenumval: longint;      trashable: boolean;    begin      trashable:=trashable_sym(p);      trashintval:=trashintvalues[localvartrashing];      { widechar is a separate type in the JVM, can't cast left hand to integer        like in common code }      if trashable and         is_widechar(tabstractvarsym(p).vardef) then        trash_small(stat,trashn,          cordconstnode.create(word(trashintval),tabstractvarsym(p).vardef,false))      { enums are class instances in the JVM -> create a valid instance }      else if trashable and         is_enum(tabstractvarsym(p).vardef) then        begin          enumdef:=tenumdef(tabstractvarsym(p).vardef);          trashenumval:=longint(trashintval);          if not assigned(enumdef.int2enumsym(trashenumval)) then            trashintval:=longint(enumdef.min);          trash_small(stat,trashn,            cordconstnode.create(trashintval,enumdef,false))        end      { can't init pointers with arbitrary values; procvardef and objectdef are        always pointer-sized here because tjvmnodeutils.trashablesym returns        false for jvm implicit pointer types }      else if trashable and         (tabstractvarsym(p).vardef.typ in [pointerdef,classrefdef,objectdef,procvardef]) then        trash_small(stat,trashn,cnilnode.create)      else if trashable and         is_real(tabstractvarsym(p).vardef) then        trash_small(stat,trashn,crealconstnode.create(trashintval,tabstractvarsym(p).vardef))      { don't use inherited routines because it typecasts left to the target        type, and that doesn't always work in the JVM }      else if trashable and         (is_integer(tabstractvarsym(p).vardef) or          is_cbool(tabstractvarsym(p).vardef) or          is_anychar(tabstractvarsym(p).vardef) or          is_currency(tabstractvarsym(p).vardef)) then        trash_small(stat,trashn,cordconstnode.create(trashintval,tabstractvarsym(p).vardef,false))      else if trashable and         is_pasbool(tabstractvarsym(p).vardef) then        trash_small(stat,trashn,cordconstnode.create(trashintval and 1,tabstractvarsym(p).vardef,false))      else        inherited;    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);      tcpuprocdef(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:=cparavarsym.create('$args',1,vs_const,search_system_type('TJSTRINGARRAY').typedef,[]);          tprocdef(pd).parast.insert(pvs);          tprocdef(pd).calcparas;        end;    end;begin  cnodeutils:=tjvmnodeutils;end.
 |