agjasmin.pas 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207
  1. {
  2. Copyright (c) 1998-2010 by the Free Pascal team
  3. This unit implements the Jasmin assembler writer
  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. { Unit for writing Jasmin assembler (JVM bytecode) output.
  18. }
  19. unit agjasmin;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. cclasses,
  24. globtype,globals,
  25. symconst,symbase,symdef,symsym,
  26. aasmbase,aasmtai,aasmdata,aasmcpu,
  27. assemble;
  28. type
  29. TJasminInstrWriter = class;
  30. {# This is a derived class which is used to write
  31. Jasmin-styled assembler.
  32. }
  33. { TJasminAssembler }
  34. TJasminAssembler=class(texternalassembler)
  35. protected
  36. jasminjar: tcmdstr;
  37. asmfiles: TCmdStrList;
  38. procedure WriteExtraHeader(obj: tabstractrecorddef);
  39. procedure WriteInstruction(hp: tai);
  40. procedure NewAsmFileForStructDef(obj: tabstractrecorddef);
  41. function VisibilityToStr(vis: tvisibility): ansistring;
  42. function MethodDefinition(pd: tprocdef): ansistring;
  43. function ConstValue(csym: tconstsym): ansistring;
  44. function ConstAssignmentValue(csym: tconstsym): ansistring;
  45. function ConstDefinition(sym: tconstsym): ansistring;
  46. function FieldDefinition(sym: tabstractvarsym): ansistring;
  47. function InnerStructDef(obj: tabstractrecorddef): ansistring;
  48. procedure WriteProcDef(pd: tprocdef);
  49. procedure WriteFieldSym(sym: tabstractvarsym);
  50. procedure WriteConstSym(sym: tconstsym);
  51. procedure WriteSymtableVarSyms(st: TSymtable);
  52. procedure WriteSymtableProcdefs(st: TSymtable);
  53. procedure WriteSymtableStructDefs(st: TSymtable);
  54. public
  55. constructor Create(smart: boolean); override;
  56. function MakeCmdLine: TCmdStr;override;
  57. procedure WriteTree(p:TAsmList);override;
  58. procedure WriteAsmList;override;
  59. destructor destroy; override;
  60. protected
  61. InstrWriter: TJasminInstrWriter;
  62. end;
  63. {# This is the base class for writing instructions.
  64. The WriteInstruction() method must be overridden
  65. to write a single instruction to the assembler
  66. file.
  67. }
  68. { TJasminInstrWriter }
  69. TJasminInstrWriter = class
  70. constructor create(_owner: TJasminAssembler);
  71. procedure WriteInstruction(hp : tai); virtual;
  72. protected
  73. owner: TJasminAssembler;
  74. end;
  75. implementation
  76. uses
  77. SysUtils,
  78. cutils,cfileutl,systems,script,
  79. fmodule,finput,verbose,
  80. symtype,symtable,jvmdef,
  81. itcpujas,cpubase,cpuinfo,cgutils,
  82. widestr
  83. ;
  84. const
  85. line_length = 70;
  86. type
  87. t64bitarray = array[0..7] of byte;
  88. t32bitarray = array[0..3] of byte;
  89. {****************************************************************************}
  90. { Support routines }
  91. {****************************************************************************}
  92. function fixline(s:string):string;
  93. {
  94. return s with all leading and ending spaces and tabs removed
  95. }
  96. var
  97. i,j,k : integer;
  98. begin
  99. i:=length(s);
  100. while (i>0) and (s[i] in [#9,' ']) do
  101. dec(i);
  102. j:=1;
  103. while (j<i) and (s[j] in [#9,' ']) do
  104. inc(j);
  105. for k:=j to i do
  106. if s[k] in [#0..#31,#127..#255] then
  107. s[k]:='.';
  108. fixline:=Copy(s,j,i-j+1);
  109. end;
  110. function constastr(p: pchar; len: longint): ansistring;
  111. var
  112. i,runstart,runlen: longint;
  113. procedure flush;
  114. begin
  115. if runlen>0 then
  116. begin
  117. setlength(result,length(result)+runlen);
  118. move(p[runstart],result[length(result)-runlen+1],runlen);
  119. runlen:=0;
  120. end;
  121. end;
  122. begin
  123. result:='"';
  124. runlen:=0;
  125. runstart:=0;
  126. for i:=0 to len-1 do
  127. begin
  128. { escape control codes }
  129. case p[i] of
  130. { LF and CR must be escaped specially, because \uXXXX parsing
  131. happens in the pre-processor, so it's the same as actually
  132. inserting a newline in the middle of a string constant }
  133. #10:
  134. begin
  135. flush;
  136. result:=result+'\n';
  137. end;
  138. #13:
  139. begin
  140. flush;
  141. result:=result+'\r';
  142. end;
  143. '"','\':
  144. begin
  145. flush;
  146. result:=result+'\'+p[i];
  147. end
  148. else if p[i]<#32 then
  149. begin
  150. flush;
  151. result:=result+'\u'+hexstr(ord(p[i]),4);
  152. end
  153. else if p[i]<#127 then
  154. begin
  155. if runlen=0 then
  156. runstart:=i;
  157. inc(runlen);
  158. end
  159. else
  160. begin
  161. { see comments in njvmcon }
  162. flush;
  163. result:=result+'\u'+hexstr(ord(p[i]),4)
  164. end;
  165. end;
  166. end;
  167. flush;
  168. result:=result+'"';
  169. end;
  170. function constwstr(w: pcompilerwidechar; len: longint): ansistring;
  171. var
  172. i: longint;
  173. begin
  174. result:='"';
  175. for i:=0 to len-1 do
  176. begin
  177. { escape control codes }
  178. case w[i] of
  179. 10:
  180. result:=result+'\n';
  181. 13:
  182. result:=result+'\r';
  183. ord('"'),ord('\'):
  184. result:=result+'\'+chr(w[i]);
  185. else if (w[i]<32) or
  186. (w[i]>=127) then
  187. result:=result+'\u'+hexstr(w[i],4)
  188. else
  189. result:=result+char(w[i]);
  190. end;
  191. end;
  192. result:=result+'"';
  193. end;
  194. function constsingle(s: single): ansistring;
  195. begin
  196. result:='0fx'+hexstr(longint(t32bitarray(s)),8);
  197. end;
  198. function constdouble(d: double): ansistring;
  199. begin
  200. // force interpretation as double (since we write it out as an
  201. // integer, we never have to swap the endianess). We have to
  202. // include the sign separately because of the way Java parses
  203. // hex numbers (0x8000000000000000 is not a valid long)
  204. result:=hexstr(abs(int64(t64bitarray(d))),16);
  205. if int64(t64bitarray(d))<0 then
  206. result:='-'+result;
  207. result:='0dx'+result;
  208. end;
  209. {****************************************************************************}
  210. { Jasmin Assembler writer }
  211. {****************************************************************************}
  212. destructor TJasminAssembler.Destroy;
  213. begin
  214. InstrWriter.free;
  215. asmfiles.free;
  216. inherited destroy;
  217. end;
  218. procedure TJasminAssembler.WriteTree(p:TAsmList);
  219. var
  220. ch : char;
  221. hp : tai;
  222. hp1 : tailineinfo;
  223. s : ansistring;
  224. i,pos : longint;
  225. InlineLevel : longint;
  226. do_line : boolean;
  227. begin
  228. if not assigned(p) then
  229. exit;
  230. InlineLevel:=0;
  231. { lineinfo is only needed for al_procedures (PFV) }
  232. do_line:=(cs_asm_source in current_settings.globalswitches);
  233. hp:=tai(p.first);
  234. while assigned(hp) do
  235. begin
  236. prefetch(pointer(hp.next)^);
  237. if not(hp.typ in SkipLineInfo) then
  238. begin
  239. hp1 := hp as tailineinfo;
  240. current_filepos:=hp1.fileinfo;
  241. { no line info for inlined code }
  242. if do_line and (inlinelevel=0) then
  243. begin
  244. { load infile }
  245. if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
  246. begin
  247. infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
  248. if assigned(infile) then
  249. begin
  250. { open only if needed !! }
  251. if (cs_asm_source in current_settings.globalswitches) then
  252. infile.open;
  253. end;
  254. { avoid unnecessary reopens of the same file !! }
  255. lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
  256. { be sure to change line !! }
  257. lastfileinfo.line:=-1;
  258. end;
  259. { write source }
  260. if (cs_asm_source in current_settings.globalswitches) and
  261. assigned(infile) then
  262. begin
  263. if (infile<>lastinfile) then
  264. begin
  265. AsmWriteLn(target_asm.comment+'['+infile.name^+']');
  266. if assigned(lastinfile) then
  267. lastinfile.close;
  268. end;
  269. if (hp1.fileinfo.line<>lastfileinfo.line) and
  270. ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
  271. begin
  272. if (hp1.fileinfo.line<>0) and
  273. ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
  274. AsmWriteLn(target_asm.comment+'['+tostr(hp1.fileinfo.line)+'] '+
  275. fixline(infile.GetLineStr(hp1.fileinfo.line)));
  276. { set it to a negative value !
  277. to make that is has been read already !! PM }
  278. if (infile.linebuf^[hp1.fileinfo.line]>=0) then
  279. infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
  280. end;
  281. end;
  282. lastfileinfo:=hp1.fileinfo;
  283. lastinfile:=infile;
  284. end;
  285. end;
  286. case hp.typ of
  287. ait_comment :
  288. Begin
  289. AsmWrite(target_asm.comment);
  290. AsmWritePChar(tai_comment(hp).str);
  291. AsmLn;
  292. End;
  293. ait_regalloc :
  294. begin
  295. if (cs_asm_regalloc in current_settings.globalswitches) then
  296. begin
  297. AsmWrite(#9+target_asm.comment+'Register ');
  298. repeat
  299. AsmWrite(std_regname(Tai_regalloc(hp).reg));
  300. if (hp.next=nil) or
  301. (tai(hp.next).typ<>ait_regalloc) or
  302. (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
  303. break;
  304. hp:=tai(hp.next);
  305. AsmWrite(',');
  306. until false;
  307. AsmWrite(' ');
  308. AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
  309. end;
  310. end;
  311. ait_tempalloc :
  312. begin
  313. if (cs_asm_tempalloc in current_settings.globalswitches) then
  314. begin
  315. {$ifdef EXTDEBUG}
  316. if assigned(tai_tempalloc(hp).problem) then
  317. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  318. tostr(tai_tempalloc(hp).tempsize)+' '+tai_tempalloc(hp).problem^)
  319. else
  320. {$endif EXTDEBUG}
  321. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  322. tostr(tai_tempalloc(hp).tempsize)+' '+tempallocstr[tai_tempalloc(hp).allocation]);
  323. end;
  324. end;
  325. ait_align :
  326. begin
  327. end;
  328. ait_section :
  329. begin
  330. end;
  331. ait_datablock :
  332. begin
  333. internalerror(2010122701);
  334. end;
  335. ait_const:
  336. begin
  337. AsmWriteln('constant');
  338. // internalerror(2010122702);
  339. end;
  340. ait_real_64bit :
  341. begin
  342. internalerror(2010122703);
  343. end;
  344. ait_real_32bit :
  345. begin
  346. internalerror(2010122703);
  347. end;
  348. ait_comp_64bit :
  349. begin
  350. internalerror(2010122704);
  351. end;
  352. ait_string :
  353. begin
  354. pos:=0;
  355. for i:=1 to tai_string(hp).len do
  356. begin
  357. if pos=0 then
  358. begin
  359. AsmWrite(#9'strconst: '#9'"');
  360. pos:=20;
  361. end;
  362. ch:=tai_string(hp).str[i-1];
  363. case ch of
  364. #0, {This can't be done by range, because a bug in FPC}
  365. #1..#31,
  366. #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
  367. '"' : s:='\"';
  368. '\' : s:='\\';
  369. else
  370. s:=ch;
  371. end;
  372. AsmWrite(s);
  373. inc(pos,length(s));
  374. if (pos>line_length) or (i=tai_string(hp).len) then
  375. begin
  376. AsmWriteLn('"');
  377. pos:=0;
  378. end;
  379. end;
  380. end;
  381. ait_label :
  382. begin
  383. if (tai_label(hp).labsym.is_used) then
  384. begin
  385. AsmWrite(tai_label(hp).labsym.name);
  386. AsmWriteLn(':');
  387. end;
  388. end;
  389. ait_symbol :
  390. begin
  391. if (tai_symbol(hp).sym.typ = AT_FUNCTION) then
  392. begin
  393. end
  394. else
  395. begin
  396. AsmWrite('data symbol: ');
  397. AsmWriteln(tai_symbol(hp).sym.name);
  398. // internalerror(2010122706);
  399. end;
  400. end;
  401. ait_symbol_end :
  402. begin
  403. end;
  404. ait_instruction :
  405. begin
  406. WriteInstruction(hp);
  407. end;
  408. ait_force_line,
  409. ait_function_name : ;
  410. ait_cutobject :
  411. begin
  412. end;
  413. ait_marker :
  414. if tai_marker(hp).kind=mark_NoLineInfoStart then
  415. inc(InlineLevel)
  416. else if tai_marker(hp).kind=mark_NoLineInfoEnd then
  417. dec(InlineLevel);
  418. ait_directive :
  419. begin
  420. AsmWrite('.'+directivestr[tai_directive(hp).directive]+' ');
  421. if assigned(tai_directive(hp).name) then
  422. AsmWrite(tai_directive(hp).name^);
  423. AsmLn;
  424. end;
  425. ait_jvar:
  426. begin
  427. AsmWrite('.var ');
  428. AsmWrite(tostr(tai_jvar(hp).stackslot));
  429. AsmWrite(' is ');
  430. AsmWrite(tai_jvar(hp).desc^);
  431. AsmWrite(' from ');
  432. AsmWrite(tai_jvar(hp).startlab.name);
  433. AsmWrite(' to ');
  434. AsmWriteLn(tai_jvar(hp).stoplab.name);
  435. end;
  436. ait_jcatch:
  437. begin
  438. AsmWrite('.catch ');
  439. AsmWrite(tai_jcatch(hp).name^);
  440. AsmWrite(' from ');
  441. AsmWrite(tai_jcatch(hp).startlab.name);
  442. AsmWrite(' to ');
  443. AsmWrite(tai_jcatch(hp).stoplab.name);
  444. AsmWrite(' using ');
  445. AsmWriteLn(tai_jcatch(hp).handlerlab.name);
  446. end;
  447. else
  448. internalerror(2010122707);
  449. end;
  450. hp:=tai(hp.next);
  451. end;
  452. end;
  453. procedure TJasminAssembler.WriteExtraHeader(obj: tabstractrecorddef);
  454. var
  455. superclass,
  456. intf: tobjectdef;
  457. n: ansistring;
  458. i: longint;
  459. toplevelowner: tsymtable;
  460. begin
  461. { JVM 1.5+ }
  462. AsmWriteLn('.bytecode 49.0');
  463. // include files are not support by Java, and the directory of the main
  464. // source file must not be specified
  465. if assigned(current_module.mainsource) then
  466. n:=ExtractFileName(current_module.mainsource^)
  467. else
  468. n:=InputFileName;
  469. AsmWriteLn('.source '+ExtractFileName(n));
  470. { class/interface name }
  471. if not assigned(obj) then
  472. begin
  473. { fake class type for unit -> name=unitname and
  474. superclass=java.lang.object, make final so you cannot descend
  475. from it }
  476. AsmWrite('.class final public ');
  477. if assigned(current_module.namespace) then
  478. AsmWrite(current_module.namespace^+'.');
  479. AsmWriteln(current_module.realmodulename^);
  480. AsmWriteLn('.super java/lang/Object');
  481. end
  482. else
  483. begin
  484. toplevelowner:=obj.owner;
  485. while not(toplevelowner.symtabletype in [staticsymtable,globalsymtable]) do
  486. toplevelowner:=toplevelowner.defowner.owner;
  487. case obj.typ of
  488. recorddef:
  489. begin
  490. { can't inherit from records }
  491. AsmWrite('.class final ');
  492. if toplevelowner.symtabletype=globalsymtable then
  493. AsmWrite('public ');
  494. AsmWriteln(obj.jvm_full_typename(true));
  495. superclass:=java_fpcbaserecordtype;
  496. end;
  497. objectdef:
  498. begin
  499. case tobjectdef(obj).objecttype of
  500. odt_javaclass:
  501. begin
  502. AsmWrite('.class ');
  503. if oo_is_sealed in tobjectdef(obj).objectoptions then
  504. AsmWrite('final ');
  505. if (oo_is_abstract in tobjectdef(obj).objectoptions) or
  506. (tobjectdef(obj).abstractcnt<>0) then
  507. AsmWrite('abstract ');
  508. if toplevelowner.symtabletype=globalsymtable then
  509. AsmWrite('public ');
  510. if (oo_is_enum_class in tobjectdef(obj).objectoptions) then
  511. AsmWrite('enum ');
  512. AsmWriteln(obj.jvm_full_typename(true));
  513. superclass:=tobjectdef(obj).childof;
  514. end;
  515. odt_interfacejava:
  516. begin
  517. AsmWrite('.interface abstract ');
  518. if toplevelowner.symtabletype=globalsymtable then
  519. AsmWrite('public ');
  520. AsmWriteLn(obj.jvm_full_typename(true));
  521. { interfaces must always specify Java.lang.object as
  522. superclass }
  523. superclass:=java_jlobject;
  524. end
  525. else
  526. internalerror(2011010906);
  527. end;
  528. end;
  529. end;
  530. { superclass }
  531. if assigned(superclass) then
  532. begin
  533. AsmWrite('.super ');
  534. if assigned(superclass.import_lib) then
  535. AsmWrite(superclass.import_lib^+'/');
  536. AsmWriteln(superclass.objextname^);
  537. end;
  538. { implemented interfaces }
  539. if (obj.typ=objectdef) and
  540. assigned(tobjectdef(obj).ImplementedInterfaces) then
  541. begin
  542. for i:=0 to tobjectdef(obj).ImplementedInterfaces.count-1 do
  543. begin
  544. intf:=TImplementedInterface(tobjectdef(obj).ImplementedInterfaces[i]).IntfDef;
  545. AsmWrite('.implements ');
  546. if assigned(intf.import_lib) then
  547. AsmWrite(intf.import_lib^+'/');
  548. AsmWriteln(intf.objextname^);
  549. end;
  550. end;
  551. { signature for enum classes (must come after superclass and
  552. implemented interfaces) }
  553. if (obj.typ=objectdef) and
  554. (oo_is_enum_class in tobjectdef(obj).objectoptions) then
  555. AsmWriteln('.signature "Ljava/lang/Enum<L'+obj.jvm_full_typename(true)+';>;"');
  556. { in case of nested class: relation to parent class }
  557. if obj.owner.symtabletype in [objectsymtable,recordsymtable] then
  558. AsmWriteln(InnerStructDef(obj));
  559. { all all nested classes }
  560. for i:=0 to obj.symtable.deflist.count-1 do
  561. if is_java_class_or_interface(tdef(obj.symtable.deflist[i])) or
  562. (tdef(obj.symtable.deflist[i]).typ=recorddef) then
  563. AsmWriteln(InnerStructDef(tabstractrecorddef(obj.symtable.deflist[i])));
  564. end;
  565. AsmLn;
  566. end;
  567. procedure TJasminAssembler.WriteInstruction(hp: tai);
  568. begin
  569. InstrWriter.WriteInstruction(hp);
  570. end;
  571. function TJasminAssembler.MakeCmdLine: TCmdStr;
  572. const
  573. jasminjarname = 'jasmin.jar';
  574. var
  575. filenames: tcmdstr;
  576. jasminjarfound: boolean;
  577. begin
  578. if jasminjar='' then
  579. begin
  580. jasminjarfound:=false;
  581. if utilsdirectory<>'' then
  582. jasminjarfound:=FindFile(jasminjarname,utilsdirectory,false,jasminjar);
  583. if not jasminjarfound then
  584. jasminjarfound:=FindFileInExeLocations(jasminjarname,false,jasminjar);
  585. if (not jasminjarfound) and not(cs_asm_extern in current_settings.globalswitches) then
  586. begin
  587. Message1(exec_e_assembler_not_found,jasminjarname);
  588. current_settings.globalswitches:=current_settings.globalswitches+[cs_asm_extern];
  589. end;
  590. if jasminjarfound then
  591. Message1(exec_t_using_assembler,jasminjar);
  592. end;
  593. result:=target_asm.asmcmd;
  594. filenames:=maybequoted(ScriptFixFileName(AsmFileName));
  595. while not asmfiles.empty do
  596. filenames:=filenames+' '+asmfiles.GetFirst;
  597. Replace(result,'$ASM',filenames);
  598. if (path<>'') then
  599. Replace(result,'$OBJDIR',maybequoted(ScriptFixFileName(path)))
  600. else
  601. Replace(result,'$OBJDIR','.');
  602. Replace(result,'$JASMINJAR',maybequoted(ScriptFixFileName(jasminjar)));
  603. end;
  604. procedure TJasminAssembler.NewAsmFileForStructDef(obj: tabstractrecorddef);
  605. begin
  606. if AsmSize<>AsmStartSize then
  607. begin
  608. AsmClose;
  609. asmfiles.Concat(maybequoted(ScriptFixFileName(AsmFileName)));
  610. end
  611. else
  612. AsmClear;
  613. AsmFileName:=obj.jvm_full_typename(false);
  614. AsmFileName:=Path+FixFileName(AsmFileName)+target_info.asmext;
  615. AsmCreate(cut_normal);
  616. end;
  617. function TJasminAssembler.VisibilityToStr(vis: tvisibility): ansistring;
  618. begin
  619. case vis of
  620. vis_hidden,
  621. vis_strictprivate:
  622. result:='private ';
  623. vis_strictprotected:
  624. result:='protected ';
  625. vis_protected,
  626. vis_private:
  627. { pick default visibility = "package" visibility; required because
  628. other classes in the same unit can also access these symbols }
  629. result:='';
  630. vis_public:
  631. result:='public '
  632. else
  633. internalerror(2010122609);
  634. end;
  635. end;
  636. function TJasminAssembler.MethodDefinition(pd: tprocdef): ansistring;
  637. begin
  638. result:=VisibilityToStr(pd.visibility);
  639. if (pd.procsym.owner.symtabletype in [globalsymtable,staticsymtable,localsymtable]) or
  640. (po_classmethod in pd.procoptions) then
  641. result:=result+'static ';
  642. if (po_abstractmethod in pd.procoptions) or
  643. is_javainterface(tdef(pd.owner.defowner)) then
  644. result:=result+'abstract ';
  645. if (pd.procsym.owner.symtabletype in [globalsymtable,staticsymtable,localsymtable]) or
  646. (po_finalmethod in pd.procoptions) or
  647. (not(po_virtualmethod in pd.procoptions) and
  648. not(pd.proctypeoption in [potype_constructor,potype_class_constructor])) then
  649. result:=result+'final ';
  650. result:=result+pd.jvmmangledbasename(false);
  651. end;
  652. function TJasminAssembler.ConstValue(csym: tconstsym): ansistring;
  653. begin
  654. case csym.consttyp of
  655. constord:
  656. { always interpret as signed value, because the JVM does not
  657. support unsigned values }
  658. case csym.constdef.size of
  659. 1:result:=tostr(shortint(csym.value.valueord.svalue));
  660. 2:result:=tostr(smallint(csym.value.valueord.svalue));
  661. 4:result:=tostr(longint(csym.value.valueord.svalue));
  662. 8:result:=tostr(csym.value.valueord.svalue);
  663. end;
  664. conststring:
  665. result:=constastr(pchar(csym.value.valueptr),csym.value.len);
  666. constreal:
  667. case tfloatdef(csym.constdef).floattype of
  668. s32real:
  669. result:=constsingle(pbestreal(csym.value.valueptr)^);
  670. s64real:
  671. result:=constdouble(pbestreal(csym.value.valueptr)^);
  672. else
  673. internalerror(2011021204);
  674. end;
  675. constset:
  676. result:='TODO: add support for constant sets';
  677. constpointer:
  678. { can only be null, but that's the default value and should not
  679. be written; there's no primitive type that can hold nill }
  680. internalerror(2011021201);
  681. constnil:
  682. internalerror(2011021202);
  683. constresourcestring:
  684. result:='TODO: add support for constant resource strings';
  685. constwstring:
  686. result:=constwstr(pcompilerwidestring(csym.value.valueptr)^.data,pcompilerwidestring(csym.value.valueptr)^.len);
  687. constguid:
  688. result:='TODO: add support for constant guids';
  689. else
  690. internalerror(2011021205);
  691. end;
  692. end;
  693. function TJasminAssembler.ConstAssignmentValue(csym: tconstsym): ansistring;
  694. begin
  695. { nil is the default value -> don't write explicitly }
  696. case csym.consttyp of
  697. constpointer:
  698. begin
  699. if csym.value.valueordptr<>0 then
  700. internalerror(2011021206);
  701. result:='';
  702. end;
  703. constnil:
  704. result:='';
  705. else
  706. begin
  707. { enums and sets are initialized as typed constants }
  708. if not assigned(csym.constdef) or
  709. not(csym.constdef.typ in [enumdef,setdef]) then
  710. result:=' = '+ConstValue(csym)
  711. end;
  712. end;
  713. end;
  714. function TJasminAssembler.ConstDefinition(sym: tconstsym): ansistring;
  715. begin
  716. result:=VisibilityToStr(sym.visibility);
  717. { formal constants are always class-level, not instance-level }
  718. result:=result+'static final ';
  719. if sp_internal in sym.symoptions then
  720. result:=result+'synthetic ';
  721. result:=result+jvmmangledbasename(sym,true);
  722. result:=result+ConstAssignmentValue(tconstsym(sym));
  723. end;
  724. function TJasminAssembler.FieldDefinition(sym: tabstractvarsym): ansistring;
  725. var
  726. vissym: tabstractvarsym;
  727. begin
  728. vissym:=sym;
  729. { static field definition -> get original field definition for
  730. visibility }
  731. if (sym.typ=staticvarsym) and
  732. (sym.owner.symtabletype in [objectsymtable,recordsymtable]) then
  733. begin
  734. vissym:=tabstractvarsym(
  735. tabstractrecorddef(sym.owner.defowner).symtable.find(
  736. internal_static_field_name(sym.name)));
  737. if not assigned(vissym) then
  738. vissym:=tabstractvarsym(
  739. tabstractrecorddef(sym.owner.defowner).symtable.find(
  740. generate_nested_name(sym.owner,'_')+'_'+sym.name));
  741. if not assigned(vissym) or
  742. not(vissym.typ in [fieldvarsym,absolutevarsym]) then
  743. internalerror(2011011501);
  744. end;
  745. case vissym.typ of
  746. staticvarsym:
  747. begin
  748. if vissym.owner.symtabletype=globalsymtable then
  749. result:='public '
  750. else
  751. { package visbility }
  752. result:='';
  753. end;
  754. fieldvarsym,
  755. absolutevarsym:
  756. result:=VisibilityToStr(tstoredsym(vissym).visibility);
  757. else
  758. internalerror(2011011204);
  759. end;
  760. if (sym.typ=staticvarsym) or
  761. (sp_static in sym.symoptions) then
  762. result:=result+'static ';
  763. if sym.varspez in [vs_const,vs_final] then
  764. result:=result+'final ';
  765. if sp_internal in sym.symoptions then
  766. result:=result+'synthetic ';
  767. { mark the class fields of enum classes that contain the initialised
  768. enum instances as "enum" (recognise them by the fact that their type
  769. is the same as their parent class, and that this parent class is
  770. marked as oo_is_enum_class) }
  771. if assigned(sym.owner.defowner) and
  772. (tdef(sym.owner.defowner).typ=objectdef) and
  773. (oo_is_enum_class in tobjectdef(sym.owner.defowner).objectoptions) and
  774. (sym.typ=staticvarsym) and
  775. (tstaticvarsym(sym).vardef=tdef(sym.owner.defowner)) then
  776. result:=result+'enum ';
  777. result:=result+jvmmangledbasename(sym,true);
  778. end;
  779. function TJasminAssembler.InnerStructDef(obj: tabstractrecorddef): ansistring;
  780. var
  781. extname: pshortstring;
  782. kindname: ansistring;
  783. begin
  784. if not(obj.owner.defowner.typ in [objectdef,recorddef]) then
  785. internalerror(2011021701);
  786. case obj.typ of
  787. recorddef:
  788. begin
  789. kindname:='class ';
  790. extname:=obj.symtable.realname;
  791. end;
  792. objectdef:
  793. begin
  794. extname:=tobjectdef(obj).objextname;
  795. case tobjectdef(obj).objecttype of
  796. odt_javaclass:
  797. kindname:='class ';
  798. odt_interfacejava:
  799. kindname:='interface ';
  800. else
  801. internalerror(2011021702);
  802. end;
  803. end;
  804. else
  805. internalerror(2011032809);
  806. end;
  807. result:=
  808. '.inner '+
  809. kindname+
  810. VisibilityToStr(obj.typesym.visibility)+
  811. { Nested classes in the Pascal sense are equivalent to "static"
  812. inner classes in Java -- will be changed when support for
  813. Java-style non-static classes is added }
  814. ' static '+
  815. extname^+
  816. ' inner '+
  817. obj.jvm_full_typename(true)+
  818. ' outer '+
  819. tabstractrecorddef(obj.owner.defowner).jvm_full_typename(true);
  820. end;
  821. procedure TJasminAssembler.WriteProcDef(pd: tprocdef);
  822. begin
  823. if not assigned(pd.exprasmlist) and
  824. not(po_abstractmethod in pd.procoptions) and
  825. (not is_javainterface(pd.struct) or
  826. (pd.proctypeoption in [potype_unitinit,potype_unitfinalize])) then
  827. exit;
  828. AsmWrite('.method ');
  829. AsmWriteln(MethodDefinition(pd));
  830. if jvmtypeneedssignature(pd) then
  831. begin
  832. AsmWrite('.signature "');
  833. AsmWrite(pd.jvmmangledbasename(true));
  834. AsmWriteln('"');
  835. end;
  836. WriteTree(pd.exprasmlist);
  837. AsmWriteln('.end method');
  838. AsmLn;
  839. end;
  840. procedure TJasminAssembler.WriteFieldSym(sym: tabstractvarsym);
  841. begin
  842. { internal static field definition alias -> skip }
  843. if sp_static in sym.symoptions then
  844. exit;
  845. { external definition -> no definition here }
  846. if vo_is_external in sym.varoptions then
  847. exit;
  848. AsmWrite('.field ');
  849. AsmWriteln(FieldDefinition(sym));
  850. end;
  851. procedure TJasminAssembler.WriteConstSym(sym: tconstsym);
  852. begin
  853. AsmWrite('.field ');
  854. AsmWriteln(ConstDefinition(sym));
  855. end;
  856. procedure TJasminAssembler.WriteSymtableVarSyms(st: TSymtable);
  857. var
  858. sym : tsym;
  859. i,j : longint;
  860. begin
  861. if not assigned(st) then
  862. exit;
  863. for i:=0 to st.SymList.Count-1 do
  864. begin
  865. sym:=tsym(st.SymList[i]);
  866. case sym.typ of
  867. staticvarsym,
  868. fieldvarsym:
  869. begin
  870. WriteFieldSym(tabstractvarsym(sym));
  871. if (sym.typ=staticvarsym) and
  872. assigned(tstaticvarsym(sym).defaultconstsym) then
  873. WriteFieldSym(tabstractvarsym(tstaticvarsym(sym).defaultconstsym));
  874. end;
  875. constsym:
  876. begin
  877. { multiple procedures can have constants with the same name }
  878. if not assigned(sym.owner.defowner) or
  879. (tdef(sym.owner.defowner).typ<>procdef) then
  880. WriteConstSym(tconstsym(sym));
  881. end;
  882. procsym:
  883. begin
  884. for j:=0 to tprocsym(sym).procdeflist.count-1 do
  885. WriteSymtableVarSyms(tprocdef(tprocsym(sym).procdeflist[j]).localst);
  886. end;
  887. end;
  888. end;
  889. end;
  890. procedure TJasminAssembler.WriteSymtableProcdefs(st: TSymtable);
  891. var
  892. i : longint;
  893. def : tdef;
  894. begin
  895. if not assigned(st) then
  896. exit;
  897. for i:=0 to st.DefList.Count-1 do
  898. begin
  899. def:=tdef(st.DefList[i]);
  900. case def.typ of
  901. procdef :
  902. begin
  903. { methods are also in the static/globalsymtable of the unit
  904. -> make sure they are only written for the objectdefs that
  905. own them }
  906. if not(st.symtabletype in [staticsymtable,globalsymtable]) or
  907. (def.owner=st) then
  908. begin
  909. WriteProcDef(tprocdef(def));
  910. if assigned(tprocdef(def).localst) then
  911. WriteSymtableProcdefs(tprocdef(def).localst);
  912. end;
  913. end;
  914. end;
  915. end;
  916. end;
  917. procedure TJasminAssembler.WriteSymtableStructDefs(st: TSymtable);
  918. var
  919. i : longint;
  920. def : tdef;
  921. obj : tabstractrecorddef;
  922. nestedstructs: tfpobjectlist;
  923. begin
  924. if not assigned(st) then
  925. exit;
  926. nestedstructs:=tfpobjectlist.create(false);
  927. for i:=0 to st.DefList.Count-1 do
  928. begin
  929. def:=tdef(st.DefList[i]);
  930. case def.typ of
  931. objectdef:
  932. if not(oo_is_external in tobjectdef(def).objectoptions) then
  933. nestedstructs.add(def);
  934. recorddef:
  935. nestedstructs.add(def);
  936. end;
  937. end;
  938. for i:=0 to nestedstructs.count-1 do
  939. begin
  940. obj:=tabstractrecorddef(nestedstructs[i]);
  941. NewAsmFileForStructDef(obj);
  942. WriteExtraHeader(obj);
  943. WriteSymtableVarSyms(obj.symtable);
  944. AsmLn;
  945. WriteSymtableProcDefs(obj.symtable);
  946. WriteSymtableStructDefs(obj.symtable);
  947. end;
  948. nestedstructs.free;
  949. end;
  950. constructor TJasminAssembler.Create(smart: boolean);
  951. begin
  952. inherited create(smart);
  953. InstrWriter:=TJasminInstrWriter.Create(self);
  954. asmfiles:=TCmdStrList.Create;
  955. end;
  956. procedure TJasminAssembler.WriteAsmList;
  957. begin
  958. {$ifdef EXTDEBUG}
  959. if assigned(current_module.mainsource) then
  960. Comment(V_Debug,'Start writing Jasmin-styled assembler output for '+current_module.mainsource^);
  961. {$endif}
  962. AsmStartSize:=AsmSize;
  963. WriteExtraHeader(nil);
  964. (*
  965. for hal:=low(TasmlistType) to high(TasmlistType) do
  966. begin
  967. AsmWriteLn(target_asm.comment+'Begin asmlist '+AsmlistTypeStr[hal]);
  968. writetree(current_asmdata.asmlists[hal]);
  969. AsmWriteLn(target_asm.comment+'End asmlist '+AsmlistTypeStr[hal]);
  970. end;
  971. *)
  972. { print all global variables }
  973. WriteSymtableVarSyms(current_module.globalsymtable);
  974. WriteSymtableVarSyms(current_module.localsymtable);
  975. AsmLn;
  976. { print all global procedures/functions }
  977. WriteSymtableProcdefs(current_module.globalsymtable);
  978. WriteSymtableProcdefs(current_module.localsymtable);
  979. WriteSymtableStructDefs(current_module.globalsymtable);
  980. WriteSymtableStructDefs(current_module.localsymtable);
  981. AsmLn;
  982. {$ifdef EXTDEBUG}
  983. if assigned(current_module.mainsource) then
  984. Comment(V_Debug,'Done writing gas-styled assembler output for '+current_module.mainsource^);
  985. {$endif EXTDEBUG}
  986. end;
  987. {****************************************************************************}
  988. { Jasmin Instruction Writer }
  989. {****************************************************************************}
  990. constructor TJasminInstrWriter.create(_owner: TJasminAssembler);
  991. begin
  992. inherited create;
  993. owner := _owner;
  994. end;
  995. function getreferencestring(var ref : treference) : ansistring;
  996. begin
  997. if (ref.arrayreftype<>art_none) or
  998. (ref.index<>NR_NO) then
  999. internalerror(2010122809);
  1000. if assigned(ref.symbol) then
  1001. begin
  1002. // global symbol or field -> full type and name
  1003. // ref.base can be <> NR_NO in case an instance field is loaded.
  1004. // This register is not part of this instruction, it will have
  1005. // been placed on the stack by the previous one.
  1006. if (ref.offset<>0) then
  1007. internalerror(2010122811);
  1008. result:=ref.symbol.name;
  1009. end
  1010. else
  1011. begin
  1012. // local symbol -> stack slot, stored in offset
  1013. if ref.base<>NR_STACK_POINTER_REG then
  1014. internalerror(2010122810);
  1015. result:=tostr(ref.offset);
  1016. end;
  1017. end;
  1018. function getopstr(const o:toper) : ansistring;
  1019. var
  1020. d: double;
  1021. s: single;
  1022. begin
  1023. case o.typ of
  1024. top_reg:
  1025. // should have been translated into a memory location by the
  1026. // register allocator)
  1027. if (cs_no_regalloc in current_settings.globalswitches) then
  1028. getopstr:=std_regname(o.reg)
  1029. else
  1030. internalerror(2010122803);
  1031. top_const:
  1032. str(o.val,result);
  1033. top_ref:
  1034. getopstr:=getreferencestring(o.ref^);
  1035. top_single:
  1036. begin
  1037. result:=constsingle(o.sval);
  1038. end;
  1039. top_double:
  1040. begin
  1041. result:=constdouble(o.dval);
  1042. end;
  1043. top_string:
  1044. begin
  1045. result:=constastr(o.pcval,o.pcvallen);
  1046. end;
  1047. top_wstring:
  1048. begin
  1049. result:=constwstr(o.pwstrval^.data,getlengthwidestring(o.pwstrval));
  1050. end
  1051. else
  1052. internalerror(2010122802);
  1053. end;
  1054. end;
  1055. procedure TJasminInstrWriter.WriteInstruction(hp: tai);
  1056. var
  1057. s: ansistring;
  1058. i: byte;
  1059. sep: ansistring;
  1060. begin
  1061. s:=#9+jas_op2str[taicpu(hp).opcode];
  1062. if taicpu(hp).ops<>0 then
  1063. begin
  1064. sep:=#9;
  1065. for i:=0 to taicpu(hp).ops-1 do
  1066. begin
  1067. s:=s+sep+getopstr(taicpu(hp).oper[i]^);
  1068. sep:=' ';
  1069. end;
  1070. end;
  1071. owner.AsmWriteLn(s);
  1072. end;
  1073. {****************************************************************************}
  1074. { Jasmin Instruction Writer }
  1075. {****************************************************************************}
  1076. const
  1077. as_jvm_jasmin_info : tasminfo =
  1078. (
  1079. id : as_jvm_jasmin;
  1080. idtxt : 'Jasmin';
  1081. asmbin : 'java';
  1082. asmcmd : '-jar $JASMINJAR $ASM -d $OBJDIR';
  1083. supported_targets : [system_jvm_java32];
  1084. flags : [];
  1085. labelprefix : 'L';
  1086. comment : ' ; ';
  1087. );
  1088. begin
  1089. RegisterAssembler(as_jvm_jasmin_info,TJasminAssembler);
  1090. end.