# WebAssembly

## Vad det är

WebAssembly, oftast förkortat Wasm, är ett binärt format för körbar kod.
Kärnspecifikationen kallar det ”a safe, portable, low-level code format designed
for efficient execution and compact representation” och beskriver det som en
virtuell instruktionsuppsättning: instruktionerna för en tänkt processor, som en
webbläsare eller en annan värd först kontrollerar och sedan översätter till
maskinkod för den verkliga. Kortformen är en sammandragning och inte en akronym,
och därför skriver specifikationen Wasm och inte WASM.

En `.wasm`-fil är oftast resultatet av en kompilator för något annat språk.
Huvudmålet är enligt specifikationen själv snabba program på webben, men
formatet gör inga antaganden om webben, så det kan också köras som en fristående
virtuell maskin eller inuti andra program. Standarden är skiktad därefter:
kärnspecifikationen definierar instruktionerna, formaten, valideringen och
exekveringen och ingen särskild miljö. Separata dokument definierar
JavaScript-API:t, som kompilerar, länkar och anropar moduler, och webb-API:t,
som hämtar dem över nätverket.

Version 1.0 blev en W3C-rekommendation den 5 december 2019. Version 2.0, som i
allt väsentligt var klar tre år före sin efterföljare, lade till
vektorinstruktioner, massoperationer på minnet, flera returvärden och enkla
referenstyper. Den 17 september 2025 meddelade projektet att version 3.0 nu är
den gällande standarden och att den redan fanns i de flesta stora webbläsare.
Samma meddelande nämner Java, OCaml, Scala, Kotlin, Scheme och Dart bland de
språk som nu kompileras till Wasm med hjälp av dess skräpsamling.

Ordförrådet är litet. Kodens enhet är en modul: den rymmer funktioner, tabeller,
minnen och globala variabler, importerar det den behöver, varje import namngiven
med ett modulnamn och ett elementnamn, och exporterar det den erbjuder under
egna namn. Det finns fyra taltyper, 32- och 64-bitars heltal och flyttal,
skrivna `i32`, `i64`, `f32` och `f64`, plus en enda 128-bitars vektortyp och
ogenomskinliga referenser. Heltalen har inget eget tecken; varje operation läser
dem som antingen med eller utan tecken, och ett 32-bitars heltal fungerar också
som booleskt värde och som minnesadress. Instruktionerna hämtar sina operander
från en implicit stack och lägger tillbaka resultaten på den, och kontrollflödet
är strukturerat: block, loopar och villkor ligger inuti varandra, och ett hopp
kan bara gå till något av dem.

Data ligger i ett linjärt minne, en sammanhängande, skrivbar följd av byte som
börjar i en angiven storlek och kan växa medan programmet körs. En läsning eller
skrivning utanför den aktuella storleken når inget annat. Den utlöser en trap,
som stoppar exekveringen omedelbart, och en trap kan inte hanteras inuti Wasm,
bara rapporteras vidare till värden runt omkring. Exemplet nedan använder det
textformat som specifikationen definierar för att människor ska kunna läsa det.

## Varför det spelar roll

Hastighet är det första skälet. Designmålen kräver prestanda nära inbyggd kod
och ett format som kan avkodas, valideras och kompileras i ett enda snabbt pass,
just in time eller i förväg. Binärformatet ska vara mindre än typiska text- och
maskinkodsformat, och det går att strömma: arbetet kan börja innan den sista
byten har kommit fram. Binärformatet håller till och med varje funktions
typdeklaration i en annan sektion än dess kropp, så att kropparna kan kompileras
parallellt och medan de strömmar in. Ett team som redan har ett vältestat
bibliotek i ett annat språk kan kompilera det för webbläsaren i stället för att
skriva om det i JavaScript.

Portabilitet är det andra. Samma modul körs på alla moderna arkitekturer, på
datorer såväl som mobila enheter, och i varje värd som bäddar in en motor: en
webbläsare, en fristående körmiljö eller ett annat program. Specifikationen
gynnar inget särskilt språk, ingen särskild programmeringsmodell och ingen
särskild objektmodell, så formatet är ett gemensamt mål och inte ett enskilt
språks privata körmiljö.

