Вступ до Project Panama. Частина 3. JEXTRACT

💡 Усі статті, обговорення, новини про Java — в одному місці. Приєднуйтесь до Java спільноти!

Перша та друга частини показують, що Project Panama пропонує чудову структуру (Foreign Function & Memory API), призначену для створення та виклику нативного коду C. У той час як частина перша була здебільшого вступом для нового API, необхідного для роботи із нативним кодом у Java, метою другої частини було заглибитися в аспекти та проблематику представлення нативних варіативних функцій в Java. У цій статті ми ще глибше розглянемо реалізацію варіативної функції, наведеної в Частині 2, а також аспекти реалізації, яку пропонує інструмент генерації коду Project Panama — jextract.

Компіляція

Компілятори Java і C діють по-різному, що обумовлено природою мов програмування (лише компіляція проти компіляції та інтерпретування). Компілятор javac перетворює текст код на байт-код, що виконується JVM, тоді як компілятор C перетворює код на машинну мову. Враховуючи специфіку компіляції нативного коду, зустрічаючи варіативні функції С, компілятор створює новий варіант цієї функції, який повністю відповідає сигнатурі виклику. Це робиться задля того, щоб середовище виконання застосунку розуміло, як саме викликати певну варіативну функцію. Наприклад, для варіативних функцій типу C printf, компілятор створить окрему варіативність функції C printf, яка відповідатиме сигнатурі виклику:

#include <stdio.h>
// printf(const char* s, …);
int main() {
    printf("Hi! My name is %d\n", "Denis");
    printf("Hi! My name is %d. I'm %d years old\n", "Denis", 31);
}

Кожен із цих викликів матиме відповідно власний тип функції:

int(const char*, const char*);
int(const char*, const char*, const int);

У Java ситуація зовсім інша. Vararg-и мають іншу природу походження: вони завжди є масивом певної довжини, де кожен елемент має тип (ширше або вужче визначення):

public int sum(int ... nums) {
    …
}

Ключовою відмінністю від С компіляції варіативних аргументів є те, що компілятор javac створює масив для зберігання даних параметрів. У цьому випадку компілятор створює масив з компонентами загального типу для зберігання аргументів (найзагальніше визначення може бути типу Object[]). Отже, обробка варіативних параметрів у Java — це суто рантайм-функціонал, а в С — лише на етапі компіляції.

С код у Java

Якщо подивитися на реалізацію нативних викликів, наведених у минулих статтях, стає зрозуміло, що процедура написання інфраструктурного коду нативного виклику є тим самим процесом, що робить С компілятор відносно С коду: для кожної комбінації варіативних аргументів необхідно створити спеціалізований варіант застосунку методу (MethodHandle), а Linker, у цьому контексті, діє як компілятор C у Java, у той же час FunctionDescriptor є носієм як типу методу (MethodType), так і очікуваної сигнатури виконання застосунку методу:

static final Linker linker = Linker.nativeLinker();
static final FunctionDescriptor puts$fd = FunctionDescriptor.of(JAVA_INT, ADDRESS);
linker.downcallType(puts$fd); // int(Addressable)

Схоже, що місія Project Panama (Foreign Function & Memory API, зокрема) полягає в тому, щоб дозволити розробникам писати С програми на Java, зберігаючи той самий рівень досвіду програмування, але з необхідністю реалізації інфраструктурного коду нативного виклику, подібно до того, що C компілятор робить проти коду C:

class PrintfImpls {
    static final Linker LINKER = Linker.nativeLinker();
    static final Addressable PRINTF_ADDR = LINKER.defaultLookup().lookup("printf").orElseThrow();
    static MethodHandle specializedPrintf(MemoryLayout... varargLayouts) {
        FunctionDescriptor specialized = PRINTF_BASE_TYPE.asVariadic(varargLayouts);
        return LINKER.downcallHandle(PRINTF_ADDR, specialized);
    }
    
