agjasmin.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  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: tobjectdef);
  39. procedure WriteInstruction(hp: tai);
  40. procedure NewAsmFileForObjectDef(obj: tobjectdef);
  41. function VisibilityToStr(vis: tvisibility): string;
  42. function MethodDefinition(pd: tprocdef): string;
  43. function FieldDefinition(sym: tabstractvarsym): string;
  44. function InnerObjDef(obj: tobjectdef): string;
  45. procedure WriteProcDef(pd: tprocdef);
  46. procedure WriteFieldSym(sym: tabstractvarsym);
  47. procedure WriteSymtableVarSyms(st: TSymtable);
  48. procedure WriteSymtableProcdefs(st: TSymtable);
  49. procedure WriteSymtableObjectDefs(st: TSymtable);
  50. public
  51. constructor Create(smart: boolean); override;
  52. function MakeCmdLine: TCmdStr;override;
  53. procedure WriteTree(p:TAsmList);override;
  54. procedure WriteAsmList;override;
  55. destructor destroy; override;
  56. protected
  57. InstrWriter: TJasminInstrWriter;
  58. end;
  59. {# This is the base class for writing instructions.
  60. The WriteInstruction() method must be overridden
  61. to write a single instruction to the assembler
  62. file.
  63. }
  64. { TJasminInstrWriter }
  65. TJasminInstrWriter = class
  66. constructor create(_owner: TJasminAssembler);
  67. procedure WriteInstruction(hp : tai); virtual;
  68. protected
  69. owner: TJasminAssembler;
  70. end;
  71. implementation
  72. uses
  73. SysUtils,
  74. cutils,cfileutl,systems,script,
  75. fmodule,finput,verbose,
  76. symtype,symtable,jvmdef,
  77. itcpujas,cpubase,cgutils,
  78. widestr
  79. ;
  80. const
  81. line_length = 70;
  82. type
  83. t64bitarray = array[0..7] of byte;
  84. t32bitarray = array[0..3] of byte;
  85. {****************************************************************************}
  86. { Support routines }
  87. {****************************************************************************}
  88. function fixline(s:string):string;
  89. {
  90. return s with all leading and ending spaces and tabs removed
  91. }
  92. var
  93. i,j,k : integer;
  94. begin
  95. i:=length(s);
  96. while (i>0) and (s[i] in [#9,' ']) do
  97. dec(i);
  98. j:=1;
  99. while (j<i) and (s[j] in [#9,' ']) do
  100. inc(j);
  101. for k:=j to i do
  102. if s[k] in [#0..#31,#127..#255] then
  103. s[k]:='.';
  104. fixline:=Copy(s,j,i-j+1);
  105. end;
  106. {****************************************************************************}
  107. { Jasmin Assembler writer }
  108. {****************************************************************************}
  109. destructor TJasminAssembler.Destroy;
  110. begin
  111. InstrWriter.free;
  112. asmfiles.free;
  113. inherited destroy;
  114. end;
  115. procedure TJasminAssembler.WriteTree(p:TAsmList);
  116. var
  117. ch : char;
  118. hp : tai;
  119. hp1 : tailineinfo;
  120. s : string;
  121. i,pos : longint;
  122. InlineLevel : longint;
  123. do_line : boolean;
  124. begin
  125. if not assigned(p) then
  126. exit;
  127. InlineLevel:=0;
  128. { lineinfo is only needed for al_procedures (PFV) }
  129. do_line:=(cs_asm_source in current_settings.globalswitches);
  130. hp:=tai(p.first);
  131. while assigned(hp) do
  132. begin
  133. prefetch(pointer(hp.next)^);
  134. if not(hp.typ in SkipLineInfo) then
  135. begin
  136. hp1 := hp as tailineinfo;
  137. current_filepos:=hp1.fileinfo;
  138. { no line info for inlined code }
  139. if do_line and (inlinelevel=0) then
  140. begin
  141. { load infile }
  142. if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
  143. begin
  144. infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
  145. if assigned(infile) then
  146. begin
  147. { open only if needed !! }
  148. if (cs_asm_source in current_settings.globalswitches) then
  149. infile.open;
  150. end;
  151. { avoid unnecessary reopens of the same file !! }
  152. lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
  153. { be sure to change line !! }
  154. lastfileinfo.line:=-1;
  155. end;
  156. { write source }
  157. if (cs_asm_source in current_settings.globalswitches) and
  158. assigned(infile) then
  159. begin
  160. if (infile<>lastinfile) then
  161. begin
  162. AsmWriteLn(target_asm.comment+'['+infile.name^+']');
  163. if assigned(lastinfile) then
  164. lastinfile.close;
  165. end;
  166. if (hp1.fileinfo.line<>lastfileinfo.line) and
  167. ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
  168. begin
  169. if (hp1.fileinfo.line<>0) and
  170. ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
  171. AsmWriteLn(target_asm.comment+'['+tostr(hp1.fileinfo.line)+'] '+
  172. fixline(infile.GetLineStr(hp1.fileinfo.line)));
  173. { set it to a negative value !
  174. to make that is has been read already !! PM }
  175. if (infile.linebuf^[hp1.fileinfo.line]>=0) then
  176. infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
  177. end;
  178. end;
  179. lastfileinfo:=hp1.fileinfo;
  180. lastinfile:=infile;
  181. end;
  182. end;
  183. case hp.typ of
  184. ait_comment :
  185. Begin
  186. AsmWrite(target_asm.comment);
  187. AsmWritePChar(tai_comment(hp).str);
  188. AsmLn;
  189. End;
  190. ait_regalloc :
  191. begin
  192. if (cs_asm_regalloc in current_settings.globalswitches) then
  193. begin
  194. AsmWrite(#9+target_asm.comment+'Register ');
  195. repeat
  196. AsmWrite(std_regname(Tai_regalloc(hp).reg));
  197. if (hp.next=nil) or
  198. (tai(hp.next).typ<>ait_regalloc) or
  199. (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
  200. break;
  201. hp:=tai(hp.next);
  202. AsmWrite(',');
  203. until false;
  204. AsmWrite(' ');
  205. AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
  206. end;
  207. end;
  208. ait_tempalloc :
  209. begin
  210. if (cs_asm_tempalloc in current_settings.globalswitches) then
  211. begin
  212. {$ifdef EXTDEBUG}
  213. if assigned(tai_tempalloc(hp).problem) then
  214. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  215. tostr(tai_tempalloc(hp).tempsize)+' '+tai_tempalloc(hp).problem^)
  216. else
  217. {$endif EXTDEBUG}
  218. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  219. tostr(tai_tempalloc(hp).tempsize)+' '+tempallocstr[tai_tempalloc(hp).allocation]);
  220. end;
  221. end;
  222. ait_align :
  223. begin
  224. end;
  225. ait_section :
  226. begin
  227. end;
  228. ait_datablock :
  229. begin
  230. internalerror(2010122701);
  231. end;
  232. ait_const:
  233. begin
  234. AsmWriteln('constant');
  235. // internalerror(2010122702);
  236. end;
  237. ait_real_64bit :
  238. begin
  239. internalerror(2010122703);
  240. end;
  241. ait_real_32bit :
  242. begin
  243. internalerror(2010122703);
  244. end;
  245. ait_comp_64bit :
  246. begin
  247. internalerror(2010122704);
  248. end;
  249. ait_string :
  250. begin
  251. pos:=0;
  252. for i:=1 to tai_string(hp).len do
  253. begin
  254. if pos=0 then
  255. begin
  256. AsmWrite(#9'strconst: '#9'"');
  257. pos:=20;
  258. end;
  259. ch:=tai_string(hp).str[i-1];
  260. case ch of
  261. #0, {This can't be done by range, because a bug in FPC}
  262. #1..#31,
  263. #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
  264. '"' : s:='\"';
  265. '\' : s:='\\';
  266. else
  267. s:=ch;
  268. end;
  269. AsmWrite(s);
  270. inc(pos,length(s));
  271. if (pos>line_length) or (i=tai_string(hp).len) then
  272. begin
  273. AsmWriteLn('"');
  274. pos:=0;
  275. end;
  276. end;
  277. end;
  278. ait_label :
  279. begin
  280. if (tai_label(hp).labsym.is_used) then
  281. begin
  282. AsmWrite(tai_label(hp).labsym.name);
  283. AsmWriteLn(':');
  284. end;
  285. end;
  286. ait_symbol :
  287. begin
  288. if (tai_symbol(hp).sym.typ = AT_FUNCTION) then
  289. begin
  290. end
  291. else
  292. begin
  293. AsmWrite('data symbol: ');
  294. AsmWriteln(tai_symbol(hp).sym.name);
  295. // internalerror(2010122706);
  296. end;
  297. end;
  298. ait_symbol_end :
  299. begin
  300. end;
  301. ait_instruction :
  302. begin
  303. WriteInstruction(hp);
  304. end;
  305. ait_force_line,
  306. ait_function_name : ;
  307. ait_cutobject :
  308. begin
  309. end;
  310. ait_marker :
  311. if tai_marker(hp).kind=mark_NoLineInfoStart then
  312. inc(InlineLevel)
  313. else if tai_marker(hp).kind=mark_NoLineInfoEnd then
  314. dec(InlineLevel);
  315. ait_directive :
  316. begin
  317. AsmWrite('.'+directivestr[tai_directive(hp).directive]+' ');
  318. if assigned(tai_directive(hp).name) then
  319. AsmWrite(tai_directive(hp).name^);
  320. AsmLn;
  321. end;
  322. ait_jvar:
  323. begin
  324. AsmWrite('.var ');
  325. AsmWrite(tostr(tai_jvar(hp).stackslot));
  326. AsmWrite(' is ');
  327. AsmWrite(tai_jvar(hp).desc^);
  328. AsmWrite(' from ');
  329. AsmWrite(tai_jvar(hp).startlab.name);
  330. AsmWrite(' to ');
  331. AsmWriteLn(tai_jvar(hp).stoplab.name);
  332. end;
  333. ait_jcatch:
  334. begin
  335. AsmWrite('.catch ');
  336. AsmWrite(tai_jcatch(hp).name^);
  337. AsmWrite(' from ');
  338. AsmWrite(tai_jcatch(hp).startlab.name);
  339. AsmWrite(' to ');
  340. AsmWrite(tai_jcatch(hp).stoplab.name);
  341. AsmWrite(' using ');
  342. AsmWriteLn(tai_jcatch(hp).handlerlab.name);
  343. end;
  344. else
  345. internalerror(2010122707);
  346. end;
  347. hp:=tai(hp.next);
  348. end;
  349. end;
  350. procedure TJasminAssembler.WriteExtraHeader(obj: tobjectdef);
  351. var
  352. superclass,
  353. intf: tobjectdef;
  354. n: string;
  355. i: longint;
  356. begin
  357. { JVM 1.5+ }
  358. AsmWriteLn('.bytecode 49.0');
  359. // include files are not support by Java, and the directory of the main
  360. // source file must not be specified
  361. if assigned(current_module.mainsource) then
  362. n:=ExtractFileName(current_module.mainsource^)
  363. else
  364. n:=InputFileName;
  365. AsmWriteLn('.source '+ExtractFileName(n));
  366. { class/interface name }
  367. if not assigned(obj) then
  368. begin
  369. { fake class type for unit -> name=unitname and
  370. superclass=java.lang.object }
  371. AsmWriteLn('.class '+current_module.realmodulename^);
  372. AsmWriteLn('.super java/lang/Object');
  373. end
  374. else
  375. begin
  376. case obj.objecttype of
  377. odt_javaclass:
  378. begin
  379. AsmWriteLn('.class '+obj.jvm_full_typename(false));
  380. superclass:=obj.childof;
  381. end;
  382. odt_interfacejava:
  383. begin
  384. AsmWriteLn('.interface abstract '+obj.objextname^);
  385. { interfaces must always specify Java.lang.object as
  386. superclass }
  387. superclass:=java_jlobject;
  388. end
  389. else
  390. internalerror(2011010906);
  391. end;
  392. { superclass }
  393. if assigned(superclass) then
  394. begin
  395. AsmWrite('.super ');
  396. if assigned(superclass.import_lib) then
  397. AsmWrite(superclass.import_lib^+'/');
  398. AsmWriteln(superclass.objextname^);
  399. end;
  400. { implemented interfaces }
  401. if assigned(obj.ImplementedInterfaces) then
  402. begin
  403. for i:=0 to obj.ImplementedInterfaces.count-1 do
  404. begin
  405. intf:=TImplementedInterface(obj.ImplementedInterfaces[i]).IntfDef;
  406. AsmWrite('.implements ');
  407. if assigned(intf.import_lib) then
  408. AsmWrite(intf.import_lib^+'/');
  409. AsmWriteln(intf.objextname^);
  410. end;
  411. end;
  412. { in case of nested class: relation to parent class }
  413. if obj.owner.symtabletype=objectsymtable then
  414. AsmWriteln(InnerObjDef(obj));
  415. { all all nested classes }
  416. for i:=0 to obj.symtable.deflist.count-1 do
  417. if is_java_class_or_interface(tdef(obj.symtable.deflist[i])) then
  418. AsmWriteln(InnerObjDef(tobjectdef(obj.symtable.deflist[i])));
  419. end;
  420. AsmLn;
  421. end;
  422. procedure TJasminAssembler.WriteInstruction(hp: tai);
  423. begin
  424. InstrWriter.WriteInstruction(hp);
  425. end;
  426. function TJasminAssembler.MakeCmdLine: TCmdStr;
  427. const
  428. jasminjarname = 'jasmin.jar';
  429. var
  430. filenames: tcmdstr;
  431. jasminjarfound: boolean;
  432. begin
  433. if jasminjar='' then
  434. begin
  435. jasminjarfound:=false;
  436. if utilsdirectory<>'' then
  437. jasminjarfound:=FindFile(jasminjarname,utilsdirectory,false,jasminjar);
  438. if not jasminjarfound then
  439. jasminjarfound:=FindFileInExeLocations(jasminjarname,false,jasminjar);
  440. if (not jasminjarfound) and not(cs_asm_extern in current_settings.globalswitches) then
  441. begin
  442. Message1(exec_e_assembler_not_found,jasminjarname);
  443. current_settings.globalswitches:=current_settings.globalswitches+[cs_asm_extern];
  444. end;
  445. if jasminjarfound then
  446. Message1(exec_t_using_assembler,jasminjar);
  447. end;
  448. result:=target_asm.asmcmd;
  449. filenames:=maybequoted(ScriptFixFileName(AsmFileName));
  450. while not asmfiles.empty do
  451. filenames:=filenames+' '+asmfiles.GetFirst;
  452. Replace(result,'$ASM',filenames);
  453. if (path<>'') then
  454. Replace(result,'$OBJDIR',maybequoted(ScriptFixFileName(path)))
  455. else
  456. Replace(result,'$OBJDIR','.');
  457. Replace(result,'$JASMINJAR',maybequoted(ScriptFixFileName(jasminjar)));
  458. end;
  459. procedure TJasminAssembler.NewAsmFileForObjectDef(obj: tobjectdef);
  460. begin
  461. if AsmSize<>AsmStartSize then
  462. begin
  463. AsmClose;
  464. asmfiles.Concat(maybequoted(ScriptFixFileName(AsmFileName)));
  465. end
  466. else
  467. AsmClear;
  468. AsmFileName:=obj.jvm_full_typename(false);
  469. AsmFileName:=Path+FixFileName(AsmFileName)+target_info.asmext;
  470. AsmCreate(cut_normal);
  471. end;
  472. function TJasminAssembler.VisibilityToStr(vis: tvisibility): string;
  473. begin
  474. case vis of
  475. vis_hidden,
  476. vis_strictprivate:
  477. result:='private ';
  478. vis_strictprotected:
  479. result:='protected ';
  480. vis_protected,
  481. vis_private:
  482. { pick default visibility = "package" visibility; required because
  483. other classes in the same unit can also access these symbols }
  484. result:='';
  485. vis_public:
  486. result:='public '
  487. else
  488. internalerror(2010122609);
  489. end;
  490. end;
  491. function TJasminAssembler.MethodDefinition(pd: tprocdef): string;
  492. begin
  493. result:=VisibilityToStr(pd.visibility);
  494. if (pd.procsym.owner.symtabletype in [globalsymtable,staticsymtable,localsymtable]) or
  495. (po_staticmethod in pd.procoptions) then
  496. result:=result+'static ';
  497. if is_javainterface(tdef(pd.owner.defowner)) then
  498. result:=result+'abstract ';
  499. result:=result+pd.jvmmangledbasename;
  500. end;
  501. function TJasminAssembler.FieldDefinition(sym: tabstractvarsym): string;
  502. var
  503. vissym: tabstractvarsym;
  504. begin
  505. vissym:=sym;
  506. { static field definition -> get original field definition for
  507. visibility }
  508. if (vissym.typ=staticvarsym) and
  509. (vissym.owner.symtabletype=objectsymtable) then
  510. begin
  511. vissym:=tabstractvarsym(search_struct_member(
  512. tobjectdef(vissym.owner.defowner),
  513. jvminternalstaticfieldname(vissym.name)));
  514. if not assigned(vissym) or
  515. (vissym.typ<>fieldvarsym) then
  516. internalerror(2011011501);
  517. end;
  518. case vissym.typ of
  519. staticvarsym:
  520. begin
  521. if vissym.owner.symtabletype=globalsymtable then
  522. result:='public '
  523. else
  524. { package visbility }
  525. result:='';
  526. end;
  527. fieldvarsym:
  528. result:=VisibilityToStr(tfieldvarsym(vissym).visibility);
  529. else
  530. internalerror(2011011204);
  531. end;
  532. if (vissym.owner.symtabletype in [staticsymtable,globalsymtable]) or
  533. (sp_static in vissym.symoptions) then
  534. result:=result+'static ';
  535. result:=result+sym.jvmmangledbasename;
  536. end;
  537. function TJasminAssembler.InnerObjDef(obj: tobjectdef): string;
  538. var
  539. kindname: string;
  540. begin
  541. if obj.owner.defowner.typ<>objectdef then
  542. internalerror(2011021701);
  543. case obj.objecttype of
  544. odt_javaclass:
  545. kindname:='class ';
  546. odt_interfacejava:
  547. kindname:='interface ';
  548. else
  549. internalerror(2011021702);
  550. end;
  551. result:=
  552. '.inner '+
  553. kindname+
  554. VisibilityToStr(obj.typesym.visibility)+
  555. { Nested classes in the Pascal sense are equivalent to "static"
  556. inner classes in Java -- will be changed when support for
  557. Java-style non-static classes is added }
  558. ' static '+
  559. obj.objextname^+
  560. ' inner '+
  561. obj.jvm_full_typename(true)+
  562. ' outer '+
  563. tobjectdef(obj.owner.defowner).jvm_full_typename(true);
  564. end;
  565. procedure TJasminAssembler.WriteProcDef(pd: tprocdef);
  566. begin
  567. if not assigned(pd.exprasmlist) and
  568. (not is_javainterface(pd.struct) or
  569. (pd.proctypeoption in [potype_unitinit,potype_unitfinalize])) then
  570. exit;
  571. AsmWrite('.method ');
  572. AsmWriteln(MethodDefinition(pd));
  573. WriteTree(pd.exprasmlist);
  574. AsmWriteln('.end method');
  575. AsmLn;
  576. end;
  577. procedure TJasminAssembler.WriteFieldSym(sym: tabstractvarsym);
  578. begin
  579. { internal static field definition alias -> skip }
  580. if sp_static in sym.symoptions then
  581. exit;
  582. AsmWrite('.field ');
  583. AsmWriteln(FieldDefinition(sym));
  584. end;
  585. procedure TJasminAssembler.WriteSymtableVarSyms(st: TSymtable);
  586. var
  587. sym : tsym;
  588. i : longint;
  589. begin
  590. if not assigned(st) then
  591. exit;
  592. for i:=0 to st.SymList.Count-1 do
  593. begin
  594. sym:=tsym(st.SymList[i]);
  595. case sym.typ of
  596. staticvarsym,
  597. fieldvarsym:
  598. begin
  599. WriteFieldSym(tabstractvarsym(sym));
  600. end;
  601. end;
  602. end;
  603. end;
  604. procedure TJasminAssembler.WriteSymtableProcdefs(st: TSymtable);
  605. var
  606. i : longint;
  607. def : tdef;
  608. begin
  609. if not assigned(st) then
  610. exit;
  611. for i:=0 to st.DefList.Count-1 do
  612. begin
  613. def:=tdef(st.DefList[i]);
  614. case def.typ of
  615. procdef :
  616. begin
  617. { methods are also in the static/globalsymtable of the unit
  618. -> make sure they are only written for the objectdefs that
  619. own them }
  620. if not(st.symtabletype in [staticsymtable,globalsymtable]) or
  621. (def.owner=st) then
  622. begin
  623. WriteProcDef(tprocdef(def));
  624. if assigned(tprocdef(def).localst) then
  625. WriteSymtableProcdefs(tprocdef(def).localst);
  626. end;
  627. end;
  628. end;
  629. end;
  630. end;
  631. procedure TJasminAssembler.WriteSymtableObjectDefs(st: TSymtable);
  632. var
  633. i : longint;
  634. def : tdef;
  635. obj : tobjectdef;
  636. nestedclasses: tfpobjectlist;
  637. begin
  638. if not assigned(st) then
  639. exit;
  640. nestedclasses:=tfpobjectlist.create(false);
  641. for i:=0 to st.DefList.Count-1 do
  642. begin
  643. def:=tdef(st.DefList[i]);
  644. case def.typ of
  645. objectdef:
  646. if not(oo_is_external in tobjectdef(def).objectoptions) then
  647. nestedclasses.add(def);
  648. end;
  649. end;
  650. for i:=0 to nestedclasses.count-1 do
  651. begin
  652. obj:=tobjectdef(nestedclasses[i]);
  653. NewAsmFileForObjectDef(obj);
  654. WriteExtraHeader(obj);
  655. WriteSymtableVarSyms(obj.symtable);
  656. AsmLn;
  657. WriteSymtableProcDefs(obj.symtable);
  658. WriteSymtableObjectDefs(obj.symtable);
  659. end;
  660. nestedclasses.free;
  661. end;
  662. constructor TJasminAssembler.Create(smart: boolean);
  663. begin
  664. inherited create(smart);
  665. InstrWriter:=TJasminInstrWriter.Create(self);
  666. asmfiles:=TCmdStrList.Create;
  667. end;
  668. procedure TJasminAssembler.WriteAsmList;
  669. begin
  670. {$ifdef EXTDEBUG}
  671. if assigned(current_module.mainsource) then
  672. Comment(V_Debug,'Start writing Jasmin-styled assembler output for '+current_module.mainsource^);
  673. {$endif}
  674. AsmStartSize:=AsmSize;
  675. WriteExtraHeader(nil);
  676. (*
  677. for hal:=low(TasmlistType) to high(TasmlistType) do
  678. begin
  679. AsmWriteLn(target_asm.comment+'Begin asmlist '+AsmlistTypeStr[hal]);
  680. writetree(current_asmdata.asmlists[hal]);
  681. AsmWriteLn(target_asm.comment+'End asmlist '+AsmlistTypeStr[hal]);
  682. end;
  683. *)
  684. { print all global variables }
  685. WriteSymtableVarSyms(current_module.globalsymtable);
  686. WriteSymtableVarSyms(current_module.localsymtable);
  687. AsmLn;
  688. { print all global procedures/functions }
  689. WriteSymtableProcdefs(current_module.globalsymtable);
  690. WriteSymtableProcdefs(current_module.localsymtable);
  691. WriteSymtableObjectDefs(current_module.globalsymtable);
  692. WriteSymtableObjectDefs(current_module.localsymtable);
  693. AsmLn;
  694. {$ifdef EXTDEBUG}
  695. if assigned(current_module.mainsource) then
  696. Comment(V_Debug,'Done writing gas-styled assembler output for '+current_module.mainsource^);
  697. {$endif EXTDEBUG}
  698. end;
  699. {****************************************************************************}
  700. { Jasmin Instruction Writer }
  701. {****************************************************************************}
  702. constructor TJasminInstrWriter.create(_owner: TJasminAssembler);
  703. begin
  704. inherited create;
  705. owner := _owner;
  706. end;
  707. function getreferencestring(var ref : treference) : string;
  708. begin
  709. if (ref.arrayreftype<>art_none) or
  710. (ref.index<>NR_NO) then
  711. internalerror(2010122809);
  712. if assigned(ref.symbol) then
  713. begin
  714. // global symbol or field -> full type and name
  715. // ref.base can be <> NR_NO in case an instance field is loaded.
  716. // This register is not part of this instruction, it will have
  717. // been placed on the stack by the previous one.
  718. if (ref.offset<>0) then
  719. internalerror(2010122811);
  720. result:=ref.symbol.name;
  721. end
  722. else
  723. begin
  724. // local symbol -> stack slot, stored in offset
  725. if ref.base<>NR_STACK_POINTER_REG then
  726. internalerror(2010122810);
  727. result:=tostr(ref.offset);
  728. end;
  729. end;
  730. function getopstr(const o:toper) : ansistring;
  731. var
  732. i,runstart,runlen: longint;
  733. d: double;
  734. s: single;
  735. begin
  736. case o.typ of
  737. top_reg:
  738. // should have been translated into a memory location by the
  739. // register allocator)
  740. if (cs_no_regalloc in current_settings.globalswitches) then
  741. getopstr:=std_regname(o.reg)
  742. else
  743. internalerror(2010122803);
  744. top_const:
  745. str(o.val,result);
  746. top_ref:
  747. getopstr:=getreferencestring(o.ref^);
  748. top_single:
  749. begin
  750. s:=o.sval;
  751. // force interpretation as single (since we write it out as an
  752. // integer, we never have to swap the endianess).
  753. result:='0fx'+hexstr(longint(t32bitarray(s)),8);
  754. end;
  755. top_double:
  756. begin
  757. d:=o.dval;
  758. // force interpretation as double (since we write it out as an
  759. // integer, we never have to swap the endianess). We have to
  760. // include the sign separately because of the way Java parses
  761. // hex numbers (0x8000000000000000 is not a valid long)
  762. result:=hexstr(abs(int64(t64bitarray(d))),16);
  763. if int64(t64bitarray(d))<0 then
  764. result:='-'+result;
  765. result:='0dx'+result;
  766. end;
  767. top_string:
  768. begin
  769. { escape control codes }
  770. runlen:=0;
  771. runstart:=0;
  772. for i:=1 to o.pcvallen do
  773. begin
  774. if o.pcval[i]<#32 then
  775. begin
  776. if runlen>0 then
  777. begin
  778. setlength(result,length(result)+runlen);
  779. move(result[length(result)-runlen],o.pcval[runstart],runlen);
  780. runlen:=0;
  781. end;
  782. result:=result+'\u'+hexstr(ord(o.pcval[i]),4);
  783. end
  784. else if o.pcval[i]<#127 then
  785. begin
  786. if runlen=0 then
  787. runstart:=i;
  788. inc(runlen);
  789. end
  790. else
  791. // since Jasmin expects an UTF-16 string, we can't safely
  792. // have high ASCII characters since they'll be
  793. // re-interpreted as utf-16 anyway
  794. internalerror(2010122808);
  795. end;
  796. if runlen>0 then
  797. begin
  798. setlength(result,length(result)+runlen);
  799. move(result[length(result)-runlen],o.pcval[runstart],runlen);
  800. end;
  801. end;
  802. top_wstring:
  803. begin
  804. { escape control codes }
  805. for i:=1 to getlengthwidestring(o.pwstrval) do
  806. begin
  807. if (o.pwstrval^.data[i]<32) or
  808. (o.pwstrval^.data[i]>127) then
  809. result:=result+'\u'+hexstr(o.pwstrval^.data[i],4)
  810. else
  811. result:=result+char(o.pwstrval^.data[i]);
  812. end;
  813. end
  814. else
  815. internalerror(2010122802);
  816. end;
  817. end;
  818. procedure TJasminInstrWriter.WriteInstruction(hp: tai);
  819. var
  820. s: ansistring;
  821. i: byte;
  822. sep: string[3];
  823. begin
  824. s:=#9+jas_op2str[taicpu(hp).opcode];
  825. if taicpu(hp).ops<>0 then
  826. begin
  827. sep:=#9;
  828. for i:=0 to taicpu(hp).ops-1 do
  829. begin
  830. s:=s+sep+getopstr(taicpu(hp).oper[i]^);
  831. sep:=' ';
  832. end;
  833. end;
  834. owner.AsmWriteLn(s);
  835. end;
  836. {****************************************************************************}
  837. { Jasmin Instruction Writer }
  838. {****************************************************************************}
  839. const
  840. as_jvm_jasmin_info : tasminfo =
  841. (
  842. id : as_jvm_jasmin;
  843. idtxt : 'Jasmin';
  844. asmbin : 'java';
  845. asmcmd : '-jar $JASMINJAR $ASM -d $OBJDIR';
  846. supported_targets : [system_jvm_java32];
  847. flags : [];
  848. labelprefix : 'L';
  849. comment : ' ; ';
  850. );
  851. begin
  852. RegisterAssembler(as_jvm_jasmin_info,TJasminAssembler);
  853. end.