Avgränsning är det tredje. En modul har ingen omgivande åtkomst till datorn den
körs på. Filer, nätverket, sidan och klockan ligger utom räckhåll om inte värden
ger den en funktion för dem som import, så det är värden som avgör exakt vad
koden får röra. På webben påpekar webb-API:t att Wasm kan köras överallt där
JavaScript kan, har i stort sett samma hotmodell och inte kan exponera mer än
JavaScript redan kunde. Version 3.0 vidgade vad som ryms innanför den gränsen:
minnen som adresseras med 64 bitar, på webben begränsade till 16 gigabyte, flera
minnen i en modul, skräpsamling för språk som förväntar sig det, och undantag
som inte längre behöver fly ut till värden, något som meddelandet kallar varken
portabelt eller effektivt.

## Så ser det ut i praktiken

Här är en modul i textformatet med en enda exporterad funktion som adderar två
32-bitars heltal:

```wat
(module
  (func (export "add") (param i32 i32) (result i32)
    local.get 0
    local.get 1
    i32.add))
```

Funktionens typ säger att den tar två `i32`-värden och returnerar ett. Kroppen
är tre instruktioner på stacken: `local.get 0` lägger på den första parametern,
`local.get 1` den andra, och `i32.add` tar av båda och lägger på summan, som
blir liggande som resultatet. `(export "add")` ger funktionen det namn som
omvärlden ser. Översatt till binärformatet börjar filen med de fyra byten
`0x00 0x61 0x73 0x6D`, en nolla följd av bokstäverna asm, och sedan
binärformatets version, som fortfarande är 1.

I en webbläsare läser JavaScript-API:t in den:

```js
const url = "/add.wasm";
const { instance } = await WebAssembly.instantiateStreaming(fetch(url));
instance.exports.add(2, 3); // 5
instance.exports.add(2147483647, 1); // -2147483648
```

`instantiateStreaming` kompilerar modulen medan svaret fortfarande är på väg och
levererar den kompilerade modulen och en instans av den. Instansens exporter är
vanliga JavaScript-funktioner. Det andra anropet visar vad typerna betyder:
heltalsaddition i Wasm slår runt modulo 2 upphöjt till 32, och JavaScript-API:t
läser ett `i32`-resultat som ett tal med tecken, så ett mer än det största
positiva värdet kommer tillbaka som det mest negativa. Inget kastas. Det gör det
däremot vid en trap: läser en funktion utanför sitt minne slutar anropet i ett
`WebAssembly.RuntimeError`.

En modul som behöver något från sin värd säger det. Med
`(import "env" "log" (func (param i32)))` i modulen behöver instansieringen ett
andra argument, `{ env: { log: console.log } }`, och modulen kan anropa `log`
som en av sina egna funktioner. Utelämna det andra argumentet så misslyckas
instansieringen med ett `TypeError`; skicka ett `env`-objekt utan en anropbar
`log` så misslyckas den med ett `WebAssembly.LinkError`, i båda fallen innan
något av modulens kod har körts. Import och export är hela gränssnittet, och
varje värde som korsar det är en av några få enkla typer; en adress i modulens
minne är bara en `i32`.

[En portföljsida om att bygga en native macOS-klient i Swift 6](/sv/portfolio/built-a-native-macos-client-in-swift-6/)
beskriver det andra sättet att återanvända kod från ett annat språk. I det
arbetet, som gjordes i augusti 2026, länkades en Rust-kärna in i en Swift-app
som ett statiskt arkiv och nåddes genom sitt C-gränssnitt, som sidan behandlar
som kontraktet. En tunn wrapper äger varje pekare och varje sträng som korsar
gränsen, och allt som gränssnittet returnerar har en ägarskapsregel, där ett
misstag ger en läcka eller en krasch utan någon kompilatorvarning. Ingen Wasm är
inblandad där, och det är just det som gör jämförelsen användbar: samma problem
med en smal gräns mellan två språk, löst med inbyggd länkning i stället för en
importlista och ett minne i en sandlåda.

## Var det går fel

