fpc/compiler/objcutil.pas
Jonas Maebe 73cae02c20 --- Merging r29821 into '.':
U    compiler/cgobj.pas
--- Recording mergeinfo for merge of r29821 into '.':
 U   .
--- Merging r30947 into '.':
C    compiler/nmem.pas
U    compiler/jvm/njvmmem.pas
C    compiler/objcutil.pas
--- Recording mergeinfo for merge of r30947 into '.':
 G   .
--- Merging r31202 into '.':
U    compiler/utils/gppc386.pp
--- Recording mergeinfo for merge of r31202 into '.':
 G   .
--- Merging r31245 into '.':
U    compiler/symtype.pas
U    compiler/symdef.pas
--- Recording mergeinfo for merge of r31245 into '.':
 G   .
--- Merging r31289 into '.':
U    rtl/inc/aliases.inc
--- Recording mergeinfo for merge of r31289 into '.':
 G   .
--- Merging r31447 into '.':
U    compiler/aasmtai.pas
--- Recording mergeinfo for merge of r31447 into '.':
 G   .
--- Merging r31457 into '.':
C    compiler/msgtxt.inc
U    compiler/msg/errore.msg
C    compiler/msgidx.inc
--- Recording mergeinfo for merge of r31457 into '.':
 G   .
--- Merging r31909 into '.':
U    utils/rstconv.pp
--- Recording mergeinfo for merge of r31909 into '.':
 G   .
--- Merging r32087 into '.':
U    tests/webtbs/tw22376.pp
--- Recording mergeinfo for merge of r32087 into '.':
 G   .
--- Merging r32412 into '.':
G    compiler/symtype.pas
G    compiler/symdef.pas
--- Recording mergeinfo for merge of r32412 into '.':
 G   .
--- Merging r32516 into '.':
U    compiler/ncgmem.pas
A    tests/webtbs/tw29064.pp
--- Recording mergeinfo for merge of r32516 into '.':
 G   .
--- Merging r32548 into '.':
U    tests/Makefile
A    tests/createlst.mak
U    tests/utils/gparmake.pp
U    tests/Makefile.fpc
--- Recording mergeinfo for merge of r32548 into '.':
 G   .
--- Merging r32593 into '.':
U    compiler/pparautl.pas
--- Recording mergeinfo for merge of r32593 into '.':
 G   .
--- Merging r32617 into '.':
U    compiler/symsym.pas
C    compiler/ppu.pas
U    compiler/utils/ppuutils/ppudump.pp
A    tests/webtbs/uw28964.pp
A    tests/webtbs/tw28964.pp
--- Recording mergeinfo for merge of r32617 into '.':
 G   .
--- Merging r32619 into '.':
U    compiler/nmat.pas
A    tests/webtbs/tw28702.pp
--- Recording mergeinfo for merge of r32619 into '.':
 G   .
--- Merging r32627 into '.':
U    rtl/inc/ustrings.inc
--- Recording mergeinfo for merge of r32627 into '.':
 G   .
--- Merging r32632 into '.':
G    compiler/symsym.pas
--- Recording mergeinfo for merge of r32632 into '.':
 G   .
--- Merging r32633 into '.':
G    compiler/cgobj.pas
--- Recording mergeinfo for merge of r32633 into '.':
 G   .
--- Merging r32634 into '.':
U    compiler/powerpc/cpupara.pas
--- Recording mergeinfo for merge of r32634 into '.':
 G   .
--- Merging r32636 into '.':
A    tests/webtbs/tw29153.pp
U    compiler/ngtcon.pas
--- Recording mergeinfo for merge of r32636 into '.':
 G   .
--- Merging r32745 into '.':
G    compiler/pparautl.pas
U    compiler/ncal.pas
--- Recording mergeinfo for merge of r32745 into '.':
 G   .
--- Merging r32781 into '.':
G    compiler/symdef.pas
--- Recording mergeinfo for merge of r32781 into '.':
 G   .
--- Merging r33004 into '.':
U    packages/rtl-extra/src/unix/ipc.pp
--- Recording mergeinfo for merge of r33004 into '.':
 G   .
--- Merging r33112 into '.':
G    compiler/nmem.pas
--- Recording mergeinfo for merge of r33112 into '.':
 G   .
--- Merging r33157 into '.':
U    rtl/java/justrings.inc
--- Recording mergeinfo for merge of r33157 into '.':
 G   .
--- Merging r33161 into '.':
G    rtl/java/justrings.inc
--- Recording mergeinfo for merge of r33161 into '.':
 G   .
