delphi – 为什么在优化构建下有两个顺序移动到EAX?
我查看了发布所有优化的发布版本的ASM代码,这是我遇到的内联函数之一:
0061F854 mov eax,[$00630bec] 0061F859 mov eax,[$00630e3c] 0061F85E mov edx,$00000001 0061F863 mov eax,[eax+edx*4] 0061F866 cmp byte ptr [eax],$01 0061F869 jnz $0061fa83 代码很容易理解,它将偏移量(1)构建到表中,将其中的字节值与1进行比较,如果是NZ则进行跳转.我知道我的表的指针存储在$00630e3c,但我不知道$00630bec来自哪里. 为什么有两个人一个接一个地转向eax?是不是第一个被第二个覆盖了?这可能是缓存优化的事情还是我错过了令人难以置信的明显/模糊的东西? 上述ASM的Delphi代码如下: if( TGameSignals.IsSet( EmitParticleSignal ) = True ) then [...] IsSet()是一个内联类函数,并调用TSignalManager的内联IsSet()函数: class function TGameSignals.IsSet(Signal: PBucketSignal): Boolean; begin Result := FSignalManagerInstance.IsSet( Signal ); end; 信号管理器的最终IsSet如下: function TSignalManagerInstance.IsSet( Signal: PBucketSignal ): Boolean; begin Result := Signal.Pending; end; 解决方法
我最好的猜测是$00630bec是对TGameSignals类的引用.你可以通过做检查
ShowMessage(IntToHex(NativeInt(TGameSignals),8)) 预优化代码可能是这样的 0061F854 mov eax,[$00630bec] //Move reference to class TGameSignals in EAX 0061F859 mov eax,[eax + $250] //Move Reference to FSignalManagerInstance at offset $250 in class TGameSignals in EAX 编译器优化[eax $250]到[$00630e3c],但没有意识到以前的MOV不再需要了. 我不是codegen的专家,所以带上一粒盐…… 另外,在delphi中,我们通常会写 if TGameSignals.IsSet( EmitParticleSignal ) then 因为以下IF可能是真的 var vBool : Boolean [...] vBool := Boolean(10); if vBool and (vBool <> True) then 当然,这不是一个好的做法,但与TRUE相比也没有意义. 编辑:正如Ped7g所指出的,我错了.指令是 0061F854 mov eax,[$00630bec] 并不是 0061F854 mov eax,$00630bec 所以我写的内容并没有多大意义…… mov eax,[$00630bec] call TGameSignals.IsSet 然后 *TGameSignals.IsSet mov eax,[$00630e3c] [...] 第一个mov仍然没有意义,因为在TGameSignals.IsSet中没有使用“Self”,但仍然需要将“self”传递给函数.当例程内联时,它确实看起来更愚蠢. 就像Arnaud Bouchez提到的那样,使TGameSignals.IsSet静态删除隐式Self参数,从而删除第一个MOV操作. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |