
Do tradutor: GraalVM é uma tecnologia nova e interessante, mas no Habré não existem muitos artigos que possam mostrar exemplos dos recursos do Graal. O artigo abaixo não é apenas uma lista do que o GraalVM pode fazer, mas também uma pequena master class semelhante à que Chris Seaton e Oleg Shelaev realizaram no Oracle CodeOne 2018. Seguindo o autor, exorto você a tentar fazer exemplos do artigo, realmente interessante
Existem muitas coisas diferentes no GraalVM , e se você já ouviu esse nome antes, ou mesmo viu relatórios, ainda há muitas coisas que você provavelmente ainda não sabe, mas que o GraalVM pode fazer. Neste artigo, examinaremos os vários recursos que o GraalVM fornece e mostraremos o que você pode fazer com eles.
- Execução rápida de Java
- Diminuir a hora de início e o uso de memória para Java
- Combinando JavaScript, Java, Ruby e R
- Execução de programas escritos em linguagens específicas da plataforma
- Ferramentas comuns para todas as linguagens de programação
- Suplemento de Aplicativo da JVM
- Aplicativos dependentes da plataforma
- Código Java como uma biblioteca específica da plataforma
- Suporte para várias linguagens de programação no banco de dados
- Criando linguagens de programação para GraalVM
Você pode fazer tudo o que é mostrado neste artigo usando o GraalVM 1.0.0 RC1, disponível no link no site do GraalVM . Eu usei o MacOS Enterprise Edition, mas o código escrito aqui funcionará no Linux e no GraalVM Community Edition.
Quando você ler o artigo, execute os programas descritos nele! O código pode ser baixado no GitHub .
Instalação
Após fazer o download em http://graalvm.org/downloads, adicionei o caminho para os executáveis do GraalVM em $PATH
. Por padrão, isso adiciona suporte à execução de Java e JavaScript.
$ git clone https://github.com/chrisseaton/graalvm-ten-things.git $ cd foo $ tar -zxf graalvm-ee-1.0.0-rc1-macos-amd64.tar.gz # or graalvm-ee-1.0.0-rc1-linux-amd64.tar.gz on Linux $ export PATH=graalvm-1.0.0-rc1/Contents/Home/bin:$PATH # or PATH=graalvm-1.0.0-rc1/bin:$PATH on Linux
O GraalVM vem com suporte JavaScript embutido e contém um gerenciador de pacotes chamado gu
que adiciona a capacidade de instalar suporte para idiomas diferentes de Java e JavaScript. Eu também instalei Ruby, Python e R, eles são baixados do GitHub.
$ gu install -c org.graalvm.ruby $ gu install -c org.graalvm.python $ gu install -c org.graalvm.R
Agora, se você executar o comando java
ou js
, verá as versões GraalVM desses mecanismos.
$ java -version java version "1.8.0_161" Java(TM) SE Runtime Environment (build 1.8.0_161-b12) GraalVM 1.0.0-rc1 (build 25.71-b01-internal-jvmci-0.42, mixed mode) $ js --version Graal JavaScript 1.0 (GraalVM 1.0.0-rc1)
1. Execução rápida de Java
"Graal" no GraalVM é o nome do compilador. Somente ele foi criado para governar tudo ! Isso significa que esta é uma implementação de compilador escrita na forma de uma biblioteca que pode ser usada para muitas coisas diferentes. Por exemplo, usamos o Graal para compilar antecipadamente e just-in-time para compilar código escrito em diferentes linguagens de programação, inclusive para diferentes arquiteturas de processador.
A primeira e mais fácil maneira de usar o Graal é usá-lo como um compilador Java JIT.
Como exemplo, usaremos um programa que produz 10 das palavras mais comuns em um documento. O programa usa os recursos da linguagem Java moderna, como Streams e coleções.
import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; public class TopTen { public static void main(String[] args) { Arrays.stream(args) .flatMap(TopTen::fileLines) .flatMap(line -> Arrays.stream(line.split("\\b"))) .map(word -> word.replaceAll("[^a-zA-Z]", "")) .filter(word -> word.length() > 0) .map(word -> word.toLowerCase()) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) .entrySet().stream() .sorted((a, b) -> -a.getValue().compareTo(b.getValue())) .limit(10) .forEach(e -> System.out.format("%s = %d%n", e.getKey(), e.getValue())); } private static Stream<String> fileLines(String path) { try { return Files.lines(Paths.get(path)); } catch (IOException e) { throw new RuntimeException(e); } } }
O GraalVM inclui o compilador javac
, mas não há diferença para esta demonstração, seja para usá-lo ou para o compilador padrão. Portanto, você pode usar o compilador javac
padrão, se desejar.
$ javac TopTen.java
Se executarmos o comando java
, incluído no GraalVM, o compilador Grait JIT será usado automaticamente - nenhuma etapa adicional será necessária. Usarei o comando time
para obter dados reais sobre o tempo gasto na execução do programa do início ao fim, em vez de implantar uma marca de microbench complexa. Uma grande quantidade de entrada também será usada para que não haja insinuações sobre os segundos salvos aqui ou ali. O tamanho do arquivo large.txt
é 150 MB.
$ make large.txt $ time java TopTen large.txt sed = 502701 ut = 392657 in = 377651 et = 352641 id = 317627 eu = 317627 eget = 302621 vel = 300120 a = 287615 sit = 282613 real 0m17.367s user 0m32.355s sys 0m1.456s
Graal é escrito em Java, não em C ++, como a maioria dos outros compiladores JIT para Java. Achamos que isso nos permite melhorá-lo mais rapidamente do que os compiladores existentes, adicionando novas otimizações poderosas (como, por exemplo, análise de escape parcial) que não estão disponíveis no compilador JIT padrão para HotSpot.
E isso pode tornar seus programas Java muito mais rápidos.
Para fins de comparação, para executar programas sem o compilador Grait JIT, usarei o -XX:-UseJVMCICompiler
. JVMCI é a interface entre Graal e a JVM. Você também pode executar o exemplo em uma JVM padrão e comparar os resultados.
$ time java -XX:-UseJVMCICompiler TopTen large.txt sed = 502701 ut = 392657 in = 377651 et = 352641 id = 317627 eu = 317627 eget = 302621 vel = 300120 a = 287615 sit = 282613 real 0m23.511s user 0m24.293s sys 0m0.579s
Este teste mostra que Graal executa nosso programa Java em cerca de três quartos do tempo necessário para executá-lo com o compilador HotSpot padrão. Onde acreditamos que melhorar a produtividade em unidades de porcentagem é uma conquista significativa, 25% é um grande negócio.
Hoje, o Twitter é a única empresa que usa o Graal em servidores de "batalha" , e eles dizem que isso é justificado por eles, em termos de economia de dinheiro real. O Twitter usa o Graal para executar aplicativos escritos no Scala - o Graal funciona no nível de bytecode da JVM, ou seja, aplicável a qualquer idioma da JVM.
Este é o primeiro caso de uso do GraalVM - simplesmente substituindo o compilador JIT por uma versão melhor para seus aplicativos Java existentes.
2. Diminua a hora de início e o uso de memória para Java
Os pontos fortes da plataforma Java são especialmente evidentes ao trabalhar com processos de longa execução e cargas de pico. Os processos de vida curta, por outro lado, sofrem com longos tempos de inicialização e uso de memória relativamente alto.
Por exemplo, se executarmos o aplicativo da seção anterior, alimentando uma quantidade muito menor de dados de entrada - cerca de 1 KB em vez de 150 MB, parece que levará um tempo excessivamente longo e bastante memória - cerca de 60 MB, para processar um arquivo tão pequeno . Usamos a opção -l
para imprimir a quantidade de memória usada, além do tempo de execução.
$ make small.txt $ /usr/bin/time -l java TopTen small.txt # -v on Linux instead of -l sed = 6 sit = 6 amet = 6 mauris = 3 volutpat = 3 vitae = 3 dolor = 3 libero = 3 tempor = 2 suscipit = 2 0.32 real 0.49 user 0.05 sys 59846656 maximum resident set size
O GraalVM nos fornece uma ferramenta que resolve esse problema. Dissemos que o Graal é uma biblioteca de compiladores e pode ser usada de várias maneiras diferentes. Um deles é compilar antecipadamente em uma imagem executável dependente da plataforma, em vez de compilar just in time no tempo de execução. Isso é semelhante ao funcionamento de um compilador comum, como o gcc
.
$ native-image --no-server TopTen classlist: 1,513.82 ms (cap): 2,333.95 ms setup: 3,584.09 ms (typeflow): 4,642.13 ms (objects): 3,073.58 ms (features): 156.34 ms analysis: 8,059.94 ms universe: 353.02 ms (parse): 1,277.02 ms (inline): 1,412.08 ms (compile): 10,337.76 ms compile: 13,776.23 ms image: 2,526.63 ms write: 1,525.03 ms [total]: 31,439.47 ms
Este comando cria um topten
plataforma chamado topten
. Este arquivo não inicia a JVM, não está vinculado à JVM e não inclui a JVM de forma alguma. O comando native-image
compila verdadeiramente seu código Java e as bibliotecas Java usadas no código completo da máquina. Para componentes de tempo de execução, como o coletor de lixo, lançamos nossa própria nova VM chamada SubstrateVM, que, como Graal, também é escrita em Java.
Se você observar as dependências que topten
usa, verá que essas são apenas bibliotecas padrão do sistema. Podemos transferir apenas esse arquivo para um sistema no qual a JVM nunca foi instalada e executá-lo lá para verificar se ele não usa a JVM ou outros arquivos. Topten
também Topten
bem pequeno - o código executável ocupa menos de 6 MB.
$ otool -L topten # ldd topten on Linux topten: .../CoreFoundation.framework ... .../libz.1.dylib ... .../libSystem.B.dylib ... $ du -h topten 5.7M topten
Se executarmos esse executável, veremos que ele inicia uma ordem de magnitude mais rapidamente e usa cerca de uma ordem de magnitude menos memória que o mesmo programa em execução na JVM. O lançamento é tão rápido que você não percebe quanto tempo levou. Se você usar a linha de comando, não sentirá a pausa que normalmente está presente quando você executa um programa pequeno e de curta duração na JVM
$ /usr/bin/time -l ./topten small.txt sed = 6 sit = 6 amet = 6 mauris = 3 volutpat = 3 vitae = 3 dolor = 3 libero = 3 tempor = 2 suscipit = 2 0.02 real 0.00 user 0.00 sys 4702208 maximum resident set size
O utilitário de native-image
tem algumas limitações . Portanto, em tempo de compilação, você deve ter todas as classes presentes, também há restrições no uso da API de reflexão. Mas existem algumas vantagens adicionais sobre a compilação básica, como a execução de inicializadores estáticos em tempo de compilação. Portanto, a quantidade de trabalho realizado sempre que o aplicativo é baixado é reduzida.
Esta é a segunda aplicação do GraalVM - a distribuição e execução de programas Java existentes, com um início rápido e menor consumo de memória. Esse método corrige problemas de configuração, como encontrar o jar certo no tempo de execução, e também permite criar imagens menores do docker.
3. Combinando JavaScript, Java, Ruby e R
Juntamente com o Java, o GraalVM inclui novas implementações dos mecanismos JavaScript, Ruby, R e Python. Eles são escritos usando uma nova estrutura chamada Trufa . Essa estrutura possibilita a criação de intérpretes de linguagem simples e de alto desempenho. Quando você escreve um intérprete de idioma usando o Truffle, ele automaticamente usa o Graal para fornecer compilação JIT para o seu idioma. Portanto, Graal não é apenas um compilador JIT e AOT para Java, mas também pode ser um compilador JIT para JavaScript, Ruby, R e Python.
O suporte a idiomas de terceiros no GraalVM visa ser uma substituição transparente dos mecanismos existentes para a execução de vários idiomas. Por exemplo, podemos instalar o módulo "color" para o Node.js:
$ npm install --global color ... + color@3.0.0 added 6 packages in 14.156s
Em seguida, escreva um programa usando este módulo para converter cores HTML RGB em HSL:
var Color = require('color'); process.argv.slice(2).forEach(function (val) { print(Color(val).hsl().string()); });
E execute-o da maneira usual:
$ node color.js '#42aaf4' hsl(204.89999999999998, 89%, 60.8%)
Os mecanismos de execução de diferentes idiomas no GraalVM trabalham juntos - existe uma API que permite executar o código de um idioma em um programa escrito em outro idioma. E isso permite que você escreva programas multilíngues - programas escritos em mais de uma linguagem de programação.
Isso pode ser necessário se você escrever a maior parte do seu programa em um idioma, mas desejar usar uma biblioteca escrita em outro idioma de programação. Por exemplo, suponha que precisamos escrever um aplicativo para converter um nome de cor de CSS em sua representação numérica no Node.js, mas queremos usar uma biblioteca de cores Ruby em vez de escrever a conversão.
var express = require('express'); var app = express(); color_rgb = Polyglot.eval('ruby', ` require 'color' Color::RGB `); app.get('/css/:name', function (req, res) { color = color_rgb.by_name(req.params.name).html() res.send('<h1 style="color: ' + color + '" >' + color + '</h1>'); }); app.listen(8080, function () { console.log('serving at http://localhost:8080') });
Nesse código, escrevemos que precisamos executar o código Ruby como uma string, mas observe que não fizemos muito aqui - apenas conectamos as bibliotecas e retornamos o objeto Ruby. No Ruby, nós o Color::RGB.by_name (name).html
assim: Color::RGB.by_name (name).html
. Se você observar como o color_rgb
usado posteriormente no JavaScript, verá que na verdade chamamos os mesmos métodos a partir do JavaScript, embora sejam objetos e métodos Ruby. Nós as passamos como strings JavaScript e combinamos o resultado, que é uma string Ruby, com uma string JavaScript.
Instale as duas dependências - Ruby e JavaScript.
$ gem install color Fetching: color-1.8.gem (100%) Successfully installed color-1.8 1 gem installed $ npm install express + express@4.16.2 updated 1 package in 10.393s
Então você precisa iniciar o node
com algumas opções adicionais: --polyglot
, para dizer que precisamos acessar outros idiomas e --jvm
, porque a imagem executável do node
por padrão, não inclui nada além de JavaScript.
$ node --polyglot --jvm color-server.js serving at http://localhost:8080
E, em seguida, acesse o URL http: // localhost: 8080 / css / orange (ou alguma outra cor), como sempre, em seu navegador.

