objcutil.pas 11 KB

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