objcutil.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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: tprocdef): 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) }
  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}
  122. result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(tclassrefdef(def).pointeddef).childof.childof));
  123. result:=objcloadbasefield(result,'ISA');
  124. typecheckpass(result);
  125. { we're done }
  126. exit;
  127. end
  128. else
  129. begin
  130. { otherwise we need the superclass of the metaclass }
  131. para:=ccallparanode.create(cstringconstnode.createstr(tobjectdef(tclassrefdef(def).pointeddef).objextname^),nil);
  132. result:=ccallnode.createinternfromunit('OBJC','OBJC_GETMETACLASS',para);
  133. end
  134. end
  135. else
  136. begin
  137. if not(oo_is_classhelper in tobjectdef(def).objectoptions) then
  138. result:=cloadvmtaddrnode.create(ctypenode.create(def))
  139. else
  140. result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(def).childof))
  141. end;
  142. {$if defined(onlymacosx10_6) or defined(arm) }
  143. { For the non-fragile ABI, the superclass send2 method itself loads the
  144. superclass. For the fragile ABI, we have to do this ourselves.
  145. NOTE: those send2 methods are only available on Mac OS X 10.6 and later!
  146. (but also on all iPhone SDK revisions we support) }
  147. if not(target_info.system in systems_objc_nfabi) then
  148. {$endif onlymacosx10_6 or arm}
  149. result:=objcloadbasefield(result,'SUPERCLASS');
  150. typecheckpass(result);
  151. end;
  152. {******************************************************************
  153. Type encoding
  154. *******************************************************************}
  155. function objcparasize(vs: tparavarsym): ptrint;
  156. begin
  157. result:=vs.paraloc[callerside].intsize;
  158. { In Objective-C, all ordinal types are widened to at least the
  159. size of the C "int" type. Assume __LP64__/4 byte ints for now. }
  160. if is_ordinal(vs.vardef) and
  161. (result<4) then
  162. result:=4;
  163. end;
  164. function objcencodemethod(pd: tprocdef): ansistring;
  165. var
  166. parasize,
  167. totalsize: aint;
  168. vs: tparavarsym;
  169. i: longint;
  170. temp: ansistring;
  171. founderror: tdef;
  172. begin
  173. result:='';
  174. totalsize:=0;
  175. pd.init_paraloc_info(callerside);
  176. {$if defined(powerpc) and defined(dummy)}
  177. { Disabled, because neither Clang nor gcc does this, and the ObjC
  178. runtime contains an explicit fix to detect this error. }
  179. { On ppc, the callee is responsible for removing the hidden function
  180. result parameter from the stack, so it has to know. On i386, it's
  181. the caller that does this. }
  182. if (pd.returndef<>voidtype) and
  183. paramgr.ret_in_param(pd.returndef,pocall_cdecl) then
  184. inc(totalsize,sizeof(pint));
  185. {$endif}
  186. for i:=0 to pd.paras.count-1 do
  187. begin
  188. vs:=tparavarsym(pd.paras[i]);
  189. if (vo_is_funcret in vs.varoptions) then
  190. continue;
  191. { objcaddencodedtype always assumes a value parameter, so add
  192. a pointer indirection for var/out parameters. }
  193. if not paramanager.push_addr_param(vs_value,vs.vardef,pocall_cdecl) and
  194. (vs.varspez in [vs_var,vs_out,vs_constref]) then
  195. result:=result+'^';
  196. { Add the parameter type. }
  197. if not objcaddencodedtype(vs.vardef,ris_initial,false,result,founderror) then
  198. { should be checked earlier on }
  199. internalerror(2009081701);
  200. { And the total size of the parameters coming before this one
  201. (i.e., the "offset" of this parameter). }
  202. result:=result+tostr(totalsize);
  203. { Update the total parameter size }
  204. parasize:=objcparasize(vs);
  205. inc(totalsize,parasize);
  206. end;
  207. { Prepend the total parameter size. }
  208. result:=tostr(totalsize)+result;
  209. { And the type of the function result (void in case of a procedure). }
  210. temp:='';
  211. if not objcaddencodedtype(pd.returndef,ris_initial,false,temp,founderror) then
  212. internalerror(2009081801);
  213. result:=temp+result;
  214. end;
  215. {******************************************************************
  216. ObjC class exporting
  217. *******************************************************************}
  218. procedure exportobjcclassfields(objccls: tobjectdef);
  219. var
  220. i: longint;
  221. vf: tfieldvarsym;
  222. prefix: string;
  223. begin
  224. prefix:=target_info.cprefix+'OBJC_IVAR_$_'+objccls.objextname^+'.';
  225. for i:=0 to objccls.symtable.SymList.Count-1 do
  226. if tsym(objccls.symtable.SymList[i]).typ=fieldvarsym then
  227. begin
  228. vf:=tfieldvarsym(objccls.symtable.SymList[i]);
  229. { TODO: package visibility (private_extern) -- must not be exported
  230. either}
  231. if not(vf.visibility in [vis_private,vis_strictprivate]) then
  232. exportname(prefix+vf.RealName,0);
  233. end;
  234. end;
  235. procedure exportobjcclass(def: tobjectdef);
  236. begin
  237. if (target_info.system in systems_objc_nfabi) then
  238. begin
  239. { export class and metaclass symbols }
  240. exportname(def.rtti_mangledname(objcclassrtti),0);
  241. exportname(def.rtti_mangledname(objcmetartti),0);
  242. { export public/protected instance variable offset symbols }
  243. exportobjcclassfields(def);
  244. end
  245. else
  246. begin
  247. { export the class symbol }
  248. exportname('.objc_class_name_'+def.objextname^,0);
  249. end;
  250. end;
  251. end.