Конференция "Начинающим" » Как получить смещение переменной в классе?
 
  • dmk © (15.08.18 12:30) [0]
    Есть встроенные способы или как то химичить надо?
    Нужно Self+Offset получить.
  • Плохиш © (15.08.18 12:33) [1]

    > Как получить смещение переменной в классе?

    Откуда в классе смещения?
  • dmk © (15.08.18 13:04) [2]
    >Откуда в классе смещения?
    В адресном пространстве класса :)

    Self <- указатель на начало класса.
    Переменные — адреса после self.
    Как в record:

     lea r9, [self.FClipRegion]

     cmp edx, [r9] //rX
     jl @Out
     cmp eax, [r9 + 4] //rY
     jl @Out
     cmp edx, [r9 + 8] //rEX
     jg @Out
     cmp eax, [r9 + 12] //rEY
     jg @Out


    Можно было бы написать класс с функцией OffsetOfVar, но наследников не будет видно.
    Просто хочу вынести из класса однотипные функции. Self то я передать смогу,
    а вот смещение компилятор видит только внутри класса. Думал просто встроенные
    средства есть, а придется опять в обход.
  • Игорь Шевченко © (15.08.18 21:16) [3]

    > Думал просто встроенные
    > средства есть, а придется опять в обход.


    Откуда им взяться, а главное - зачем ?
  • dmk © (15.08.18 22:24) [4]
    >а главное - зачем ?
    Мне для оптимизации надо. Absolute не везде работает.
  • Игорь Шевченко © (15.08.18 22:34) [5]

    > Мне для оптимизации надо. Absolute не везде работает.


    unit main;

    interface

    uses
     Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
     Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

    type
     TForm1 = class(TForm)
       Edit1: TEdit;
       procedure FormCreate(Sender: TObject);
     private
       FFoo: Integer;
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.dfm}

    procedure TForm1.FormCreate(Sender: TObject);
    begin
     Edit1.Text := IntToStr(NativeInt(@TForm1(nil).FFoo));
    end;

    end.



    А так - тоже не работает ?
  • dmk © (15.08.18 22:48) [6]
    >А так - тоже не работает ?
    Да чего то забылся :) Addr есть же.

    Примерно то же самое. Работает.

    procedure Test;
    var
     hh: double;
     s: string;

    begin
     hh := 620.343463;  
     P := QWord(Addr(hh));
     S := FloatToStrR(PDouble(P)^, 2, false);
    end;
  • Dimka Maslov © (20.08.18 19:44) [7]
     TClass1 = class (TObject)
     private
       FN: Integer;
     public
       constructor Create(AN: Integer);
       function GetN: Integer;
     end;

    { TClass1 }

    constructor TClass1.Create(AN: Integer);
    begin
     FN := AN;
    end;

    function TClass1.GetN: Integer;
    asm
     mov eax, eax.TClass1.FN
    end;
  • Leonid Troyanovsky © (25.08.18 16:49) [8]

    > dmk ©   (15.08.18 22:24) [4]

    Непонятно, чем хак может помочь оптимизации
    собс-ручно написуемого кода.

    --
    Regards, LVT.
  • dmk © (28.08.18 14:03) [9]
    >Непонятно, чем хак может помочь оптимизации
    >собс-ручно написуемого кода.

    Да не хак это. В классе образовалось штук 20 перегружаемых функций (11к строк).
    Хочется вынести их в inc или в другой модуль, но данные нужны из класса.
    Для этого нужны глобальные переменные - смещения или лучше прямые адреса.
    В общем внутри хочется избавиться от зависимости self.
    На самом деле еще не решил как сделать правильно, поэтому думаю.
    Вопрос не решен.
    Кроме того вся эта затея из-за выравнивания переменных на 16.
    В классе они не выравниваются. Иногда выравниваюся, а иногда выскакивает AV.

    Просто для примера:
    procedure TBitmap64.SetZPixel64(P: TVertex; dColor: TColorRef);
    asm
     .NOFRAME

     movq xmm1, qword ptr [P] //Читаем X,Y
     cvtss2sd xmm0, dword ptr [P + 8] //Конвертируем Z в Double
     cvtps2dq xmm1, xmm1 //Конвертируем X,Y
     extractps edx, xmm1, 0 //Извлекаем X
     extractps eax, xmm1, 1 //Извлекаем Y

     imul eax, dword ptr [self.FWidth] //Y в eax
     add rax, rdx //X в rdx
     shl rax, 2
     mov rdx, rax //Сохраним относительное смещение, чтобы не считать повторно
     shl rax, 1
     add rax, qword ptr [self.FZBufferAddr] //rax = ZAddr

     comisd xmm0, [rax]
     jbe @P
     ret

    @P:
     movsd [rax], xmm0
     add rdx, [self.FMemAddr]
     mov [rdx], r8d
    end;


    Мне нужны вот эти данные:
    self.FWidth
    self.FMemAddr
    self.FZBufferAddr
    и еще куча self.Переменных

    Просто если я вынесу функции в другой модуль, то откуда мне их брать вне класса?
    Хочется, чтобы шло обращение к массиву с заранее выравненными переменными.
    Ибо выравненные переменные иногда до 10% быстрее считаются.
    10% в моем случае - это очень хорошо!
  • dmk © (28.08.18 14:07) [10]
    Просто компилятор знает как посчитать смещения, а я нет.
    Можно вручную конечно, но это каждый раз заморочка если добавил переменную.
    Все адреса плывут.
  • Leonid Troyanovsky © (30.08.18 14:35) [11]

    > dmk ©   (28.08.18 14:03) [9]

    > Хочется вынести их в inc или в другой модуль, но данные
    > нужны из класса.
    > Для этого нужны глобальные переменные - смещения или лучше
    > прямые адреса.
    > В общем внутри хочется избавиться от зависимости self.

    Что-то всё это выглядит очень запущенным.

    Может и не нужны никакие классы? Рекорды тоже можно снабдить методами, ЕМНИП.

    Ну, а если уж классы, то сделай им единственное поле в виде рекорда с нужным выравниванием $A..
    (хотя, в D32 было максимум 8, а не 16). Т.е., если поле класса одно, то и доступ к нему по одному и тому же смещению.

    Вынести же процедуры в другой модуль можно,  при условии, что первым параметром в них будет Self.

    С простыми структурами (или массивами) возможно, в данном случае, и проще.

    --
    Regards, LVT.
  • dmk © (30.08.18 14:58) [12]
    Да с выравниванием я вопрос решил. Просто написал свой класс, который генерит переменные с нужным выравниванием. Правда много ^^^^, но вариантов нет.
    Если только свой компилятор писать. Не выравнивает дельфи переменные.
    Только массивы и record'ы.

    А смещение я нашел как считать:
    type
     TSomeClass = (TObject)
       private
         T: Double;
       protected
       public
       ...
     end;

    var
     dA, cA, dif: QWord;

    procedure CheckOffset;
    var
     k: Double;

    begin
     k := PDouble(cA + dif)^; //<--- 1.2 !!! :)
    end;

    procedure TForm.ClassProc;
    begin
     T := 1.2;
     dA := QWord(@T);
     cA := QWord(Self);
     dif := (dA - cA);

     CheckOffset;
    end;
  • dmk © (30.08.18 15:01) [13]
    Выравнивание мне 20 fps добавило.
  • Leonid Troyanovsky © (30.08.18 15:23) [14]

    > dmk ©   (30.08.18 14:58) [12]

    > А смещение я нашел как считать:

    Если поле в классе одно, то ничего считать и не надо.
    См., например, [7].

    Или так (тоже хак):


    type
     THSomeClass = class (TSomeClass)
      private
         ft: Double;
     end;

     sc :=  TSomeClass.Create;
     sc.T := 1.2


    Далее, в любом месте (в другом модуле)
    имея sc получаем доступ к полю T путем THClass(sc).ft

    --
    Regards, LVT.
  • dmk © (30.08.18 16:11) [15]
    >Если поле в классе одно, то ничего считать и не надо.
    У меня класс - 3D-объект. Куча полей и переменных.
    Просто выношу смещения отдельно в константы, а вызов вне класс выглядит так:

    procedure LoadColorA(VA: PVertexAttrib);
    asm
     .NOFRAME

     movd mm7, dword ptr [VA + AT_DC0] // VA = RCX (self) или любой другой указатель
    end;


    В итоге процедура или функция не принадлежит классу, но читает из класса ее переменные. Просто для компактности. Выглядит криво, но удобно с точки зрения использования, т.к. можно вызывать из других классов и компоновать в сборки кода. Иначе приходится плодить однотипные процедуры, которые различаются незначительно и находятся в разных классах.
 
Конференция "Начинающим" » Как получить смещение переменной в классе?
Есть новые Нет новых   [118682   +10][b:0][p:0.001]