n386ic.pas 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Kovacs Attila Zoltan
  4. Generate i386 assembly wrapper code interface implementor objects
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  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. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit n386ic;
  19. interface
  20. uses
  21. aasm,
  22. symbase,symtype,symtable,symdef,symsym;
  23. procedure cgintfwrapper(asmlist: paasmoutput; procdef: pprocdef; const labelname: string; ioffset: longint);
  24. implementation
  25. uses
  26. globtype, systems,
  27. cobjects, verbose, globals,
  28. symconst, types,
  29. {$ifdef GDB}
  30. strings, gdb,
  31. {$endif GDB}
  32. hcodegen, temp_gen,
  33. cpubase, cpuasm,
  34. cgai386, tgeni386;
  35. {
  36. possible calling conventions:
  37. default stdcall cdecl pascal popstack register saveregisters
  38. default(0): OK OK OK(1) OK OK(1) OK OK
  39. virtual(2): OK OK OK(3) OK OK(3) OK OK(4)
  40. (0):
  41. set self parameter to correct value
  42. jmp mangledname
  43. (1): The code is the following
  44. set self parameter to correct value
  45. call mangledname
  46. set self parameter to interface value
  47. (2): The wrapper code use %eax to reach the virtual method address
  48. set self to correct value
  49. move self,%eax
  50. mov 0(%eax),%eax ; load vmt
  51. jmp vmtoffs(%eax) ; method offs
  52. (3): The wrapper code use %eax to reach the virtual method address
  53. set self to correct value
  54. move self,%eax
  55. mov 0(%eax),%eax ; load vmt
  56. jmp vmtoffs(%eax) ; method offs
  57. set self parameter to interface value
  58. (4): Virtual use eax to reach the method address so the following code be generated:
  59. set self to correct value
  60. push %ebx ; allocate space for function address
  61. push %eax
  62. mov self,%eax
  63. mov 0(%eax),%eax ; load vmt
  64. mov vmtoffs(%eax),eax ; method offs
  65. mov %eax,4(%esp)
  66. pop %eax
  67. ret 0; jmp the address
  68. }
  69. function getselfoffsetfromsp(procdef: pprocdef): longint;
  70. begin
  71. if not assigned(procdef^.parast^.symindex^.first) then
  72. getselfoffsetfromsp:=4
  73. else
  74. if psym(procdef^.parast^.symindex^.first)^.typ=varsym then
  75. getselfoffsetfromsp:=pvarsym(procdef^.parast^.symindex^.first)^.address+4
  76. else
  77. Internalerror(2000061310);
  78. end;
  79. procedure cgintfwrapper(asmlist: paasmoutput; procdef: pprocdef; const labelname: string; ioffset: longint);
  80. procedure checkvirtual;
  81. begin
  82. if (procdef^.extnumber=-1) then
  83. Internalerror(200006139);
  84. end;
  85. procedure adjustselfvalue(ioffset: longint);
  86. begin
  87. { sub $ioffset,offset(%esp) }
  88. emit_const_ref(A_SUB,S_L,ioffset,new_reference(R_ESP,getselfoffsetfromsp(procdef)));
  89. end;
  90. procedure getselftoeax(offs: longint);
  91. begin
  92. { mov offset(%esp),%eax }
  93. emit_ref_reg(A_MOV,S_L,new_reference(R_ESP,getselfoffsetfromsp(procdef)),R_EAX);
  94. end;
  95. procedure loadvmttoeax;
  96. begin
  97. checkvirtual;
  98. { mov 0(%eax),%eax ; load vmt}
  99. emit_ref_reg(A_MOV,S_L,new_reference(R_EAX,0),R_EAX);
  100. end;
  101. procedure op_oneaxmethodaddr(op: TAsmOp);
  102. begin
  103. { call/jmp vmtoffs(%eax) ; method offs }
  104. emit_ref(op,S_L,new_reference(R_EAX,procdef^._class^.vmtmethodoffset(procdef^.extnumber)));
  105. end;
  106. procedure loadmethodoffstoeax;
  107. begin
  108. { mov vmtoffs(%eax),%eax ; method offs }
  109. emit_ref_reg(A_MOV,S_L,new_reference(R_EAX,procdef^._class^.vmtmethodoffset(procdef^.extnumber)),R_EAX);
  110. end;
  111. var
  112. oldexprasmlist: paasmoutput;
  113. begin
  114. if procdef^.proctypeoption<>potype_none then
  115. Internalerror(200006137);
  116. if not assigned(procdef^._class) or
  117. (procdef^.procoptions*[po_containsself, po_classmethod, po_staticmethod,
  118. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  119. Internalerror(200006138);
  120. oldexprasmlist:=exprasmlist;
  121. exprasmlist:=asmlist;
  122. exprasmlist^.concat(new(pai_symbol,initname(labelname,0)));
  123. { set param1 interface to self }
  124. adjustselfvalue(ioffset);
  125. { case 1 or 2 }
  126. if (pocall_clearstack in procdef^.proccalloptions) then
  127. begin
  128. if po_virtualmethod in procdef^.procoptions then
  129. begin { case 2 }
  130. getselftoeax(0);
  131. loadvmttoeax;
  132. op_oneaxmethodaddr(A_CALL);
  133. end
  134. else { case 1 }
  135. begin
  136. emitcall(procdef^.mangledname);
  137. end;
  138. { restore param1 value self to interface }
  139. adjustselfvalue(-ioffset);
  140. end
  141. { case 3 }
  142. else if [po_virtualmethod,po_saveregisters]*procdef^.procoptions=[po_virtualmethod,po_saveregisters] then
  143. begin
  144. emit_reg(A_PUSH,S_L,R_EBX); { allocate space for address}
  145. emit_reg(A_PUSH,S_L,R_EAX);
  146. getselftoeax(8);
  147. loadvmttoeax;
  148. loadmethodoffstoeax;
  149. { mov %eax,4(%esp) }
  150. emit_reg_ref(A_MOV,S_L,R_EAX,new_reference(R_ESP,4));
  151. { pop %eax }
  152. emit_reg(A_POP,S_L,R_EAX);
  153. { ret ; jump to the address }
  154. emit_none(A_RET,S_L);
  155. end
  156. { case 4 }
  157. else if po_virtualmethod in procdef^.procoptions then
  158. begin
  159. getselftoeax(0);
  160. loadvmttoeax;
  161. op_oneaxmethodaddr(A_JMP);
  162. end
  163. { case 0 }
  164. else
  165. begin
  166. emitcall(procdef^.mangledname);
  167. end;
  168. exprasmlist:=oldexprasmlist;
  169. end;
  170. end.
  171. {
  172. $Log$
  173. Revision 1.1 2000-11-04 14:25:23 florian
  174. + merged Attila's changes for interfaces, not tested yet
  175. Revision 1.1.2.2 2000/06/15 15:05:30 kaz
  176. * An minor bug fix
  177. Revision 1.1.2.1 2000/06/15 06:26:34 kaz
  178. * Initial version
  179. }