    static final FunctionDescriptor PRINTF_BASE_TYPE = FunctionDescriptor.of(JAVA_INT, ADDRESS);
    public static final MethodHandle WithInt = specializedPrintf(JAVA_INT);
    public static final MethodHandle WithString = specializedPrintf(ADDRESS);
    public static final MethodHandle WithIntAndString = specializedPrintf(JAVA_INT, ADDRESS);
}

Підхід, описаний у Частині 1 і Частині 2, базується на тому факті, що розробник повинен створити екземпляр Linker, дескрипторів функцій та застосунків методів, які відповідають певній функції C (наприклад, C printf у stdio.h). Найбільше занепокоєння викликає те, що розробник зосереджений не на створенні програми, яка використовує нативну функцію, а на тому, щоб витратити деякий час на написання інфраструктурного коду нативних функцій.

Це одна з проблем, яку прагне вирішити Project Panama, впроваджуючи новий інструмент (jextract) для генерації інфраструктурного коду навколо нативних функцій, для того, щоб сфокусуватися на головному обов’язку — написанні програм, які вже використовують нативний код.

jextract

Цікавий факт: новий інструмент генерації коду є першим інструментом коду, який є частиною OpenJDK, але не частиною дистрибутиву. Є кілька причин, чому цей інструмент не є частиною дистрибутива JDK. По-перше, не всі Java розробники працюють з нативним кодом напряму, тому інструмент jextract не для всіх. Друга (і, напевно, найголовніша) причина — це великий розмір самого інструменту. Зазвичай розмір дистрибутиву JDK становить менше 400 Мб, а інструмент jextract сягає майже 180 Мб.

Треба розуміти, що саме jextract є нетиповим рішенням, бо частіше за все сама JDK залежить від інструментів типу javac, javap, jlink і так далі. Але у випадку з jextract ситуація зовсім інша, бо залежність зворотня — jextract залежить від самої JDK, бо використовує Foreign Function & Memory API. А в якості бекенду для обробки С коду використовується libclang (llvm).

libclang

Призначення інструменту jextract — створювати інфраструктурний код Java для нативних символів мови C на основі файлу C-заголовка. Взагалі, libclang відповідає за:

  • переклад вихідного коду C у деякий проміжний стан (також званий «інтерфейсом»),
  • перевести проміжний стан вихідного коду C у машинний код (також називається «back-end», Clang використовує для цього LLVM).

Найголовніше те, що Clang — це не просто компілятор, це також бібліотека, або так званий «С інтерфейс для Clang». Цей функціонал інструмент jextract й використовує, а саме: аналіз C-хедерів для створення інфраструктурного коду на нативних символах (структури, визначення типів, макроси, змінні, функції). Тобто, кожний об’єкт у С-хедері буде мати своє відображення у мовних конструкціях Java.

JDK 19

Інструмент jextact написаний на двох мовах: С та Java. Якщо із С кодом все зрозуміло, то із Java питання відкрите. jextract використовує пакет java.lang.foreign, який містить Foreign Function & Memory API. Але найцікавішим є те, що jextract використовує Foreign Function & Memory API-класи для двох цілей: як для роботи з libclang, так і для моделювання інфраструктурного коду для нативних бібліотек. jextract як уроборос — цей інстурмент використовує сам себе для створення коду для роботи із libclang, який використовується для генерації інфраструктурного коду бібліотек, відносно котрих цей інструмент був застосований. Отже, jextract сам використовує себе, і що це, як не доказ самоконтролю якості коду та функціоналу?

Використання jextract

Найкращий спосіб зрозуміти, що робить інструмент jextract, це подивитися, що він генерує для бібліотеки C stdio.

Інсталяція

Як згадувалося раніше, jextract є першим самостійним інструментом кодогенерації у OpenJDK, який не є частиною дистрибутиву. Це означає, що для початку роботи з інструментом jextract необхідно встановити самі інструменти, дистибутив, доступний за адресою jdk.java.net/jextract. Процес інсталяції схожий на інсталяцію JDK, оскільки дистрибутивний пакет jextract — це не просто один бінарний файл, а JRE, зібране за допомогою jlink з додатковим модулем функціоналу.

