Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
HOR / TOTAL.DOC
Скачиваний:
8
Добавлен:
16.04.2013
Размер:
312.83 Кб
Скачать

4.7. Поддержка протоколаGiop в рамках отображения дляObject Pascal.

При реализации отображения для языка Object Pascal наиболее актуальным было обеспечение возможности быстрого и удобного кодирования данных, потому что вызов изDLL написанных наC функций не обеспечивал ни первого, ни второго. В языкеC++ весьма удобным механизмом является использование стандартных потоков с перегруженными операциями<< и>>. В качестве результата хотелось бы иметь нечто аналогичное. В итоге получилось следующее.

Имеющиеся в Delphi стандартные классы потоком, наследников отTStream позволяют производить только чтение и запись абстрактного буфера данных. Было принято решение не изменять имеющееся определение классаTStream, а вместо этого определить классTStreamable, у которого помимо всего прочего будет поле - типаTStream, что даст возможность осуществлять чтение и запись у любого потока.

Сначала был определен набор методов для чтение/записи базовых типов. В качестве примера можно привести методы для чтения и записи типаLong (являющегося аналогом типаCardinal вObject Pascal):

procedureTStreamable.WriteLong(L: Long);

begin

Align4;

Stream.Write(L, 4);

end;

functionTStreamable.ReadLong: Long;

begin

Align4;

Stream.Read(Result7, 4);

end;

Метод Align4 производит выравнивание границы начала записи числа на позицию, кратную 4, как того требует спецификацияCDR. Например, чтобы поместить в поток два числа2и8, а также строку‘Hello’нужно было написать примерно следующий код:

S.WriteLong(2);

S.WriteLong(8);

S.WriteString(‘Hello’);

После некоторых опытов пришла идея сделать все методы чтения/записи функцией с одним параметров - значением или переменной соответствующего типа, которая будет возвращать ссылку на тот же самый объект типаTStreamable, у которого она определена. Тогда было введено еще два набора функций, которые были реализованы следующим образом:

functionTStreamable.PutLong(L: Long): TStreamable;

begin

Align4;

Stream.Write(L, 4);

Result := Self;

end;

function TStreamable.GetLong(var L: Long): TStreamable;

begin

Align4;

Stream.Read(Result, 4);

Result := Self;

end;

Перевызов соответствующих методов WriteLong иReadLong уменьшил бы эффективность полученного кода (за счет дополнительного присваивания) и поэтому код просто дублировался. В результате на первый взгляд небольшой потери в эффективности появилась возможность написания выражений в гораздо более красивом и удобном8стиле. Приведенный выше пример мог теперь быть записан следующим образом:

S.PutLong(2).PutLong(8).PutString(‘Hello’);

Соответственно чтение из потока стало выглядеть так:

var

L1, L2: Long;

Msg: string;

...

S.GetLong(L1).GetLong(L2).GetString(Msg);

Более того, была проведена оптимизация создаваемого кода, посредством реализации данным методов на встроенном ассемблере. В соответствии с моделью вызовов register, которая по умолчанию принята компиляторомDelphi, первый параметр функции (указатель на объект) передается в регистреEAX, а результат функции, если он помещается тоже возвращается в регистреEAX. Соответственно при реализации данных методов на языке ассемблера нужно всего лишь на протяжении выполнения всего метода сохранить переданное в самом начале значение. Кроме того, можно сэкономить на формировании фрейма стека. В итоге были получены следующие результаты. Ассемблерный код для методаWriteLong, сгенерированный компилятором, который можно получить в отладчикеTurbo Debugger for Win32 содержит 19 команд ассемблера и выполняется по приблизительным оценкам за 21 такт процессораIntel Pentium. Код для методаPutLong, написанный на ассемблере, содержит 15 команд ассемблера и выполняется за 17 тактов процессораIntel Pentium. Листинг обоих методов приведен в приложении Б. При оценке количества тактов не учитывалась возможность процессораIntel Pentium параллельного выполнения нескольких команд и использовались данные, представленные в литературе [4].

В итоге был получен более производительный и более удобный в использовании код. В плане оптимизации несколько методов были также переписаны на языке ассемблера. Но после анализа алгоритма выяснилось, что потенциально большое время занимает выполнение метода Write у потоков. Поэтому в будущем планируется написание специализированного класса, специально оптимизированного под кодирование/декодирование данных в соответствии сCDR.

Соседние файлы в папке HOR