compiler: translate_disp_call:

- fix arguments description if the first argument is empty
  - fix restype field value (describes result value type in variant types)

git-svn-id: trunk@14790 -
This commit is contained in:
paul 2010-01-24 12:06:52 +00:00
parent c6ffbe9eda
commit ba3744b38e
3 changed files with 57 additions and 33 deletions

View File

@ -201,7 +201,7 @@ interface
tcallparanodeclass = class of tcallparanode; tcallparanodeclass = class of tcallparanode;
function reverseparameters(p: tcallparanode): tcallparanode; function reverseparameters(p: tcallparanode): tcallparanode;
function translate_disp_call(selfnode,parametersnode,putvalue : tnode;methodname : ansistring = '';dispid : longint = 0;useresult : boolean = false) : tnode; function translate_disp_call(selfnode,parametersnode,putvalue : tnode;methodname : ansistring;dispid : longint;resultdef : tdef) : tnode;
var var
ccallnode : tcallnodeclass; ccallnode : tcallnodeclass;
@ -255,7 +255,7 @@ implementation
end; end;
function translate_disp_call(selfnode,parametersnode,putvalue : tnode;methodname : ansistring = '';dispid : longint = 0;useresult : boolean = false) : tnode; function translate_disp_call(selfnode,parametersnode,putvalue : tnode;methodname : ansistring;dispid : longint;resultdef : tdef) : tnode;
const const
DISPATCH_METHOD = $1; DISPATCH_METHOD = $1;
DISPATCH_PROPERTYGET = $2; DISPATCH_PROPERTYGET = $2;
@ -277,6 +277,8 @@ implementation
vardatadef, vardatadef,
pvardatadef : tdef; pvardatadef : tdef;
dispatchbyref : boolean; dispatchbyref : boolean;
useresult: boolean;
restype: byte;
calldesc : packed record calldesc : packed record
calltype,argcount,namedargcount : byte; calltype,argcount,namedargcount : byte;
@ -306,6 +308,23 @@ implementation
} }
end; end;
function getvardef(sourcedef: TDef): longint;
begin
if is_ansistring(sourcedef) then
result:=varStrArg
else
if is_interface(sourcedef) then
begin
{ distinct IDispatch and IUnknown interfaces }
if tobjectdef(sourcedef).is_related(tobjectdef(search_system_type('IDISPATCH').typedef)) then
result:=vardispatch
else
result:=varunknown;
end
else
result:=sourcedef.getvardef;
end;
begin begin
variantdispatch:=selfnode.resultdef.typ=variantdef; variantdispatch:=selfnode.resultdef.typ=variantdef;
dispintfinvoke:=not(variantdispatch); dispintfinvoke:=not(variantdispatch);
@ -313,6 +332,7 @@ implementation
result:=internalstatements(statements); result:=internalstatements(statements);
fillchar(calldesc,sizeof(calldesc),0); fillchar(calldesc,sizeof(calldesc),0);
useresult := assigned(resultdef) and not is_void(resultdef);
if useresult then if useresult then
begin begin
{ get temp for the result } { get temp for the result }
@ -329,9 +349,12 @@ implementation
begin begin
typecheckpass(para.left); typecheckpass(para.left);
{ if it is not a parameter then break the loop } { skip non parameters }
if para.left.nodetype=nothingn then if para.left.nodetype=nothingn then
break; begin
para:=tcallparanode(para.nextpara);
continue;
end;
inc(paracount); inc(paracount);
{ insert some extra casts } { insert some extra casts }
@ -388,9 +411,14 @@ implementation
if dispintfinvoke then if dispintfinvoke then
begin begin
{ dispid }
calldescnode.append(dispid,sizeof(dispid)); calldescnode.append(dispid,sizeof(dispid));
// add dymmy restype byte which is not used by fpc { restype }
calldescnode.append(dispid,sizeof(byte)); if useresult then
restype:=getvardef(resultdef)
else
restype:=0;
calldescnode.append(restype,sizeof(restype));
end; end;
{ build up parameters and description } { build up parameters and description }
para:=tcallparanode(parametersnode); para:=tcallparanode(parametersnode);
@ -399,8 +427,12 @@ implementation
names := ''; names := '';
while assigned(para) do while assigned(para) do
begin begin
{ skip non parameters }
if para.left.nodetype=nothingn then if para.left.nodetype=nothingn then
break; begin
para:=tcallparanode(para.nextpara);
continue;
end;
if assigned(para.parametername) then if assigned(para.parametername) then
begin begin
@ -440,20 +472,7 @@ implementation
ctypeconvnode.create_internal(para.left,assignmenttype))); ctypeconvnode.create_internal(para.left,assignmenttype)));
end; end;
if is_ansistring(para.left.resultdef) then calldesc.argtypes[currargpos]:=getvardef(para.left.resultdef);
calldesc.argtypes[currargpos]:=varStrArg
else
if is_interface(para.left.resultdef) then
begin
{ distinct IDispatch and IUnknown interfaces }
if tobjectdef(para.left.resultdef).is_related(tobjectdef(search_system_type('IDISPATCH').typedef)) then
calldesc.argtypes[currargpos]:=vardispatch
else
calldesc.argtypes[currargpos]:=varunknown;
end
else
calldesc.argtypes[currargpos]:=para.left.resultdef.getvardef;
if dispatchbyref then if dispatchbyref then
calldesc.argtypes[currargpos]:=calldesc.argtypes[currargpos] or $80; calldesc.argtypes[currargpos]:=calldesc.argtypes[currargpos] or $80;
@ -2865,13 +2884,13 @@ implementation
converted_result_data:=ctempcreatenode.create(procdefinition.returndef,sizeof(procdefinition.returndef),tt_persistent,true); converted_result_data:=ctempcreatenode.create(procdefinition.returndef,sizeof(procdefinition.returndef),tt_persistent,true);
addstatement(statements,converted_result_data); addstatement(statements,converted_result_data);
addstatement(statements,cassignmentnode.create(ctemprefnode.create(converted_result_data), addstatement(statements,cassignmentnode.create(ctemprefnode.create(converted_result_data),
ctypeconvnode.create_internal(translate_disp_call(methodpointer,parameters,nil,'',tprocdef(procdefinition).dispid,true), ctypeconvnode.create_internal(translate_disp_call(methodpointer,parameters,nil,'',tprocdef(procdefinition).dispid,procdefinition.returndef),
procdefinition.returndef))); procdefinition.returndef)));
addstatement(statements,ctempdeletenode.create_normal_temp(converted_result_data)); addstatement(statements,ctempdeletenode.create_normal_temp(converted_result_data));
addstatement(statements,ctemprefnode.create(converted_result_data)); addstatement(statements,ctemprefnode.create(converted_result_data));
end end
else else
result:=translate_disp_call(methodpointer,parameters,nil,'',tprocdef(procdefinition).dispid,false); result:=translate_disp_call(methodpointer,parameters,nil,'',tprocdef(procdefinition).dispid,voidtype);
{ don't free reused nodes } { don't free reused nodes }
methodpointer:=nil; methodpointer:=nil;