**Promiset avvisas innan något har kompilerats.** En saknad `Content-Type`,
eller något annat värde än `application/wasm` oavsett skiftläge, misslyckas med
ett `TypeError`, och specifikationen påpekar att extra parametrar inte är
tillåtna, inte ens ett tomt `application/wasm;`. En status som inte är ok
misslyckas på samma sätt, och det gör också ett svar från ett annat ursprung när
CORS inte gör det till samma ursprung. Rätta serverns medietyp och headers.
`WebAssembly.instantiate` på byte som du själv har hämtat hoppar över kontrollen
av medietypen men förlorar den strömmade kompileringen.

**En vy av minnet slutar fungera.** JavaScript ser en moduls minne genom
`memory.buffer` och de arrayer som byggs på den. När minnet växer kopplar
JavaScript-API:t loss en buffert med fast längd och ersätter den med en ny, så
arrayer byggda på den gamla bufferten är avskurna från minnet. Det händer efter
`memory.grow()` anropat från JavaScript och också efter en
`memory.grow`-instruktion inuti modulen, under ett anrop som utifrån ser
harmlöst ut. Skapa vyer från `memory.buffer` på nytt efter varje anrop som kan
få minnet att växa, i stället för att behålla en under hela sidans livstid.

**Att vänta sig att Wasm når sidan på egen hand.** En modul har ingen omgivande
åtkomst till något, så varje effekt på sidan, nätverket eller lagringen går
genom en funktion som JavaScript ger den som import. Typerna biter vid samma
gräns: en `i64` korsar som en `BigInt`, inte som ett tal, och en funktion med en
`v128`-parameter eller ett `v128`-returvärde kastar ett `TypeError` varje gång
JavaScript anropar den. Utforma import- och exportlistan som ett gränssnitt med
enkla tal, och håll vektorerna på Wasm-sidan.

**Att ta sandlådan för ett säkert program.** Sandlådan skyddar värden mot
modulen. Den skyddar inte modulen mot sig själv. Specifikationen slår fast att
den inte kan hindra ett osäkert språk som kompilerats till Wasm från att
förstöra sin egen minneslayout inuti det linjära minnet: ett
buffertöverskridande i kompilerad kod skriver över modulens egna data, och bara
en åtkomst bortom slutet av hela minnet utlöser en trap. Behåll källspråkets
egna kontroller och tester, och behandla data som modulen tar emot utifrån som
opålitliga.

**Att skicka ut binärfilen utan att skydda den.** Registreringen av
`application/wasm` säger att formatet saknar skydd för integritet och sekretess,
och att sådant skydd, där det behövs, måste komma utifrån, till exempel genom
HTTPS. Liksom för JavaScript begränsas vissa sätt att läsa in och köra den genom
same-origin-policyn eller Content Security Policy. Och eftersom Wasm blir
maskinkod på verklig hårdvara varnar kärnspecifikationen för att det kan vara
sårbart för sidokanalsattacker på hårdvarunivå. Servera moduler över HTTPS, och
vakta vem som får ändra en modul lika noga som vem som får ändra ett skript.

## Läs mer

- [WebAssembly Specification](https://webassembly.github.io/spec/core/)
  — kärnspecifikationen för version 3.0: struktur, validering, exekvering och
  binär- och textformatet.
- [Introduction](https://webassembly.github.io/spec/core/intro/introduction.html)
  — definitionen, designmålen, vad varje dokument täcker och
  säkerhetsövervägandena.
- [WebAssembly JavaScript Interface](https://webassembly.github.io/spec/js-api/)
  — kompilering och instansiering från JavaScript, hur värden korsar gränsen,
  `Memory.grow` och de tre felklasserna.
- [WebAssembly Web API](https://webassembly.github.io/spec/web-api/)
  — `instantiateStreaming`, kontrollerna av svaret och registreringen av
  `application/wasm`.
- [Wasm 3.0 Completed](https://webassembly.org/news/2025-09-17-wasm-3.0/)
  — meddelandet från den 17 september 2025 och vad version 3.0 lägger till.
- [WebAssembly Core Specification 1.0](https://www.w3.org/TR/wasm-core-1/)
  — W3C-rekommendationen från den 5 december 2019.

<https://engineer.company/sv/glossary/webassembly/>
