我发现Delphi 5在特定情况下会生成无效的汇编代码.一般来说,我无法理解在什么情况下.以下示例产生访问冲突,因为发生了非常奇怪的优化.对于记录或数组中的一个字节,Delphi生成push dword [...],pop ebx,mov ..,bl如果在此字节后面有数据(我们至少需要三个正确推送dword)才能正常工作,但是失败了如果数据不可访问.我在这里使用win32 Virtual*函数模拟了严格的界限
具体而言,当在FeedBytesToClass过程中访问块的最后一个字节时,会发生错误.如果我尝试更改类似于使用数据数组而不是删除actionFlag变量的对象属性,Delphi会生成正确的汇编指令.
const
BlockSize = 4096;
type
TSomeClass = class
private
fBytes: PByteArray;
public
property Bytes: PByteArray read fBytes;
constructor Create;
destructor Destroy;override;
end;
constructor TSomeClass.Create;
begin
inherited Create;
GetMem(fBytes, BlockSize);
end;
destructor TSomeClass.Destroy;
begin
FreeMem(fBytes);
inherited;
end;
procedure FeedBytesToClass(SrcDataBytes: PByteArray; Count: integer);
var
j: integer;
Ofs: integer;
actionFlag: boolean;
AClass: TSomeClass;
begin
AClass:=TSomeClass.Create;
try
actionFlag:=true;
for j:=0 to Count-1 do
begin
Ofs:=j;
if actionFlag then
begin
AClass.Bytes[Ofs]:=SrcDataBytes[j];
end;
end;
finally
AClass.Free;
end;
end;
procedure TForm31.Button1Click(Sender: TObject);
var
SrcDataBytes: PByteArray;
begin
SrcDataBytes:=VirtualAlloc(Nil, BlockSize, MEM_COMMIT, PAGE_READWRITE);
try
if VirtualLock(SrcDataBytes, BlockSize) then
try
FeedBytesToClass(SrcDataBytes, BlockSize);
finally
VirtualUnLock(SrcDataBytes, BlockSize);
end;
finally
VirtualFree(SrcDataBytes, MEM_DECOMMIT, BlockSize);
end;
end;
Run Code Online (Sandbox Code Playgroud)
最初,当我使用位图位的RGB数据访问时发生错误,但是那里的代码太复杂,所以我把它缩小到这个片段.
所以问题是这里有什么特别的东西让Delphi产生推,弹,动优化.我需要知道这一点,以避免一般的副作用.
Pau*_*Jan 10
哎呀,确实是痛苦的问题.常量actionFlag的存在(结合4的倍数的常量计数)触发了处理数据的push/pop样式.对于那些对实际汇编程序感兴趣的人,(在cpu视图不提供复制/粘贴的日子里,手动输入后面的内容):
AClass.Bytes[Ofs] := SrcDataBytes[j];
mov exc,[ebp-$04]
push dword ptr [ecx+eax] <- ouch
mov ecx,[ebp-$08]
mov ecx,[exc+04]
lea esi,[exc+esi]
pop ecx
mov [esi],cl
end;
inc eax
Run Code Online (Sandbox Code Playgroud)
这样做了4096次.我检查过,Delphi 6没有这种行为.我认为我们可以安全地假设它在任何更高版本中都已修复.
作为一种解决方法,我建议只在该方法中添加{$ O - }/{$ O +}.我不会过多地考虑确切的取证,因为触发Delphi执行这种错误优化的条件似乎很少见,Delphi版本确实相当古老.
常量标志通常不会成为内循环的一部分,我怀疑你的计数通常也是动态的.但是,你已经遇到了生产代码的这个问题,所以也许它并不像它看起来那么罕见.我只能说我从来没有碰到它,我们在Delphi 5中编写了90%的生产代码.也许这只是默认内存分配的安全性.
| 归档时间: |
|
| 查看次数: |
523 次 |
| 最近记录: |