pjvm.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. {
  2. Copyright (c) 2011 by Jonas Maebe
  3. This unit implements some JVM parser helper routines.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. {$i fpcdefs.inc}
  18. unit pjvm;
  19. interface
  20. uses
  21. globtype,
  22. symtype,symbase,symdef,symsym;
  23. { the JVM specs require that you add a default parameterless
  24. constructor in case the programmer hasn't specified any }
  25. procedure maybe_add_public_default_java_constructor(obj: tabstractrecorddef);
  26. { records are emulated via Java classes. They require a default constructor
  27. to initialise temps, a deep copy helper for assignments, and clone()
  28. to initialse dynamic arrays }
  29. procedure add_java_default_record_methods_intf(def: trecorddef);
  30. procedure jvm_maybe_create_enum_class(const name: TIDString; def: tdef);
  31. procedure jvm_add_typed_const_initializer(csym: tconstsym);
  32. implementation
  33. uses
  34. cutils,cclasses,
  35. verbose,systems,
  36. fmodule,
  37. parabase,aasmdata,
  38. pdecsub,
  39. symtable,symconst,symcreat,defcmp,jvmdef,
  40. defutil,paramgr;
  41. { the JVM specs require that you add a default parameterless
  42. constructor in case the programmer hasn't specified any }
  43. procedure maybe_add_public_default_java_constructor(obj: tabstractrecorddef);
  44. var
  45. sym: tsym;
  46. ps: tprocsym;
  47. pd: tprocdef;
  48. topowner: tdefentry;
  49. i: longint;
  50. sstate: symcreat.tscannerstate;
  51. needclassconstructor: boolean;
  52. begin
  53. { if there is at least one constructor for a class, do nothing (for
  54. records, we'll always also need a parameterless constructor) }
  55. if not is_javaclass(obj) or
  56. not (oo_has_constructor in obj.objectoptions) then
  57. begin
  58. { check whether the parent has a parameterless constructor that we can
  59. call (in case of a class; all records will derive from
  60. java.lang.Object or a shim on top of that with a parameterless
  61. constructor) }
  62. if is_javaclass(obj) then
  63. begin
  64. pd:=nil;
  65. sym:=tsym(tobjectdef(obj).childof.symtable.find('CREATE'));
  66. if assigned(sym) and
  67. (sym.typ=procsym) then
  68. pd:=tprocsym(sym).find_bytype_parameterless(potype_constructor);
  69. if not assigned(pd) then
  70. begin
  71. Message(sym_e_no_matching_inherited_parameterless_constructor);
  72. exit
  73. end;
  74. end;
  75. { we call all constructors CREATE, because they don't have a name in
  76. Java and otherwise we can't determine whether multiple overloads
  77. are created with the same parameters }
  78. sym:=tsym(obj.symtable.find('CREATE'));
  79. if assigned(sym) then
  80. begin
  81. { does another, non-procsym, symbol already exist with that name? }
  82. if (sym.typ<>procsym) then
  83. begin
  84. Message1(sym_e_duplicate_id_create_java_constructor,sym.realname);
  85. exit;
  86. end;
  87. ps:=tprocsym(sym);
  88. { is there already a parameterless function/procedure create? }
  89. pd:=ps.find_bytype_parameterless(potype_function);
  90. if not assigned(pd) then
  91. pd:=ps.find_bytype_parameterless(potype_procedure);
  92. if assigned(pd) then
  93. begin
  94. Message1(sym_e_duplicate_id_create_java_constructor,pd.fullprocname(false));
  95. exit;
  96. end;
  97. end;
  98. if not assigned(sym) then
  99. begin
  100. ps:=tprocsym.create('Create');
  101. obj.symtable.insert(ps);
  102. end;
  103. { determine symtable level }
  104. topowner:=obj;
  105. while not(topowner.owner.symtabletype in [staticsymtable,globalsymtable]) do
  106. topowner:=topowner.owner.defowner;
  107. { create procdef }
  108. pd:=tprocdef.create(topowner.owner.symtablelevel+1);
  109. { method of this objectdef }
  110. pd.struct:=obj;
  111. { associated procsym }
  112. pd.procsym:=ps;
  113. { constructor }
  114. pd.proctypeoption:=potype_constructor;
  115. { needs to be exported }
  116. include(pd.procoptions,po_global);
  117. { for Delphi mode }
  118. include(pd.procoptions,po_overload);
  119. { generate anonymous inherited call in the implementation }
  120. pd.synthetickind:=tsk_anon_inherited;
  121. { public }
  122. pd.visibility:=vis_public;
  123. { result type }
  124. pd.returndef:=obj;
  125. { calling convention, self, ... }
  126. handle_calling_convention(pd);
  127. { register forward declaration with procsym }
  128. proc_add_definition(pd);
  129. end;
  130. { also add class constructor if class fields that need wrapping, and
  131. if none was defined }
  132. if obj.find_procdef_bytype(potype_class_constructor)=nil then
  133. begin
  134. needclassconstructor:=false;
  135. for i:=0 to obj.symtable.symlist.count-1 do
  136. begin
  137. if (tsym(obj.symtable.symlist[i]).typ=staticvarsym) and
  138. jvmimplicitpointertype(tstaticvarsym(obj.symtable.symlist[i]).vardef) then
  139. begin
  140. needclassconstructor:=true;
  141. break;
  142. end;
  143. end;
  144. if needclassconstructor then
  145. begin
  146. replace_scanner('custom_class_constructor',sstate);
  147. if str_parse_method_dec('constructor fpc_jvm_class_constructor;',potype_class_constructor,true,obj,pd) then
  148. pd.synthetickind:=tsk_empty
  149. else
  150. internalerror(2011040501);
  151. restore_scanner(sstate);
  152. end;
  153. end;
  154. end;
  155. procedure add_java_default_record_methods_intf(def: trecorddef);
  156. var
  157. sstate: tscannerstate;
  158. pd: tprocdef;
  159. begin
  160. maybe_add_public_default_java_constructor(def);
  161. replace_scanner('record_jvm_helpers',sstate);
  162. { no override, because not supported in records; the parser will still
  163. accept "inherited" though }
  164. if str_parse_method_dec('function clone: JLObject;',potype_function,false,def,pd) then
  165. pd.synthetickind:=tsk_jvm_clone
  166. else
  167. internalerror(2011032806);
  168. { can't use def.typesym, not yet set at this point }
  169. if not assigned(def.symtable.realname) then
  170. internalerror(2011032803);
  171. if str_parse_method_dec('procedure fpcDeepCopy(out result:'+def.symtable.realname^+');',potype_procedure,false,def,pd) then
  172. pd.synthetickind:=tsk_record_deepcopy
  173. else
  174. internalerror(2011032807);
  175. restore_scanner(sstate);
  176. end;
  177. procedure jvm_maybe_create_enum_class(const name: TIDString; def: tdef);
  178. var
  179. arrdef: tarraydef;
  180. arrsym: ttypesym;
  181. juhashmap: tdef;
  182. enumclass: tobjectdef;
  183. pd: tprocdef;
  184. old_current_structdef: tabstractrecorddef;
  185. i: longint;
  186. sym: tstaticvarsym;
  187. fsym: tfieldvarsym;
  188. sstate: symcreat.tscannerstate;
  189. sl: tpropaccesslist;
  190. begin
  191. { if it's a subrange type, don't create a new class }
  192. if assigned(tenumdef(def).basedef) then
  193. exit;
  194. replace_scanner('jvm_enum_class',sstate);
  195. { create new class (different internal name than enum to prevent name clash) }
  196. enumclass:=tobjectdef.create(odt_javaclass,'$'+name+'$InternEnum',java_jlenum);
  197. tenumdef(def).classdef:=enumclass;
  198. include(enumclass.objectoptions,oo_is_enum_class);
  199. include(enumclass.objectoptions,oo_is_sealed);
  200. { create an alias for this type inside itself: this way we can choose a
  201. name that can be used in generated Pascal code without risking an
  202. identifier conflict (since it is local to this class; the global name
  203. is unique because it's an identifier that contains $-signs) }
  204. enumclass.symtable.insert(ttypesym.create('__FPC_TEnumClassAlias',enumclass));
  205. { also create an alias for the enum type so that we can iterate over
  206. all enum values when creating the body of the class constructor }
  207. enumclass.symtable.insert(ttypesym.create('__FPC_TEnumAlias',def));
  208. { but the name of the class as far as the JVM is concerned will match
  209. the enum's original name (the enum type itself won't be output in
  210. any class file, so no conflict there) }
  211. enumclass.objextname:=stringdup(name);
  212. { now add a bunch of extra things to the enum class }
  213. old_current_structdef:=current_structdef;
  214. current_structdef:=enumclass;
  215. symtablestack.push(enumclass.symtable);
  216. { create static fields representing all enums }
  217. for i:=0 to tenumdef(def).symtable.symlist.count-1 do
  218. begin
  219. sym:=tstaticvarsym.create(tenumsym(tenumdef(def).symtable.symlist[i]).realname,vs_final,enumclass,[]);
  220. enumclass.symtable.insert(sym);
  221. { alias for consistency with parsed staticvarsyms }
  222. sl:=tpropaccesslist.create;
  223. sl.addsym(sl_load,sym);
  224. enumclass.symtable.insert(tabsolutevarsym.create_ref('$'+internal_static_field_name(sym.name),enumclass,sl));
  225. end;
  226. { create local "array of enumtype" type for the "values" functionality
  227. (used internally by the JDK) }
  228. arrdef:=tarraydef.create(0,tenumdef(def).symtable.symlist.count-1,s32inttype);
  229. arrdef.elementdef:=enumclass;
  230. arrsym:=ttypesym.create('__FPC_TEnumValues',arrdef);
  231. enumclass.symtable.insert(arrsym);
  232. { insert "public static values: array of enumclass" that returns $VALUES.clone()
  233. (rather than a dynamic array and using clone --which we don't support yet for arrays--
  234. simply use a fixed length array and copy it) }
  235. if not str_parse_method_dec('function values: __FPC_TEnumValues;',potype_function,true,enumclass,pd) then
  236. internalerror(2011062301);
  237. include(pd.procoptions,po_staticmethod);
  238. pd.synthetickind:=tsk_jvm_enum_values;
  239. { do we have to store the ordinal value separately? (if no jumps, we can
  240. just call the default ordinal() java.lang.Enum function) }
  241. if tenumdef(def).has_jumps then
  242. begin
  243. { add field for the value }
  244. fsym:=tfieldvarsym.create('__fpc_fenumval',vs_final,s32inttype,[]);
  245. enumclass.symtable.insert(fsym);
  246. tobjectsymtable(enumclass.symtable).addfield(fsym,vis_strictprivate);
  247. { add class field with hash table that maps from FPC-declared ordinal value -> enum instance }
  248. juhashmap:=search_system_type('JUHASHMAP').typedef;
  249. sym:=tstaticvarsym.create('__fpc_ord2enum',vs_final,juhashmap,[]);
  250. enumclass.symtable.insert(sym);
  251. { alias for consistency with parsed staticvarsyms }
  252. sl:=tpropaccesslist.create;
  253. sl.addsym(sl_load,sym);
  254. enumclass.symtable.insert(tabsolutevarsym.create_ref('$'+internal_static_field_name(sym.name),enumclass,sl));
  255. { add custom constructor }
  256. if not str_parse_method_dec('constructor Create(const __fpc_name: JLString; const __fpc_ord, __fpc_initenumval: longint);',potype_constructor,false,enumclass,pd) then
  257. internalerror(2011062401);
  258. pd.synthetickind:=tsk_jvm_enum_jumps_constr;
  259. pd.visibility:=vis_strictprivate;
  260. end
  261. else
  262. begin
  263. { insert "private constructor(string,int,int)" that calls inherited and
  264. initialises the FPC value field }
  265. add_missing_parent_constructors_intf(enumclass,vis_strictprivate);
  266. end;
  267. { add instance method to get the enum's value as declared in FPC }
  268. if not str_parse_method_dec('function FPCOrdinal: longint;',potype_function,false,enumclass,pd) then
  269. internalerror(2011062402);
  270. pd.synthetickind:=tsk_jvm_enum_fpcordinal;
  271. { add static class method to convert an ordinal to the corresponding enum }
  272. if not str_parse_method_dec('function FPCValueOf(__fpc_int: longint): __FPC_TEnumClassAlias; static;',potype_function,true,enumclass,pd) then
  273. internalerror(2011062402);
  274. pd.synthetickind:=tsk_jvm_enum_fpcvalueof;
  275. { insert "public static valueOf(string): tenumclass" that returns tenumclass(inherited valueOf(tenumclass,string)) }
  276. if not str_parse_method_dec('function valueOf(const __fpc_str: JLString): __FPC_TEnumClassAlias; static;',potype_function,true,enumclass,pd) then
  277. internalerror(2011062302);
  278. include(pd.procoptions,po_staticmethod);
  279. pd.synthetickind:=tsk_jvm_enum_valueof;
  280. { create array called "$VALUES" that will contain a reference to all
  281. enum instances (JDK convention)
  282. Disable duplicate identifier checking when inserting, because it will
  283. check for a conflict with "VALUES" ($<id> normally means "check for
  284. <id> without uppercasing first"), which will conflict with the
  285. "Values" instance method -- that's also the reason why we insert the
  286. field only now, because we cannot disable duplicate identifier
  287. checking when creating the "Values" method }
  288. sym:=tstaticvarsym.create('$VALUES',vs_final,arrdef,[]);
  289. sym.visibility:=vis_strictprivate;
  290. enumclass.symtable.insert(sym,false);
  291. { alias for consistency with parsed staticvarsyms }
  292. sl:=tpropaccesslist.create;
  293. sl.addsym(sl_load,sym);
  294. enumclass.symtable.insert(tabsolutevarsym.create_ref('$'+internal_static_field_name(sym.name),arrdef,sl));
  295. { alias for accessing the field in generated Pascal code }
  296. sl:=tpropaccesslist.create;
  297. sl.addsym(sl_load,sym);
  298. enumclass.symtable.insert(tabsolutevarsym.create_ref('__fpc_FVALUES',arrdef,sl));
  299. { add initialization of the static class fields created above }
  300. if not str_parse_method_dec('constructor fpc_enum_class_constructor;',potype_class_constructor,true,enumclass,pd) then
  301. internalerror(2011062303);
  302. pd.synthetickind:=tsk_jvm_enum_classconstr;
  303. symtablestack.pop(enumclass.symtable);
  304. current_structdef:=old_current_structdef;
  305. restore_scanner(sstate);
  306. end;
  307. procedure jvm_add_typed_const_initializer(csym: tconstsym);
  308. var
  309. ssym: tstaticvarsym;
  310. esym: tenumsym;
  311. i: longint;
  312. sstate: symcreat.tscannerstate;
  313. begin
  314. case csym.constdef.typ of
  315. enumdef:
  316. begin
  317. replace_scanner('jvm_enum_const',sstate);
  318. { make sure we don't emit a definition for this field (we'll do
  319. that for the constsym already) -> mark as external }
  320. ssym:=tstaticvarsym.create(internal_static_field_name(csym.realname),vs_final,csym.constdef,[vo_is_external]);
  321. csym.owner.insert(ssym);
  322. { alias storage to the constsym }
  323. ssym.set_mangledname(csym.realname);
  324. for i:=0 to tenumdef(csym.constdef).symtable.symlist.count-1 do
  325. begin
  326. esym:=tenumsym(tenumdef(csym.constdef).symtable.symlist[i]);
  327. if esym.value=csym.value.valueord.svalue then
  328. break;
  329. esym:=nil;
  330. end;
  331. { can happen in case of explicit typecast from integer constant
  332. to enum type }
  333. if not assigned(esym) then
  334. begin
  335. MessagePos(csym.fileinfo,parser_e_range_check_error);
  336. exit;
  337. end;
  338. str_parse_typedconst(current_asmdata.asmlists[al_typedconsts],esym.name+';',ssym);
  339. restore_scanner(sstate);
  340. end
  341. else
  342. internalerror(2011062701);
  343. end;
  344. end;
  345. end.