为什么对智能指针的这种优化不起作用?

约翰

我一直在研究Sergey Antonov的smartpointer示例,请参见:http ://blog.barrkel.com/2008/11/reference-counted-pointers-revisited.html (在注释中的某个位置)。

SSCCE:

program TestSmartPointer;
{$APPTYPE CONSOLE}    
uses
  System.SysUtils;

type
TInjectType<T> = record
public
  VMT: pointer;
  unknown: IInterface;
  RefCount: integer;
  AValue: T;
end;

TInject<T> = class
public type
  TInjectType = TInjectType<T>;
  PInjectType = ^TInjectType;
end;

PInjectObjectType = TInject<TObject>.PInjectType;


TSmartPointer<T: class> = class
  class function Wrap(const AValue: T): TFunc<T>; static;
end;

function Trick_Release(const obj:  PInjectObjectType): Integer; stdcall; forward;
function Trick_AddRef(const obj: PInjectObjectType): Integer; stdcall; forward;
function Invoke(var obj): TObject; forward;

const
  PSEUDO_VMT: array [0 .. 3] of pointer = (nil, @Trick_AddRef, @Trick_Release, @Invoke);

function Trick_AddRef(const obj: PInjectObjectType): Integer; stdcall;
begin
  Result:= AtomicIncrement(Obj^.RefCount);
end;

function Trick_Release(const obj:  PInjectObjectType): Integer; stdcall;
begin
  Result:= AtomicDecrement(Obj^.RefCount);
  if Result = 0 then obj^.AValue.Free;
end;

function Invoke(const obj:  PInjectObjectType): TObject;
begin
  Result:= obj^.AValue;
end;

class function TSmartPointer<T>.Wrap(const AValue: T): TFunc<T>;
var
  h: TInjectType<T>;
begin
  h.RefCount:= 1;
  pointer(h.unknown):= @h;
  h.VMT:= @PSEUDO_VMT;
  h.AValue:= AValue;
  //Alternative A, this fails
  Result:= TFunc<T>(@h);   
  Inc(h.RefCount);          
  ////Alternative B, this works
  //Result:= function: T      
  //  begin
  //    Result:= h.AValue;
  //  end;
end;

type
  TTestObject = class(TObject)
    procedure Test;
    destructor Destroy; override;
  end;


{ TTestObject }

procedure TTestObject.Test;
begin
  WriteLn('Test');
end;

destructor TTestObject.Destroy;
begin
  WriteLn('Free');
  inherited;
end;

procedure Test;
var
  TestObject: TFunc<TTestObject>;
begin
  TestObject:= TSmartPointer<TTestObject>.Wrap(TTestObject.Create);
  TestObject.Test;
  ReadLn;   //Works up to this point.
  <<<--- generates a AV here.
end;

begin
  WriteLn('Start');
  Test;
  WriteLn('End');
  ReadLn;
end.

巴里·凯利(Barry Kelly)解释说:

TFunc =对函数的引用:T;

直接等于:

TFunc =接口函数调用:T; 结尾;

除了可以使用函数,方法或匿名方法的值分配方法引用类型的位置之外。

匿名方法被实现为与隐藏类上的方法引用相似的接口。位置捕获是通过移动(对于本地人)和复制(对于参数)到隐藏类的字段来实现的。主过程主体中捕获位置的任何访问都将转换为访问隐藏类上的字段;名为$ frame的局部变量指向此隐藏类的实例。

目标
我想优化智能指针的创建。
为此,我手工制作了VMT并使用它来模拟接口。

如果我这样定义我的wrap函数:

class function TSmartPointer<T>.Wrap(const AValue: T): TFunc<T>;
var
  h: TInjectType<T>;
begin
  pointer(h.unknown):= @h;
  h.VMT:= @PSEUDO_VMT;
  h.AValue:= AValue;
  Result:= function: T      
    begin
      Result:= h.AValue;
    end;
end;

一切正常。

如果我将其优化为:

class function TSmartPointer<T>.Wrap(const AValue: T): TFunc<T>;
var
  h: TInjectType<T>;
begin
  h.RefCount:= 1;
  pointer(h.unknown):= @h;
  h.VMT:= @PSEUDO_VMT;
  h.AValue:= AValue;
  //Alternative A, this fails
  Result:= TFunc<T>(@h);   
  Inc(h.RefCount);          
end;

几乎可以工作,但是在调用函数关闭时立即给出AV。

procedure Test;
var
  TestObject: TFunc<TTestObject>;
begin
  TestObject:= TSmartPointer<TTestObject>.Wrap(TTestObject.Create);
  TestObject.Test;
  ReadLn;   
  //Works up to this point.
  <<<--- generates a AV here.
end; 

您可能希望AV出现在_Release中,但事实并非如此,实际上是在此之前发生的。

    TestNewStringHelper.dpr.98: TestObject.Test;
00419F0B 8B45FC           mov eax,[ebp-$04]        

这里 EAX = 0018FF40

00419F0E 8B10             mov edx,[eax]
00419F10 FF520C           call dword ptr [edx+$0c]
00419F13 E82CFFFFFF       call TTestObject.Test
TestNewStringHelper.dpr.100: end;
00419F18 33C0             xor eax,eax
00419F1A 5A               pop edx
00419F1B 59               pop ecx
00419F1C 59               pop ecx
00419F1D 648910           mov fs:[eax],edx
00419F20 68359F4100       push $00419f35
00419F25 8D45FC           lea eax,[ebp-$04]