Отже, завантажте, розпакуйте та додайте до $PATH. Переконайтеся, що інструмент jextract доступний:

$ jextract --version
jextract 19
JDK version 19-ea+23-1706
clang version 13.0.0

Функціонал

Настав час розібрати можливості jextract. Щоб сгенерувати вихідні Java класи для бібліотеки С, необхідно надати інструменту jextract наступні інструкції:

jextract --source -t com.clang.stdlib.stdio -I /usr/include --output src/main/java /usr/include/stdio.h

Примітка. У macOS C stdlib містить папку (шлях під параметром -I), розташовану тут:

/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include

Наведена вище команда наказує jextract сгенерувати Java класи для /usr/include/stdio.h, базовою папкою інклудів є /usr/include, отримані класи мають бути розміщені в src/main/java в межах пакету com.clang.stdlib.stdio. Зверніть увагу, що такі параметри, як -I (папка з інклудами), є тими самими параметрами, представленими в компіляторі gcc/clang. Параметр -l, не згаданий у команді вище, є комбінацією двох прапорців gcc: -L <каталог> і -l <назва-бібліотеки>, значенням для цього параметра може бути ім’я бібліотеки або її абсолютний шлях.

Вивчення вмісту пакета

У результаті інструмент jextract створить новий пакет Java, що містить класи Java, що охоплюють API бібліотеки C stdio, згаданий у файлі заголовка stdio.h:

src/main/java/com/clang/stdlib/stdio
├── Constants$root.java
├── FILE.java
├── RuntimeHelper.java
├── __darwin_mbstate_t.java
├── __darwin_pthread_attr_t.java
├── __darwin_pthread_cond_t.java
├── __darwin_pthread_condattr_t.java
├── __darwin_pthread_handler_rec.java
├── __darwin_pthread_mutex_t.java
├── __darwin_pthread_mutexattr_t.java
├── __darwin_pthread_once_t.java
├── __darwin_pthread_rwlock_t.java
├── __darwin_pthread_rwlockattr_t.java
├── __mbstate_t.java
├── __sFILE.java
├── __sbuf.java
├── _opaque_pthread_attr_t.java
├── _opaque_pthread_cond_t.java
├── _opaque_pthread_condattr_t.java
├── _opaque_pthread_mutex_t.java
├── _opaque_pthread_mutexattr_t.java
├── _opaque_pthread_once_t.java
├── _opaque_pthread_rwlock_t.java
├── _opaque_pthread_rwlockattr_t.java
├── _opaque_pthread_t.java
├── constants$0.java
...
├── constants$17.java
├── funopen$x0.java
├── funopen$x1.java
├── funopen$x2.java
├── funopen$x3.java
└── stdio_h.java
0 directories, 48 files

Java класи, що містяться у цьому пакеті, відповідатимуть контекту С-хедера stdio.h. Слід врахувати, що за замовчанням цей контент є платформено-залежним, бо місить нативні символи, притаманні платформі macOS, наприклад. Водночас, визначення функцій бібліотеки C stdio є платформено-незалежним.

Характерні властивості пакету:

  • є лише один публічний API класс, який містить Java методи, що є фасадами до нативних викликів
  • кожен нативний символ матиме публічний доступ (структура, функція, макрос і так далі)

Розширені можливості

Як бачите, інструмент jextract генерує багато Java коду для файлу заголовка C stdio.h. Не всі ці файли заголовків можуть знадобитися для виконання конкретної функції C, або взагалі є платформено-специфічними. Щоб перевірити, що саме jextract згенерує для файлу заголовка, він має такий параметр:

--dump-includes <file>         dump included symbols into specified file

Цей параметр накаже jextract створити файл, що містить усі нативні символи, які він потенційно може отримати з файлу заголовка. Щойно створений файл міститиме комбінацію таких значень параметрів:

