Os compiladores no navegador executam seu código dentro da própria página, usando WebAssembly: um formato binário compacto e isolado (sandbox) que os navegadores traduzem em código de máquina rápido. Compiladores e interpretadores de verdade, como Clang, CPython, R e SQLite, são eles mesmos compilados para WebAssembly, baixados uma única vez e então compilam ou executam seu programa no seu próprio dispositivo, sem enviar nada a um servidor. Os compiladores online tradicionais funcionam ao contrário: enviam seu código a um servidor que o executa e devolve a saída.
- O WebAssembly é um alvo de compilação portátil que todos os principais navegadores executam em velocidades próximas à do código nativo, dentro do mesmo sandbox de segurança do JavaScript.
- Nossos compiladores de C e C++ rodam o Clang na aba: ele transforma seu código em um módulo WebAssembly, que depois é executado com uma pequena camada WASI que fornece entrada e saída.
- Python, R, SQL, Ruby, PHP, Lua e Prolog rodam como versões em WebAssembly de seus interpretadores oficiais; as linguagens da família JavaScript usam o próprio motor do navegador.
- Rodar localmente significa privacidade, nenhuma fila no servidor e uso offline depois que o runtime está em cache.
- As desvantagens são um download inicial único, ausência de threads e de sockets de rede, um sistema de arquivos temporário na memória e, em nossa versão de C++, ausência de exceções.
O que é o WebAssembly
O WebAssembly (muitas vezes abreviado como Wasm) é um formato de instruções de baixo nível criado para ser um alvo de compilação. Em geral você não o escreve à mão. Em vez disso, um compilador como o Clang ou o compilador do Rust gera um arquivo .wasm a partir de código-fonte comum, do mesmo modo que geraria um executável para um processador x86 ou ARM. O formato é um padrão aberto desenvolvido no W3C, documentado em webassembly.org e compatível com Chrome, Edge, Firefox e Safari.
Três propriedades o tornam útil para executar código em um navegador:
- Portátil. O mesmo arquivo
.wasmroda em Windows, macOS, Linux, Android e iOS, em qualquer processador, porque o navegador o traduz para o código de máquina local. - Rápido. O WebAssembly é tipado e próximo do hardware, então os motores dos navegadores podem compilá-lo antes da execução em código de máquina eficiente. Códigos pesados para a CPU costumam rodar muito mais rápido que o JavaScript equivalente e na mesma faixa geral do código nativo, embora geralmente um pouco mais lentos.
- Isolado (sandbox). Um módulo WebAssembly recebe um bloco de memória privada e só pode chamar as funções que lhe são fornecidas explicitamente. Ele não consegue ler seus arquivos, abrir conexões de rede nem mexer no resto da página, a menos que o código hospedeiro dê uma forma de fazer isso.
WASI: uma interface de sistema para o WebAssembly
Um programa em C espera um sistema operacional: algo de onde ler a entrada padrão, para onde escrever a saída, abrir arquivos e obter a hora. O WebAssembly não traz nada disso embutido. A WebAssembly System Interface (WASI) define um conjunto padrão dessas funções que um programa WebAssembly pode importar. Fora do navegador, runtimes como o Wasmtime implementam a WASI sobre um sistema operacional de verdade. Dentro de um navegador, uma pequena biblioteca JavaScript chamada WASI shim implementa essas funções sobre dados na memória.
Como funcionam os compiladores online tradicionais
A maioria dos compiladores online e sites de exercícios de programação mais antigos executa seu código nos servidores deles:
- Seu navegador envia o código-fonte (e qualquer entrada) ao servidor do site.
- O servidor o coloca em um ambiente isolado, geralmente um contêiner ou uma máquina virtual leve, com limites de tempo, memória e processos.
- O compilador ou interpretador de verdade instalado ali compila e executa o programa.
- A saída é capturada e enviada de volta ao seu navegador, e o ambiente é descartado.
Esse modelo tem vantagens reais. O servidor pode oferecer quase qualquer linguagem e versão, recursos completos do sistema operacional, como threads e processos, e às vezes acesso à rede e bibliotecas grandes. Mas seu código sai do seu dispositivo, serviços muito usados podem enfileirar as requisições, cada execução depende de uma ida e volta pela rede, e o operador precisa pagar pelo poder de processamento a cada execução, e é por isso que muitos limitam as execuções ou exigem uma conta.
Como funcionam nossos compiladores no navegador
Em nossos compiladores online, o runtime de cada linguagem é baixado para o seu navegador e executado dentro de um Web Worker, uma thread em segundo plano que mantém a página responsiva enquanto seu programa roda. Um limite de tempo e um botão Parar permitem que a página encerre o worker se um programa demorar demais, por exemplo por causa de um laço infinito. Os arquivos de runtime são fixados em versões exatas, e a maioria é verificada com um hash criptográfico antes de ser executada.
C e C++: um compilador de verdade na aba
O Compilador C online e o Compilador C++ online usam o Clang 21, o compilador baseado em LLVM, empacotado como WebAssembly pelo projeto YoWASP. Cada execução acontece em duas etapas:
- Compilar. O Clang, rodando ele mesmo como WebAssembly, compila seu
main.coumain.cppcom otimização e avisos ativados (C17 ou C++20). A saída não é um executável x86 ou ARM, mas um novo módulo WebAssembly voltado à WASI. Os avisos e erros do compilador aparecem exatamente como o Clang os imprime. - Executar. O navegador compila esse módulo para código de máquina e o inicia com um WASI shim. O shim liga a entrada padrão ao texto da caixa de entrada e envia a saída padrão e o erro padrão ao painel de saída.
Em outras palavras, um compilador compilado para WebAssembly produz seu programa compilado para WebAssembly, e os dois rodam na mesma aba.
Interpretadores compilados para WebAssembly
| Linguagem | Runtime | O que é |
|---|---|---|
| Python | Pyodide | O CPython, o interpretador de referência do Python, compilado para WebAssembly. Pacotes como NumPy e pandas também já vêm prontos para ele. |
| R | webR | A versão oficial do R em WebAssembly, incluindo os gráficos básicos. |
| SQL | sql.js | O mecanismo de banco de dados SQLite compilado para WebAssembly, com o banco mantido na memória. |
| Ruby | ruby.wasm | O interpretador oficial CRuby compilado para WASI, com sua biblioteca padrão. |
| PHP | php-wasm | O interpretador PHP compilado para WebAssembly. |
| Lua | wasmoon | O interpretador de referência do Lua 5.4 compilado para WebAssembly. |
| Prolog | swipl-wasm | O SWI-Prolog compilado para WebAssembly. |
Como são os mesmos interpretadores que as pessoas instalam nos computadores, o comportamento e as mensagens de erro ficam muito parecidos com os das versões para desktop. Você pode testá-los no Compilador Python online, no Compilador R online e no Compilador SQL online.
Linguagens que usam o próprio motor do navegador
Algumas linguagens não precisam de WebAssembly. O Compilador JavaScript online executa o código diretamente no motor JavaScript do navegador. TypeScript e CoffeeScript são traduzidos para JavaScript por seus compiladores oficiais, distribuídos em JavaScript, e o resultado é então executado da mesma forma. O Scheme usa o BiwaScheme e o Clojure usa o SCI (Small Clojure Interpreter), ambos interpretadores que rodam eles mesmos em JavaScript.
Vantagens de executar código no navegador
- Privacidade. Seu código-fonte e sua entrada ficam no seu dispositivo. Não são enviados, armazenados nem registrados em log pelo nosso servidor, porque o servidor nunca os recebe.
- Sem fila e sem conta. Cada visitante usa o próprio processador, então não há fila de execução compartilhada nem necessidade de racionar as execuções.
- Funciona offline depois de carregar. Quando a página e o runtime foram baixados e colocados em cache, você pode continuar editando e executando código se a conexão cair, desde que a aba continue aberta. Pacotes extras carregados sob demanda, como algumas bibliotecas Python, ainda precisam de conexão na primeira vez.
- Execuções repetidas rápidas. Depois do primeiro carregamento, as linguagens interpretadas iniciam quase instantaneamente, e não há ida e volta pela rede entre apertar Executar e ver a saída.
Limites e desvantagens
| Limite | Por que existe | O que significa na prática |
|---|---|---|
| Tamanho do download | O compilador ou interpretador inteiro precisa chegar ao seu navegador. | Clang, R e Ruby têm dezenas de megabytes; Lua e SQLite têm menos de um. Nas visitas seguintes usa-se o cache do navegador. |
| Sem threads | Nossos runtimes rodam em uma única thread; as threads do WebAssembly exigem configurações extras de isolamento no navegador e suporte no runtime. | pthread, std::thread ou o threading do Python para paralelismo real não funcionarão como em um desktop. |
| Sem sockets de rede | O sandbox não dá aos programas nenhuma forma de abrir conexões de rede brutas. | Códigos que abrem sockets ou fazem requisições HTTP em C, Python ou R vão falhar. O JavaScript do navegador ainda pode usar fetch. |
| Sem sistema de arquivos real | Os runtimes recebem, no máximo, um sistema de arquivos virtual na memória, nunca o seu disco. | Python e alguns outros runtimes podem criar arquivos durante uma sessão, mas eles desaparecem quando a página é fechada; nossos programas em C e C++ só recebem entrada e saída padrão. |
| Sem exceções em C++ | Nossa versão de C++ é compilada com as exceções desativadas (-fno-exceptions). | Códigos que usam try, catch ou throw não compilam; use valores de retorno ou códigos de erro. |
| Memória | O WebAssembly de 32 bits consegue endereçar no máximo 4 GiB, e os navegadores ou dispositivos podem permitir menos. | Arrays ou conjuntos de dados muito grandes podem falhar com erros de falta de memória, principalmente em celulares. |
| A entrada não é interativa | A entrada padrão é fornecida antes de o programa começar. | Digite toda a entrada na caixa de entrada antes; os prompts não podem esperar por você no meio da execução. |
Para aprender, testar algoritmos e fazer trabalhos de curso, esses limites raramente importam. Para programas que precisam de rede, vários processos ou muita memória, use uma instalação local ou um ambiente com servidor.
O modelo de segurança
Executar código arbitrário parece arriscado, mas os compiladores no navegador contam com proteções que os navegadores já aplicam a todos os sites.
- Isolamento do WebAssembly. Um módulo só pode ler e gravar a própria memória linear, que tem os limites verificados, e só pode chamar funções importadas explicitamente para ele. Um programa em C com estouro de buffer pode corromper a própria memória, mas não consegue escapar para o navegador nem para o sistema operacional.
- O sandbox do navegador. Todo o código da página, incluindo WebAssembly e Web Workers, roda dentro do sandbox de processos do navegador e das regras de mesma origem, então não pode ler dados de outros sites nem seus arquivos.
- Workers e limites de tempo. Rodar em um worker significa que um programa descontrolado pode ser encerrado sem travar nem recarregar a página.
- Runtimes verificados. Fixar versões exatas dos runtimes e verificar hashes quando o método de carregamento permite protege contra uma rede de distribuição de conteúdo (CDN) que sirva em silêncio um arquivo diferente ou modificado.
Uma ressalva: o JavaScript que você executa no compilador JavaScript tem as mesmas capacidades de qualquer script de uma página da web, inclusive fazer requisições de rede. Como com qualquer código, execute apenas trechos que você entende, principalmente os copiados de desconhecidos.
Quando usar cada tipo de compilador online
- Se o seu código é privado, por exemplo trabalhos de curso ou código do trabalho, prefira um compilador no navegador para que ele nunca saia do seu dispositivo.
- Se você precisa de threads, sockets, uma biblioteca de sistema específica ou uma linguagem sem versão em WebAssembly, use um serviço com servidor ou uma instalação local.
- Se você está em uma conexão lenta ou limitada, comece pelos runtimes mais leves; o primeiro carregamento de um runtime grande é o principal custo.
Perguntas frequentes
Meu código é enviado a um servidor quando uso seus compiladores online?
Não. A página baixa o compilador ou interpretador, e seu código e sua entrada são compilados e executados no seu próprio dispositivo. O servidor apenas entrega a página e os arquivos do runtime.
O WebAssembly é tão rápido quanto o código nativo?
Geralmente fica próximo, mas um pouco mais lento, e a diferença depende da carga de trabalho e do navegador. Em exercícios e algoritmos típicos a diferença não é perceptível; o download da primeira vez é o atraso maior.
Por que a primeira execução demora mais?
A primeira execução baixa e inicializa o runtime, o que para Clang, R ou Ruby significa dezenas de megabytes. O navegador guarda esses arquivos em cache, então as visitas seguintes começam bem mais rápido.
Por que meu código C++ com try e catch não compila?
Nossa versão de C++ é compilada com as exceções desativadas, porque o tratamento de exceções no WebAssembly exige suporte extra da toolchain e do runtime que esta configuração não usa. Reescreva o tratamento de erros usando valores de retorno, std::optional ou códigos de erro, ou compile localmente se precisar de exceções.
Um programa em um compilador online pode danificar meu computador?
Um código executado como WebAssembly no navegador fica confinado à sua própria memória e às funções que a página fornece, e o sandbox do navegador acrescenta mais uma camada. Ele não consegue ler seus arquivos nem instalar software. O código JavaScript ainda pode fazer requisições web como qualquer script de página, então evite executar códigos em que você não confia.