Fiddling with anonymous methods.
Fiddling with anonymous methods.
This recently filed issue (https://bitbucket.org/sglienke/spring4d/issues/146) and my not yet confirmed guess made me think.
Why can't the compiler do the following for cases where no variable capturing is required (which is the case for standalone routines or even stateless anonymous methods - for instance methods it secretly captures Self so it can call the method on the correct instance):
The stuff within the region would need to be compiler generated.
program anonymous_method_routine;
{$APPTYPE CONSOLE}
uses
SysUtils;
procedure MyHandler;
begin
Writeln('foo');
end;
{$REGION 'VTable stuff'}
function NopAddref(inst: Pointer): Integer; stdcall;
begin
Result := -1;
end;
function NopRelease(inst: Pointer): Integer; stdcall;
begin
Result := -1;
end;
function NopQueryInterface(inst: Pointer; const IID: TGUID; out Obj): HResult; stdcall;
begin
Result := E_NOINTERFACE;
end;
const
MyHandler_Vtable: array[0..3] of Pointer =
(
@NopQueryInterface,
@NopAddref,
@NopRelease,
@MyHandler
);
MyHandler_Instance: Pointer =@MyHandler_Vtable;
{$ENDREGION}
var
p: TProc;
begin
try
p := MyHandler;
// what the compiler actually generates
// p := procedure begin MyHandler() end;
p(); // <- step into it and look at the callstack
// what the compiler actually should generate
PPointer(@p)^:=@MyHandler_Instance;
p(); // <- check the callstack - it does not contain any compiler generated stuff
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
Allen Bauer Marco Cantù ping
This recently filed issue (https://bitbucket.org/sglienke/spring4d/issues/146) and my not yet confirmed guess made me think.
Why can't the compiler do the following for cases where no variable capturing is required (which is the case for standalone routines or even stateless anonymous methods - for instance methods it secretly captures Self so it can call the method on the correct instance):
The stuff within the region would need to be compiler generated.
program anonymous_method_routine;
{$APPTYPE CONSOLE}
uses
SysUtils;
procedure MyHandler;
begin
Writeln('foo');
end;
{$REGION 'VTable stuff'}
function NopAddref(inst: Pointer): Integer; stdcall;
begin
Result := -1;
end;
function NopRelease(inst: Pointer): Integer; stdcall;
begin
Result := -1;
end;
function NopQueryInterface(inst: Pointer; const IID: TGUID; out Obj): HResult; stdcall;
begin
Result := E_NOINTERFACE;
end;
const
MyHandler_Vtable: array[0..3] of Pointer =
(
@NopQueryInterface,
@NopAddref,
@NopRelease,
@MyHandler
);
MyHandler_Instance: Pointer =@MyHandler_Vtable;
{$ENDREGION}
var
p: TProc;
begin
try
p := MyHandler;
// what the compiler actually generates
// p := procedure begin MyHandler() end;
p(); // <- step into it and look at the callstack
// what the compiler actually should generate
PPointer(@p)^:=@MyHandler_Instance;
p(); // <- check the callstack - it does not contain any compiler generated stuff
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
Allen Bauer Marco Cantù ping
/sub.
ReplyDelete/sub
ReplyDelete/sub
ReplyDeleteThe compiler could do that. It just doesn't. I would guess that the designers chose the expedient option at the cost of performance.
ReplyDelete/sub
ReplyDelete