--header-class-name <name>         
--include-function <name>
--include-enum <name>
--include-macro <name>
--include-struct <name>
--include-typedef <name>
--include-union <name>
--include-var <name>

Використовуючи комбінацію цих параметрів, можна обмежити кількість коду, який може створити jextract. Наприклад, наступна команда створить інфраструктурний код лише для нативної функції C printf:

jextract --source -t com.clang.stdlib.stdio -I /usr/include --output src/main/java --include-function printf /usr/include/stdio.h

Фільтрування допомагає уникнути створення непотрібних Java класів, а також зайвих відображень нативних символів типу як макросів, структур, змінних і типів.

Отже, файл дампа — це файлове сховище для параметрів jextract (типовий концепт для shell), цей файл можна надати за допомогою простого трюку shell — @<file>:

jextract --source -t com.clang.stdlib.stdio -I /usr/include --output src/main/java  @dump.txt /usr/include/stdio.h

Примітка. Дуже важливо знати, що ви робите під час фільтрації, може існувати залежність між компонентами файлу заголовка, як-от типи stdio.h FILE і __sFILE:

typedef struct __sFILE {
….
} FILE;

де нативний символ FILE є аліасом для типу структури sFILE. Виключення одного може призвести до проблем з іншими.

Згенеровані Java класи міститимуть мінімальний код, необхідний для виклику функції C printf, дескриптор функції та застосунок методу:

class constants$0 {
    static final FunctionDescriptor printf$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT,
        Constants$root.C_POINTER$LAYOUT
    );
    static final MethodHandle printf$MH = RuntimeHelper.downcallHandleVariadic(
        "printf",
        constants$0.printf$FUNC
    );
}

а також публічні методи:

public class stdio_h  {
    /* package-private */ stdio_h() {}
    public static MethodHandle printf$MH() {
        return RuntimeHelper.requireNonNull(constants$0.printf$MH,"printf");
    }
    public static int printf ( Addressable x0, Object... x1) {
        var mh$ = printf$MH();
        try {
            return (int)mh$.invokeExact(x0, x1);
        } catch (Throwable ex$) {
            throw new AssertionError("should not reach here", ex$);
        }
    }
}

Трохи висновків

З інструментом jextract шлях від визначення необхідної нативної бібліотеки C до її фактичної інтеграції у Java застосунку набагато коротший, порівняно з підходом, описаним у Частинах 1 і Частина 2. Отже, єдине, за що відповідає розробник, — це нативний розподіл пам’яті та інтеграція функцій.

Обсяг роботи, яку необхідно виконати перед викликом нативної функції, вимагає набагато менше часу та зусиль:

import java.lang.foreign.MemorySession;
import java.lang.foreign.SegmentAllocator;
import com.java_devrel.samples.stdlib.stdio.stdio_h;
public class Printf {
    public static void main(String[] args) {
        try (var memorySession = MemorySession.openConfined()) {
            stdio_h.printf(memorySession.allocateUtf8String(
                    "Welcome from the other side!\n"));
        }
    }
}

Можливість фільтрації допомагає точніше визначити, що саме має бути витягнуто з файлу заголовка. Враховуйте, що інструмент jextract не відстежує залежності поміж нативними символами, наприклад, як функція

 int vfscanf(FILE * __restrict __stream, const char * __restrict __format, va_list) 

залежить від структури FILE. Але створення інфраструктурного коду для vfscanf не призведе до створення JAva представлення структури FILE. Отже, дуже важливо чітко визначити, що саме ви хотіли б отримати в результаті, інструмент jextract — це повторюваний процес кодогенерації, де не відбувається ніякої магії. Іншими словами, або генеруйте усе, або витратьте трохи часу на те, щоб визначитися, які саме нативні символи вам вкрай необхідні, бо jextract працює по моделі «або все, або те, що замовляли».

Як бачите, jextract якісно змінює підхід до кодогенерації Java представлень для нативного коду, тим самим зберігаючи час на відповідне написання цільового коду замість інфраструктурного.

