Come funzionano i compilatori online: codice nel browser

I compilatori nel browser eseguono il tuo codice dentro la pagina web stessa, grazie a WebAssembly: un formato binario compatto e isolato in una sandbox, che i browser traducono in codice macchina veloce. Compilatori e interpreti veri come Clang, CPython, R e SQLite vengono a loro volta compilati in WebAssembly, scaricati una volta sola e poi compilano o eseguono il tuo programma sul tuo dispositivo, senza inviare nulla a un server. I compilatori online tradizionali funzionano al contrario: caricano il tuo codice su un server che lo esegue e ti rimanda l'output.

Punti chiave
  • WebAssembly è un target di compilazione portabile che tutti i principali browser eseguono a velocità vicine a quelle del codice nativo, nella stessa sandbox di sicurezza di JavaScript.
  • I nostri compilatori C e C++ eseguono Clang nella scheda: trasforma il tuo codice in un modulo WebAssembly, che viene poi eseguito con un piccolo livello WASI che fornisce input e output.
  • Python, R, SQL, Ruby, PHP, Lua e Prolog girano come build WebAssembly dei loro interpreti ufficiali; i linguaggi della famiglia JavaScript usano il motore del browser.
  • Eseguire in locale significa privacy, nessuna coda sul server e uso offline una volta che il runtime è nella cache.
  • Il rovescio della medaglia: un download iniziale una tantum, niente thread né socket di rete, un file system temporaneo in memoria e, nella nostra build C++, niente eccezioni.

Che cos'è WebAssembly

WebAssembly (spesso abbreviato in Wasm) è un formato di istruzioni a basso livello pensato come target di compilazione. Di solito non lo si scrive a mano. È un compilatore come Clang, o quello di Rust, a produrre un file .wasm a partire dal normale codice sorgente, proprio come produrrebbe un eseguibile per un processore x86 o ARM. Il formato è uno standard aperto sviluppato dal W3C, documentato su webassembly.org e supportato da Chrome, Edge, Firefox e Safari.

Tre proprietà lo rendono utile per eseguire codice in un browser:

  • Portabile. Lo stesso file .wasm gira su Windows, macOS, Linux, Android e iOS, su qualsiasi processore, perché il browser lo traduce nel codice macchina locale.
  • Veloce. WebAssembly è tipizzato e vicino all'hardware, quindi i motori dei browser possono compilarlo prima dell'esecuzione in codice macchina efficiente. Il codice che sfrutta molto la CPU di solito gira molto più velocemente del JavaScript equivalente e nello stesso ordine di grandezza del codice nativo, anche se in genere un po' più lentamente.
  • Isolato in una sandbox. Un modulo WebAssembly riceve un blocco di memoria privata e può chiamare solo le funzioni che gli vengono date esplicitamente. Non può leggere i tuoi file, aprire connessioni di rete né toccare il resto della pagina, a meno che il codice host non gliene offra un modo.

WASI: un'interfaccia di sistema per WebAssembly

Un programma C si aspetta un sistema operativo: qualcosa da cui leggere lo standard input, su cui scrivere l'output, con cui aprire file e ottenere l'ora. WebAssembly non ha nulla di tutto questo integrato. La WebAssembly System Interface (WASI) definisce un insieme standard di queste funzioni che un programma WebAssembly può importare. Fuori dal browser, runtime come Wasmtime implementano WASI sopra un vero sistema operativo. Dentro un browser, una piccola libreria JavaScript chiamata WASI shim implementa quelle funzioni sopra dati in memoria.

Come funzionano i compilatori online tradizionali

