wasihostapp.pas 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. unit wasihostapp;
  2. {$mode ObjFPC}
  3. interface
  4. uses
  5. Classes, SysUtils, JS, browserapp, web, webassembly, wasienv;
  6. Type
  7. TStartDescriptor = record
  8. Memory : TJSWebAssemblyMemory;
  9. Table : TJSWebAssemblyTable;
  10. Exported : TWASIExports;
  11. Instance : TJSWebAssemblyInstance;
  12. end;
  13. { TWASIHostApplication }
  14. TStartCallBack = Reference to Function (Sender : TObject; aDescriptor : TStartDescriptor) : Boolean;
  15. TWASIHostApplication = class(TBrowserApplication)
  16. private
  17. FEnv: TPas2JSWASIEnvironment;
  18. FExported: TWASIExports;
  19. FMemoryDescriptor : TJSWebAssemblyMemoryDescriptor;
  20. FRunEntryFunction: String;
  21. FTableDescriptor : TJSWebAssemblyTableDescriptor;
  22. procedure DoStdRead(Sender: TObject; var AInput: string);
  23. protected
  24. procedure DoStdWrite(Sender: TObject; const aOutput: String); virtual;
  25. function CreateWebAssembly(aPath: string; aImportObject: TJSObject): TJSPromise; virtual;
  26. Function CreateWasiEnvironment : TPas2JSWASIEnvironment; virtual;
  27. function GetTable: TJSWebAssemblyTable; virtual;
  28. function GetMemory: TJSWebAssemblyMemory; virtual;
  29. public
  30. Constructor Create(aOwner : TComponent); override;
  31. Destructor Destroy; override;
  32. // Load and start webassembly. If DoRun is true, then Webassembly entry point is called.
  33. // If aCallback is specified, then it is called prior to calling run.
  34. Procedure StartWebAssembly(aPath: string; DoRun : Boolean = True; aCallBack : TStartCallback = Nil);
  35. // Initial memory descriptor
  36. Property MemoryDescriptor : TJSWebAssemblyMemoryDescriptor Read FMemoryDescriptor Write FMemoryDescriptor;
  37. // Import/export table descriptor
  38. Property TableDescriptor : TJSWebAssemblyTableDescriptor Read FTableDescriptor Write FTableDescriptor;
  39. // Environment to be used
  40. Property WasiEnvironment : TPas2JSWASIEnvironment Read FEnv;
  41. // Exported functions. Also available in start descriptor.
  42. Property Exported : TWASIExports Read FExported;
  43. Property RunEntryFunction : String Read FRunEntryFunction Write FRunEntryFunction;
  44. end;
  45. implementation
  46. { TWASIHostApplication }
  47. function TWASIHostApplication.CreateWasiEnvironment: TPas2JSWASIEnvironment;
  48. begin
  49. Result:=TPas2JSWASIEnvironment.Create;
  50. end;
  51. constructor TWASIHostApplication.Create(aOwner: TComponent);
  52. begin
  53. inherited Create(aOwner);
  54. FEnv:=CreateWasiEnvironment;
  55. FEnv.OnStdErrorWrite:=@DoStdWrite;
  56. FEnv.OnStdOutputWrite:=@DoStdWrite;
  57. Fenv.OnGetConsoleInputString:=@DoStdRead;
  58. FMemoryDescriptor.initial:=256;
  59. FMemoryDescriptor.maximum:=256;
  60. FTableDescriptor.initial:=0;
  61. FTableDescriptor.maximum:=0;
  62. FTableDescriptor.element:='anyfunc';
  63. end;
  64. destructor TWASIHostApplication.Destroy;
  65. begin
  66. FreeAndNil(FEnv);
  67. inherited Destroy;
  68. end;
  69. function TWASIHostApplication.GetTable : TJSWebAssemblyTable;
  70. begin
  71. Result:=TJSWebAssemblyTable.New(FTableDescriptor);
  72. end;
  73. function TWASIHostApplication.GetMemory : TJSWebAssemblyMemory;
  74. begin
  75. Result:=TJSWebAssemblyMemory.New(FMemoryDescriptor);
  76. end;
  77. procedure TWASIHostApplication.StartWebAssembly(aPath: string; DoRun : Boolean = True; ACallBack: TStartCallback = Nil);
  78. Var
  79. ImportObj : TJSObject;
  80. Res : TStartDescriptor;
  81. function InitEnv(aValue: JSValue): JSValue;
  82. Var
  83. Module : TJSInstantiateResult absolute aValue;
  84. begin
  85. Result:=True;
  86. Res.Instance:=Module.Instance;
  87. Res.Exported:=TWASIExports(TJSObject(Module.Instance.exports_));
  88. // These 2 prevent running different instances simultaneously.
  89. FExported:=Res.Exported;
  90. WasiEnvironment.Instance:=Module.Instance;
  91. if Assigned(aCallBack) then
  92. DoRun:=aCallBack(Self,Res) and DoRun;
  93. if DoRun then
  94. if FRunEntryFunction='' then
  95. Res.Exported.Start
  96. else
  97. TProcedure(Res.Exported[RunEntryFunction])();
  98. end;
  99. begin
  100. Res.Memory:=GetMemory;
  101. Res.Table:=GetTable;
  102. ImportObj:=new([
  103. 'js', new([
  104. 'mem', Res.Memory,
  105. 'tbl', Res.Table
  106. ])
  107. ]);
  108. FEnv.AddImports(ImportObj);
  109. CreateWebAssembly(aPath,ImportObj)._then(@initEnv)
  110. end;
  111. procedure TWASIHostApplication.DoStdRead(Sender: TObject; var AInput: string);
  112. begin
  113. aInput:=Window.prompt('Please enter the input for the running webassembly program.');
  114. end;
  115. procedure TWASIHostApplication.DoStdWrite(Sender: TObject; const aOutput: String
  116. );
  117. begin
  118. Console.log('Webassembly output: ', aOutput);
  119. end;
  120. function TWASIHostApplication.CreateWebAssembly(aPath: string; aImportObject: TJSObject): TJSPromise;
  121. Function ArrayOK(res2 : jsValue) : JSValue;
  122. begin
  123. Result:=TJSWebAssembly.instantiate(TJSArrayBuffer(res2),aImportObject);
  124. end;
  125. function fetchOK(res : jsValue) : JSValue;
  126. begin
  127. Result:=TJSResponse(Res).arrayBuffer._then(@ArrayOK,Nil)
  128. end;
  129. begin
  130. Result:=window.fetch(aPath)._then(@fetchOK,Nil);
  131. end;
  132. end.