Vamos tentar fazer um exemplo mais sério, que usa mais idiomas e módulos.
O JavaScript não suporta números inteiros muito grandes. Encontrei vários módulos, como o número inteiro grande , mas todos são ineficientes porque armazene os componentes de um número como números de ponto flutuante JavaScript. A classe BigInteger
em Java é mais eficiente, vamos usá-la para fazer algumas operações aritméticas com números inteiros grandes.
O JavaScript também não possui suporte interno para desenhar gráficos, enquanto R desenha excelentemente gráficos. Vamos usar o módulo svg
de R para desenhar um gráfico de dispersão de uma função trigonométrica no espaço 3D.
Nos dois casos, usaremos a API para oferecer suporte ao multilinguismo do GraalVM (doravante denominada API Polyglot) e podemos simplesmente inserir os resultados da execução de programas em outros idiomas no JavaScript.
const express = require('express') const app = express() const BigInteger = Java.type('java.math.BigInteger') app.get('/', function (req, res) { var text = 'Hello World from Graal.js!<br> '
Abra http: // localhost: 3000 / no seu navegador para ver o resultado:

Esta é a terceira coisa que podemos fazer com o GraalVM - execute programas escritos em várias linguagens e use módulos dessas linguagens juntos em um programa. Apresentamos isso como uma maneira de unificar ambientes e bibliotecas de tempo de execução - você pode usar a linguagem de programação que achar melhor para resolver a tarefa atual e qualquer biblioteca que desejar, independentemente da linguagem de programação em que está escrita.
Outra linguagem que o GraalVM suporta é C. O GraalVM pode executar o código C da mesma maneira que executa programas escritos em JavaScript e Ruby.
O que o GraalVM realmente suporta é a execução do código resultante da execução dos utilitários LLVM, ou seja, código de bits, não suporte direto a C. Isso significa que você pode usar as ferramentas existentes para a linguagem C e outras que suportam LLVM, como C ++, Fortran e, potencialmente, mais idiomas no futuro. Para simplificar a demonstração, eu executo uma versão especial do gzip , que é montada em um único arquivo ( Stephen McCamant suporta esta versão). Este é apenas o código-fonte gzip
e a configuração do autoconf
combinados em um arquivo para simplificar. Eu tive que corrigir algumas coisas para fazê-lo funcionar no macOS e com o clang, mas não fiz nada especificamente para oferecer suporte ao GraalVM.
Compilamos o gzip usando o clang
padrão (compilador LLVM para C) e queremos que ele nos torne um código de bits LLVM, e não uma compilação específica da plataforma, porque o GraalVM não o inicia. Estou usando o clang
4.0.1.
$ clang -c -emit-llvm gzip.c
E, em seguida, execute o resultado, diretamente usando o comando lli (interpretador de código de bits LLVM) do GraalVM. Vamos tentar compactar o arquivo usando o meu arquivador do sistema gzip e descompacte-o usando o gzip executado no GraalVM.
$ cat small.txt Lorem ipsum dolor sit amet... $ gzip small.txt $ lli gzip.bc -d small.txt.gz $ cat small.txt Lorem ipsum dolor sit amet...
As implementações Ruby e Python no GraalVM usam a mesma técnica para executar extensões escritas em C para essas linguagens. Isso significa que você pode executar essas extensões dentro da VM e isso nos permite manter alta velocidade de execução, mesmo se usarmos interfaces de extensão específicas da plataforma desatualizadas.
Esta é a quarta maneira de usar o GraalVM - executando programas escritos em linguagens específicas da plataforma, como C ou C ++, além de iniciar extensões para linguagens como Python ou Ruby, que não são capazes de fazer implementações de JVM dessas linguagens, como o JRuby.
5. Ferramentas gerais para todas as linguagens de programação
Se você programa em Java, provavelmente está usando ferramentas de alta qualidade, como IDEs, depuradores e criadores de perfil. Nem todos os idiomas possuem este kit de ferramentas, mas você pode obter um se usar idiomas suportados pelo GraalVM.
O suporte para todas as linguagens no GraalVM (exceto Java, no momento) é implementado usando uma estrutura comum - Truffle. Isso nos permite criar a funcionalidade, por exemplo, um depurador, uma vez e usá-la para todos os idiomas.
Para tentar isso, escreveremos o programa mais simples - o FizzBuzz , porque é visual (imprime algo na tela) e possui ramificações claras que são usadas apenas em algumas iterações. Assim, será mais fácil definir pontos de interrupção. Vamos começar com uma implementação JavaScript.
function fizzbuzz(n) { if ((n % 3 == 0) && (n % 5 == 0)) { return 'FizzBuzz'; } else if (n % 3 == 0) { return 'Fizz'; } else if (n % 5 == 0) { return 'Buzz'; } else { return n; } } for (var n = 1; n <= 20; n++) { print(fizzbuzz(n)); }
Iniciamos o programa como de costume, usando o utilitário js
, no GraalVM.
$ js fizzbuzz.js 1 2 Fizz 4 Buzz Fizz
Também podemos executar o programa com o sinalizador --inspect
. Isso nos dará um link que você pode abrir no Chrome e interromper o programa no depurador.
$ js --inspect fizzbuzz.js Debugger listening on port 9229. To start debugging, open the following URL in Chrome: chrome-devtools://devtools/bundled/inspector.html?ws=127.0.0.1:9229/6c478d4e-1350b196b409
Você pode definir um ponto de interrupção no código do FizzBuzz e continuar a execução. Quando o programa interrompe a execução, veremos o valor da variável n
no depurador e podemos continuar a execução do programa ou estudar a interface do depurador.

O depurador do Chrome é normalmente usado para JavaScript, mas para o GraalVM em JavaScript não há nada diferente de outros idiomas. O sinalizador --inspect
também --inspect
disponível e funciona nas implementações Python, Ruby e R. Não mostrarei a origem de cada programa, mas elas são executadas da mesma maneira e você obtém o mesmo depurador no Chrome para cada um deles.
$ graalpython --jvm --inspect fizzbuzz.py

$ ruby --inspect fizzbuzz.rb

$ Rscript --inspect fizzbuzz.r

Outra ferramenta que você pode estar familiarizado com Java é o VisualVM. Ele fornece uma interface com o usuário através da qual você pode ingressar em uma JVM em execução em sua máquina local ou através de uma rede para inspecionar vários aspectos da execução do programa, como uso de memória ou execução de encadeamento.
O GraalVM inclui o VisualVM como um utilitário jvisualvm
padrão.
$ jvisualvm &> /dev/null &
Se executarmos o VisualVM enquanto o programa TopTen
Java estiver em TopTen
, poderemos observar o uso da memória ou, por exemplo, tirar uma captura instantânea do conteúdo da memória e ver quais tipos de objetos usamos memória no heap.
$ java TopTen large.txt

Eu escrevi este programa em Ruby para gerar algum lixo na memória em tempo de execução.
require 'erb' x = 42 template = ERB.new <<-EOF The value of x is: <%= x %> EOF loop do puts template.result(binding) end
Se você executar a implementação padrão do Ruby na JVM - JRuby, ficará desapontado com o VisualVM porque verá apenas objetos Java internos em vez de objetos em sua linguagem.
Se você usar a versão do Ruby para GraalVM, o VisualVM reconhecerá objetos Ruby. Precisamos usar a opção --jvm
para usar o VisualVM, pois não suporta versões nativas do Ruby.
$ ruby --jvm render.rb
Você pode, se necessário, examinar o instantâneo do heap com objetos Java internos, como vimos anteriormente, ou, na guia Resumo, você pode selecionar o Ruby Heap e ver os objetos reais do Ruby.

A estrutura do Truffle é semelhante ao Nexus para idiomas e ferramentas . Se você criar seu próprio mecanismo de idioma usando o Truffle e criar suas próprias ferramentas, como um depurador, levando em consideração a API Truffle para ferramentas, cada uma dessas ferramentas funcionará em qualquer idioma baseado no Truffle, e você precisará escrevê-lo apenas um vezes.
, GraalVM — , . Truffle GraalVM , VisualVM.
6. JVM
, , , Java . API org.graalvm.polyglot
, .
import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Value; public class ExtendJava { public static void main(String[] args) { String language = "js"; try (Context context = Context.newBuilder().allowNativeAccess(true).build()) { for (String arg: args) { if (arg.startsWith("-")) { language = arg.substring(1); } else { Value v = context.eval(language, arg); System.out.println(v); } } } } }
javac
java
GraalVM, org.graalvm.*
classpath
, .. .
$ javac ExtendJava.java $ java ExtendJava '14 + 2' 16 $ java ExtendJava -js 'Math.sqrt(14)' 3.7416573867739413 $ java ExtendJava -python '[2**n for n in range(0, 8)]' [1, 2, 4, 8, 16, 32, 64, 128] $ java ExtendJava -ruby '[4, 2, 3].sort' [2, 3, 4]
, — , node
ruby
, GraalVM.
GraalVM — Java . Polyglot API “” Java , .
GraalVM , , — , , GraalVM, - . , JavaScript , V8, Python — CPython , .. . GraalVM — Polyglot .
GraalVM, , JavaScript. Polyglot , , :
$ graalvm-1.0.0-rc1/Contents/Home/jre/lib/svm/bin/rebuild-images libpolyglot
C, , , GraalVM, . ExtendJava
, , .
#include <stdlib.h> #include <stdio.h> #include <polyglot_api.h> int main(int argc, char **argv) { graal_isolate_t *isolate = NULL; graal_isolatethread_t *thread = NULL; if (graal_create_isolate(NULL, &isolate) != 0 || (thread = graal_current_thread(isolate)) == NULL) { fprintf(stderr, "initialization error\n"); return 1; } poly_context context = NULL; if (poly_create_context(thread, NULL, 0, &context) != poly_ok) { fprintf(stderr, "initialization error\n"); return 1; } char* language = "js"; for (int n = 1; n < argc; n++) { if (argv[n][0] == '-') { language = &argv[n][1]; } else { poly_value result = NULL; if (poly_context_eval(thread, context, language, "unicalc", argv[n], &result) != poly_ok) { fprintf(stderr, "eval error\n"); return 1; } char buffer[1024]; size_t length; if (poly_value_to_string_utf8(thread, result, buffer, sizeof(buffer), &length) != poly_ok) { fprintf(stderr, "to string error\n"); return 1; } buffer[length] = '\0'; printf("%s\n", buffer); poly_destroy_handle(thread, result); } } return 0; }
, polyglot GraalVM. , , JVM.
$ clang -Igraalvm-1.0.0-rc1/Contents/Home/jre/lib/polyglot / -rpath graalvm-1.0.0-rc1/Contents/Home / -Lgraalvm-1.0.0-rc1/Contents/Home/jre/lib/polyglot / -lpolyglot extendc.c -o extendc $ otool -L extendc extendc: .../libpolyglot.dylib ... .../libSystem.B.dylib ...
$ ./extendc '14 + 2' 16 $ ./extendc -js 'Math.sqrt(14)' 3.7416573867739413 $ ./extendc -python '[2**n for n in range(0, 8)]' [1, 2, 4, 8, 16, 32, 64, 128]
, GraalVM — - , , GraalVM.
Java , , , , - , . Java - , JVM , .
GraalVM Java , , - , . , , Java JVM.
, Apache SIS , ( ) . SIS 0.8, http://sis.apache.org/ jar.
import org.apache.sis.distance.DistanceUtils; public class Distance { public static void main(String[] args) { final double aLat = Double.parseDouble(args[0]); final double aLong = Double.parseDouble(args[1]); final double bLat = Double.parseDouble(args[2]); final double bLong = Double.parseDouble(args[3]); System.out.printf("%.2f km%n", DistanceUtils.getHaversineDistance(aLat, aLong, bLat, bLong)); } public static double distance(IsolateThread thread, double aLat, double aLong, double bLat, double bLong) { return DistanceUtils.getHaversineDistance(aLat, aLong, bLat, bLong); } }
, -
$ javac -cp sis.jar -parameters Distance.java $ java -cp sis.jar:. Distance 51.507222 -0.1275 40.7127 -74.0059 5570.25 km
, topten
.
$ native-image --no-server -cp sis.jar:. Distance ... $ ./distance 51.507222 -0.1275 40.7127 -74.0059 5570.25 km
, . , @CEntryPoint
... import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.c.function.CEntryPoint; public class Distance { ... @CEntryPoint(name = "distance") public static double distance(IsolateThread thread, double a_lat, double a_long, double b_lat, double b_long) { return DistanceUtils.getHaversineDistance(a_lat, a_long, b_lat, b_long); } ... }
javac
, GraalVM API classpath
. C .
$ native-image --no-server -cp sis.jar:. -H:Kind=SHARED_LIBRARY \ -H:Name=libdistance $ otool -L libdistance.dylib # .so on Linux libdistance.dylib: .../libdistance.dylib ... .../CoreFoundation.framework ... .../libz.1.dylib ... .../libSystem.B.dylib ... $ du -h libdistance.dylib 4.8M libdistance.dylib
, . , : VM , , .
#include <stdlib.h> #include <stdio.h> #include <libdistance.h> int main(int argc, char **argv) { graal_isolate_t *isolate = NULL; graal_isolatethread_t *thread = NULL; if (graal_create_isolate(NULL, &isolate) != 0 || (thread = graal_current_thread(isolate)) == NULL) { fprintf(stderr, "initialization error\n"); return 1; } double a_lat = strtod(argv[1], NULL); double a_long = strtod(argv[2], NULL); double b_lat = strtod(argv[3], NULL); double b_long = strtod(argv[4], NULL); printf("%.2f km\n", distance(thread, a_lat, a_long, b_lat, b_long)); return 0; }
, ( LD_LIBRARY_PARTH=.
Linux)
$ clang -I. -L. -ldistance distance.c -o distance $ otool -L distance distance: .../libdistance.dylib ... .../libSystem.B.dylib ... $ ./distance 51.507222 -0.1275 40.7127 -74.0059 5570.25 km
GraalVM — java - , JVM
9.
Polyglot — Oracle. Oracle Database Multilingual Engine (MLE), GraalVM SQL.
, front-end, JavaScript email , JavaScript validator
. - , SQL PL/SQL. , .
MLE Docker :
https://oracle.imtqy.com/oracle-db-mle/releases/0.2.7/docker/
Docker Daemon.
$ docker load --input mle-docker-0.2.7.tar.gz
, Docker, , ( ), Bash .
$ docker run mle-docker-0.2.7 $ docker ps $ docker exec -ti <container_id> bash -li
sqlplus
( SQL ), Bash, , , .
$ sqlplus scott/tiger@localhost:1521/ORCLCDB
, sqlplus
. , Bash Docker, dbjs
, . sqlplus
.
$ npm install validator $ npm install @types/validator $ dbjs deploy -u scott -p tiger -c localhost:1521/ORCLCDB validator $ sqlplus scott/tiger@localhost:1521/ORCLCDB
validator
SQL .
SQL> select validator.isEmail('hello.world@oracle.com') from dual; VALIDATOR.ISEMAIL('HELLO.WORLD@ORACLE.COM') ------------------------------------------- 1 SQL> select validator.isEmail('hello.world') from dual; VALIDATOR.ISEMAIL('HELLO.WORLD') -------------------------------- 0
, GraalVM — , GraalVM, Oracle. , front-end back-end, , , .
10. GraalVM
Oracle Labs JavaScript, R, Ruby, Python C , Truffle, GraalVM.
Truffle — java , (AST). AST — , , , , , . , , Truffle Graal JIT , AST .
Truffle, GraalVM , , DSL. Truffle Graal , , Truffle — GraalVM. , , , , . , , . Oracle labs Ruby , , .
, , , SimpleLanguage — Truffle, JavaScript. , , , , , if .
, Truffle Oracle Labs, SmallTalk , Newspeak Lisp . Lisp , .
Conclusão
GraalVM — , , . , , , , .
GraalVM, http://www.graalvm.org/ . , , .
, , . , GraalVM @ChrisGSeaton @shelajev .
: Oleg Šelajev , Olya Gupalo Doug Simon