View File

@ -1118,7 +1118,7 @@ implementation
{ concat value parameter too } { concat value parameter too }
p2:=ccallparanode.create(p2,nil); p2:=ccallparanode.create(p2,nil);
{ passing p3 here is only for information purposes } { passing p3 here is only for information purposes }
p1:=translate_disp_call(p1,p2,p2,'',propsym.dispid,false); p1:=translate_disp_call(p1,p2,p2,'',propsym.dispid,voidtype);
end end
else else
begin begin
@ -1175,7 +1175,7 @@ implementation
converted_result_data:=ctempcreatenode.create(propsym.propdef,sizeof(propsym.propdef),tt_persistent,true); converted_result_data:=ctempcreatenode.create(propsym.propdef,sizeof(propsym.propdef),tt_persistent,true);
addstatement(statements,converted_result_data); addstatement(statements,converted_result_data);
addstatement(statements,cassignmentnode.create(ctemprefnode.create(converted_result_data), addstatement(statements,cassignmentnode.create(ctemprefnode.create(converted_result_data),
ctypeconvnode.create_internal(translate_disp_call(p1,nil,nil,'',propsym.dispid,true), ctypeconvnode.create_internal(translate_disp_call(p1,nil,nil,'',propsym.dispid,propsym.propdef),
propsym.propdef))); propsym.propdef)));
addstatement(statements,ctempdeletenode.create_normal_temp(converted_result_data)); addstatement(statements,ctempdeletenode.create_normal_temp(converted_result_data));
addstatement(statements,ctemprefnode.create(converted_result_data)); addstatement(statements,ctemprefnode.create(converted_result_data));
@ -2069,15 +2069,15 @@ implementation
{ concat value parameter too } { concat value parameter too }
p2:=ccallparanode.create(p3,p2); p2:=ccallparanode.create(p3,p2);
{ passing p3 here is only for information purposes } { passing p3 here is only for information purposes }
p1:=translate_disp_call(p1,p2,p3,dispatchstring,0,false); p1:=translate_disp_call(p1,p2,p3,dispatchstring,0,voidtype);
end end
else else
begin
p1:=translate_disp_call(p1,p2,nil,dispatchstring,0,
{ this is only an approximation { this is only an approximation
setting useresult if not necessary is only a waste of time, no more, no less (FK) } setting useresult if not necessary is only a waste of time, no more, no less (FK) }
afterassignment or in_args or (token<>_SEMICOLON)); if afterassignment or in_args or (token<>_SEMICOLON) then
end; p1:=translate_disp_call(p1,p2,nil,dispatchstring,0,cvarianttype)
else
p1:=translate_disp_call(p1,p2,nil,dispatchstring,0,voidtype);
end end
else { Error } else { Error }
Consume(_ID); Consume(_ID);