La maggior parte dei compilatori online storici e dei siti di esercizi di programmazione esegue il tuo codice sui propri server:

  1. Il tuo browser invia il codice sorgente (e l'eventuale input) al server del sito.
  2. Il server lo colloca in un ambiente isolato, in genere un container o una macchina virtuale leggera, con limiti di tempo, memoria e processi.
  3. Il vero compilatore o interprete installato lì compila ed esegue il programma.
  4. L'output viene catturato e rimandato al tuo browser, e l'ambiente viene eliminato.

Questo modello ha vantaggi concreti. Il server può offrire quasi qualsiasi linguaggio e versione, tutte le funzioni del sistema operativo come thread e processi e, a volte, accesso alla rete e grandi librerie. Ma il tuo codice lascia il tuo dispositivo, i servizi molto usati possono mettere le richieste in coda, ogni esecuzione dipende da un viaggio di andata e ritorno in rete e il gestore deve pagare la potenza di calcolo per ogni esecuzione, ed è per questo che molti limitano le esecuzioni o richiedono un account.

Come funzionano i nostri compilatori nel browser

Sui nostri compilatori online, il runtime di ogni linguaggio viene scaricato nel tuo browser ed eseguito dentro un Web Worker, un thread in background che mantiene reattiva la pagina mentre il programma gira. Un limite di tempo e un pulsante Interrompi permettono alla pagina di terminare il worker se un programma resta in esecuzione troppo a lungo, per esempio a causa di un ciclo infinito. I file del runtime sono fissati a versioni precise e la maggior parte viene verificata con un hash crittografico prima di essere eseguita.

C e C++: un vero compilatore nella scheda

Il compilatore C e il compilatore C++ usano Clang 21, il compilatore basato su LLVM, pacchettizzato come WebAssembly dal progetto YoWASP. Ogni esecuzione avviene in due fasi:

  1. Compilazione. Clang, che a sua volta gira come WebAssembly, compila il tuo main.c o main.cpp con ottimizzazione e avvisi attivi (C17 o C++20). Il suo output non è un eseguibile x86 o ARM, ma un nuovo modulo WebAssembly destinato a WASI. Avvisi ed errori del compilatore vengono mostrati esattamente come li stampa Clang.
  2. Esecuzione. Il browser compila quel modulo in codice macchina e lo avvia con uno WASI shim. Lo shim collega lo standard input al testo nella casella di input e invia standard output e standard error al pannello di output.

In altre parole, un compilatore compilato in WebAssembly produce il tuo programma compilato in WebAssembly, ed entrambi girano nella stessa scheda.

Interpreti compilati in WebAssembly

LinguaggioRuntimeChe cos'è
PythonPyodideCPython, l'interprete Python di riferimento, compilato in WebAssembly. Per esso sono già pronti anche pacchetti come NumPy e pandas.
RwebRLa build WebAssembly ufficiale di R, inclusa la grafica di base.
SQLsql.jsIl motore di database SQLite compilato in WebAssembly, con il database tenuto in memoria.
Rubyruby.wasmL'interprete ufficiale CRuby compilato per WASI, con la sua libreria standard.
PHPphp-wasmL'interprete PHP compilato in WebAssembly.
LuawasmoonL'interprete Lua 5.4 di riferimento compilato in WebAssembly.
Prologswipl-wasmSWI-Prolog compilato in WebAssembly.

Poiché sono gli stessi interpreti che le persone installano sul proprio computer, comportamento e messaggi di errore corrispondono da vicino a quelli delle versioni desktop. Puoi provarli sul Compilatore Python online, sul Compilatore R online e sul Compilatore SQL online.

Linguaggi che usano il motore del browser

Alcuni linguaggi non hanno bisogno di WebAssembly. Il Compilatore JavaScript online esegue il codice direttamente nel motore JavaScript del browser. TypeScript e CoffeeScript vengono tradotti in JavaScript dai loro compilatori ufficiali, distribuiti come JavaScript, e il risultato viene poi eseguito allo stesso modo. Scheme usa BiwaScheme e Clojure usa SCI (Small Clojure Interpreter), due interpreti che girano a loro volta come JavaScript.

Vantaggi di eseguire il codice nel browser

  • Privacy. Il tuo codice sorgente e il tuo input restano sul tuo dispositivo. Non vengono caricati, archiviati né registrati dal nostro server, perché il server non li riceve mai.
  • Nessuna coda e nessun account. Ogni visitatore usa il proprio processore, quindi non c'è una coda di esecuzione condivisa né bisogno di razionare le esecuzioni.
  • Funziona offline dopo il caricamento. Una volta scaricati e messi nella cache la pagina e il runtime, puoi continuare a modificare ed eseguire codice anche se la connessione cade, finché la scheda resta aperta. I pacchetti aggiuntivi caricati su richiesta, come alcune librerie Python, richiedono comunque una connessione la prima volta.
  • Esecuzioni successive veloci. Dopo il primo caricamento, i linguaggi interpretati partono quasi all'istante e non c'è alcun viaggio di andata e ritorno in rete tra la pressione di Esegui e la comparsa dell'output.

Limiti e compromessi

LimitePerché esisteCosa significa in pratica
Dimensione del downloadL'intero compilatore o interprete deve arrivare al tuo browser.Clang, R e Ruby pesano decine di megabyte; Lua e SQLite meno di uno. Le visite successive usano la cache del browser.
Niente threadI nostri runtime sono a thread singolo; i thread WebAssembly richiedono impostazioni di isolamento aggiuntive del browser e il supporto del runtime.pthread, std::thread o il threading di Python per un vero parallelismo non funzioneranno come su un desktop.
Niente socket di reteLa sandbox non dà ai programmi alcun modo di aprire connessioni di rete grezze.Il codice che apre socket o fa richieste HTTP da C, Python o R fallirà. Il JavaScript del browser può comunque usare fetch.
Nessun vero file systemI runtime ottengono, al massimo, un file system virtuale in memoria, mai il tuo disco.Python e alcuni altri runtime possono creare file durante una sessione, ma spariscono alla chiusura della pagina; i nostri programmi C e C++ hanno solo standard input e output.
Niente eccezioni C++La nostra build C++ è compilata con le eccezioni disattivate (-fno-exceptions).Il codice che usa try, catch o throw non verrà compilato; usa invece valori di ritorno o codici di errore.
MemoriaWebAssembly a 32 bit può indirizzare al massimo 4 GiB, e browser o dispositivi possono consentirne meno.Array o set di dati molto grandi possono fallire con errori di memoria esaurita, soprattutto sugli smartphone.
L'input non è interattivoLo standard input viene fornito prima dell'avvio del programma.Scrivi prima tutto l'input nella casella di input; i prompt non possono aspettare la tua risposta a metà esecuzione.

Per imparare, testare algoritmi e svolgere esercitazioni, questi limiti raramente contano. Per i programmi che richiedono rete, più processi o molta memoria, usa un'installazione locale o un ambiente basato su server.

Il modello di sicurezza

Eseguire codice arbitrario sembra rischioso, ma i compilatori nel browser si affidano a protezioni che i browser applicano già a ogni sito web.

  • Isolamento di WebAssembly. Un modulo può leggere e scrivere solo la propria memoria lineare, controllata nei limiti, e può chiamare solo le funzioni importate esplicitamente al suo interno. Un programma C con un buffer overflow può corrompere la propria memoria, ma non può evadere nel browser o nel sistema operativo.
  • La sandbox del browser. Tutto il codice della pagina, compresi WebAssembly e Web Worker, gira dentro la sandbox di processo del browser e le regole di same-origin, quindi non può leggere i dati di altri siti né i tuoi file.
  • Worker e limiti di tempo. Eseguire in un worker significa che un programma fuori controllo può essere terminato senza bloccare né ricaricare la pagina.
  • Runtime verificati. Fissare le versioni esatte dei runtime e controllare gli hash dove il metodo di caricamento lo consente protegge dal rischio che una content delivery network serva di nascosto un file diverso o modificato.

Un'avvertenza: il JavaScript che esegui nel Compilatore JavaScript online ha le stesse capacità di qualsiasi script in una pagina web, comprese le richieste di rete. Come per qualsiasi codice, esegui solo frammenti che capisci, soprattutto se copiati da sconosciuti.

Quando usare quale tipo di compilatore online

  1. Se il tuo codice è privato, per esempio esercitazioni o codice di lavoro, preferisci un compilatore nel browser, così non lascia mai il tuo dispositivo.
  2. Se ti servono thread, socket, una specifica libreria di sistema o un linguaggio senza build WebAssembly, usa un servizio basato su server o un'installazione locale.
  3. Se hai una connessione lenta o a consumo, parti dai runtime più leggeri; il primo caricamento di uno grande è il costo principale.

Domande frequenti

Il mio codice viene inviato a un server quando uso i vostri compilatori online?

No. La pagina scarica il compilatore o l'interprete, e il tuo codice e il tuo input vengono compilati ed eseguiti sul tuo dispositivo. Il server si limita a consegnare la pagina e i file del runtime.

WebAssembly è veloce quanto il codice nativo?

Di solito gli si avvicina ma è un po' più lento, e il divario dipende dal carico di lavoro e dal browser. Per esercizi e algoritmi tipici la differenza non si nota; il download della prima volta è il ritardo maggiore.

Perché la prima esecuzione richiede più tempo?

La prima esecuzione scarica e inizializza il runtime, che per Clang, R o Ruby significa decine di megabyte. Il browser mette questi file nella cache, quindi le visite successive partono molto più in fretta.

Perché il mio codice C++ con try e catch non viene compilato?

La nostra build C++ è compilata con le eccezioni disattivate, perché la gestione delle eccezioni in WebAssembly richiede un supporto aggiuntivo da toolchain e runtime che questa configurazione non usa. Riscrivi la gestione degli errori usando valori di ritorno, std::optional o codici di errore, oppure compila in locale se ti servono le eccezioni.

Un programma in un compilatore online può danneggiare il mio computer?

Il codice che gira come WebAssembly nel browser è confinato alla propria memoria e alle funzioni fornite dalla pagina, e la sandbox del browser aggiunge un altro livello. Non può leggere i tuoi file né installare software. Il codice JavaScript può comunque fare richieste web come qualsiasi script di pagina, quindi evita di eseguire codice di cui non ti fidi.

Provalo tu stesso

Metti in pratica questa guida con i nostri strumenti gratuiti.

Continua a leggere

Copiato negli appunti