--- Merging r33167 into '.':
U    packages/numlib/tests/invgente.pas
U    packages/numlib/tests/sleglste.pas
U    packages/numlib/tests/eiggg1te.pas
U    packages/numlib/tests/roof1rte.pas
U    packages/numlib/tests/roopolte.pas
U    packages/numlib/tests/eigbs3te.pas
U    packages/numlib/tests/slegente.pas
U    packages/numlib/tests/eiggs3te.pas
U    packages/numlib/tests/spege1te.pas
U    packages/numlib/tests/invgpdte.pas
U    packages/numlib/tests/spemaxte.pas
U    packages/numlib/tests/eigts3te.pas
U    packages/numlib/tests/detgsyte.pas
U    packages/numlib/tests/slegbalt.pas
U    packages/numlib/tests/detgpbte.pas
U    packages/numlib/tests/slegsylt.pas
U    packages/numlib/tests/slegpdte.pas
U    packages/numlib/tests/slegpblt.pas
U    packages/numlib/tests/odeiv2te.pas
U    packages/numlib/tests/intge3te.pas
U    packages/numlib/tests/sledtrte.pas
U    packages/numlib/tests/eigsv1te.pas
U    packages/numlib/tests/slegtrte.pas
U    packages/numlib/tests/eigge1te.pas
U    packages/numlib/tests/eiggg4te.pas
U    packages/numlib/tests/eigbs2te.pas
U    packages/numlib/tests/eiggs2te.pas
U    packages/numlib/tests/timer.pas
U    packages/numlib/tests/eigts2te.pas
U    packages/numlib/tests/spepolte.pas
U    packages/numlib/tests/roofnrt1.pas
U    packages/numlib/tests/test.pas
U    packages/numlib/tests/odeiv1te.pas
U    packages/numlib/tests/intge2te.pas
U    packages/numlib/tests/speentte.pas
U    packages/numlib/tests/sleglslt.pas
U    packages/numlib/tests/eiggg3te.pas
U    packages/numlib/tests/eigbs1te.pas
U    packages/numlib/tests/turte.pas
U    packages/numlib/tests/invgsyte.pas
U    packages/numlib/tests/eiggs1te.pas
U    packages/numlib/tests/slegenlt.pas
U    packages/numlib/tests/eigts1te.pas
U    packages/numlib/tests/slegbate.pas
U    packages/numlib/tests/roofnrte.pas
U    packages/numlib/tests/slegsyte.pas
U    packages/numlib/tests/detgpdte.pas
U    packages/numlib/tests/slegpbte.pas
U    packages/numlib/tests/spepowte.pas
U    packages/numlib/tests/slegpdlt.pas
U    packages/numlib/tests/intge1te.pas
U    packages/numlib/tests/detgtrte.pas
U    packages/numlib/tests/eigsv3te.pas
U    packages/numlib/tests/eigge3te.pas
U    packages/numlib/tests/eiggg2te.pas
U    packages/numlib/tests/iomwrmte.pas
U    packages/numlib/tests/eigbs4te.pas
U    packages/numlib/tests/eiggs4te.pas
U    packages/numlib/tests/spesgnte.pas
U    packages/numlib/tests/eigts4te.pas
--- Recording mergeinfo for merge of r33167 into '.':
 G   .
--- Merging r33191 into '.':
U    compiler/cutils.pas
A    tests/webtbs/tw29620.pp
--- Recording mergeinfo for merge of r33191 into '.':
 G   .
--- Merging r33193 into '.':
U    compiler/symtable.pas
--- Recording mergeinfo for merge of r33193 into '.':
 G   .
--- Merging r33202 into '.':
U    compiler/options.pas
--- Recording mergeinfo for merge of r33202 into '.':
 G   .
--- Merging r33203 into '.':
U    rtl/inc/flt_core.inc
--- Recording mergeinfo for merge of r33203 into '.':
 G   .
--- Merging r33268 into '.':
U    compiler/pinline.pas
A    tests/test/tw29833.pp
--- Recording mergeinfo for merge of r33268 into '.':
 G   .
--- Merging r33270 into '.':
U    tests/test/units/sysutils/tfexpand2.pp
U    tests/test/units/system/tdir2.pp
--- Recording mergeinfo for merge of r33270 into '.':
 G   .
--- Merging r33271 into '.':
U    rtl/objpas/sysutils/sysuni.inc
A    tests/test/units/sysutils/twstralloc.pp
--- Recording mergeinfo for merge of r33271 into '.':
 G   .
--- Merging r33382 into '.':
A    tests/webtbs/tw29923.pp
G    compiler/cgobj.pas
--- Recording mergeinfo for merge of r33382 into '.':
 G   .
--- Merging r33413 into '.':
C    compiler/ncnv.pas
A    tests/webtbs/tw29930.pp
--- Recording mergeinfo for merge of r33413 into '.':
 G   .
--- Merging r33480 into '.':
U    compiler/pdecsub.pas
A    tests/webtbs/tw29992.pp
--- Recording mergeinfo for merge of r33480 into '.':
 G   .