View File

@ -18,12 +18,13 @@ type
property Disp402: wordbool dispid 402; property Disp402: wordbool dispid 402;
procedure DispArg1(Arg: IUnknown); procedure DispArg1(Arg: IUnknown);
procedure DispArg2(Arg: IDispatch); procedure DispArg2(Arg: IDispatch);
procedure DispArg3(var Arg: wordbool); function DispArg3(var Arg: wordbool): widestring;
end; end;
var var
cur_dispid: longint; cur_dispid: longint;
cur_argtype: byte; cur_argtype: byte;
cur_restype: byte;
{$HINTS OFF} {$HINTS OFF}
procedure DoDispCallByID(res: Pointer; const disp: IDispatch; desc: PDispDesc; procedure DoDispCallByID(res: Pointer; const disp: IDispatch; desc: PDispDesc;
@ -40,6 +41,8 @@ var
halt(4); halt(4);
if desc^.calldesc.argtypes[0] <> cur_argtype then if desc^.calldesc.argtypes[0] <> cur_argtype then
halt(cur_argtype); halt(cur_argtype);
if desc^.restype <> cur_restype then
halt($FF);
end; end;
@ -61,10 +64,12 @@ begin
II.Disp402 := True; II.Disp402 := True;
// check arguments // check arguments
DispCallByIDProc := @DoDispCallByIDArg; DispCallByIDProc := @DoDispCallByIDArg;
cur_restype := varempty;
cur_argtype := varunknown; cur_argtype := varunknown;
II.DispArg1(nil); II.DispArg1(nil);
cur_argtype := vardispatch; cur_argtype := vardispatch;
II.DispArg2(nil); II.DispArg2(nil);
cur_restype := varolestr;
cur_argtype := varboolean or $80; cur_argtype := varboolean or $80;
B := False; B := False;
II.DispArg3(B); II.DispArg3(B);