wasmmodule.pas 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163
  1. { This file is part of wasmbin - a collection of WebAssembly binary utils.
  2. Copyright (C) 2019, 2020 Dmitry Boyarintsev <[email protected]>
  3. Copyright (C) 2020 by the Free Pascal development team
  4. This source is free software; you can redistribute it and/or modify it under
  5. the terms of the GNU General Public License as published by the Free
  6. Software Foundation; either version 2 of the License, or (at your option)
  7. any later version.
  8. This code is distributed in the hope that it will be useful, but WITHOUT ANY
  9. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  10. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  11. details.
  12. A copy of the GNU General Public License is available on the World Wide Web
  13. at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
  14. to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
  15. Boston, MA 02110-1335, USA.
  16. }
  17. unit wasmmodule;
  18. {$mode objfpc}{$H+}
  19. interface
  20. uses
  21. Classes, SysUtils, wasmbin, wasmbincode, wasmlink;
  22. type
  23. TLinkBind = (lbUndefined = 0
  24. ,lbWeak
  25. ,lbLocal
  26. ,lbForHost
  27. );
  28. TLinkInfo = record
  29. Name : string;
  30. Binding : TLinkBind;
  31. isHidden : Boolean;
  32. isUndefined : Boolean;
  33. NoStrip : Boolean;
  34. end;
  35. TExportInfo = record
  36. isExport : Boolean;
  37. name : string;
  38. end;
  39. { TWasmId }
  40. TWasmId = record
  41. idNum : integer;
  42. id : string;
  43. end;
  44. { TWasmParam }
  45. TWasmParam = class(TObject)
  46. id : string;
  47. tp : byte;
  48. procedure CopyTo(d: TWasmParam);
  49. end;
  50. { TWasmType }
  51. // function signature
  52. { TWasmFuncType }
  53. TWasmFuncType = class(TObject)
  54. public
  55. params : TList;
  56. results : TList;
  57. typeNum : Integer; // if Idx < 0 then type is declared from typeDef
  58. typeIdx : string; // if typeID='' then type is declared from typeDef
  59. // linking information
  60. constructor Create;
  61. destructor Destroy; override;
  62. function AddResult(tp: byte = 0): TWasmParam;
  63. function AddParam(tp: byte = 0; const id: string = ''): TWasmParam;
  64. function GetParam(i: integer): TWasmParam;
  65. function GetResult(i: integer): TWasmParam; overload;
  66. function GetResult: TWasmParam; overload;
  67. function ResultCount: Integer;
  68. function ParamCount: Integer;
  69. function isNumOrIdx: Boolean;
  70. procedure CopyTo(t: TWasmFuncType);
  71. end;
  72. TWasmInstrOperandType = (
  73. otNotused,
  74. otText,
  75. otSInt32,
  76. otUInt32,
  77. otSInt64,
  78. otUInt64,
  79. otFloat32,
  80. otFloat64
  81. );
  82. TWasmInstrOperand = record
  83. textVal : string;
  84. case tp : TWasmInstrOperandType of
  85. otSInt32: (s32: Int32);
  86. otUInt32: (u32: UInt32);
  87. otSInt64: (s64: Int64);
  88. otUInt64: (u64: UInt64);
  89. otFloat32: (f32: single);
  90. otFloat64: (f64: double);
  91. end;
  92. { TWasmInstr }
  93. TWasmInstr = class(TObject)
  94. code : byte;
  95. operandIdx : string;
  96. operandNum : integer; // for "call_indirect" this is table index
  97. // for "if", "loop", "block" - it's type
  98. operand1 : TWasmInstrOperand; // it's "offset" for load operations
  99. operand2 : TWasmInstrOperand; // it's "align" for load operations
  100. insttype : TWasmFuncType; // used by call_indirect only
  101. jumplabel : string; // the label is used only for "loop", "block" and "if"
  102. hasRelocIdx : Boolean;
  103. //relocIdx : integer;
  104. relocType : Byte;
  105. relocObj : TObject; //
  106. vecTableCount : Integer;
  107. vecTable : array of TWasmId;
  108. function addInstType: TWasmFuncType;
  109. constructor Create;
  110. destructor Destroy; override;
  111. procedure SetReloc(ARelocType: byte; ARelocObj: TObject);
  112. property offsetText : TWasmInstrOperand read operand1 write operand1;
  113. property alignText : TWasmInstrOperand read operand2 write operand2;
  114. end;
  115. { TWasmInstrList }
  116. TWasmInstrList = class(TObject)
  117. private
  118. items: TList;
  119. function GetItem(i: integer): TWasmInstr;
  120. public
  121. constructor Create;
  122. destructor Destroy; override;
  123. function AddInstr(acode: byte = 0): TWasmInstr;
  124. function Count: Integer;
  125. property Item[i: integer]: TWasmInstr read GetItem; default;
  126. end;
  127. { TWasmGlobal }
  128. TWasmGlobal = class(TObject)
  129. public
  130. id : TWasmId;
  131. tp : byte; // byte;
  132. isMutable : Boolean; // is mutable
  133. value : TWasmInstrList;
  134. LinkInfo : TLinkInfo;
  135. ExportInfo : TExportInfo;
  136. function StartValue: TWasmInstrList;
  137. destructor Destroy; override;
  138. end;
  139. { TWasmFunc }
  140. TWasmFunc = class(TObject)
  141. public
  142. locals : TList;
  143. LinkInfo : TLinkInfo;
  144. id : string;
  145. idNum : Integer; // reference number (after Normalization)
  146. instr : TWasmInstrList;
  147. functype : TWasmFuncType;
  148. constructor Create;
  149. destructor Destroy; override;
  150. function AddLocal: TWasmParam;
  151. function GetLocal(i: integer): TWasmParam;
  152. function LocalsCount: integer;
  153. end;
  154. { TWasmElement }
  155. TWasmElement = class(TObject)
  156. tableId : TWasmId;
  157. offset : TWasmInstrList; // offset expression
  158. funcCount : Integer;
  159. funcs : array of TWasmId;
  160. function AddFunc(idx: integer): integer;
  161. function AddFuncId(const idx: TWasmID): integer;
  162. function AddOffset: TWasmInstrList;
  163. constructor Create;
  164. destructor Destroy; override;
  165. end;
  166. { TWasmExport }
  167. TWasmExport = class(TObject)
  168. name : string;
  169. exportType : byte;
  170. exportNum : integer;
  171. exportIdx : string;
  172. constructor Create;
  173. end;
  174. { TWasmTable }
  175. TWasmTable = class(TObject)
  176. id : TWasmId;
  177. elemsType : Byte; // type of elements
  178. min : LongWord;
  179. max : LongWord;
  180. elem : TWasmElement;
  181. function AddElem: TWasmElement;
  182. procedure RemoveElem;
  183. destructor Destroy; override;
  184. end;
  185. { TWasmData }
  186. TWasmData = class(TObject)
  187. id : TWasmId;
  188. offset : TWasmInstrList;
  189. databuf : array of byte;
  190. function StartOffset: TWasmInstrList;
  191. destructor Destroy; override;
  192. end;
  193. { TWasmMemory }
  194. TWasmMemory = class(TObject)
  195. id : TWasmId;
  196. min : LongWord;
  197. max : LongWord; // limit
  198. LinkInfo : TLinkInfo;
  199. exportInfo : TExportInfo;
  200. end;
  201. { TWasmImport }
  202. TWasmImport = class(TObject)
  203. LinkInfo : TLinkInfo;
  204. module : string;
  205. name : string;
  206. fn : TWasmFunc;
  207. mem : TWasmMemory;
  208. glob : TWasmGlobal;
  209. table : TWasmTable;
  210. destructor Destroy; override;
  211. function AddFunc: TWasmFunc;
  212. function AddMemory: TWasmMemory;
  213. function AddGlobal: TWasmGlobal;
  214. function AddTable: TWasmTable;
  215. end;
  216. { TWasmModule }
  217. TWasmModule = class(TObject)
  218. private
  219. globals : TList;
  220. memes : TList;
  221. imports : TList;
  222. types : TList;
  223. funcs : TList;
  224. exp : TList;
  225. tables : TList;
  226. elems : TList;
  227. data : TList;
  228. public
  229. constructor Create;
  230. destructor Destroy; override;
  231. function AddMemory: TWasmMemory;
  232. function GetMemory(i: integer): TWasmMemory;
  233. function MemoryCount: Integer;
  234. function AddTable: TWasmTable;
  235. function GetTable(i: integer): TWasmTable;
  236. function TableCount: Integer;
  237. function AddImport: TWasmImport;
  238. function GetImport(i: integer): TWasmImport;
  239. function ImportCount: Integer;
  240. function AddFunc: TWasmFunc;
  241. function GetFunc(i: integer): TWasmFunc;
  242. function FuncCount: integer;
  243. function AddType: TWasmFuncType;
  244. function GetType(i: integer): TWasmFuncType;
  245. function TypesCount: integer;
  246. function AddExport: TWasmExport;
  247. function GetExport(i: integer): TWasmExport;
  248. function ExportCount: integer;
  249. function AddElement: TWasmElement;
  250. function GetElement(i: integer): TWasmElement;
  251. function ElementCount: Integer;
  252. function AddData: TWasmData;
  253. function GetData(i: integer): TWasmData;
  254. function DataCount: Integer;
  255. function AddGlobal: TWasmGlobal;
  256. function GetGlobal(i: integer): TWasmGlobal;
  257. function GlobalCount: Integer;
  258. end;
  259. // making binary friendly. finding proper "nums" for each symbol "index"
  260. // used or implicit type declartions
  261. function WasmBasTypeToChar(b: byte): Char;
  262. function WasmFuncTypeDescr(t: TWasmFuncType): string;
  263. function FindGlobal(m: TWasmModule; const globIdx: string): integer;
  264. function FindFunc(m: TWasmModule; const funcIdx: string): integer;
  265. function FindParam(l: TList; const idx: string): Integer;
  266. function FindFuncType(m: TWasmModule; const typeIdx: string): integer;
  267. // tries to register a function in the module
  268. // the returned value is the offset of the element within the TABLE.
  269. function RegisterFuncIdxInElem(m: TWasmModule; const func: Integer): integer;
  270. function RegisterFuncInElem(m: TWasmModule; const funcId: string): integer;
  271. function RegisterFuncType(m: TWasmModule; funcType: TWasmFuncType): integer;
  272. // tries to get a constant value from instruction list
  273. // right now, it only pulls the first i32_const expression and tries
  274. // to get the value out of it.
  275. // todo: it should be more sophistacated
  276. //
  277. // returns false, if instruction "l" is invalid, or no i32 instruction
  278. function InstrGetConsti32Value(l: TWasmInstrList; var vl: Integer): Boolean;
  279. procedure OperandSetType(var op: TWasmInstrOperand; tp: TWasmInstrOperandType); inline;
  280. procedure OperandSetInt32(var op: TWasmInstrOperand; i32: Int32); inline;
  281. procedure OperandSetText(var op: TWasmInstrOperand; const txt: string); inline;
  282. // should be used after normalization
  283. // todo: what about imported functions?
  284. function GetFuncByNum(m: TWasmModule; const idNum: Integer): TWasmFunc;
  285. function GetGlobalByNum(m: TWasmModule; const idNum: Integer): TWasmGlobal;
  286. function GetMemByNum(m: TWasmModule; const idNum: Integer): TWasmMemory;
  287. implementation
  288. procedure OperandSetType(var op: TWasmInstrOperand; tp: TWasmInstrOperandType); inline;
  289. begin
  290. if op.tp<>tp then op.tp:=tp;
  291. end;
  292. procedure OperandSetInt32(var op: TWasmInstrOperand; i32: Int32);
  293. begin
  294. OperandSetType(op, otSInt32);
  295. op.s32:=i32;
  296. end;
  297. procedure OperandSetText(var op: TWasmInstrOperand; const txt: string); inline;
  298. begin
  299. OperandSetType(op, otText);
  300. op.textVal := txt;
  301. end;
  302. // returing a basic wasm basic type to a character
  303. // i32 = i
  304. // i64 = I
  305. // f32 = f
  306. // f64 = F
  307. function WasmBasTypeToChar(b: byte): Char;
  308. begin
  309. case b of
  310. valtype_i32: Result:='i';
  311. valtype_i64: Result:='I';
  312. valtype_f32: Result:='f';
  313. valtype_f64: Result:='F';
  314. else
  315. Result:='.';
  316. end;
  317. end;
  318. // converting function type to the type string
  319. // result and params are separated by ":"
  320. // iI:i (param i32)(param i32) (result i32)
  321. // :f (result f32)
  322. // FF (param f64)(param(64)
  323. function WasmFuncTypeDescr(t: TWasmFuncType): string;
  324. var
  325. cnt : integer;
  326. i : integer;
  327. j : integer;
  328. begin
  329. cnt:=t.ParamCount;
  330. if t.Resultcount>0 then inc(cnt, t.ResultCount+1);
  331. SetLength(Result, cnt);
  332. if cnt=0 then Exit;
  333. j:=1;
  334. for i:=0 to t.ParamCount-1 do begin
  335. Result[j]:=WasmBasTypeToChar(t.GetParam(i).tp);
  336. inc(j);
  337. end;
  338. if t.ResultCount=0 then Exit;
  339. Result[j]:=':';
  340. inc(j);
  341. for i:=0 to t.ResultCount-1 do begin
  342. Result[j]:=WasmBasTypeToChar(t.GetResult(i).tp);
  343. inc(j);
  344. end;
  345. end;
  346. // deleting objects from the list and clearing the list
  347. procedure ClearList(l: TList);
  348. var
  349. i : integer;
  350. begin
  351. for i:=0 to l.Count-1 do
  352. TObject(l[i]).Free;
  353. l.Clear;
  354. end;
  355. { TWasmGlobal }
  356. function TWasmGlobal.StartValue: TWasmInstrList;
  357. begin
  358. if not Assigned(value) then
  359. value:=TWasmInstrList.Create;
  360. Result:=value;
  361. end;
  362. destructor TWasmGlobal.Destroy;
  363. begin
  364. value.Free;
  365. inherited Destroy;
  366. end;
  367. { TWasmTable }
  368. function TWasmTable.AddElem: TWasmElement;
  369. begin
  370. if not Assigned(elem) then
  371. elem:= TWasmElement.Create;
  372. Result := elem;
  373. end;
  374. procedure TWasmTable.RemoveElem;
  375. begin
  376. elem.Free;
  377. elem:=nil;
  378. end;
  379. destructor TWasmTable.Destroy;
  380. begin
  381. RemoveElem;
  382. inherited Destroy;
  383. end;
  384. { TWasmData }
  385. function TWasmData.StartOffset: TWasmInstrList;
  386. begin
  387. if not Assigned(offset) then
  388. offset := TWasmInstrList.Create;
  389. Result:=offset;
  390. end;
  391. destructor TWasmData.Destroy;
  392. begin
  393. if Assigned(offset) then offset.Free;
  394. inherited Destroy;
  395. end;
  396. { TWasmElement }
  397. function TWasmElement.AddFunc(idx: integer): integer;
  398. var
  399. w : TWasmId;
  400. begin
  401. w.id:='';
  402. w.idNum:=idx;
  403. Result := AddFuncId(w);
  404. end;
  405. function TWasmElement.AddFuncId(const idx: TWasmID): integer;
  406. begin
  407. if funcCount = length(funcs) then begin
  408. if funcCount=0 then SetLength(funcs, 4)
  409. else SetLength(funcs, funcCount*2);
  410. end;
  411. Result:=funcCount;
  412. funcs[funcCount] := idx;
  413. inc(funcCount);
  414. end;
  415. function TWasmElement.AddOffset: TWasmInstrList;
  416. begin
  417. if not Assigned(offset) then offset:=TWasmInstrList.Create;
  418. Result := offset;
  419. end;
  420. constructor TWasmElement.Create;
  421. begin
  422. inherited Create;
  423. offset := TWasmInstrList.Create;
  424. end;
  425. destructor TWasmElement.Destroy;
  426. begin
  427. offset.Free;
  428. inherited Destroy;
  429. end;
  430. { TWasmImport }
  431. destructor TWasmImport.Destroy;
  432. begin
  433. mem.Free;
  434. fn.Free;
  435. glob.Free;
  436. table.Free;
  437. inherited Destroy;
  438. end;
  439. function TWasmImport.AddFunc: TWasmFunc;
  440. begin
  441. if not Assigned(fn) then fn:= TWasmFunc.Create;
  442. Result:=fn;
  443. end;
  444. function TWasmImport.AddMemory: TWasmMemory;
  445. begin
  446. if not Assigned(mem) then
  447. mem := TWasmMemory.Create;
  448. Result := mem;
  449. end;
  450. function TWasmImport.AddGlobal: TWasmGlobal;
  451. begin
  452. if not Assigned(glob) then
  453. glob := TWasmGlobal.Create;
  454. Result := glob;
  455. end;
  456. function TWasmImport.AddTable: TWasmTable;
  457. begin
  458. if not Assigned(table) then
  459. table := TWasmTable.Create;
  460. Result := table;
  461. end;
  462. { TWasmExport }
  463. constructor TWasmExport.Create;
  464. begin
  465. inherited Create;
  466. exportNum:=-1;
  467. end;
  468. { TWasmParam }
  469. procedure TWasmParam.CopyTo(d: TWasmParam);
  470. begin
  471. d.tp:=tp;
  472. end;
  473. { TWasmInstr }
  474. function TWasmInstr.addInstType: TWasmFuncType;
  475. begin
  476. if insttype=nil then insttype := TWasmFuncType.Create;
  477. result:=insttype;
  478. end;
  479. constructor TWasmInstr.Create;
  480. begin
  481. operandNum:=-1;
  482. end;
  483. destructor TWasmInstr.Destroy;
  484. begin
  485. insttype.Free;
  486. inherited Destroy;
  487. end;
  488. procedure TWasmInstr.SetReloc(ARelocType: byte; ARelocObj: TObject);
  489. begin
  490. hasRelocIdx := true;
  491. relocType := ARelocType;
  492. relocObj := ARelocObj;
  493. end;
  494. { TWasmInstrList }
  495. function TWasmInstrList.GetItem(i: integer): TWasmInstr;
  496. begin
  497. if (i>=0) and (i < items.Count) then
  498. Result:=TWasmInstr(items[i])
  499. else
  500. Result:=nil;
  501. end;
  502. constructor TWasmInstrList.Create;
  503. begin
  504. inherited Create;
  505. items:=TList.Create;
  506. end;
  507. destructor TWasmInstrList.Destroy;
  508. begin
  509. ClearList(items);
  510. items.Free;
  511. inherited Destroy;
  512. end;
  513. function TWasmInstrList.AddInstr(acode: byte = 0): TWasmInstr;
  514. begin
  515. Result:=TWasmInstr.Create;
  516. Result.code:=acode;
  517. items.Add(Result);
  518. end;
  519. function TWasmInstrList.Count: Integer;
  520. begin
  521. Result:=items.Count;
  522. end;
  523. { TWasmFuncType }
  524. constructor TWasmFuncType.Create;
  525. begin
  526. inherited Create;
  527. typeNum:=-1;
  528. params:=Tlist.Create;
  529. results:=Tlist.Create;
  530. end;
  531. destructor TWasmFuncType.Destroy;
  532. begin
  533. ClearList(params);
  534. ClearList(results);
  535. params.free;
  536. results.free;
  537. inherited Destroy;
  538. end;
  539. function TWasmFuncType.AddResult(tp: byte): TWasmParam;
  540. begin
  541. Result:=TWasmParam.Create;
  542. Result.tp:=tp;
  543. results.Add(Result);
  544. end;
  545. function TWasmFuncType.AddParam(tp: byte; const id: string): TWasmParam;
  546. begin
  547. Result:=TWasmParam.Create;
  548. Result.tp:=tp;
  549. Result.id:=id;
  550. params.Add(Result);
  551. end;
  552. function TWasmFuncType.GetParam(i: integer): TWasmParam;
  553. begin
  554. if (i>=0) and (i<params.Count) then
  555. Result:=TWasmParam(params[i])
  556. else
  557. Result:=nil;
  558. end;
  559. function TWasmFuncType.GetResult(i: integer): TWasmParam;
  560. begin
  561. if (i>=0) and (i<results.Count) then
  562. Result:=TWasmParam(results[i])
  563. else
  564. Result:=nil;
  565. end;
  566. function TWasmFuncType.GetResult: TWasmParam;
  567. begin
  568. Result:=GetResult(0);
  569. end;
  570. function TWasmFuncType.ResultCount: Integer;
  571. begin
  572. Result:=results.Count;
  573. end;
  574. function TWasmFuncType.ParamCount: Integer;
  575. begin
  576. Result:=params.Count;
  577. end;
  578. function TWasmFuncType.isNumOrIdx: Boolean;
  579. begin
  580. Result:=(typeIdx<>'') or (typeNum>=0);
  581. end;
  582. procedure TWasmFuncType.CopyTo(t: TWasmFuncType);
  583. var
  584. i : integer;
  585. s : TWasmParam;
  586. d : TWasmParam;
  587. begin
  588. for i:=0 to ParamCount-1 do begin
  589. d := t.AddParam;
  590. s := GetParam(i);
  591. s.CopyTo(d);
  592. end;
  593. for i:=0 to ResultCount-1 do begin
  594. d := t.AddResult;
  595. s := GetResult(i);
  596. s.CopyTo(d);
  597. end;
  598. end;
  599. { TWasmModule }
  600. constructor TWasmModule.Create;
  601. begin
  602. inherited Create;
  603. globals := TList.Create;
  604. types := TList.Create;
  605. funcs := TList.Create;
  606. exp := TList.Create;
  607. imports := TList.Create;
  608. tables := TList.Create;
  609. elems := TList.Create;
  610. memes := TList.Create;
  611. data := TList.Create;
  612. end;
  613. destructor TWasmModule.Destroy;
  614. begin
  615. ClearList(data);
  616. data.Free;
  617. ClearList(memes);
  618. memes.Free;
  619. ClearList(elems);
  620. elems.Free;
  621. ClearList(tables);
  622. tables.Free;
  623. ClearList(imports);
  624. imports.Free;
  625. ClearList(exp);
  626. exp.Free;
  627. ClearList(types);
  628. types.Free;
  629. ClearList(funcs);
  630. funcs.Free;
  631. ClearList(globals);
  632. globals.Free;
  633. inherited Destroy;
  634. end;
  635. function TWasmModule.AddMemory: TWasmMemory;
  636. begin
  637. Result:=TWasmMemory.Create;
  638. memes.Add(result);
  639. end;
  640. function TWasmModule.GetMemory(i: integer): TWasmMemory;
  641. begin
  642. if (i>=0) and (i<memes.Count) then
  643. Result:=TWasmMemory(memes[i])
  644. else
  645. Result:=nil;
  646. end;
  647. function TWasmModule.MemoryCount: Integer;
  648. begin
  649. Result:=memes.Count;
  650. end;
  651. function TWasmModule.AddTable: TWasmTable;
  652. begin
  653. Result:=TWasmTable.Create;
  654. tables.Add(Result);
  655. end;
  656. function TWasmModule.GetTable(i: integer): TWasmTable;
  657. begin
  658. if (i>=0) and (i<tables.Count) then
  659. Result:=TWasmTable(tables[i])
  660. else
  661. Result:=nil;
  662. end;
  663. function TWasmModule.TableCount: Integer;
  664. begin
  665. Result:=tables.Count;
  666. end;
  667. function TWasmModule.AddImport: TWasmImport;
  668. begin
  669. Result:=TWasmImport.Create;
  670. imports.Add(Result);
  671. end;
  672. function TWasmModule.GetImport(i: integer): TWasmImport;
  673. begin
  674. if (i>=0) and (i<imports.Count) then
  675. Result:=TWasmImport(imports[i])
  676. else
  677. Result:=nil;
  678. end;
  679. function TWasmModule.ImportCount: Integer;
  680. begin
  681. Result:=imports.Count;
  682. end;
  683. function TWasmModule.AddFunc: TWasmFunc;
  684. begin
  685. Result:=TWasmFunc.Create;
  686. funcs.Add(Result);
  687. end;
  688. function TWasmModule.AddType: TWasmFuncType;
  689. begin
  690. Result:=TWasmFuncType.Create;
  691. types.Add(Result);
  692. end;
  693. function TWasmModule.GetFunc(i: integer): TWasmFunc;
  694. begin
  695. if (i>=0) and (i<funcs.Count) then
  696. Result:=TWasmFunc(funcs[i])
  697. else
  698. Result:=nil;
  699. end;
  700. function TWasmModule.FuncCount: integer;
  701. begin
  702. Result:=funcs.Count;
  703. end;
  704. function TWasmModule.GetType(i: integer): TWasmFuncType;
  705. begin
  706. if (i>=0) and (i<types.Count) then
  707. Result:=TWasmFuncType(types[i])
  708. else
  709. Result:=nil;
  710. end;
  711. function TWasmModule.TypesCount: integer;
  712. begin
  713. Result:=types.Count;
  714. end;
  715. function TWasmModule.AddExport: TWasmExport;
  716. begin
  717. Result:=TWasmExport.Create;
  718. exp.add(Result);
  719. end;
  720. function TWasmModule.GetExport(i: integer): TWasmExport;
  721. begin
  722. if (i>=0) and (i<exp.Count) then
  723. Result:=TWasmExport(exp[i])
  724. else
  725. Result:=nil;
  726. end;
  727. function TWasmModule.ExportCount: integer;
  728. begin
  729. Result:=exp.Count;
  730. end;
  731. function TWasmModule.AddElement: TWasmElement;
  732. begin
  733. Result:=TWasmElement.Create;
  734. elems.add(Result);
  735. end;
  736. function TWasmModule.GetElement(i: integer): TWasmElement;
  737. begin
  738. if (i>=0) and (i<elems.Count) then
  739. Result:=TWasmElement(elems[i])
  740. else
  741. Result:=nil;
  742. end;
  743. function TWasmModule.ElementCount: Integer;
  744. begin
  745. Result := elems.Count;
  746. end;
  747. function TWasmModule.AddData: TWasmData;
  748. begin
  749. Result:=TWasmData.Create;
  750. data.Add(Result);
  751. end;
  752. function TWasmModule.GetData(i: integer): TWasmData;
  753. begin
  754. if (i>=0) and (i<data.Count) then
  755. Result:=TWasmData(data[i])
  756. else
  757. Result:=nil;
  758. end;
  759. function TWasmModule.DataCount: Integer;
  760. begin
  761. Result:=data.Count;
  762. end;
  763. function TWasmModule.AddGlobal: TWasmGlobal;
  764. begin
  765. Result:=TWasmGlobal.Create;
  766. globals.Add(Result);
  767. end;
  768. function TWasmModule.GetGlobal(i: integer): TWasmGlobal;
  769. begin
  770. if (i>=0) and (i<globals.Count) then
  771. Result:=TWasmGlobal(globals[i])
  772. else
  773. Result:=nil;
  774. end;
  775. function TWasmModule.GlobalCount: Integer;
  776. begin
  777. Result:=globals.Count;
  778. end;
  779. { TWasmFunc }
  780. constructor TWasmFunc.Create;
  781. begin
  782. inherited;
  783. locals:=TList.Create;
  784. instr:=TWasmInstrList.Create;
  785. functype:=TWasmFuncType.Create;
  786. idNum:=-1;
  787. end;
  788. destructor TWasmFunc.Destroy;
  789. begin
  790. ClearList(locals);
  791. locals.Free;
  792. functype.Free;
  793. instr.Free;
  794. inherited Destroy;
  795. end;
  796. function TWasmFunc.AddLocal: TWasmParam;
  797. begin
  798. Result:=TWasmParam.Create;
  799. locals.AdD(Result);
  800. end;
  801. function TWasmFunc.GetLocal(i: integer): TWasmParam;
  802. begin
  803. if (i>=0) and (i<locals.Count) then
  804. Result:=TWasmParam(locals[i])
  805. else
  806. Result:=nil;
  807. end;
  808. function TWasmFunc.LocalsCount: integer;
  809. begin
  810. result:=locals.Count;
  811. end;
  812. // registering new or finding the existing type for a function type
  813. // it's assumed the function type is explicitly types
  814. function RegisterFuncType(m: TWasmModule; funcType: TWasmFuncType): integer;
  815. var
  816. i : integer;
  817. trg : string;
  818. d : string;
  819. begin
  820. trg := WasmFuncTypeDescr(funcType);
  821. for i:=0 to m.TypesCount-1 do begin
  822. d := WasmFuncTypeDescr(m.GetType(i));
  823. if trg = d then begin
  824. Result:= i;
  825. Exit;
  826. end;
  827. end;
  828. Result:=m.TypesCount;
  829. funcType.CopyTo(m.AddType);
  830. end;
  831. // searching through TWasmParam list for the specified index-by-name
  832. function FindParam(l: TList; const idx: string): Integer;
  833. var
  834. i : integer;
  835. begin
  836. if not Assigned(l) then begin
  837. Result:=-1;
  838. Exit;
  839. end;
  840. for i:=0 to l.Count-1 do
  841. if TWasmParam(l[i]).id=idx then begin
  842. Result:=i;
  843. Exit;
  844. end;
  845. Result:=-1;
  846. end;
  847. // finding functions by funcIdx
  848. function FindFunc(m: TWasmModule; const funcIdx: string): integer;
  849. var
  850. i : integer;
  851. im : TWasmImport;
  852. begin
  853. Result:=-1;
  854. for i:=0 to m.ImportCount-1 do begin
  855. im:=m.GetImport(i);
  856. if Assigned(im.fn) and (im.fn.id = funcIdx) then begin
  857. Result:=im.fn.idNum;
  858. Exit;
  859. end;
  860. end;
  861. for i:=0 to m.FuncCount-1 do
  862. if m.GetFunc(i).id = funcIdx then begin
  863. Result:=m.GetFunc(i).idNum;
  864. Exit;
  865. end;
  866. end;
  867. function FindGlobal(m: TWasmModule; const globIdx: string): integer;
  868. var
  869. i : integer;
  870. im : TWasmImport;
  871. begin
  872. Result:=-1;
  873. {for i:=0 to m.ImportCount-1 do begin
  874. im:=m.GetImport(i);
  875. if Assigned(im.fn) and (im.fn.id = funcIdx) then begin
  876. Result:=im.fn.idNum;
  877. Exit;
  878. end;
  879. end;}
  880. for i:=0 to m.GlobalCount-1 do
  881. if m.GetGlobal(i).id.id = globIdx then begin
  882. Result:=m.GetGlobal(i).id.idNum;
  883. Exit;
  884. end;
  885. end;
  886. function GetFuncByNum(m: TWasmMOdule; const idNum: Integer): TWasmFunc;
  887. var
  888. i : integer;
  889. begin
  890. for i:=0 to m.FuncCount-1 do begin
  891. Result := m.GetFunc(i);
  892. if Assigned(Result) and (Result.idNum = idNum) then
  893. Exit;
  894. end;
  895. Result:=nil;
  896. end;
  897. function GetGlobalByNum(m: TWasmModule; const idNum: Integer): TWasmGlobal;
  898. var
  899. i : integer;
  900. begin
  901. for i:=0 to m.GlobalCount-1 do begin
  902. Result := m.GetGlobal(i);
  903. if Assigned(Result) and (Result.id.idNum = idNum) then
  904. Exit;
  905. end;
  906. Result:=nil;
  907. end;
  908. function GetMemByNum(m: TWasmModule; const idNum: Integer): TWasmMemory;
  909. var
  910. i : integer;
  911. begin
  912. for i:=0 to m.MemoryCount-1 do begin
  913. Result := m.GetMemory(i);
  914. if Assigned(Result) and (Result.id.idNum = idNum) then
  915. Exit;
  916. end;
  917. Result:=nil;
  918. end;
  919. // only looking up for the by the type index name
  920. function FindFuncType(m: TWasmModule; const typeIdx: string): integer;
  921. var
  922. i : integer;
  923. begin
  924. Result:=-1;
  925. for i:=0 to m.TypesCount-1 do
  926. if m.GetType(i).typeIdx = typeIdx then begin
  927. Result:=i;
  928. Exit;
  929. end;
  930. end;
  931. function RegisterFuncIdxInElem(m: TWasmModule; const func: Integer): integer;
  932. var
  933. el : TWasmElement;
  934. i : Integer;
  935. ofs : Integer;
  936. const
  937. NON_ZEROFFSET = 1; // being compliant with Linking convention
  938. // The output table elements shall begin at a non-zero offset within
  939. // the table, so that a call_indirect 0 instruction is guaranteed to fail.
  940. // Finally, when processing table relocations for symbols which
  941. // have neither an import nor a definition (namely, weakly-undefined
  942. // function symbols), the value 0 is written out as the value of the relocation.
  943. NON_ZEROFFSET_STR = '1';
  944. begin
  945. if m.ElementCount=0 then begin
  946. el := m.AddElement;
  947. OperandSetInt32( el.offset.AddInstr(INST_i32_const).operand1, NON_ZEROFFSET);
  948. el.offset.AddInstr(INST_END);
  949. end else
  950. el := m.GetElement(0);
  951. if not InstrGetConsti32Value(el.offset, ofs) then ofs := 0;
  952. Result:=-1;
  953. for i:=0 to el.funcCount-1 do begin
  954. if el.funcs[i].idNum = func then
  955. Result:=i;
  956. end;
  957. if Result<0 then
  958. Result := el.AddFunc(func);
  959. Result := Result + ofs;
  960. end;
  961. function RegisterFuncInElem(m: TWasmModule; const funcId: string): integer;
  962. var
  963. fnidx : integer;
  964. begin
  965. fnidx := FindFunc(m, funcId);
  966. if fnidx>=0 then
  967. Result := RegisterFuncIdxInElem(m, fnidx)
  968. else
  969. Result := -1;
  970. end;
  971. function InstrGetConsti32Value(l: TWasmInstrList; var vl: Integer): Boolean;
  972. var
  973. err : integer;
  974. begin
  975. //todo: it must be more complicated than that
  976. Result:=Assigned(l) and (l.Count>0) and (l.Item[0].code = INST_i32_const);
  977. if not Result then Exit;
  978. vl := l.Item[0].operand1.s32; // todo: check the type
  979. end;
  980. end.