0Pricing
Java Academy · Aula

Handles de downcall

Chame funções nativas.

Handles de downcall é uma aula grátis de Java Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Java Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Java Academy inclui 4 aulas no total.

Chamando funções nativas

Uma chamada descendente é uma chamada do Java para dentro do código nativo. FFM representa cada função nativa como um MethodHandle criado a partir de um Linker.

Esta lição mostra como encontrar, descrever e invocar uma função C.

O vinculador nativo

Linker.nativeLinker() retorna o vinculador da plataforma em execução. Ele conhece a convenção de chamada C e pode produzir identificadores para funções nativas.

import java.lang.foreign.Linker;

public class Main {
    public static void main(String[] args) {
        Linker linker = Linker.nativeLinker();
        System.out.println("Got native linker: " + linker);
    }
}

Encontrando um símbolo

Você precisa do endereço da função. linker.defaultLookup() pesquisa a biblioteca C padrão; SymbolLookup.libraryLookup(name, arena) carrega uma biblioteca compartilhada específica.

import java.lang.foreign.*;

public class Main {
    public static void main(String[] args) {
        Linker linker = Linker.nativeLinker();
        SymbolLookup stdlib = linker.defaultLookup();
        MemorySegment addr = stdlib.find("strlen").orElseThrow();
        System.out.println("strlen address found: " + addr);
    }
}

Descrevendo a assinatura

Um FunctionDescriptor descreve a assinatura C em termos de descrições. Para size_t strlen(const char*), o retorno é um inteiro longo e o argumento é um ponteiro (ADDRESS).

import java.lang.foreign.*;

public class Main {
    public static void main(String[] args) {
        FunctionDescriptor desc = FunctionDescriptor.of(
            ValueLayout.JAVA_LONG,   // return: size_t
            ValueLayout.ADDRESS);    // arg: const char*
        System.out.println("Descriptor: " + desc);
    }
}

Criando o identificador

Combine o símbolo e a descrição com downcallHandle para obter um MethodHandle que você pode invocar como qualquer método Java.

import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;

public class Main {
    public static void main(String[] args) {
        Linker linker = Linker.nativeLinker();
        MethodHandle strlen = linker.downcallHandle(
            linker.defaultLookup().find("strlen").orElseThrow(),
            FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS));
        System.out.println("Handle ready: " + strlen.type());
    }
}

Invocando a função

Para chamar strlen, passe um ponteiro para uma cadeia de caracteres nativa. Aloque a cadeia em uma arena e depois invoke o identificador. O resultado retorna como um inteiro longo Java.

import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;

public class Main {
    public static void main(String[] args) throws Throwable {
        Linker linker = Linker.nativeLinker();
        MethodHandle strlen = linker.downcallHandle(
            linker.defaultLookup().find("strlen").orElseThrow(),
            FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS));
        try (Arena arena = Arena.ofConfined()) {
            MemorySegment str = arena.allocateUtf8String("Hello, FFM");
            long len = (long) strlen.invoke(str);
            System.out.println("Length = " + len);
        }
    }
}

Mapeando tipos

Cada tipo C corresponde a uma descrição:

  • int para ValueLayout.JAVA_INT
  • long/size_t para JAVA_LONG
  • double para JAVA_DOUBLE
  • qualquer ponteiro para ADDRESS

Fazer essas correspondências corretamente é essencial; caso contrário, a chamada corromperá os dados.

Funções que retornam ponteiros

Quando uma função C retorna um ponteiro, o identificador retorna um MemorySegment de tamanho zero. Para ler além do início, você precisa reinterpretá-lo para o tamanho correto com reinterpret(byteSize).

Passando vários argumentos

FunctionDescriptor.of(returnLayout, arg1, arg2, ...) lista os argumentos na ordem. Para uma função void, use FunctionDescriptor.ofVoid(args...) sem uma descrição de retorno.

import java.lang.foreign.*;

public class Main {
    public static void main(String[] args) {
        // int (*)(const char*, int)
        FunctionDescriptor two = FunctionDescriptor.of(
            ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.JAVA_INT);
        // void (*)(int)
        FunctionDescriptor noReturn = FunctionDescriptor.ofVoid(ValueLayout.JAVA_INT);
        System.out.println(two + " / " + noReturn);
    }
}

Lidando com erros usando uma declaração de exceção

Como MethodHandle.invoke declara throws Throwable, o método que o chama precisa tratar ou declarar isso. É por isso que os exemplos declaram throws Throwable.

Armazenando o identificador em cache

Criar um identificador de chamada descendente é relativamente caro, portanto faça isso uma vez e reutilize-o. Um padrão comum é vincular o identificador a um campo static final durante a inicialização da classe e invocá-lo muitas vezes.

O identificador em si é seguro para chamadas concorrentes.

Verificação rápida

Lembre-se de como um argumento ponteiro C é descrito.

Recapitulação

Você aprendeu a chamar funções nativas:

  • Linker.nativeLinker() junto com um SymbolLookup para encontrar símbolos
  • FunctionDescriptor descreve a assinatura com descrições
  • downcallHandle fornece um MethodHandle que você invoke
  • Ponteiros correspondem a ADDRESS; invoke gera Throwable

A seguir: descrever dados nativos complexos com descrições e estruturas.

Perguntas Frequentes

A aula “Handles de downcall” é grátis?

Sim — o texto completo de “Handles de downcall” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Java Academy, atualize para CoddyKit PRO. O curso de Java Academy inclui 4 aulas no total.

O que vou aprender em “Handles de downcall”?

Chame funções nativas. Você pratica Java Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Java Academy?

Nenhuma experiência prévia é necessária. Java Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Handles de downcall”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Java Academy?

Sim. Cada aula de Java Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Por que FFM em vez de JNI
  2. MemorySegment e Arena
  3. Handles de downcall
  4. Layouts e structs
← Voltar para Java Academy