Встроенный ассемблер и свойства класса Delphi

Я пытаюсь переписать метод TList.IndexOf на ассемблере (XE3). Вот мой код

function TFastList.IndexOfAsm(Item: Pointer): Integer;
{var
  P: PPointer;
begin
  P := Pointer(FList);
  for Result := 0 to FCount - 1 do
  begin
    if P^ = Item then
      Exit;
    Inc(P);
  end;
  Result := -1;}
var
  FCnt, rslt: Integer;
  FData: Pointer;
begin
  FCnt := Count;
  FData := List;
asm
  push edi

  mov ecx, FCnt
  mov edi, FData
  mov eax, Item
  repne scasd

  mov eax, FCnt
  sub eax, ecx
  dec eax
  mov rslt, eax

  pop edi
end;
  Result := rslt;
end;

Естественно, я хотел бы напрямую использовать такие свойства, как Count или List. Я понимаю, почему компилятор отказывается предоставить доступ к закрытым полям FCount и FList, но как мне получить доступ к соответствующим свойствам? Count, Self.Count и [eax] .Count все дают встроенную ошибку ассемблера.

JIC: Я не намерен разбираться с ситуацией, которая здесь не найдена.


person Anton Duzenko    schedule 17.08.2014    source источник
comment
Вы не можете получить доступ к свойствам из asm. Вы отказались от этой привилегии, когда отказались от компилятора.   -  person David Heffernan    schedule 18.08.2014


Ответы (1)


Вы не можете получить доступ к свойству объекта через ассемблер Delphi!

Компилятор Delphi хорош, и, как я полагаю, скомпилированный код Delphi также очень быстр.

В вашем коде есть ошибка, потому что он не проверяет счетчик нуля, а именно, что должно вызвать нарушение доступа к памяти!

Не используйте repne scasd, потому что это медленно.

Однако вы можете взломать код вручную, чтобы провести тест ... :)

function TFastList.IndexOfAsm(Item: Pointer): Integer;
//eax = self
//edx = Item
{var
  P: PPointer;
begin
  P := Pointer(FList);
  for Result := 0 to FCount - 1 do
  begin
    if P^ = Item then
      Exit;
    Inc(P);
  end;
  Result := -1;}
const
  FItems = 4; //data offset of FItems
  FCount = 8; //data offset of FCount
asm
  mov   ecx, [eax].FItems  //ecx = @FItems
  mov   eax, [eax].FCount  //eax = FCount
  dec   eax                //test zero count!
  js    @Exit              //if count was 0 then exit as -1
@Loop:                     //repeat
  cmp   Item, [ecx + eax * 4]
  jz    @Exit
  dec   eax
  jns   @Loop              //until eax < 0 (actually -1)
@Exit:
end;
person GJ.    schedule 17.08.2014
comment
Мне нравится, как вы здесь создали смещения свойств. Однако медлительность Scasd еще предстоит измерить. - person Anton Duzenko; 21.08.2014
comment
@ Антон Дузенко: есть несколько способов. Вы можете использовать отладчик и перейти к функции TList.add до строки FList[result] := Item, затем переключить окно отладчика на CPU и прочитать индекс FList. Вы также можете вычислить индекс. Проверьте в System.Classes, как сделан класс TList. FList является первым членом класса данных, поэтому индекс равен 4 (индекс 0 - ClassInfo), чем FCount, который равен 8, потому что размер целого числа или указателя составляет 4 байта. - person GJ.; 21.08.2014
comment
Да, я знаю это. Теперь я провел быстрый тест, и на моих реальных данных (около 64 элементов в списке) ваш код примерно на 4% быстрее, чем scasd. В больших списках (512+ элементов) scasd немного быстрее. IndexOf delphi примерно на 30% медленнее, чем asm. В общем, вы №1. - person Anton Duzenko; 22.08.2014