Код

Код для цієї статті доступний тут.

P.S.

Пам’ятайте про те, що Foreign Function & Memory API доступно у режимі Preview. Для того, щоб працювати з цим API:

  • Скомпілюйте програму за допомогою javac --release 19 --enable-preview Main.java та запустіть її за допомогою java --enable-preview Main.
  • Використовуючи програму запуску вихідного коду, запустіть програму з java --source 19 --enable-preview Main.java.
  • Використовуючи jshell, почніть його з jshell --enable-preview.

----

dev.java | inside.java | Java on YouTube | Java on Twitter | Me on Twitter

Сподобалась стаття? Підписуйтесь на автора, щоб отримувати сповіщення про нові публікації на пошту.

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Десь у підвалах Oracle є спеціальна секретна локація, де релійний орден Бюрократистів (діє з 1899) впродовж дванадцяти років змалечку готує технікал райтерів. Їх тренують писати так, щоб видавати максимум інформації, якою ніхто не зможе скористатися. Якщо хтось зміг — такого писаку усипляють перепрошивають на юриста, а вже тоді усипляють (бо їх не жалко).

Якщо серйозно, ти пропустив частину 0 та «-1». А саме:
0) Для чого взагалі створили інструмент. І не 1-2 строчки бла-бла-бла, а реально потрібна стаття про типові задачі, вирішувані цим інструментом. Із коротесеньким поясненням, чому не підійшли інші (чи підійшли погано), акцент на слові «чому», і що сталося після. Важливо: це треба пояснювати в картинках, тобто інфографікою, яка дає можливість візуально побачити РОЗМІРИ роботи (наприклад, пропорційно витраченому машиною часу, чи пропорційно реального часу написання типових програм, чи те і інше).
Чому так: ти пишеш для людей. Якщо ти втратив ланку розуміння нішевого інструменту, все інше що в тебе написано — просто мотлох.
Гірше можна зробити тільки знявши відео для ютубчика, ще гірше — виступ на конференції. Бо це по суті зводиться до «дивіться які я знаю розумні слова».

Власне, створення фундаменту розуміння інструменту — важливіше за усі інші розповіді. Бо левова доля IT інструментів просто вмирають через неможливість взагалі зрозуміти, а для чого вони потрібні, як тим користуватися, і коли воно треба.

-1) Юридична частина. Що із цим можна робити, кому за що треба платити, які обмеження матиме кінцевий продукт. Бо мати справу із Ораклом — сам розумієш, бомба сповільненої дії, яка може похоронити увесь проект через якісь пару строчок коду. Оракл має ну дуже неоднозначну репутацію стосовно юридичного лайна, яке закладається у технології розробки. Не в тому проблема, що щось є платним, щось халявним, але в тому, що готовий продукт стає залежним від трактування невідомо якої глибини юридичного болота в невідомо якій юрисдикції.

Далі треба пояснювати (знову ж таки інфографікою), що є типовим продуктом, і які витрати на його дистрибуцію. Бо з нативними продуктами то все зрозуміло: вони працюють під операційну систему, відповідно треба під неї і писати інсталятор чи конфігуратор портейбла. З жабою все ну дууже неоднозначно — жаба сама по собі продукт, який потребує (чи не потребує) постійного оновлення та затикання дір. Те саме з її існуванням в операційній системі — вона все ще сумнівна із точки зору споживання оперативної пам′яті та можливості адаптуватися в життєвому циклі, де окрім неї ще десятки інших програм працюють. Це взагалі і для нативних програм та ще проблема, а от твори Франкенштейна — фактично має всі шанси стати монстром.

Потрібна інфографіка типового споживання готовим процесом в роботі, саме для типової задачі, а не для HelloWorld. Тобто, що йому треба по оперативі, як одне від одного залежать процеси, скільки та яких потрібно, хто і як менеджить їх життєвий цикл. Повторюся, це не на бла-бла-бла питання, а саме на розуміння типового семпла, як це МОЖЕ працювати для конкретної задачі.

