.
С.С. Гайсарян, К.Н. Долгова, Труды Института системного программирования РАН
Статья посвящена исследованию возможности вызова программ, реализованных на языке Fortran 95, из среды Java. Для того, чтобы среды могли обмениваться данными, должно быть отображение данных одной среды на данные другой. В статье представлено описание отображения данных языка Fortran на данные языка Java и обратно. Также описан способ эффективной передачи данных из среды Java в среду Fortran и обратно. Он заключается в том, что память, выделенная средой Fortran для размещения общих блоков и массивов, отождествляется с прямыми буферами среды Java. То есть прямые буферы среды Java размещаются по тем же адресам памяти, по которым размещены общие блоки и массивы языка Fortran. Помимо этого, в статье описан метод организации вызова подпрограмм, реализованных на языке Fortran из окружения Java, заключающийся в передаче параметров через прямые буферы окружения Java.
Введение
Имеется достаточно большое количество программ, реализованных на языке Fortran и не потерявших ценность. В настоящее время широкую популярность получила среда программирования Java, обеспечивающая переносимость программ. Следовательно, возникает потребность иметь возможность вызывать подпрограммы, реализованные на языках Fortran, из Java-программ.
Для вызова подпрограмм, реализованных на языке С из Java программ есть JNI, который доступен, начиная с версии JDK 1.2. Аналогичного интерфейса для вызова Fortran-подпрограмм нет. Предложенная работа повещена разработке методики вызова Fortran-подпрограмм из Java-среды.
В настоящей работе рассмотрены основные отличия языков С и Fortran, препятствующие использованию методики, аналогичной JNI для вызова Fortran-подпрограмм из Java-программ. Построено отображение данных языка Fortran на данные Java и обратно. Предложена методика реализации общей области памяти для Java- и Fortran-сред через прямые буферы пакета java.nio. В последнем разделе описана прототипная реализация, выполненная с использованием JNI, которая показала эффективность предложенной методики.
1. Отличия языков C и Fortran
У языков программирования C и Fortran существует ряд различий, из-за которых нельзя перенести организацию JNI для языка С на организацию подобного интерфейса для языка Fortran.
В стандарте языка С напрямую не указан размер примитивных типов [1]. Выбор наилучшего для данной архитектуры размера типов оставлен на рассмотрение разработчиков компилятора. В стандарте языка Fortran для каждого примитивного типа данных строго задан их размер. Это позволяет установить взаимно однозначное соответствие между типами языка Java и типами языка Fortran, не используя промежуточных типов, как это реализовано в JNI.
Среда Fortran размещает данные в статической области памяти программы. К данным есть доступ только по ссылке, и нет возможности получить адрес памяти, где они расположены. Среда Fortran не поддерживает динамически создаваемых объектов данных. Среда C, во-первых, располагает данные программы в стеке, в куче и в статической области памяти программы, во-вторых, определена операция взятия адреса, позволяющие получить доступ не только к значениям данных, но и к адресам памяти, где они расположены. Соответственно, для передачи данных из Java среды в C среду JNI достаточно указать адрес области памяти, где данные хранятся. Передачу данных из Java среды в Fortran среду нельзя выполнить аналогично тому, как это сделано в JNI.
Все параметры в языке Fortran передаются только по ссылке, потому что в нем не определено понятие адреса переменной. В языке С параметры передаются только по значению, однако есть возможность передавать в качестве параметра функции указатели на ту область памяти, где хранится переменная. Соответственно, передачу данных из среды Java в среду Fortran и обратно нельзя выполнить аналогично тому, как это сделано в JNI.
В многомерных массивах языка С данные располагаются по строкам, тогда как в многомерных массивах языка Fortran данные располагаются по столбцам. В языке Fortran есть возможность непосредственно работать с частями массива - вырезками и сечениями. В языке С такой возможности нет. Следовательно, методика передачи массивов, реализованная в JNI, не может быть применена для среды Fortran.
В языке Fortran есть общие блоки COMMON. Эти блоки можно размечать по-разному в каждой подпрограмме. Так, например, в одной подпрограмме может быть объявлен массив типа complex размера 100, расположенный в общем блоке /A/, а в другой подпрограмме на этой же памяти, то есть в том же общем блоке /A/, может быть объявлен массив типа real размера 200. Оба массива будут размещаться в памяти, начиная с одного и того же виртуального адреса, данные, которые в нем расположены - одни и те же, однако тип данных разный. В языке С аналогичная возможность может быть реализована посредством использования объявления union. Однако передача данных, расположенных в COMMON блоках, с целью повышения эффективности должна выполняться по схеме, отличной от той, которая реализована в JNI. Однако передача данных, расположенных в COMMON блоках с целью эффективности должна выполняться по схеме, отличной той, которая реализована в JNI для передачи данных, объявленных в union.
Учитывая то, что в реализации связывания подпрограмм, написанных на языке Fortran, с Java окружением должна быть сделана эффективная передача данных между Fortran-подпрограммами и основным Java-модулем, а так же принимая во внимание отличия языков С и Fortran, можно сделать вывод о том, что организация связывания между виртуальной машиной Java и подпрограммами, реализованными на языке Fortran, должна осуществляться по несколько иной схеме, нежели связывание C-методов и виртуальной машины Java.
2. Размещение данных в среде Fortran
Программа, написанная на языке Fortran, допускает использование следующих видов программных единиц: стандартных функций, подпрограмм FUNCTION, подпрограмм SUBROUTINE, операторов - функций, подпрограмм, написанных на других языках программирования, и подпрограмм BLOCK DATA [2].
Формальные параметры языка Fortran передаются обычно по ссылке, за исключением тех случаев, когда параметр не модифицируется в подпрограмме [3]. В языке Fortran имеются средства, позволяющие использовать одну и ту же область памяти для хранения данных, общих для двух или более программных модулей выполняемой программы. Таким средством является общий блок [3]. Значения объектов из общего блока доступны всем программным единицам, в которых этот блок описан [2]. Каждый общий блок обязательно занимает в памяти непрерывный участок. Если некоторый программный модуль содержит несколько объявлений COMMON с одним и тем же именем, то все они рассматриваются как одно объявление и располагаются в памяти непрерывно и последовательно.
Для объявления массивов в языке Fortran существуют специальные предложения спецификации: объявление размерности DIMENSION [3]. Так же массивы могут быть расположены в общих блоках. Массивы, полученные объявлением DIMENSION, представляют собой локальные данные той подпрограммы, внутри которой они описаны.
При вызове подпрограмм, реализованных на языке Fortran, из Java окружения необходимо передавать данные из среды Java в среду Fortran. Также может возникнуть необходимость передавать данные из среды Fortran в среду Java, если вызываемая программная единица из среды Fortran - FUNCTION - возвращает значение. Все параметры Java-среда передает только по значению, в среде Java нет методов работы с указателями, а все данные Java-программы расположены в куче.
Любая подпрограмма, реализованная на языке Fortran, может получать данные извне либо как параметры, либо через общие блоки, которые в ней описаны.
Если Fortran-подпрограмма получает данные для обработки через общие блоки, то вызывающая Java-программа должна иметь доступ на запись и чтение к той памяти, в которой эти общие блоки расположены. Такой доступ Java-программе возможно обеспечить, если на памяти, где располагается общий блок, разместить Java-объект. В качестве такого Java-объекта может быть взят прямой буфер класса Buffer, методы работы с которым доступный через пакет java.nio. Для того чтобы получить такой буфер, нужно из Fortran среды передать адрес начала общего блока и его размер. Дальше достаточно создать прямой буфер байтов, адрес начала которого будет совпадать с адресом начала общего блока, а размер будет такой же, как у соответствующего общего блока.
Если Fortran-подпрограмма получает данные для обработки через формальные параметры, то для передачи таких параметров из Java окружения необходимо выделить прямой буфер в Java-окружении, на который передаваемые параметры будут помещены. После того, как передаваемые параметры будут расположены на буфере, Fortran-подпрограмме нужно передавать только адрес этого буфера и смещение в нем, по которому расположен соответствующий параметр.
Возврат данных из функций языка Fortran осуществляется по значению. Для передачи возвращаемого значения функцией языка Fortran в Java-окружении, нужно это значение располагать в той области памяти, которая доступна и Java-окружению, и среде Fortran. Такой областью памяти с точки зрения среды Java может выступать прямой буфер. На нем необходимо выделить место для значения, возвращаемого функцией среды Fortran, и передать смещение в буфере Fortran-функции как параметр. А Fortran-функция запишет по полученному адресу возвращаемое значение.
3. Отображение типов данных языка Java в типы данных языка Fortran
Основные типы языка Java и соответствующие им типы языка Fortran представлены в таблице 1. Данные для таблиц взяты из литературы [4] и [2].
Таблица 1. Отображение примитивных типов языка Java в типы языка Fortran.
Тип данных языка Java | Требуемый объем памяти | Тип данных языка Fortran |
Int | 4 байт | INTEGER |
Short | 2 байт | INTEGER*2 |
Long | 8 байт | INTEGER*8 |
Byte | 1 байт | CHARACTER |
Float | 4 байт | REAL |
Double | 8 байт | DOUBLE PRECISION |
Char | 2 байт | CHARACTER |
Boolean | 1 байт | LOGICAL*1 |
Массив языка Java можно отобразить на такое представление данных языка Fortran как массив. Отображение массива языка Java на массив языка Fortran можно сделать через прямой буфер, средства работы с которым предоставлены в пакете "java.nio".