invoke.inc 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
  1. {%MainUnit ../inc/rtti.pp}
  2. {
  3. This file is part of the Free Pascal run time library.
  4. Copyright (C) 2019 Sven Barth
  5. member of the Free Pascal development team.
  6. Function call manager for i386
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. }
  13. {$define SYSTEM_HAS_INVOKE}
  14. function ReturnResultInParam(aType: PTypeInfo): Boolean;
  15. var
  16. td: PTypeData;
  17. begin
  18. { Only on Win32 structured types of sizes 1, 2 and 4 are returned directly
  19. instead of a result parameter }
  20. Result := False;
  21. if Assigned(aType) then begin
  22. case aType^.Kind of
  23. tkMethod,
  24. tkSString,
  25. tkAString,
  26. tkUString,
  27. tkWString,
  28. tkInterface,
  29. tkDynArray:
  30. Result := True;
  31. tkArray: begin
  32. {$ifdef win32}
  33. td := GetTypeData(aType);
  34. Result := not (td^.ArrayData.Size in [1, 2, 4]);
  35. {$else}
  36. Result := True;
  37. {$endif}
  38. end;
  39. tkRecord: begin
  40. {$ifdef win32}
  41. td := GetTypeData(aType);
  42. Result := not (td^.RecSize in [1, 2, 4]);
  43. {$else}
  44. Result := True;
  45. {$endif}
  46. end;
  47. tkSet: begin
  48. td := GetTypeData(aType);
  49. case td^.OrdType of
  50. otUByte:
  51. Result := not (td^.SetSize in [1, 2, 4]);
  52. otUWord,
  53. otULong:
  54. Result := False;
  55. end;
  56. end;
  57. end;
  58. end;
  59. end;
  60. procedure InvokeKernelRegister(aCodeAddress: CodePointer; aArgs: Pointer; aArgCount: LongInt); assembler; nostackframe;
  61. label
  62. nostackargs;
  63. asm
  64. pushl %ebp
  65. movl %esp, %ebp
  66. { keep stack aligned to 16 bytes? }
  67. {$if FPC_STACKALIGNMENT=16}
  68. leal -8(%esp),%esp
  69. {$endif FPC_STACKALIGNMENT=16}
  70. pushl %edi
  71. pushl %esi
  72. pushl %eax
  73. pushl %edx
  74. cmpl $3, %ecx
  75. jle nostackargs
  76. { copy arguments to stack }
  77. subl $3, %ecx
  78. { allocate count (%ecx) * 4 space on stack }
  79. movl %ecx, %eax
  80. shll $2, %eax
  81. { keep stack aligned to 16 bytes? }
  82. {$if FPC_STACKALIGNMENT=16}
  83. addl $15, %eax
  84. movl %eax, %esi
  85. andl $15, %esi
  86. subl %esi, %eax
  87. {$endif FPC_STACKALIGNMENT=16}
  88. sub %eax, %esp
  89. movl %esp, %edi
  90. lea 12(%edx), %esi
  91. cld
  92. rep movsd
  93. nostackargs:
  94. movl 8(%edx), %ecx
  95. movl (%edx), %eax
  96. movl 4(%edx), %edx
  97. {$if FPC_STACKALIGNMENT=16}
  98. call -20(%ebp)
  99. { ensure stack is cleared }
  100. leal -24(%ebp),%esp
  101. {$else FPC_STACKALIGNMENT=16}
  102. call -12(%ebp)
  103. {$endif FPC_STACKALIGNMENT=16}
  104. popl %ecx
  105. movl %eax, (%ecx)
  106. movl %edx, 4(%ecx)
  107. popl %ecx
  108. popl %esi
  109. popl %edi
  110. movl %ebp, %esp
  111. popl %ebp
  112. end;
  113. resourcestring
  114. SErrFailedToConvertArg = 'Failed to convert argument %d of type %s';
  115. procedure SystemInvokeRegister(aCodeAddress: CodePointer; const aArgs: TFunctionCallParameterArray; aCallConv: TCallConv;
  116. aResultType: PTypeInfo; aResultValue: Pointer; aFlags: TFunctionCallFlags);
  117. var
  118. regstack: array of PtrUInt;
  119. stackargs: array of SizeInt;
  120. argcount, regidx, stackidx, stackcnt, i: LongInt;
  121. retinparam, isstack: Boolean;
  122. td: PTypeData;
  123. floatres: Extended;
  124. procedure AddRegArg(aValue: PtrUInt);
  125. begin
  126. if regidx < 3 then begin
  127. regstack[regidx] := aValue;
  128. Inc(regidx);
  129. end else begin
  130. if 3 + stackidx = Length(regstack) then
  131. SetLength(regstack, Length(regstack) * 2);
  132. regstack[3 + stackidx] := aValue;
  133. Inc(stackidx);
  134. end;
  135. end;
  136. procedure AddStackArg(aValue: PtrUInt);
  137. begin
  138. if 3 + stackidx = Length(regstack) then
  139. SetLength(regstack, Length(regstack) * 2);
  140. regstack[3 + stackidx] := aValue;
  141. Inc(stackidx);
  142. end;
  143. begin
  144. { for the register calling convention we always have the registers EAX, EDX, ECX
  145. and then the stack; if a parameter does not fit into a register its moved to the
  146. next available stack slot and the next parameter gets a chance to be in a register }
  147. retinparam := ReturnResultInParam(aResultType);
  148. { we allocate at least three slots for EAX, ECX and EDX }
  149. argcount := Length(aArgs);
  150. if retinparam then
  151. Inc(argcount);
  152. if argcount < 3 then
  153. SetLength(regstack, 3)
  154. else
  155. SetLength(regstack, argcount);
  156. regidx := 0;
  157. stackidx := 0;
  158. SetLength(stackargs, Length(aArgs));
  159. stackcnt := 0;
  160. { first pass: handle register parameters }
  161. for i := 0 to High(aArgs) do begin
  162. if regidx >= 3 then begin
  163. { all register locations already used up }
  164. stackargs[stackcnt] := i;
  165. Inc(stackcnt);
  166. Continue;
  167. end;
  168. isstack := False;
  169. if pfArray in aArgs[i].Info.ParamFlags then
  170. AddRegArg(PtrUInt(aArgs[i].ValueRef))
  171. else if aArgs[i].Info.ParamFlags * [pfOut, pfVar, pfConstRef] <> [] then
  172. AddRegArg(PtrUInt(aArgs[i].ValueRef))
  173. else if (pfConst in aArgs[i].Info.ParamFlags) and not Assigned(aArgs[i].Info.ParamType) then
  174. AddRegArg(PtrUInt(aArgs[i].ValueRef))
  175. else begin
  176. td := GetTypeData(aArgs[i].Info.ParamType);
  177. case aArgs[i].Info.ParamType^.Kind of
  178. tkSString,
  179. tkMethod:
  180. AddRegArg(PtrUInt(aArgs[i].ValueRef));
  181. tkArray:
  182. if td^.ArrayData.Size <= 4 then
  183. isstack := True
  184. else
  185. AddRegArg(PtrUInt(aArgs[i].ValueRef));
  186. tkRecord:
  187. if td^.RecSize <= 4 then
  188. isstack := True
  189. else
  190. AddRegArg(PtrUInt(aArgs[i].ValueRef));
  191. tkObject,
  192. tkWString,
  193. tkUString,
  194. tkAString,
  195. tkDynArray,
  196. tkClass,
  197. tkClassRef,
  198. tkInterface,
  199. tkInterfaceRaw,
  200. tkProcVar,
  201. tkPointer:
  202. AddRegArg(PPtrUInt(aArgs[i].ValueRef)^);
  203. tkInt64,
  204. tkQWord:
  205. isstack := True;
  206. tkSet: begin
  207. case td^.OrdType of
  208. otUByte: begin
  209. case td^.SetSize of
  210. 0, 1:
  211. AddRegArg(PByte(aArgs[i].ValueRef)^);
  212. 2:
  213. AddRegArg(PWord(aArgs[i].ValueRef)^);
  214. 3:
  215. AddRegArg(PtrUInt(aArgs[i].ValueRef));
  216. 4:
  217. AddRegArg(PLongWord(aArgs[i].ValueRef)^);
  218. else
  219. AddRegArg(PtrUInt(aArgs[i].ValueRef));
  220. end;
  221. end;
  222. otUWord:
  223. AddRegArg(PWord(aArgs[i].ValueRef)^);
  224. otULong:
  225. AddRegArg(PLongWord(aArgs[i].ValueRef)^);
  226. end;
  227. end;
  228. tkEnumeration,
  229. tkInteger: begin
  230. case td^.OrdType of
  231. otSByte: AddRegArg(PShortInt(aArgs[i].ValueRef)^);
  232. otUByte: AddRegArg(PByte(aArgs[i].ValueRef)^);
  233. otSWord: AddRegArg(PSmallInt(aArgs[i].ValueRef)^);
  234. otUWord: AddRegArg(PWord(aArgs[i].ValueRef)^);
  235. otSLong: AddRegArg(PLongInt(aArgs[i].ValueRef)^);
  236. otULong: AddRegArg(PLongWord(aArgs[i].ValueRef)^);
  237. end;
  238. end;
  239. tkBool: begin
  240. case td^.OrdType of
  241. otUByte: AddRegArg(ShortInt(System.PBoolean(aArgs[i].ValueRef)^));
  242. otUWord: AddRegArg(Byte(PBoolean16(aArgs[i].ValueRef)^));
  243. otULong: AddRegArg(SmallInt(PBoolean32(aArgs[i].ValueRef)^));
  244. otUQWord: isstack := True;
  245. otSByte: AddRegArg(Word(PByteBool(aArgs[i].ValueRef)^));
  246. otSWord: AddRegArg(LongInt(PWordBool(aArgs[i].ValueRef)^));
  247. otSLong: AddRegArg(LongWord(PLongBool(aArgs[i].ValueRef)^));
  248. otSQWord: isstack := True;
  249. end;
  250. end;
  251. tkFloat:
  252. { all float types are passed in on stack }
  253. isstack := True;
  254. else
  255. raise EInvocationError.CreateFmt(SErrFailedToConvertArg, [i, aArgs[i].Info.ParamType^.Name]);
  256. end;
  257. end;
  258. if isstack then begin
  259. stackargs[stackcnt] := i;
  260. Inc(stackcnt);
  261. end;
  262. end;
  263. { then add the result parameter reference (if any) }
  264. if Assigned(aResultType) and retinparam then
  265. AddRegArg(PtrUInt(aResultValue));
  266. { second pass: handle stack arguments from right to left }
  267. if stackcnt > 0 then begin
  268. for i := stackcnt - 1 downto 0 do begin
  269. if pfArray in aArgs[stackargs[i]].Info.ParamFlags then
  270. AddStackArg(PtrUInt(aArgs[stackargs[i]].ValueRef))
  271. else if aArgs[stackargs[i]].Info.ParamFlags * [pfOut, pfVar, pfConstRef] <> [] then
  272. AddStackArg(PtrUInt(aArgs[stackargs[i]].ValueRef))
  273. else if (pfConst in aArgs[stackargs[i]].Info.ParamFlags) and not Assigned(aArgs[stackargs[i]].Info.ParamType) then
  274. AddStackArg(PtrUInt(aArgs[stackargs[i]].ValueRef))
  275. else begin
  276. td := GetTypeData(aArgs[stackargs[i]].Info.ParamType);
  277. case aArgs[stackargs[i]].Info.ParamType^.Kind of
  278. tkSString,
  279. tkMethod:
  280. AddStackArg(PtrUInt(aArgs[stackargs[i]].ValueRef));
  281. tkArray:
  282. if td^.ArrayData.Size <= 4 then
  283. AddStackArg(PPtrUInt(aArgs[stackargs[i]].ValueRef)^)
  284. else
  285. AddStackArg(PtrUInt(aArgs[stackargs[i]].ValueRef));
  286. tkRecord:
  287. if td^.RecSize <= 4 then
  288. AddStackArg(PPtrUInt(aArgs[stackargs[i]].ValueRef)^)
  289. else
  290. AddStackArg(PtrUInt(aArgs[stackargs[i]].ValueRef));
  291. tkObject,
  292. tkWString,
  293. tkUString,
  294. tkAString,
  295. tkDynArray,
  296. tkClass,
  297. tkClassRef,
  298. tkInterface,
  299. tkInterfaceRaw,
  300. tkProcVar,
  301. tkPointer:
  302. AddStackArg(PPtrUInt(aArgs[stackargs[i]].ValueRef)^);
  303. tkInt64,
  304. tkQWord: begin
  305. AddStackArg(PInt32(PInt64(aArgs[stackargs[i]].ValueRef))[0]);
  306. AddStackArg(PInt32(PInt64(aArgs[stackargs[i]].ValueRef))[1]);
  307. end;
  308. tkSet: begin
  309. case td^.OrdType of
  310. otUByte: begin
  311. case td^.SetSize of
  312. 0, 1:
  313. AddStackArg(PByte(aArgs[stackargs[i]].ValueRef)^);
  314. 2:
  315. AddStackArg(PWord(aArgs[stackargs[i]].ValueRef)^);
  316. 3:
  317. AddStackArg(PtrUInt(aArgs[stackargs[i]].ValueRef));
  318. 4:
  319. AddStackArg(PLongWord(aArgs[stackargs[i]].ValueRef)^);
  320. else
  321. AddStackArg(PtrUInt(aArgs[stackargs[i]].ValueRef));
  322. end;
  323. end;
  324. otUWord:
  325. AddStackArg(PWord(aArgs[stackargs[i]].ValueRef)^);
  326. otULong:
  327. AddStackArg(PLongWord(aArgs[stackargs[i]].ValueRef)^);
  328. end;
  329. end;
  330. tkEnumeration,
  331. tkInteger: begin
  332. case td^.OrdType of
  333. otSByte: AddStackArg(PShortInt(aArgs[stackargs[i]].ValueRef)^);
  334. otUByte: AddStackArg(PByte(aArgs[stackargs[i]].ValueRef)^);
  335. otSWord: AddStackArg(PSmallInt(aArgs[stackargs[i]].ValueRef)^);
  336. otUWord: AddStackArg(PWord(aArgs[stackargs[i]].ValueRef)^);
  337. otSLong: AddStackArg(PLongInt(aArgs[stackargs[i]].ValueRef)^);
  338. otULong: AddStackArg(PLongWord(aArgs[stackargs[i]].ValueRef)^);
  339. end;
  340. end;
  341. tkBool: begin
  342. case td^.OrdType of
  343. otUByte: AddStackArg(ShortInt(System.PBoolean(aArgs[stackargs[i]].ValueRef)^));
  344. otUWord: AddStackArg(Byte(PBoolean16(aArgs[stackargs[i]].ValueRef)^));
  345. otULong: AddStackArg(SmallInt(PBoolean32(aArgs[stackargs[i]].ValueRef)^));
  346. otUQWord: AddStackArg(QWord(PBoolean64(aArgs[stackargs[i]].ValueRef)));
  347. otSByte: AddStackArg(Word(PByteBool(aArgs[stackargs[i]].ValueRef)^));
  348. otSWord: AddStackArg(LongInt(PWordBool(aArgs[stackargs[i]].ValueRef)^));
  349. otSLong: AddStackArg(LongWord(PLongBool(aArgs[stackargs[i]].ValueRef)^));
  350. otSQWord: AddStackArg(PtrUInt(PQWordBool(aArgs[stackargs[i]].ValueRef)));
  351. end;
  352. end;
  353. tkFloat: begin
  354. case td^.FloatType of
  355. ftCurr : begin
  356. AddStackArg(PInt32(PCurrency(aArgs[stackargs[i]].ValueRef))[0]);
  357. AddStackArg(PInt32(PCurrency(aArgs[stackargs[i]].ValueRef))[1]);
  358. end;
  359. ftSingle : AddStackArg(PInt32(PSingle(aArgs[stackargs[i]].ValueRef))^);
  360. ftDouble : begin
  361. AddStackArg(PInt32(PDouble(aArgs[stackargs[i]].ValueRef))[0]);
  362. AddStackArg(PInt32(PDouble(aArgs[stackargs[i]].ValueRef))[1]);
  363. end;
  364. ftExtended: begin
  365. AddStackArg(PInt32(PExtended(aArgs[stackargs[i]].ValueRef))[0]);
  366. AddStackArg(PInt32(PExtended(aArgs[stackargs[i]].ValueRef))[1]);
  367. AddStackArg(PWord(PExtended(aArgs[stackargs[i]].ValueRef))[4]);
  368. end;
  369. ftComp : begin
  370. AddStackArg(PInt32(PComp(aArgs[stackargs[i]].ValueRef))[0]);
  371. AddStackArg(PInt32(PComp(aArgs[stackargs[i]].ValueRef))[1]);
  372. end;
  373. end;
  374. end;
  375. else
  376. raise EInvocationError.CreateFmt(SErrFailedToConvertArg, [stackargs[i], aArgs[stackargs[i]].Info.ParamType^.Name]);
  377. end;
  378. end;
  379. end;
  380. end;
  381. InvokeKernelRegister(aCodeAddress, @regstack[0], 3 + stackidx);
  382. if Assigned(aResultType) and not retinparam then begin
  383. if aResultType^.Kind = tkFloat then begin
  384. td := GetTypeData(aResultType);
  385. asm
  386. lea floatres, %eax
  387. fstpt (%eax)
  388. end ['eax'];
  389. case td^.FloatType of
  390. ftSingle:
  391. PSingle(aResultValue)^ := floatres;
  392. ftDouble:
  393. PDouble(aResultValue)^ := floatres;
  394. ftExtended:
  395. PExtended(aResultValue)^ := floatres;
  396. ftCurr:
  397. PCurrency(aResultValue)^ := floatres / 10000;
  398. ftComp:
  399. PComp(aResultValue)^ := Comp(floatres);
  400. end;
  401. end else if aResultType^.Kind in [tkQWord, tkInt64] then
  402. PQWord(aResultValue)^ := regstack[0] or (QWord(regstack[1]) shl 32)
  403. else
  404. PPtrUInt(aResultValue)^ := regstack[0];
  405. end;
  406. end;
  407. procedure SystemInvoke(aCodeAddress: CodePointer; const aArgs: TFunctionCallParameterArray; aCallConv: TCallConv;
  408. aResultType: PTypeInfo; aResultValue: Pointer; aFlags: TFunctionCallFlags);
  409. begin
  410. case aCallConv of
  411. ccReg:
  412. SystemInvokeRegister(aCodeAddress, aArgs, aCallConv, aResultType, aResultValue, aFlags);
  413. otherwise
  414. Assert(False, 'Unsupported calling convention');
  415. end;
  416. end;
  417. const
  418. PlaceholderContext = LongWord($12345678);
  419. PlaceholderAddress = LongWord($87654321);
  420. PlaceholderRetPop = Word($1234);
  421. RetNear = $C2;
  422. RetFar = $CA;
  423. label
  424. CallbackRegisterContext,
  425. CallbackRegisterAddress,
  426. CallbackRegisterCall,
  427. CallbackRegisterRet,
  428. CallbackRegisterEnd;
  429. const
  430. CallbackRegisterContextPtr: Pointer = @CallbackRegisterContext;
  431. CallbackRegisterAddressPtr: Pointer = @CallbackRegisterAddress;
  432. CallbackRegisterCallPtr: Pointer = @CallbackRegisterCall;
  433. CallbackRegisterRetPtr: Pointer = @CallbackRegisterRet;
  434. CallbackRegisterEndPtr: Pointer = @CallbackRegisterEnd;
  435. procedure CallbackRegister; assembler; nostackframe;
  436. asm
  437. { establish frame }
  438. pushl %ebp
  439. movl %esp, %ebp
  440. { store registers }
  441. pushl %ecx
  442. pushl %edx
  443. pushl %eax
  444. { store pointer to stack area (including GP registers) }
  445. lea (%esp), %edx
  446. {$if FPC_STACKALIGNMENT=16}
  447. { keep stack aligned, before the call below stack must be aligned to a 16 byte boundary }
  448. leal -8(%esp),%esp
  449. {$endif FPC_STACKALIGNMENT=16}
  450. { also store ebx as we'll use that for the function address }
  451. pushl %ebx
  452. { call function with context }
  453. CallbackRegisterContext:
  454. movl $0x12345678, %eax
  455. CallbackRegisterAddress:
  456. movl $0x87654321, %ebx
  457. CallbackRegisterCall:
  458. call *%ebx
  459. { restore ebx }
  460. popl %ebx
  461. { restore stack }
  462. movl %ebp, %esp
  463. popl %ebp
  464. CallbackRegisterRet:
  465. ret $0x1234
  466. CallbackRegisterEnd:
  467. end;
  468. type
  469. TSystemFunctionCallback = class(TFunctionCallCallback)
  470. private type
  471. {$ScopedEnums On}
  472. TArgType = (
  473. GenReg,
  474. Stack
  475. );
  476. {$ScopedEnums Off}
  477. TArgInfo = record
  478. ArgType: TArgType;
  479. ArgIdx: SizeInt;
  480. Slots: SizeInt;
  481. Offset: SizeInt;
  482. Deref: Boolean;
  483. end;
  484. private
  485. fData: Pointer;
  486. fSize: PtrUInt;
  487. fFlags: TFunctionCallFlags;
  488. fContext: Pointer;
  489. fArgs: specialize TArray<TFunctionCallParameterInfo>;
  490. fArgInfos: specialize TArray<TArgInfo>;
  491. fRefArgs: specialize TArray<SizeInt>;
  492. fResultType: PTypeInfo;
  493. fResultIdx: SizeInt;
  494. fResultInParam: Boolean;
  495. private
  496. function Handler(aStack: Pointer): Int64;
  497. protected
  498. procedure CreateCallback;
  499. procedure CreateArgInfos;
  500. function GetCodeAddress: CodePointer; override;
  501. procedure CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer); virtual; abstract;
  502. public
  503. constructor Create(aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
  504. destructor Destroy; override;
  505. end;
  506. TSystemFunctionCallbackMethod = class(TSystemFunctionCallback)
  507. private
  508. fHandler: TFunctionCallMethod;
  509. protected
  510. procedure CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer); override;
  511. public
  512. constructor Create(aHandler: TFunctionCallMethod; aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
  513. end;
  514. TSystemFunctionCallbackProc = class(TSystemFunctionCallback)
  515. private
  516. fHandler: TFunctionCallProc;
  517. protected
  518. procedure CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer); override;
  519. public
  520. constructor Create(aHandler: TFunctionCallProc; aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
  521. end;
  522. function TSystemFunctionCallback.Handler(aStack: Pointer): Int64;
  523. {
  524. aStack has the following layout:
  525. 0: EAX
  526. 4: EDX
  527. 8: ECX
  528. 12: EBP (not needed)
  529. 16: RET (not needed)
  530. 20: ARGS
  531. }
  532. var
  533. args: specialize TArray<Pointer>;
  534. i, len: SizeInt;
  535. val: PPtrUInt;
  536. resptr: Pointer;
  537. genargs, stackargs: PPtrUInt;
  538. floatres, floattmp: Extended;
  539. td: PTypeData;
  540. begin
  541. len := Length(fArgInfos);
  542. if fResultInParam then
  543. Dec(len);
  544. SetLength(args, len);
  545. genargs := PPtrUInt(aStack);
  546. stackargs := @genargs[5];
  547. for i := 0 to High(fArgInfos) do begin
  548. if i = fResultIdx then
  549. Continue;
  550. case fArgInfos[i].ArgType of
  551. TArgType.GenReg:
  552. val := @genargs[fArgInfos[i].Offset];
  553. TArgType.Stack:
  554. val := @stackargs[fArgInfos[i].Offset];
  555. end;
  556. if fArgInfos[i].Deref then
  557. args[fArgInfos[i].ArgIdx] := PPtrUInt(val^)
  558. else
  559. args[fArgInfos[i].ArgIdx] := val;
  560. end;
  561. if fResultInParam then begin
  562. case fArgInfos[fResultIdx].ArgType of
  563. TArgType.GenReg:
  564. resptr := @genargs[fArgInfos[fResultIdx].Offset];
  565. TArgType.Stack:
  566. resptr := @stackargs[fArgInfos[fResultIdx].Offset];
  567. end;
  568. if fArgInfos[fResultIdx].Deref then
  569. resptr := PPointer(resptr)^;
  570. end else if Assigned(fResultType) then begin
  571. if fResultType^.Kind = tkFloat then begin
  572. resptr := @floatres;
  573. end else
  574. resptr := @Result;
  575. end else
  576. resptr := Nil;
  577. CallHandler(args, resptr, fContext);
  578. if Assigned(fResultType) and not fResultInParam and (fResultType^.Kind = tkFloat) then begin
  579. td := GetTypeData(fResultType);
  580. case td^.FloatType of
  581. ftSingle:
  582. asm
  583. lea floatres, %eax
  584. flds (%eax)
  585. fwait
  586. end ['eax'];
  587. ftDouble:
  588. asm
  589. lea floatres, %eax
  590. fldl (%eax)
  591. fwait
  592. end ['eax'];
  593. ftExtended:
  594. asm
  595. lea floatres, %eax
  596. fldt (%eax)
  597. fwait
  598. end ['eax'];
  599. ftCurr,
  600. ftComp:
  601. asm
  602. lea floatres, %eax
  603. fildq (%eax)
  604. fwait
  605. end ['eax'];
  606. end;
  607. end;
  608. end;
  609. procedure TSystemFunctionCallback.CreateCallback;
  610. procedure ReplacePlaceholder(aPlaceholder: PtrUInt; aValue: PtrUInt; aOfs, aSize: PtrUInt);
  611. var
  612. found: Boolean;
  613. i: PtrUInt;
  614. begin
  615. found := False;
  616. for i := aOfs to aOfs + aSize - 1 do begin
  617. if PPtrUInt(@PByte(fData)[i])^ = PtrUInt(aPlaceholder) then begin
  618. PPtrUInt(@(PByte(fData)[i]))^ := PtrUInt(aValue);
  619. found := True;
  620. Break;
  621. end;
  622. end;
  623. if not found then
  624. raise Exception.Create(SErrMethodImplCreateFailed);
  625. end;
  626. var
  627. src: Pointer;
  628. ofs, size: PtrUInt;
  629. method: TMethod;
  630. i, stacksize: SizeInt;
  631. begin
  632. fSize := PtrUInt(CallbackRegisterEndPtr) - PtrUInt(@CallbackRegister) + 1;
  633. fData := AllocateMemory(fSize);
  634. if not Assigned(fData) then
  635. raise Exception.Create(SErrMethodImplCreateFailed);
  636. src := @CallbackRegister;
  637. Move(src^, fData^, fSize);
  638. ofs := PtrUInt(CallbackRegisterContextPtr) - PtrUInt(@CallbackRegister);
  639. size := PtrUInt(CallbackRegisterAddressPtr) - PtrUInt(CallbackRegisterContextPtr);
  640. method := TMethod(@Handler);
  641. ReplacePlaceholder(PlaceholderContext, PtrUInt(method.Data), ofs, size);
  642. ofs := PtrUInt(CallbackRegisterAddressPtr) - PtrUInt(@CallbackRegister);
  643. size := PtrUInt(CallbackRegisterCallPtr) - PtrUInt(CallbackRegisterAddressPtr);
  644. ReplacePlaceholder(PlaceholderAddress, PtrUInt(method.Code), ofs, size);
  645. ofs := PtrUInt(CallbackRegisterRetPtr) - PtrUInt(@CallbackRegister);
  646. size := PtrUInt(CallbackRegisterEndPtr) - PtrUInt(CallbackRegisterRetPtr);
  647. if not (PByte(fData)[ofs] = RetNear) and not (PByte(fData)[ofs] = RetFar) then
  648. raise Exception.Create(SErrMethodImplCreateFailed);
  649. stacksize := 0;
  650. for i := 0 to High(fArgInfos) do
  651. if fArgInfos[i].ArgType = TArgType.Stack then
  652. Inc(stacksize, fArgInfos[i].Slots);
  653. stacksize := stacksize * 4;
  654. Inc(ofs);
  655. if PWord(@PByte(fData)[ofs])^ = PlaceholderRetPop then
  656. PWord(@PByte(fData)[ofs])^ := Word(stacksize);
  657. if not ProtectMemory(fData, fSize, True) then
  658. raise Exception.Create(SErrMethodImplCreateFailed);
  659. end;
  660. procedure TSystemFunctionCallback.CreateArgInfos;
  661. var
  662. pass, genofs, stackofs: LongInt;
  663. td: PTypeData;
  664. i, c, argcount, stackcount, idx, argidx: SizeInt;
  665. stackargs: array of SizeInt;
  666. begin
  667. fResultInParam := ReturnResultInParam(fResultType);
  668. genofs := 0;
  669. stackofs := 0;
  670. argidx := 0;
  671. argcount := Length(fArgs);
  672. if fResultInParam then begin
  673. if fcfStatic in fFlags then
  674. fResultIdx := 0
  675. else
  676. fResultIdx := 1;
  677. Inc(argcount);
  678. end else
  679. fResultIdx := -1;
  680. SetLength(fArgInfos, argcount);
  681. SetLength(fRefArgs, argcount);
  682. if fResultIdx >= 0 then begin
  683. fArgInfos[fResultIdx].ArgType := TArgType.GenReg;
  684. fArgInfos[fResultIdx].Offset := fResultIdx;
  685. end;
  686. SetLength(stackargs, argcount);
  687. stackcount := 0;
  688. for pass := 0 to 1 do begin
  689. if pass = 0 then
  690. c := High(fArgs)
  691. else
  692. c := stackcount - 1;
  693. for i := 0 to c do begin
  694. if argidx = fResultIdx then
  695. Inc(argidx);
  696. if pfResult in fArgs[i].ParamFlags then begin
  697. fResultIdx := argidx;
  698. fResultInParam := True;
  699. end;
  700. if (pass = 0) and (genofs >= 3) then begin
  701. stackargs[stackcount] := i;
  702. Inc(stackcount);
  703. Continue;
  704. end;
  705. if pass = 0 then
  706. idx := i
  707. else
  708. idx := stackargs[c - i];
  709. if pass = 0 then
  710. fArgInfos[argidx].ArgType := TArgType.GenReg
  711. else
  712. fArgInfos[argidx].ArgType := TArgType.Stack;
  713. fArgInfos[argidx].Deref := False;
  714. fArgInfos[argidx].Slots := 1;
  715. if pfArray in fArgs[idx].ParamFlags then
  716. fArgInfos[argidx].Deref := True
  717. else if fArgs[idx].ParamFlags * [pfOut, pfVar, pfConstRef] <> [] then
  718. fArgInfos[argidx].Deref := True
  719. else if (pfConst in fArgs[idx].ParamFlags) and not Assigned(fArgs[idx].ParamType) then
  720. fArgInfos[argidx].Deref := True
  721. else begin
  722. td := GetTypeData(fArgs[idx].ParamType);
  723. case fArgs[idx].ParamType^.Kind of
  724. tkSString,
  725. tkMethod:
  726. fArgInfos[argidx].Deref := True;
  727. tkArray:
  728. if td^.ArrayData.Size <= 4 then begin
  729. fArgInfos[argidx].Deref := True;
  730. fArgInfos[argidx].ArgType := TArgType.Stack;
  731. end;
  732. tkRecord:
  733. if td^.RecSize <= 4 then begin
  734. fArgInfos[argidx].Deref := True;
  735. fArgInfos[argidx].ArgType := TArgType.Stack;
  736. end;
  737. tkObject,
  738. tkWString,
  739. tkUString,
  740. tkAString,
  741. tkDynArray,
  742. tkClass,
  743. tkClassRef,
  744. tkInterface,
  745. tkInterfaceRaw,
  746. tkProcVar,
  747. tkPointer:
  748. ;
  749. tkInt64,
  750. tkQWord: begin
  751. fArgInfos[argidx].ArgType := TArgType.Stack;
  752. fArgInfos[argidx].Slots := 2;
  753. end;
  754. tkSet: begin
  755. case td^.OrdType of
  756. otUByte: begin
  757. case td^.SetSize of
  758. 0, 1, 2, 4:
  759. ;
  760. else
  761. fArgInfos[argidx].Deref := True;
  762. end;
  763. end;
  764. otUWord,
  765. otULong:
  766. ;
  767. end;
  768. end;
  769. tkEnumeration,
  770. tkInteger:
  771. ;
  772. tkBool:
  773. case td^.OrdType of
  774. otUQWord,
  775. otSQWord:
  776. fArgInfos[argidx].ArgType := TArgType.Stack;
  777. end;
  778. tkFloat: begin
  779. fArgInfos[argidx].ArgType := TArgType.Stack;
  780. case td^.FloatType of
  781. ftSingle:
  782. ;
  783. ftCurr,
  784. ftComp,
  785. ftDouble:
  786. fArgInfos[argidx].Slots := 2;
  787. ftExtended:
  788. fArgInfos[argidx].Slots := 3;
  789. end;
  790. end;
  791. else
  792. raise EInvocationError.CreateFmt(SErrFailedToConvertArg, [idx, fArgs[idx].ParamType^.Name]);
  793. end;
  794. end;
  795. { ignore stack arguments in first pass }
  796. if (pass = 0) and (fArgInfos[argidx].ArgType = TArgType.Stack) then begin
  797. stackargs[stackcount] := idx;
  798. Inc(stackcount);
  799. Continue;
  800. end;
  801. if fArgInfos[argidx].ArgType = TArgType.GenReg then begin
  802. fArgInfos[argidx].ArgIdx := idx;
  803. fArgInfos[argidx].Offset := genofs;
  804. Inc(genofs);
  805. end else if fArgInfos[argidx].ArgType = TArgType.Stack then begin
  806. fArgInfos[argidx].ArgIdx := idx;
  807. fArgInfos[argidx].Offset := stackofs;
  808. Inc(stackofs, fArgInfos[argidx].Slots);
  809. end;
  810. Inc(argidx);
  811. end;
  812. end;
  813. end;
  814. function TSystemFunctionCallback.GetCodeAddress: CodePointer;
  815. begin
  816. Result := fData;
  817. end;
  818. constructor TSystemFunctionCallback.Create(aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
  819. function CallConvName: String; inline;
  820. begin
  821. WriteStr(Result, aCallConv);
  822. end;
  823. var
  824. i: SizeInt;
  825. begin
  826. if not (aCallConv in [ccReg]) then
  827. raise ENotImplemented.CreateFmt(SErrCallConvNotSupported, [CallConvName]);
  828. fContext := aContext;
  829. SetLength(fArgs, Length(aArgs));
  830. for i := 0 to High(aArgs) do
  831. fArgs[i] := aArgs[i];
  832. fResultType := aResultType;
  833. fFlags := aFlags;
  834. CreateArgInfos;
  835. CreateCallback;
  836. end;
  837. destructor TSystemFunctionCallback.Destroy;
  838. begin
  839. if Assigned(fData) then
  840. FreeMemory(fData, fSize);
  841. end;
  842. constructor TSystemFunctionCallbackProc.Create(aHandler: TFunctionCallProc; aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
  843. begin
  844. inherited Create(aContext, aCallConv, aArgs, aResultType, aFlags);
  845. fHandler := aHandler;
  846. end;
  847. procedure TSystemFunctionCallbackProc.CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer);
  848. begin
  849. fHandler(aArgs, aResult, aContext);
  850. end;
  851. constructor TSystemFunctionCallbackMethod.Create(aHandler: TFunctionCallMethod; aContext: Pointer; aCallConv: TCallConv; constref aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags);
  852. begin
  853. inherited Create(aContext, aCallConv, aArgs, aResultType, aFlags);
  854. fHandler := aHandler;
  855. end;
  856. procedure TSystemFunctionCallbackMethod.CallHandler(constref aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer);
  857. begin
  858. fHandler(aArgs, aResult, aContext);
  859. end;
  860. function SystemCreateCallbackProc(aHandler: TFunctionCallProc; aCallConv: TCallConv; aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags; aContext: Pointer): TFunctionCallCallback;
  861. begin
  862. Result := TSystemFunctionCallbackProc.Create(aHandler, aContext, aCallConv, aArgs, aResultType, aFlags);
  863. end;
  864. function SystemCreateCallbackMethod(aHandler: TFunctionCallMethod; aCallConv: TCallConv; aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags; aContext: Pointer): TFunctionCallCallback;
  865. begin
  866. Result := TSystemFunctionCallbackMethod.Create(aHandler, aContext, aCallConv, aArgs, aResultType, aFlags);
  867. end;
  868. const
  869. SystemFunctionCallManager: TFunctionCallManager = (
  870. Invoke: @SystemInvoke;
  871. CreateCallbackProc: @SystemCreateCallbackProc;
  872. CreateCallbackMethod: @SystemCreateCallbackMethod;
  873. );
  874. procedure InitSystemFunctionCallManager;
  875. begin
  876. SetFunctionCallManager([ccReg{, ccCdecl, ccPascal, ccStdCall}], SystemFunctionCallManager);
  877. end;