Ну і на останок: Чому саме Java? Який саме резон використовувати саме Java аплікуху чи сервіс, що такого під тією жабою є типовою задачею, можеш привести кілька прикладів (реальних, не гіпотетичних).
__________________
Технічні питання:
1) Хто врешті решт менеджить пам′ять, JVM чи інший збирач сміття? Як це виглядає у життєвому циклі? Потрібне пояснення не просто інфографікою, а із розумінням співвідносних масштабів, тобто велике має бути великим, маленьке малим.
2) Своп. Що буде, коли процес залітає у своп, нехай і невеличкою частиною? Це взагалі-то нормальне явище для процесів із довгим життєвим циклом. Як саме менеджити рідко використовувані об′єкти даних, щоб вони могли безпечно потрапляти у своп із тим щоб їх не витягувало звідти при першому ліпшому проході збирача сміття? Можливо відповідь криється у першому питанні — який процес взагалі керує пам′яттю, чи їх кілька окремих?
3) Задача дистрибуції софту. Чи є вже типові моделі, якими саме можуть бути продукти на цьому інструменті? В плані компонентів — як це виглядатиме із точки зору кінцевого отримувача, в тому числі які процеси апдейтів?

PS. Чи продукт є халявним, чи таки в нього є цінник за використання? Чи планується? Бо інструмент виглядає досить нішевим, я б скоріше зрозумів його комерційну розробку, тобто із витратами на підтримку. Чи є кілька моделей/версій/ліцензій? Краще коротко та зрозумілою мовою.

0) Для чого взагалі створили інструмент. І не 1-2 строчки бла-бла-бла, а реально потрібна стаття про типові задачі, вирішувані цим інструментом. Із коротесеньким поясненням, чому не підійшли інші (чи підійшли погано), акцент на слові «чому», і що сталося після. Важливо: це треба пояснювати в картинках, тобто інфографікою, яка дає можливість візуально побачити РОЗМІРИ роботи (наприклад, пропорційно витраченому машиною часу, чи пропорційно реального часу написання типових програм, чи те і інше).
Чому так: ти пишеш для людей. Якщо ти втратив ланку розуміння нішевого інструменту, все інше що в тебе написано — просто мотлох.

Відповім вам як Java-розробник Java-рознобнику: відповідь на це питання полягає в нерозумінні специфіки роботи із нативним кодом. Досить давно, ще починаючи із JDK 1.2, існувала можливість створювати так званий JNI — багатокомпоненту структуру яка складається із C-бібліотеки, хедеру до неї та native Java методів. Проблема полягала у тому, що фокус розробки зсувався у сторону С, ніж Java. Наразі ж, увесь Project Panama переслідує мету залишити розробку у площині Java, ніж C/C++ використовуючи C ABI.

На скільки це краще — покаже час, але сфера застосування вже відома, є дуже багато проектів які прагнуть позбутися JNI, той же Hadoop, Spark, Cassandra. Також є AI/ML фрейморки в яких є C API, то ж створення доступу до них буде ще просішим та повністью сфокусованим у рантаймі JVM.

Гірше можна зробити тільки знявши відео для ютубчика, ще гірше — виступ на конференції. Бо це по суті зводиться до «дивіться які я знаю розумні слова».

Як скажете, ще ніхто не скаржився на мої доповіді та їх якість.

-1) Юридична частина. Що із цим можна робити, кому за що треба платити, які обмеження матиме кінцевий продукт. Бо мати справу із Ораклом — сам розумієш, бомба сповільненої дії, яка може похоронити увесь проект через якісь пару строчок коду. Оракл має ну дуже неоднозначну репутацію стосовно юридичного лайна, яке закладається у технології розробки. Не в тому проблема, що щось є платним, щось халявним, але в тому, що готовий продукт стає залежним від трактування невідомо якої глибини юридичного болота в невідомо якій юрисдикції.

