Termrepresentationer
Tillåtna sorter: atomer/booleska värden, godtyckliga heltal, ändliga binary64-flyttal, tupler, äkta/oäkta listor och strängar, maps, bitstrings och vanliga tupel-records; native records (native records); funs (funktionsvärden); lokala pids, portar och referenser (nedan, portar). Ordkodningar finns i abi.md.
Ägarskap
- Sammansatta värden lever i sin processheap (heapkontrakt)
eller i en moduls skrivskyddade literalområde
(områden). Processpekare pekar alltid på början av
ett objekt. Admissionen (endast Debug-byggen; Release litar på ord,
CHECKED_ADMISSION) kontrollerar det ägda intervallet och huvudets form och avvisar främmande adresser och ogiltiga former (admission); sort och utsträckning avkodas från huvudet. - En värd-
Termär exakt ettWord, trivialt kopierbar, med endastvalue_. En heap-Term är giltig till heapens nästa skräpsamling eller processens slut (rötter); den fäster inget och bär varken heap, livstidstoken eller antal skräpsamlingar. Åtkomst läser då flyttat eller frigjort minne och är odefinierad; ingetstale_term-fel finns. Destruktion är säker. Fabriker, reservationer och meddelandebuffertar behåller sina egna livstidskontroller och rapporterar ännuexpired_context. - Konstruktion validerar barn, reserverar, initierar och publicerar sedan i ett steg; vid fel rullas minne och räknare tillbaka.
Term::from_word(word)tillåter endast ägaroberoende omedelbara värden;Term::from_word(word, context)tillåter även atomer och heaptermer från den kontexten. Överlämning inom samma heap behåller identiteten.copy_to/ProcessHeap::addkopierar en graf från en annan process med ett anroparkontrakt om samma runtime; termfabriker vägrar främmande indata medwrong_owner(kopiering mellan heapar).- Celler lever tills en skräpsamling finner dem onåbara, eller tills heapen rivs (skräpsamling).
Atomer
AtomStorageper runtime, internerade vid behov efter exakt UTF-8-stavning, utan normalisering eller borttagning.RuntimeOptions::max_atoms1..2^26, standard 2^20; modul- och exportnamn räknas. Befintliga stavningar lyckas även vid full kapacitet.- Upp till 255 Unicode-skalärer; tom sträng, NUL och supplementära tecken tillåts; felaktig/överlång/surrogat-UTF-8 avvisas.
- Nyttolaster kommer från en räknare för hela processen och återanvänds aldrig, inte heller mellan runtimes. Det globala indexet rymmer 2^28 nummer, begränsat av ordets atomnyttolast på 32-bitarsmål (2^26 identiteter under livstiden). Gränserna per runtime är oförändrade. Atomnummer lämnar aldrig en nod: ETF och diskformat använder stavningar.
detail::atom_tableger låsfria läsningar efter atomnummer: fasta poster direkt, sedan block om 4 096 platser som behålls under processens livstid. VarjeAtomStorageäger sina poster efter stavning, publicerar dem i detta index och godtar endast egna eller fasta poster. Vid nedrivning tas dess platser ur bruk.- Atom-Terms fäster inget.
atom_spelling()lånar fram till runtimens nedrivning; den ochatom_utf8()rapporterarexpired_contextefter att en icke-fast atoms runtime rivits. Att flytta en atom mellan runtimes innebär att dess stavning interneras i målet medan källans runtime lever. - Booleska värden är atomerna
true/false. De fasta atomernafalse,true,undefined,okocherror(abi::v1::fixed_atom_spellings) har orden för atomnummer 0–4 i varje runtime, med odödliga statiska poster, hittas utan låset och räknas varken avsize()eller motmax_atoms; genererad kod använder dem som konstanter. Varje annat atomord är privat för sin runtime. - Sammansatta literaler (strängar, listor, tupler och maps av literaler, flyttal, bignums, konstanta binaries) är modulliteraler: kodade vid kompilering, avkodade en gång per runtime vid registrering till dess literalheap och delade (literalområden); heltalsliteraler i det lilla intervallet är omedelbara värden.
- Andra atomliteraler laddas från modulens atomcache
(
ModuleDescriptor::atom_cache: den anspråkstagande runtimens identitet, sedan ett ord per plats), som den första runtime som registrerar modulen fyller; en kontext varsFrameState::runtimematchar anspråket läser den utan anrop, alla andra anroparCLAUSE_atom_v3. Anspråket lämnas tillbaka när runtimens kodserver släpper modulen. - Runtime-kod i C++ skriver literala atomer som
"name"_atom(atom_names.hpp): en statiskCachedAtomper stavning behåller det ord som senast internerades för den, ochAtomStorage::internreturnerar det efter en låsfri indexläsning när denna runtime utfärdade det och hoppar över validering, det delade låset och stavnings-mapen. Ett ord från en annan eller en nedriven runtime klarar inte kontrollen och ersätts, så att flera runtimes i en process fungerar korrekt (de uppdaterar bara cachen). Hjälpfunktioner för inbyggda funktioner tarAtomName, en stavning med eller utan en sådan cache. - Internering och uppslag är säkra från samtidiga schemaläggararbetare (trådar); en stavning behåller ett ord.
Heltal
- Värden som ryms i målets 28/60-bitars nyttolast är omedelbara värden; större är oföränderliga celler med tecken/belopp. Noll och små värden normaliseras alltid till omedelbara värden. Ingen avsmalning av literaler till värdens bredd.
- Vid
-O2hoppar operander som inferensen bevisar vara små över sina taggtester, och ett bevisat resultatintervall hoppar även över overflow-kontrollen och reservvägen (bevis). - Genererade
+,-,*provar en inline snabbväg för två omedelbara värden, annars anropas runtime-tjänsten:+och-adderar eller subtraherar de taggade orden direkt (a + (b ^ 15)) och faller tillbaka när ordet svämmar över, vilket sker exakt när resultatet lämnar det lilla intervallet;*beräknar med dubbel bredd och explicita gränser. Detsamma görband,bor,bxor,bsr,div,remoch jämförelser av två små heltal (inline-former). - Tjänsten multiplicerar ett bignum (eller en liten produkt som svämmat över) med ett litet heltal limb för limb, från operandens cell direkt till den nya; andra bignum-operationer går via ett värde med godtycklig precision.
divtrunkerar mot noll;remfår dividendens tecken; bitvisa operationer använder oändligt tvåkomplement; negativa skiftantal vänder riktning; enorma högerskift mättas till 0 eller -1.- Fel: felaktiga operander och nolldivisor →
badarith;abs/1→badarg. - Gränser: som i ERTS, ett belopp på högst
BIG_ARITY_MAXord: 4 194 240 bitar på 64-bitarsmål (65 535 ord), 4 194 272 på 32-bitars (131 071 ord); decimal text följer (1 262 593 och 1 262 602 siffror). Ett större aritmetiskt resultat gererror:system_limiti en kropp (ValueOutcome::system_limit, ABI) och får en guard att misslyckas; ett heltalssegment som extraherar ett större värde matchar inte. Kompilatorn avvisar en literal över 4 194 240 bitar (illegal integer, som OTP:s scanner) och ett konstant mönster över gränsen (illegal pattern).
Flyttal
- IEEE binary64-bitar skickas till runtime som åtta byte i nätverksordning; NaN och oändlighet avvisas. Ingen fast-math.
+ - *förblir exakta för två heltal; en flyttalsoperand ger binary64./konverterar alltid båda. Icke-ändliga resultat och nolldivisorer →badarith.float/1avrundar till närmaste jämna;round/1avrundar lika avstånd bort från noll;trunc,floor,ceilreturnerar godtyckliga heltal. Felaktiga operander →badarg.- Exakt likhet skiljer
1från1.0och0.0från-0.0; numerisk jämförelse jämför flyttalets exakta heltalsdel och bråkdel och avrundar aldrig heltalet.min/maxreturnerar den första operanden vid lika värden.
Tupler, listor, strängar
- Tupel: aritetshuvud + fält. Cons: huvud- och svansord.
{}och[]är omedelbara värden. Strängar är listor av kodpunkter. Listor har ingen längdgräns utöver minnet (inklusive en valfri heapbudget). Tupler rymmer upp till 16 777 215 element (MAX_TUPLE_ARITY, OTP:sMAX_ARITYVAL); konstruktorer rapporterar en större somresource_limit; inbyggda funktioner (make_tuple,list_to_tuple/1) gerbadarg. - Tjänster:
hd,tl,length,tuple_size,size, ettbaseradelement.
Maps
- Oföränderliga tabeller sorterade i exakt nyckelordning. Dubblerade nycklar vid
konstruktion behåller det sista värdet. Konstruktion sorterar nycklarna
(O(n log n) jämförelser; redan stigande nycklar kontrolleras bara). Upp till
32 poster är en map en heapcell och en uppdatering infogar med binärsökning i
en kopia; däröver är den ett B+-träd av heapceller som uppdateras genom
sökvägskopiering i O(log n) (map-träd). Ingen
storleks- eller arbetsgräns utöver minnet, som i OTP. Heltals- och
flyttalsnycklar skiljer sig (även
0.0mot-0.0, även nästlat). - Uppdateringar med
K := Vkräver nyckeln;K => Vinfogar eller ersätter. Uppdateringar förbereder en ny tabell och publicerar en gång. - Fel i kroppar:
{badmap, M},{badkey, K}; guards avvisar i stället. - Tjänster:
is_map,map_size,map_get,is_map_key, konstruktion, uppdatering.
Bitstrings
- Packade med mest signifikanta bit först, exakt bitlängd och nollad utfyllnad. Upp till 64 byte lever inline i en heap-binary dimensionerad efter datat; större värden använder en delad oföränderlig buffert utanför heapen, och utsnitt är sub-binary-celler av sitt original (binaries utanför heapen). Det finns ingen storleksgräns utöver en valfri heapbudget för processen; heltalssegment skrivs utan att ett heltal lika brett som segmentet byggs.
- Konstruktion förbereder alla segment före publicering. Heltalssegment trunkeras; inbyggd byteordning kommer från målets datalayout. Ett heltalssegment med ett litet värde och en bredd på högst 64 bitar skrivs från sitt maskinord (hela byte åt gången på en bytegräns); andra tar vägen med godtycklig precision. Genererad kod bygger små konstruktioner med konstant bredd inline (ramar och överföringar).
- Tillägg, som OTP:s skrivbara binaries: en konstruktion som börjar med en hel
binary (
<<Acc/binary, ...>>) på mer än 64 byte bygger sitt resultat i en buffert med extra utrymme (storleken avrundad uppåt till en tvåpotens, minst 256 byte) vars cell utanför heapen i den skapande processen registrerar dess använda bitar och kapacitet (noll i varje annan cell, även kopior). Ett senare tillägg vars ackumulatorvy slutar exakt där skriver de nya byten i det extra utrymmet, som ingen vy täcker, och returnerar en längre vy av samma buffert: en sub-binary av buffertens egen cell utanför heapen, som kan nå bortom den cellens bitar. Varje annan ackumulator (en äldre vy, en annan process, en ojusterad, en full buffert) kopieras en gång till en ny buffert, som minst fördubblar en full buffert. Andra vyer av bufferten ändras aldrig. Frigjorda buffertar återanvänds (buffertåteranvändning). - Flyttalssegment: bredderna 16/32/64; konstruktion kan koda oändlighet, men
matchning avvisar oändliga fält och NaN-fält. Flyttalsmatchningar med bredd
noll extraherar
0.0. - UTF-8/16/32-segment validerar skalärer, surrogat och trunkering.
- Matchning flyttar fram en explicit bitmarkör endast vid lyckat utfall;
:allsom explicit storlek är ogiltigt. - Tjänster:
is_binary,is_bitstring,bit_size,byte_size(avrundar uppåt),size(avrundar nedåt),binary_part/2,3. Fel →badarg.
Records
- Vanliga records expanderas till tupler
{Tag, Fields...}. Deklarationer måste komma före användning; dubbletter, okända fält, framåt-/självreferenser och ogiltiga jokerteckenfält är fel. - Konstruktion utvärderar fält i deklarationsordning: explicit värde, annars
jokerteckenstandard
_ = V, annars deklarerat standardvärde, annarsundefined. Varje standardvärde utvärderas separat vid varje användning. - Mönster kontrollerar aritet och tagg och sedan endast de listade fälten.
#r.fär det ettbaserade indexet (taggen på 1). - Fältåtkomst kontrollerar aritet och tagg; fel ger
{badrecord, V}i kroppar och avvisning i guards. is_record(V, r)använder den deklarerade ariteten.is_record/3kräver en atomtagg och en heltalsaritet (icke-positiv → falskt; fel typer →badarg); en atom som tredje argument är frågan för native records och returnerar falskt. Guards kräver literala argument.- Uppdateringen
Expr#r{f = V, ...}utvärderar de nya värdena i källkodsordning, sedanExpr, kontrollerar därefter aritet och tagg ({badrecord, Value}vid avvikelse, även förExpr#r{}) och bygger en ny tupel; övriga fält kopieras._ = Vavvisas i uppdateringar; uppdateringar är otillåtna i mönster och guards. record_info(fields | size, r)expanderas vid kompilering till listan med fältnamn eller tupelstorleken. Båda argumenten måste vara literala atomer ochrett tupel-record som deklarerats tidigare; det är otillåtet i guards, och en lokalrecord_info/2avvisas som redan definierad.- Native records: native records (lokala, kvalificerade, importerade och anonyma former).
Pids och referenser
self/0 returnerar den anropande processens pid, make_ref/0 en ny referens;
pid_to_list/1 och ref_to_list/1 returnerar deras text.
- En pid är ett omedelbart ord (låga fyra bitar
0x3) som innehåller processens nummer. Nummer kommer från en enda sekvens för hela processen och återanvänds aldrig, så en runtime tillåter ett pid-ord endast om den delat ut det numret: ett förfalskat ord (aldrig utdelat) eller en annan runtimes pid ärwrong_owner. Pid:en för en avslutad process förblir en giltig term, som i OTP. 32-bitarsmål har 2^28 nummer per programkörning, 64-bitarsmål 2^60; att skapa en process bortom dem misslyckas medresource_limit. - En port är ett omedelbart ord (låga fyra bitar
0x7) som innehåller dess nummer från en egen sekvens som aldrig återanvänds, och tillåts som en pid; den skrivs ut som#Port<0.N>och ordnas mellan funs och pids (portar). - En referens är en heapcell (
reference: huvud plus ett ospårat 64-bitars nummer) som tillåts som alla heaptermer: endast i sin egen process, kopieras som värde mellan processer. En orotad värd-Termfår inte läsas efter skräpsamling eller processens slut. Nummer kommer från en räknare för hela processen, så varje referens i en programkörning är unik. - En handtagsreferens (en magisk referens i OTP) är en referenscell som också innehåller en buffert utanför heapen; den är samma referens för varje tjänst och delar sin buffert med varje kopia (handtagsreferenser).
- Utskrift följer OTP:s lokala identiteter: en pid som
<0.N.S>(N de låga 28 bitarna av dess nummer, S resten), en referens som#Ref<0.A.B.C>(C de låga 18 bitarna av dess nummer, B de nästa 32, A resten), i både~w- och display-stil. Pids ordnas efter nummer, referenser efter nummer, så senare referenser i ett program ordnas efter tidigare.
Jämförelse och ordning
Iterativ utan arbetsgräns, som i OTP: endast minnet för väntande par begränsar
en jämförelse, inklusive nyckelsökningar i maps, och identiska ord är lika utan
genomgång. Byte-justerade bitstrings jämför hela byte åt gången. Ordning: tal <
atomer < referenser < funs < portar < pids < tupler < native records < maps <
nil < listor < bitstrings (funs ordnas
sinsemellan).
Atomer jämförs efter UTF-8-stavning (kodpunktsordning); tupler efter aritet och
sedan fält; maps efter storlek, sedan nycklar, sedan värden; bitstrings efter
logiska bitar. Tal (små heltal, flyttal, bignums efter tecken och limbar),
atomer (efter sina stavningar i atomtabellen, via det låsfria nummerindexet),
lokala referenser (efter nummer), binaries med hela byte samt tupler och
listor av dessa nästlade upp till 8 nivåer ordnas direkt från sina ord och
celler (detail::word_order), utan admission av termer; alla andra par, ett
flyttal mot ett bignum med samma bitlängd, eller ett litet heltal bortom 2^53
mot ett flyttal tar den strukturella ordningen. =:= tar samma väg
(detail::word_exact): par som den ordnar olika är olika, och ett ord eller
två referenser som den finner lika är lika, så att en receive som matchar ett
svars referens inte gör någon admission av termer. lists:sort/1 och
lists:usort/1 sorterar elementord på plats: listor med enbart små heltal eller
atomer efter ord eller stavning, andra med en stabil sortering efter
ordjämförelse.
Utskrift
format_term (output.hpp)
återger varje tillåten term i en av två OTP-stilar. Heltal, tupler (records är
tupler) och nästling ser likadana ut i båda.
~w (TermStyle::write) | erlang:display/1 (TermStyle::display) | |
|---|---|---|
| Atomer | Citeras om den inte börjar med en gemen Latin-1-bokstav följd av namntecken (med @); reserverade ord och maybe/else citeras; tecken utanför Latin-1 skrivs som \x{H} | Citeras om den inte börjar med en gemen Latin-1-bokstav följd av alfanumeriska tecken eller _; reserverade ord och @ har ingen specialregel; UTF-8 behålls |
| Flyttal | Kortaste tur-och-retur i OTP:s layout: 0.1, 100.0, 1.0e16, 1.5e-7 | C %.6e: 1.500000e+00 |
| Listor | Element: [104,105], [1,2|3] | En platt lista av utskrivbara Latin-1-byte skrivs som "hi" (råa byte; endast \n och " skyddas) |
| Bitstrings | <<1,2,5:3>> | En utskrivbar ASCII-binary skrivs som <<"hi">>, andra som ~w |
| Maps | #{k => v,k2 => v2} | #{k=>v,k2=>v2} |
- Maps skrivs ut i map-nyckelordning (
maps:iterator(M, ordered), som OTP:s~kw). OTP:s standard-~wocherlang:display/1följer i stället dess interna layout: atomtabellens ordning för atomnycklar i små maps (den varierar mellan VM-körningar) och hashordning över 32 nycklar. Clause återskapar inte den ordningen. - Återgivningen är iterativ, så djupet begränsas endast av termen. Texten är
som standard begränsad till 64 MiB; att överskrida den (till exempel med en
vitt delad delterm) misslyckas med
resource_limitoch returnerar ingen deltext. - Goldens:
runtime_printingjämför båda stilarna med OTP (alla korpusresultat plus författade gränsfall); display-rader vars map-ordning i OTP är intern hoppas över (fixturer).
Clause