--- Merging r33536 into '.':
U    compiler/systems.pas
--- Recording mergeinfo for merge of r33536 into '.':
 G   .
--- Merging r33539 into '.':
U    compiler/powerpc/nppcadd.pas
A    tests/webtbs/tw30035a.pp
A    tests/webtbs/tw30035.pp
--- Recording mergeinfo for merge of r33539 into '.':
 G   .
--- Merging r33567 into '.':
U    rtl/jvm/jvm.inc
--- Recording mergeinfo for merge of r33567 into '.':
 G   .

git-svn-id: branches/fixes_3_0@33584 -
2016-04-30 21:02:02 +00:00

309 lines
11 KiB
ObjectPascal

{
Copyright (c) 2009-2010 by Jonas Maebe
This unit implements some Objective-C helper routines at the node tree
level.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
{$i fpcdefs.inc}
unit objcutil;
interface
uses
node,
symtype,symdef;
{ Check whether a string contains a syntactically valid selector name. }
function objcvalidselectorname(value_str: pchar; len: longint): boolean;
{ Generate a node loading the superclass structure necessary to call
an inherited Objective-C method. }
function objcsuperclassnode(def: tdef): tnode;
{ Encode a method's parameters and result type into the format used by the
run time (for generating protocol and class rtti). }
function objcencodemethod(pd: tprocdef): ansistring;
{ Exports all assembler symbols related to the obj-c class }
procedure exportobjcclass(def: tobjectdef);
{ loads a field of an Objective-C root class (such as ISA) }
function objcloadbasefield(n: tnode; const fieldname: string): tnode;
implementation
uses
globtype,
cutils,cclasses,
pass_1,
verbose,systems,
symtable,symconst,symsym,
objcdef,
defutil,paramgr,
nbas,nmem,ncal,nld,ncon,ncnv,
export;
{******************************************************************
validselectorname
*******************************************************************}
function objcvalidselectorname(value_str: pchar; len: longint): boolean;
var
i : longint;
gotcolon : boolean;
begin
result:=false;
{ empty name is not allowed }
if (len=0) then
exit;
gotcolon:=false;
{ if the first character is a colon, all of them must be colons }
if (value_str[0] = ':') then
begin
for i:=1 to len-1 do
if (value_str[i]<>':') then
exit;
end
else
begin
{ no special characters other than ':'
}
for i:=0 to len-1 do
if (value_str[i] = ':') then
gotcolon:=true
else if not(value_str[i] in ['_','A'..'Z','a'..'z','0'..'9',':']) then
exit;
{ if there is at least one colon, the final character must
also be a colon (in case it's only one character that is
a colon, this was already checked before the above loop)
}
if gotcolon and
(value_str[len-1] <> ':') then
exit;
end;
result:=true;
end;
{******************************************************************
objcsuperclassnode
*******************************************************************}
function objcloadbasefield(n: tnode; const fieldname: string): tnode;
var
vs : tsym;
begin
vs:=tsym(tabstractrecorddef(objc_objecttype).symtable.Find(fieldname));
if not assigned(vs) or
(vs.typ<>fieldvarsym) then
internalerror(200911301);
if fieldname='ISA' then
result:=ctypeconvnode.create_internal(
cderefnode.create(
ctypeconvnode.create_internal(n,
getpointerdef(getpointerdef(voidpointertype))
)
),tfieldvarsym(vs).vardef
)
else
begin
result:=cderefnode.create(ctypeconvnode.create_internal(n,objc_idtype));
result:=csubscriptnode.create(vs,result);
end;
end;
function objcsuperclassnode(def: tdef): tnode;
var
para : tcallparanode;
begin
{ only valid for Objective-C classes and classrefs }
if not is_objcclass(def) and
not is_objcclassref(def) then
internalerror(2009090901);
{ Can be done a lot more efficiently with direct symbol accesses, but
requires extra node types. Maybe later. }
if is_objcclassref(def) then
begin
if (oo_is_classhelper in tobjectdef(tclassrefdef(def).pointeddef).objectoptions) then
begin
{ in case we are in a category method, we need the metaclass of the
superclass class extended by this category (= metaclass of superclass of superclass)
for the fragile abi, and the metaclass of the superclass for the non-fragile ABI }
{$if defined(onlymacosx10_6) or defined(arm) }
{ NOTE: those send2 methods are only available on Mac OS X 10.6 and later!
(but also on all iPhone SDK revisions we support) }
if (target_info.system in systems_objc_nfabi) then
result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(tclassrefdef(def).pointeddef).childof))
else
{$endif onlymacosx10_6 or arm}
result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(tclassrefdef(def).pointeddef).childof.childof));
tloadvmtaddrnode(result).forcall:=true;
result:=cloadvmtaddrnode.create(result);
typecheckpass(result);
{ we're done }
exit;
end
else
begin
{ otherwise we need the superclass of the metaclass }
para:=ccallparanode.create(cstringconstnode.createstr(tobjectdef(tclassrefdef(def).pointeddef).objextname^),nil);
result:=ccallnode.createinternfromunit('OBJC','OBJC_GETMETACLASS',para);
end
end
else
begin
if not(oo_is_classhelper in tobjectdef(def).objectoptions) then
result:=cloadvmtaddrnode.create(ctypenode.create(def))
else
result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(def).childof));
tloadvmtaddrnode(result).forcall:=true;
end;
{$if defined(onlymacosx10_6) or defined(arm) }
{ For the non-fragile ABI, the superclass send2 method itself loads the
superclass. For the fragile ABI, we have to do this ourselves.
NOTE: those send2 methods are only available on Mac OS X 10.6 and later!
(but also on all iPhone SDK revisions we support) }
if not(target_info.system in systems_objc_nfabi) then
{$endif onlymacosx10_6 or arm}
result:=objcloadbasefield(result,'SUPERCLASS');
typecheckpass(result);
end;
{******************************************************************
Type encoding
*******************************************************************}
function objcparasize(vs: tparavarsym): ptrint;
begin
result:=vs.paraloc[callerside].intsize;
{ In Objective-C, all ordinal types are widened to at least the
size of the C "int" type. Assume __LP64__/4 byte ints for now. }
if is_ordinal(vs.vardef) and
(result<4) then
result:=4;
end;
function objcencodemethod(pd: tprocdef): ansistring;
var
parasize,
totalsize: aint;
vs: tparavarsym;
i: longint;
temp: ansistring;
founderror: tdef;
begin
result:='';
totalsize:=0;
pd.init_paraloc_info(callerside);
{$if defined(powerpc) and defined(dummy)}
{ Disabled, because neither Clang nor gcc does this, and the ObjC
runtime contains an explicit fix to detect this error. }
{ On ppc, the callee is responsible for removing the hidden function
result parameter from the stack, so it has to know. On i386, it's
the caller that does this. }
if (pd.returndef<>voidtype) and
paramgr.ret_in_param(pd.returndef,pocall_cdecl) then
inc(totalsize,sizeof(pint));
{$endif}
for i:=0 to pd.paras.count-1 do
begin
vs:=tparavarsym(pd.paras[i]);
if (vo_is_funcret in vs.varoptions) then
continue;
{ objcaddencodedtype always assumes a value parameter, so add
a pointer indirection for var/out parameters. }
if not paramanager.push_addr_param(vs_value,vs.vardef,pocall_cdecl) and
(vs.varspez in [vs_var,vs_out,vs_constref]) then
result:=result+'^';
{ Add the parameter type. }
if not objcaddencodedtype(vs.vardef,ris_initial,false,result,founderror) then
{ should be checked earlier on }
internalerror(2009081701);
{ And the total size of the parameters coming before this one
(i.e., the "offset" of this parameter). }
result:=result+tostr(totalsize);
{ Update the total parameter size }
parasize:=objcparasize(vs);
inc(totalsize,parasize);
end;
{ Prepend the total parameter size. }
result:=tostr(totalsize)+result;
{ And the type of the function result (void in case of a procedure). }
temp:='';
if not objcaddencodedtype(pd.returndef,ris_initial,false,temp,founderror) then
internalerror(2009081801);
result:=temp+result;
end;
{******************************************************************
ObjC class exporting
*******************************************************************}
procedure exportobjcclassfields(objccls: tobjectdef);
var
i: longint;
vf: tfieldvarsym;
prefix: string;
begin
prefix:=target_info.cprefix+'OBJC_IVAR_$_'+objccls.objextname^+'.';
for i:=0 to objccls.symtable.SymList.Count-1 do
if tsym(objccls.symtable.SymList[i]).typ=fieldvarsym then
begin
vf:=tfieldvarsym(objccls.symtable.SymList[i]);
{ TODO: package visibility (private_extern) -- must not be exported
either}
if not(vf.visibility in [vis_private,vis_strictprivate]) then
exportname(prefix+vf.RealName,0);
end;
end;
procedure exportobjcclass(def: tobjectdef);
begin
if (target_info.system in systems_objc_nfabi) then
begin
{ export class and metaclass symbols }
exportname(def.rtti_mangledname(objcclassrtti),0);
exportname(def.rtti_mangledname(objcmetartti),0);
{ export public/protected instance variable offset symbols }
exportobjcclassfields(def);
end
else
begin
{ export the class symbol }
exportname('.objc_class_name_'+def.objextname^,0);
end;
end;
end.