agjasmin.pas 42 KB

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