2
0

agjs.pas 42 KB

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