这里EAX = 0018FF6C显然应该和以前一样。事实并非如此,这是随后出现AV的原因:

00419F28 E87BF6FEFF       call @IntfClear    <<-- AV

呼叫IntfClearAV,因为找不到适合的目标_ReleaseIOW呼叫永远不会到达_Release,但会跳入未知状态。

System.pas.36036: MOV     EDX,[EAX]
004095A8 8B10             mov edx,[eax]
System.pas.36037: TEST    EDX,EDX
004095AA 85D2             test edx,edx
System.pas.36038: JE      @@1
004095AC 740E             jz $004095bc
System.pas.36039: MOV     DWORD PTR [EAX],0
004095AE C70000000000     mov [eax],$00000000
System.pas.36043: PUSH    EAX
004095B4 50               push eax
System.pas.36044: PUSH    EDX
004095B5 52               push edx
System.pas.36045: MOV     EAX,[EDX]
004095B6 8B02             mov eax,[edx]
System.pas.36046: CALL    DWORD PTR [EAX] + VMTOFFSET IInterface._Release
004095B8 FF5008           call dword ptr [eax+$08]  <<-- AV here

为什么要这样做,我需要进行哪些调整才能使优化版本正常工作?

戴维·赫弗南

起作用的代码捕获局部变量h这意味着其寿命得以延长。编译器通过h在堆上分配变量做到这一点

您的代码没有任何变量捕获。这意味着h在函数返回时会在堆栈上分配它,并且其生存期结束。因此,您随后的引用h无效。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在这种情况下,为什么要使用智能指针?

来自分类Dev

为什么这种展开不起作用?

来自分类Dev

为什么这种缩放不起作用?

来自分类Dev

为什么采用char指针指针的函数不起作用?

来自分类Dev

为什么这种C ++多态性不起作用?

来自分类Dev

为什么这种热键组合:“ Super + V”不起作用?

来自分类Dev

为什么这种可重复的随机算法不起作用?

来自分类Dev

为什么multiprocessing.pool的这种实现不起作用?

来自分类Dev

为什么这种Lua模式不起作用?

来自分类Dev

VBA,为什么这种情况不起作用?

来自分类Dev

为什么这种mongo排序不起作用

来自分类Dev

Java-为什么这种模式匹配不起作用?

来自分类Dev

为什么这种关闭方式不起作用?

来自分类Dev

为什么getElementsByTagName在这种逻辑下不起作用?

来自分类Dev

为什么在jquery中不起作用这种反弹效果?

来自分类Dev

为什么这种情况在Ubuntu中不起作用?

来自分类Dev

为什么这种复制文件的方式不起作用

来自分类Dev

为什么多处理池的这种实现不起作用?

来自分类Dev

为什么这种基于条件的列表理解不起作用?

来自分类Dev

为什么这种重新分配不起作用

来自分类Dev

为什么这种检查 undefined 的方法不起作用?

来自分类Dev

为什么这种算法的“改进”不起作用?

来自分类Dev

为什么这种负面前瞻不起作用?

来自分类Dev

为什么这种合并排序的实现不起作用?

来自分类Dev

为什么对列表列表的这种迭代不起作用?

来自分类Dev

是否可以优化智能指针?

来自分类Dev

为什么to_proc在Ruby优化中不起作用?

来自分类Dev

为什么我更喜欢在智能指针上引用而不是在C ++中将智能指针作为参数

来自分类Dev

功能指针在getopt中不起作用

Related 相关文章

  1. 1

    在这种情况下,为什么要使用智能指针?

  2. 2

    为什么这种展开不起作用?

  3. 3

    为什么这种缩放不起作用?

  4. 4

    为什么采用char指针指针的函数不起作用?

  5. 5

    为什么这种C ++多态性不起作用?

  6. 6

    为什么这种热键组合:“ Super + V”不起作用?

  7. 7

    为什么这种可重复的随机算法不起作用?

  8. 8

    为什么multiprocessing.pool的这种实现不起作用?

  9. 9

    为什么这种Lua模式不起作用?

  10. 10

    VBA,为什么这种情况不起作用?

  11. 11

    为什么这种mongo排序不起作用

  12. 12

    Java-为什么这种模式匹配不起作用?

  13. 13

    为什么这种关闭方式不起作用?

  14. 14

    为什么getElementsByTagName在这种逻辑下不起作用?

  15. 15

    为什么在jquery中不起作用这种反弹效果?

  16. 16

    为什么这种情况在Ubuntu中不起作用?

  17. 17

    为什么这种复制文件的方式不起作用

  18. 18

    为什么多处理池的这种实现不起作用?

  19. 19

    为什么这种基于条件的列表理解不起作用?

  20. 20

    为什么这种重新分配不起作用

  21. 21

    为什么这种检查 undefined 的方法不起作用?

  22. 22

    为什么这种算法的“改进”不起作用?

  23. 23

    为什么这种负面前瞻不起作用?

  24. 24

    为什么这种合并排序的实现不起作用?

  25. 25

    为什么对列表列表的这种迭代不起作用?

  26. 26

    是否可以优化智能指针?

  27. 27

    为什么to_proc在Ruby优化中不起作用?

  28. 28

    为什么我更喜欢在智能指针上引用而不是在C ++中将智能指针作为参数

  29. 29

    功能指针在getopt中不起作用

热门标签

归档