І знов, ваше питання базується на нерозумінні принципів ліцензування Java. Дякую за це, є ще одна тема для статті на DOU. Надам коротку відповідь — інструмент безкоштовний, як і сама OpenJDK.

З жабою все ну дууже неоднозначно — жаба сама по собі продукт, який потребує (чи не потребує) постійного оновлення та затикання дір

Якийсь у вас дивний досвід, якщо честно.

Потрібна інфографіка типового споживання готовим процесом в роботі, саме для типової задачі, а не для HelloWorld. Тобто, що йому треба по оперативі, як одне від одного залежать процеси, скільки та яких потрібно, хто і як менеджить їх життєвий цикл.

Ваше питання дещо натякає на нерозуміння концепції кодогенерації. Ви jextract запускаєте ЛИШЕ ОДИН РАЗ для генерації класів і все, вам не треба мати цей інструмент під рукою увесь час, ба більше того, в рантаймі вам цей інструмент не потрібний.

1) Хто врешті решт менеджить пам′ять, JVM чи інший збирач сміття? Як це виглядає у життєвому циклі?

Про це як раз наступна стаття, яка вийде згодом.

2) Своп. Що буде, коли процес залітає у своп, нехай і невеличкою частиною? Це взагалі-то нормальне явище для процесів із довгим життєвим циклом. Як саме менеджити рідко використовувані об′єкти даних, щоб вони могли безпечно потрапляти у своп із тим щоб їх не витягувало звідти при першому ліпшому проході збирача сміття? Можливо відповідь криється у першому питанні — який процес взагалі керує пам′яттю, чи їх кілька окремих?

Використовуючи нативну пам’ять у JVM ви не потрапите до свопу жодним чином. Якщо пам’яті не можливо виділити скільки треба, то JVM вас про це сповістить через ексепшн.

3) Задача дистрибуції софту. Чи є вже типові моделі, якими саме можуть бути продукти на цьому інструменті? В плані компонентів — як це виглядатиме із точки зору кінцевого отримувача, в тому числі які процеси апдейтів?

Це гарне питання і на нього в мене є відповідь, ось вам посилання на референсний проект github.com/...​-Java-API/libopencv-clang — там є відповіді на всі ващі питання!

PS. Чи продукт є халявним, чи таки в нього є цінник за використання? Чи планується? Бо інструмент виглядає досить нішевим, я б скоріше зрозумів його комерційну розробку, тобто із витратами на підтримку. Чи є кілька моделей/версій/ліцензій? Краще коротко та зрозумілою мовою.

Безкоштовний, перша збірка доступна тут jdk.java.net/jextract

Я так і сказав: десь вас таки навчають говорити незрозумілою мовою. Багато тексту можете. Але відповісти на просте питання ЩО ЦЕ ТАКЕ — майже жоден технічний райтер не здатен. Можу лише припустити, що тих, хто може вийти за рамки паралельного світу бюрократії — згодовують крокодилам.

Як працює Жаба ми знаємо. Інструмент-то був зібраний, щоб змусити працювати так, як вона без нього НЕ працювала. Чому і є неозвученим питання: ЩО ЦЕ ТАКЕ? Хто отримає вигоду і що буде продуктом.

Як я розумію зараз — це просто намагання транслювати нативний код у код на Java, і виконувати вже в рамках JVM? Тобто, всі вигоди роботи саме нативного коду втрачаються, нативний код не працює у нативному середовищі взагалі? Тоді яку мету переслідує проект? І що є його первинним продуктом для перетворення — вже готовий нативний код, чи який-сь сурогат, чи первинний код на С чи CPP?

З JNI все більш-менш зрозуміло, це цілком нативний код, що виконується в нативному середовищі, жаба для нього лише обгортка. А от що таке Panama? Я жодного зрозумілого пояснення не побачив. Не тільки у вас. Просто ще один JNI? Чи обгортка для існуючого JNI?

