objcutil.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. {
  2. Copyright (c) 2009-2010 by Jonas Maebe
  3. This unit implements some Objective-C helper routines at the node tree
  4. level.
  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. {$i fpcdefs.inc}
  19. unit objcutil;
  20. interface
  21. uses
  22. node,
  23. symtype,symdef;
  24. { Check whether a string contains a syntactically valid selector name. }
  25. function objcvalidselectorname(value_str: pchar; len: longint): boolean;
  26. { Generate a node loading the superclass structure necessary to call
  27. an inherited Objective-C method. }
  28. function objcsuperclassnode(def: tdef): tnode;
  29. { Encode a method's parameters and result type into the format used by the
  30. run time (for generating protocol and class rtti). }
  31. function objcencodemethod(pd: tabstractprocdef): ansistring;
  32. { Exports all assembler symbols related to the obj-c class }
  33. procedure exportobjcclass(def: tobjectdef);
  34. implementation
  35. uses
  36. globtype,
  37. cutils,cclasses,
  38. pass_1,
  39. verbose,systems,
  40. symtable,symconst,symsym,
  41. objcdef,
  42. defutil,paramgr,
  43. nbas,nmem,ncal,nld,ncon,ncnv,
  44. export;
  45. {******************************************************************
  46. validselectorname
  47. *******************************************************************}
  48. function objcvalidselectorname(value_str: pchar; len: longint): boolean;
  49. var
  50. i : longint;
  51. gotcolon : boolean;
  52. begin
  53. result:=false;
  54. { empty name is not allowed }
  55. if (len=0) then
  56. exit;
  57. gotcolon:=false;
  58. { if the first character is a colon, all of them must be colons }
  59. if (value_str[0] = ':') then
  60. begin
  61. for i:=1 to len-1 do
  62. if (value_str[i]<>':') then
  63. exit;
  64. end
  65. else
  66. begin
  67. { no special characters other than ':'
  68. }
  69. for i:=0 to len-1 do
  70. if (value_str[i] = ':') then
  71. gotcolon:=true
  72. else if not(value_str[i] in ['_','A'..'Z','a'..'z','0'..'9',':']) then
  73. exit;
  74. { if there is at least one colon, the final character must
  75. also be a colon (in case it's only one character that is
  76. a colon, this was already checked before the above loop)
  77. }
  78. if gotcolon and
  79. (value_str[len-1] <> ':') then
  80. exit;
  81. end;
  82. result:=true;
  83. end;
  84. {******************************************************************
  85. objcsuperclassnode
  86. *******************************************************************}
  87. function objcloadbasefield(n: tnode; const fieldname: string): tnode;
  88. var
  89. vs : tsym;
  90. begin
  91. result:=cderefnode.create(ctypeconvnode.create_internal(n,objc_idtype));
  92. vs:=tsym(tabstractrecorddef(objc_objecttype).symtable.Find(fieldname));
  93. if not assigned(vs) or
  94. (vs.typ<>fieldvarsym) then
  95. internalerror(200911301);
  96. result:=csubscriptnode.create(vs,result);
  97. end;
  98. function objcsuperclassnode(def: tdef): tnode;
  99. var
  100. para : tcallparanode;
  101. begin
  102. { only valid for Objective-C classes and classrefs }
  103. if not is_objcclass(def) and
  104. not is_objcclassref(def) then
  105. internalerror(2009090901);
  106. { Can be done a lot more efficiently with direct symbol accesses, but
  107. requires extra node types. Maybe later. }
  108. if is_objcclassref(def) then
  109. begin
  110. if (oo_is_classhelper in tobjectdef(tclassrefdef(def).pointeddef).objectoptions) then
  111. begin
  112. { in case we are in a category method, we need the metaclass of the
  113. superclass class extended by this category (= metaclass of superclass of superclass)
  114. for the fragile abi, and the metaclass of the superclass for the non-fragile ABI }
  115. {$if defined(onlymacosx10_6) or defined(arm) or defined(aarch64)}
  116. { NOTE: those send2 methods are only available on Mac OS X 10.6 and later!
  117. (but also on all iPhone SDK revisions we support) }
  118. if (target_info.system in systems_objc_nfabi) then
  119. result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(tclassrefdef(def).pointeddef).childof))
  120. else
  121. {$endif onlymacosx10_6 or arm aarch64}
  122. result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(tclassrefdef(def).pointeddef).childof.childof));
  123. tloadvmtaddrnode(result).forcall:=true;
  124. if target_info.system<>system_aarch64_darwin then
  125. result:=objcloadbasefield(result,'ISA')
  126. else
  127. result:=cloadvmtaddrnode.create(result);
  128. typecheckpass(result);
  129. { we're done }
  130. exit;
  131. end
  132. else
  133. begin
  134. { otherwise we need the superclass of the metaclass }
  135. para:=ccallparanode.create(cstringconstnode.createstr(tobjectdef(tclassrefdef(def).pointeddef).objextname^),nil);
  136. result:=ccallnode.createinternfromunit('OBJC','OBJC_GETMETACLASS',para);
  137. end
  138. end
  139. else
  140. begin
  141. if not(oo_is_classhelper in tobjectdef(def).objectoptions) then
  142. result:=cloadvmtaddrnode.create(ctypenode.create(def))
  143. else
  144. result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(def).childof));
  145. tloadvmtaddrnode(result).forcall:=true;
  146. end;
  147. {$if defined(onlymacosx10_6) or defined(arm) or defined(aarch64)}
  148. { For the non-fragile ABI, the superclass send2 method itself loads the
  149. superclass. For the fragile ABI, we have to do this ourselves.
  150. NOTE: those send2 methods are only available on Mac OS X 10.6 and later!
  151. (but also on all iPhone SDK revisions we support) }
  152. if not(target_info.system in systems_objc_nfabi) then
  153. {$endif onlymacosx10_6 or arm or aarch64}
  154. result:=objcloadbasefield(result,'SUPERCLASS');
  155. typecheckpass(result);
  156. end;
  157. {******************************************************************
  158. Type encoding
  159. *******************************************************************}
  160. function objcparasize(vs: tparavarsym): ptrint;
  161. begin
  162. result:=vs.paraloc[callerside].intsize;
  163. { In Objective-C, all ordinal types are widened to at least the
  164. size of the C "int" type. Assume __LP64__/4 byte ints for now. }
  165. if is_ordinal(vs.vardef) and
  166. (result<4) then
  167. result:=4;
  168. end;
  169. function objcencodemethod(pd: tabstractprocdef): ansistring;
  170. var
  171. parasize,
  172. totalsize: aint;
  173. vs: tparavarsym;
  174. i: longint;
  175. temp: ansistring;
  176. founderror: tdef;
  177. begin
  178. result:='';
  179. totalsize:=0;
  180. pd.init_paraloc_info(callerside);
  181. {$if defined(powerpc) and defined(dummy)}
  182. { Disabled, because neither Clang nor gcc does this, and the ObjC
  183. runtime contains an explicit fix to detect this error. }
  184. { On ppc, the callee is responsible for removing the hidden function
  185. result parameter from the stack, so it has to know. On i386, it's
  186. the caller that does this. }
  187. if (pd.returndef<>voidtype) and
  188. paramgr.ret_in_param(pd.returndef,pocall_cdecl) then
  189. inc(totalsize,sizeof(pint));
  190. {$endif}
  191. for i:=0 to pd.paras.count-1 do
  192. begin
  193. vs:=tparavarsym(pd.paras[i]);
  194. if (vo_is_funcret in vs.varoptions) then
  195. continue;
  196. { objcaddencodedtype always assumes a value parameter, so add
  197. a pointer indirection for var/out parameters. }
  198. if not paramanager.push_addr_param(vs_value,vs.vardef,pocall_cdecl) and
  199. (vs.varspez in [vs_var,vs_out,vs_constref]) then
  200. result:=result+'^';
  201. { Add the parameter type. }
  202. if (vo_is_parentfp in vs.varoptions) and
  203. (po_is_block in pd.procoptions) then
  204. { special case: self parameter of block procvars has to be @? }
  205. result:=result+'@?'
  206. else if not objcaddencodedtype(vs.vardef,ris_initial,false,result,founderror) then
  207. { should be checked earlier on }
  208. internalerror(2009081701);
  209. { And the total size of the parameters coming before this one
  210. (i.e., the "offset" of this parameter). }
  211. result:=result+tostr(totalsize);
  212. { Update the total parameter size }
  213. parasize:=objcparasize(vs);
  214. inc(totalsize,parasize);
  215. end;
  216. { Prepend the total parameter size. }
  217. result:=tostr(totalsize)+result;
  218. { And the type of the function result (void in case of a procedure). }
  219. temp:='';
  220. if not objcaddencodedtype(pd.returndef,ris_initial,false,temp,founderror) then
  221. internalerror(2009081801);
  222. result:=temp+result;
  223. end;
  224. {******************************************************************
  225. ObjC class exporting
  226. *******************************************************************}
  227. procedure exportobjcclassfields(objccls: tobjectdef);
  228. var
  229. i: longint;
  230. vf: tfieldvarsym;
  231. prefix: string;
  232. begin
  233. prefix:=target_info.cprefix+'OBJC_IVAR_$_'+objccls.objextname^+'.';
  234. for i:=0 to objccls.symtable.SymList.Count-1 do
  235. if tsym(objccls.symtable.SymList[i]).typ=fieldvarsym then
  236. begin
  237. vf:=tfieldvarsym(objccls.symtable.SymList[i]);
  238. { TODO: package visibility (private_extern) -- must not be exported
  239. either}
  240. if not(vf.visibility in [vis_private,vis_strictprivate]) then
  241. exportname(prefix+vf.RealName,0);
  242. end;
  243. end;
  244. procedure exportobjcclass(def: tobjectdef);
  245. begin
  246. if (target_info.system in systems_objc_nfabi) then
  247. begin
  248. { export class and metaclass symbols }
  249. exportname(def.rtti_mangledname(objcclassrtti),0);
  250. exportname(def.rtti_mangledname(objcmetartti),0);
  251. { export public/protected instance variable offset symbols }
  252. exportobjcclassfields(def);
  253. end
  254. else
  255. begin
  256. { export the class symbol }
  257. exportname('.objc_class_name_'+def.objextname^,0);
  258. end;
  259. end;
  260. end.