objcutil.pas 11 KB

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