Я так і сказав: десь вас таки навчають говорити незрозумілою мовою. Багато тексту можете. Але відповісти на просте питання ЩО ЦЕ ТАКЕ — майже жоден технічний райтер не здатен. Можу лише припустити, що тих, хто може вийти за рамки паралельного світу бюрократії — згодовують крокодилам.

Ну, якщо ви не переходили по посиланням і не читали текст, то надам відповіть тут, стисло: jextract — інструмент кодогенерації інфраструктурного коду, який використовується як для виклику нативних функцій (downcall), так і для зворотньої процедури (upcall). До інфраструктурного коду входять наступні компоненти: MethodHandle, VarHandle, Linker, SymbolLookup, FunctionDescriptor.

Хто отримає вигоду і що буде продуктом.

Вигоду отримують розробники економлячи час на написанні коду руками. Вибачте, питання дивне, бо навіть абстрагуючись, відповідь на питання кому вигідна кодогенерація і так зрозумілий.

це просто намагання транслювати нативний код у код на Java, і виконувати вже в рамках JVM?

ніякої трансляції нема, є реалізація концпету ABI.

Тобто, всі вигоди роботи саме нативного коду втрачаються, нативний код не працює у нативному середовищі взагалі?

Знов дивне питання. Результат роботи інструменту — згенеровані Java класи, структура яких відповідає С-хедер файлу відносно якого ці класи генеруються.

І що є його первинним продуктом для перетворення — вже готовий нативний код, чи який-сь сурогат, чи первинний код на С чи CPP?

Основний ресурс для jextract — С-хедер файл. Далі, як кажуть, дивись C ABI документацію, бо цей концепт працює в усіх мовах програмування написаних на С: C++, Rust, Golang, Node, Python, Java і так далі.

З JNI все більш-менш зрозуміло, це цілком нативний код, що виконується в нативному середовищі

Не вірно. JNI лише складається з нативного коду, Java code та недоступного функціоналу зашитого у JVM який й відповідає за поєднання скомпільованої shared-бібліотеки та рантаймом.

А от що таке Panama?

Project Panama — ініціатива у межах OpenJDK метою якою є концептуально якісно змінити підход до роботи із нативним кодом. У рамках цього проекту реалізується два блоки нових API: Foreign Function & Memory API (реалізація C ABI та керування пам’яттю типу malloc/realloc/calloc) та великого блоку Vectors API (SIMD).

Просто ще один JNI? Чи обгортка для існуючого JNI?

Ніт, ніт і ще раз ніт. Не може бути «ще одного JNI», не може бути й обгортки навкого JNI. Foreign Function & Memory API (частиною якого є jextract) це реалізація концепту C ABI. Якщо в вас виникають питання що таке JNI і чому воно не C ABI, то це стаття не проце.

Питання було — що є продуктом, а не його частинами. В цілому відповідь знайшов у статті одного із ідеологів, це по суті повноцінна реалізація нативного коду, принаймні його насуттєвіших частин, безпосередньо під керуванням JVM без необхідності підтримувати по суті інший продукт написаний на іншій мові зі своїм життєвим циклом.

Якою буде практика інтеграції самої Панами як частини продукту — про те почитаю згодом. Бо зараз усе ще досить сире, інтеграційні частини зазвичай пишуться повноцінними вже на етапі релізу.

Ну і питання було до того, наскільки тяжкою власне для виконання коду є цей інструмент. На жаль, тут інфи мало, пишуть в основному евангелісти, а вони пишуть про «всьо хорошо», а не про те, що є вузькимі місцями та які власне практики співпраці з нативним кодом.

В цілому проект не просто цяця, це брильянт для Java екосистеми, сподіваюся його не профукають. Бо це шанс нарешті зробити жабу — не жабою, а мати під капотом доступ до повноцінного ресурсу операційної системи. І хоча до повноцінності там ще дуже далеко, але принаймні можна висунути носа за межі JVM, не втрачаючи при цьому відносної дешевизни програмування саме на Java для левової долі обслуговуючого коду.

Підписатись на коментарі