12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018openAst.Binaryletheader="\000asm\001\000\000\000"(*** The input channel and primitive readers ***)typech={filename:stringoption;buf:string;mutablepos:int;limit:int;mutablehas_data_count:bool;diagnostics:Wax_utils.Diagnostic.context;(* Gated encodings actually decoded, recorded via [Feature.mark_used]: the
binary stores no feature declaration, so this is how a caller learns which
optional proposals the module exercises (e.g. to stamp [#![feature]]
attributes on decompiled output). *)features:Wax_utils.Feature.set;}letpositionchpos={Lexing.pos_fname=Option.value~default:"-"ch.filename;pos_lnum=1;pos_bol=0;pos_cnum=pos;}(* Report a diagnostic anchored at byte offset [pos] (default: the current
position) and abort. Used for every malformed-input case, so the parser
never escapes through [assert false]/[failwith]. *)leterror?poschfmt=letstart=matchposwithSomep->p|None->ch.posinletloc_start=positionchstartinletloc_end=positionch(maxch.posstart)inPrintf.ksprintf(funmsg->Wax_utils.Diagnostic.reportch.diagnostics~location:{Ast.loc_start;loc_end}~severity:Error~message:(Wax_utils.Message.textmsg)();Wax_utils.Diagnostic.abort())fmt(* Follow the reference decoder's read order so the diagnostic matches the spec:
the 4 magic bytes, then the 4 version bytes, each preceded by an
end-of-input check. *)letcheck_headerch=ifch.limit<4thenerror~pos:0ch"unexpected end"elseifnot(String.equal(String.subch.buf04)(String.subheader04))thenerror~pos:0ch"magic header not detected"elseifch.limit<8thenerror~pos:4ch"unexpected end"elseifnot(String.equal(String.subch.buf44)(String.subheader44))thenerror~pos:4ch"unknown binary version"letpos_inch=ch.posletseek_inchpos=ch.pos<-posletinput_bytech=letpos=ch.posinifpos>=ch.limitthenerrorch"unexpected end of section or function";ch.pos<-pos+1;Char.codech.buf.[pos]letpeek_bytech=ifch.pos>=ch.limitthenerrorch"unexpected end of section or function";Char.codech.buf.[ch.pos](* Reads a length-prefixed byte range (a name or segment payload); an
overlong length is reported as the spec's "length out of bounds". *)letreally_input_stringchlen=letpos=ch.posin(* Test [len] against the bytes remaining rather than [pos + len > ch.limit]:
[len] is an untrusted decoded length, and the sum could overflow the OCaml
[int] on a 32-bit / js_of_ocaml build. [ch.pos <= ch.limit] always. *)iflen<0||len>ch.limit-posthenerrorch"length out of bounds";ch.pos<-pos+len;String.subch.bufposlen(* On the last permitted byte, a set continuation bit (>= 128) means the
encoding is longer than the type allows ("integer representation too long"),
while extra value bits mean the number is out of range ("integer too
large"). *)letrecuint?(n=5)ch=leti=input_bytechinifn=1thenifi>=128thenerrorch"integer representation too long"elseifi>=16thenerrorch"integer too large";ifi<128thenielsei-128+(uint~n:(n-1)chlsl7)letrecuint64_rec?(n=10)ch=leti=input_bytechinifn=1thenifi>=128thenerrorch"integer representation too long"elseifi>=2thenerrorch"integer too large";ifi<128thenInt64.of_intielseInt64.add(Int64.sub(Int64.of_inti)128L)(Int64.shift_left(uint64_rec~n:(n-1)ch)7)letuint64ch=Wax_utils.Uint64.of_int64(uint64_recch)letrecsint?(n=5)ch=leti=input_bytechinifn=1thenifi>=128thenerrorch"integer representation too long"elseifnot(i<8||(i>120&&i<128))thenerrorch"integer too large";ifi<64thenielseifi<128theni-128elsei-128+(sint~n:(n-1)chlsl7)letrecsint32?(n=5)ch=leti=Int32.of_int(input_bytech)in(ifn=1thenifInt32.comparei128l>=0thenerrorch"integer representation too long"elseletsign_bit=Int32.logandi0x08l<>0linletunused_bits=Int32.logandi0x70linififsign_bitthenunused_bits<>0x70lelseunused_bits<>0lthenerrorch"integer too large");ifInt32.comparei64l<0thenielseifInt32.comparei128l<0thenInt32.subi128lelseInt32.add(Int32.subi128l)(Int32.shift_left(sint32~n:(n-1)ch)7)letrecsint64?(n=10)ch=leti=Int64.of_int(input_bytech)in(ifn=1thenifInt64.comparei128L>=0thenerrorch"integer representation too long"elseletsign_bit=Int64.logandi1L<>0Linletunused_bits=Int64.logandi0x7ELinififsign_bitthenunused_bits<>0x7ELelseunused_bits<>0Lthenerrorch"integer too large");ifInt64.comparei64L<0thenielseifInt64.comparei128L<0thenInt64.subi128LelseInt64.add(Int64.subi128L)(Int64.shift_left(sint64~n:(n-1)ch)7)(* The raw 32 bits of an f32 constant. We keep them as an [int32] rather than
decoding to an OCaml [float]: widening single->double would quiet a signaling
NaN, losing the exact value. *)letfloat32_bitsch=letb1=input_bytechinletb2=input_bytechinletb3=input_bytechinletb4=input_bytechinleti=Int32.of_intb1inleti=Int32.logori(Int32.shift_left(Int32.of_intb2)8)inleti=Int32.logori(Int32.shift_left(Int32.of_intb3)16)inInt32.logori(Int32.shift_left(Int32.of_intb4)24)letfloat64ch=letb1=Int64.of_int(input_bytech)inletb2=Int64.of_int(input_bytech)inletb3=Int64.of_int(input_bytech)inletb4=Int64.of_int(input_bytech)inletb5=Int64.of_int(input_bytech)inletb6=Int64.of_int(input_bytech)inletb7=Int64.of_int(input_bytech)inletb8=Int64.of_int(input_bytech)inleti=b1inleti=Int64.logori(Int64.shift_leftb28)inleti=Int64.logori(Int64.shift_leftb316)inleti=Int64.logori(Int64.shift_leftb424)inleti=Int64.logori(Int64.shift_leftb532)inleti=Int64.logori(Int64.shift_leftb640)inleti=Int64.logori(Int64.shift_leftb748)inInt64.logori(Int64.shift_leftb856)|>Int64.float_of_bitsletrepeatnfch=(* A vector's [n] elements each occupy at least one byte, so a count larger
than the bytes left in the module cannot be satisfied. Reject it before
[Array.init] allocates an [n]-element array, so a bogus huge count (from a
truncated or corrupt binary) is a clean error rather than a memory blow-up. *)ifn>ch.limit-ch.posthenerrorch"length out of bounds";Array.initn(fun_->fch)letvecfch=repeat(uintch)fchletv128ch=really_input_stringch16letnamech=lets=really_input_stringch(uintch)inifnot(String.is_valid_utf_8s)thenerrorch"malformed UTF-8 encoding";s(*** Section framing ***)typesection={id:int;pos:int;size:int}letnext_sectionch=ifpos_inch=ch.limitthenNoneelseletid=input_bytechinletsize=uintchinletpos=pos_inchin(* A section declares its byte length; reject one that runs past the end of
the module (a truncated section) rather than silently parsing whatever
content is present and ignoring the missing bytes. Compare against the
bytes remaining rather than [pos + size]: [size] is untrusted and the sum
could overflow the OCaml [int] on a 32-bit / js_of_ocaml build. *)ifsize>ch.limit-posthenerror~posch"unexpected end";Some{id;pos;size}letskip_section(ch:ch){pos;size;_}=ifch.pos>pos+sizethenerrorch"section size mismatch";seek_inch(pos+size)(*** Type and entity decoding ***)letheaptypech=leti=sintchinmatchi+128with|0x74->NoExn|0x73->NoFunc|0x72->NoExtern|0x71->None_|0x70->Func|0x6F->Extern|0x6E->Any|0x6D->Eq|0x6C->I31|0x6B->Struct|0x6A->Array|0x69->Exn|0x68->Cont|0x75->NoCont(* [exact x]: the index is a u32 that follows the 0x62 tag. *)|0x62->Wax_utils.Feature.mark_usedch.featuresCustom_descriptors;Exact(uintch)|_->ifi<0thenerrorch"unknown heap type %d"i;Typeiletnullabletyp={nullable=true;typ}letref_eq={nullable=false;typ=Eq}letref_i31={nullable=false;typ=I31}letreftypeich=matchiwith|0x74->nullableNoExn|0X73->nullableNoFunc|0x72->nullableNoExtern|0x71->nullableNone_|0x70->nullableFunc|0x6F->nullableExtern|0x6E->nullableAny|0x6D->nullableEq|0x6C->nullableI31|0x6B->nullableStruct|0x6A->nullableArray|0x69->nullableExn|0x68->nullableCont|0x75->nullableNoCont|0x63->nullable(heaptypech)|0x64->{nullable=false;typ=heaptypech}|_->errorch"malformed reference type 0x%02x"iletreftype_first_bytech=reftype(input_bytech)chletref_i31=Refref_i31letref_eq=Refref_eqletvaltypeich=matchiwith|0x7B->V128|0x7C->F64|0x7D->F32|0x7E->I64|0x7F->I32|0x64->(matchpeek_bytechwith|0x6C->ignore(input_bytech);ref_i31|0x6D->ignore(input_bytech);ref_eq|_->Ref{nullable=false;typ=heaptypech})|_->Ref(reftypeich)(* The discriminator is a single byte (the spec reads it as [s7], a one-byte
signed LEB), not an unbounded LEB: an overlong encoding like [ff 00] must be
rejected, not read as its 7-bit value ([0x7f], i.e. [i32]). *)letvaltype_first_bytech=valtype(input_bytech)chletblocktypech=letc=peek_bytechinifc=0x40then(ignore(input_bytech);None)elseifc>0x40&&c<0x80thenSome(Valtype(valtype_first_bytech))elseSome(Typeuse(sintch))letstoragetypech=(* The discriminator is a single byte, as in [valtype_first_byte]: the packed
types share the value-type encoding, so an overlong [ff 00] must be rejected
rather than read as [0x7f] ([i32]). *)leti=input_bytechinmatchiwith|0x78->PackedI8|0x77->PackedI16|_->Value(valtypeich)letfieldtypech=lettyp=storagetypechinletc=input_bytechinletmut=matchcwith0->false|1->true|_->errorch"malformed mutability"in{mut;typ}letcomptypeich=matchiwith|0x5D->(matchheaptypechwith|Typei->Conti|_->errorch"invalid continuation type")|0x5E->Array(fieldtypech)|0x5F->Struct(vecfieldtypech)|0x60->letparams=vecvaltype_first_bytechinletresults=vecvaltype_first_bytechinFunc{params;results}|c->errorch"unknown composite type 0x%02x"cletsupertypech=matchinput_bytechwith|0->None|1->lett=uintchinSomet|_->errorch"malformed sub type"(* The [describes]/[descriptor] clauses (custom-descriptors) wrap the composite
type, [0x4C x] (describes) outermost then [0x4D x] (descriptor); [b] is the
already-read leading byte. *)letdescribed_comptypebch=(* Read the index before the next tag byte: a tuple would leave the order
unspecified (OCaml evaluates it right-to-left). *)letdescribes,b=ifb=0x4Cthenletx=uintchin(Somex,input_bytech)else(None,b)inletdescriptor,b=ifb=0x4Dthenletx=uintchin(Somex,input_bytech)else(None,b)inifdescribes<>None||descriptor<>NonethenWax_utils.Feature.mark_usedch.featuresCustom_descriptors;(describes,descriptor,comptypebch)letsubtypeich=matchiwith|0x50->letsupertype=supertypechinletdescribes,descriptor,typ=described_comptype(input_bytech)chin{final=false;supertype;typ;descriptor;describes}|0x4F->letsupertype=supertypechinletdescribes,descriptor,typ=described_comptype(input_bytech)chin{final=true;supertype;typ;descriptor;describes}|_->letdescribes,descriptor,typ=described_comptypeichin{final=true;supertype=None;typ;descriptor;describes}letrectypech=matchinput_bytechwith|0x4E->vec(funch->subtype(input_bytech)ch)ch|i->[|subtypeich|]lettype_sectionch=letn=uintchinrepeatnrectypechletlimits?(page_size=false)ch=letkind=input_bytechin(* Bit 3 (a custom page size follows) is only valid for a memory. *)ifkind>=ifpage_sizethen16else8thenerrorch"malformed limits flags";letaddress_type=ifkindland4=0then`I32else`I64inletshared=kindland2<>0inletmi=uint64chinletma=ifkindland1=0thenNoneelseSome(uint64ch)inletpage_size_log2=ifkindland8=0thenNoneelseletp=uintchinifp>64thenerrorch"malformed custom page size";Somepin{mi;ma;address_type;page_size_log2;shared}letmemtypech=limits~page_size:truechlettabletypech=letreftype=reftype_first_bytechinletlimits=limitschin{limits;reftype}lettypeidxch=uintchletglobaltypech=lettyp=valtype_first_bytechinletmut=input_bytechinifmut>=2thenerrorch"malformed mutability";{mut=mut<>0;typ}letimportdescchd=matchdwith|0->Func{exact=false;typ=uintch}(* 0x20: an exact function import (bit 6 of the func kind marks exactness). *)|0x20->Wax_utils.Feature.mark_usedch.featuresCustom_descriptors;Func{exact=true;typ=uintch}|1->Table(tabletypech)|2->Memory(memtypech)|3->Global(globaltypech)|4->(* The attribute is a single byte (as in [tag] for the tag section), not an
unbounded LEB: an overlong [80 00] must not read as the required 0. *)letb=input_bytechinifb<>0thenerrorch"malformed tag attribute";Tag(uintch)|_->errorch"malformed import kind 0x%02x"d(* One entry of the import section, kept as an [import_entry] so the compact
grouping survives a round-trip. The compact-import-section proposal reuses the
externtype-kind position: after the module name and a (conventionally empty)
second name, a [0x7F] marker groups a whole [(field name, externtype)] list
under the one module name ([Group1]), and [0x7E] groups a [field name] list
that all share one externtype ([Group2]). Neither marker is a valid kind byte,
so a plain import stays unambiguous. Like every externtype kind, the marker is
a single byte, not an unbounded LEB: an overlong [ff 00] must not read as the
[0x7F] group marker. *)letimport_entrych=letmodule_=namechinletnm=namechin(* A group leaves the field-name position unused, and the proposal fixes it at
the empty name; a group carrying one there would silently lose it. *)letgroup_name_must_be_empty()=ifnm<>""thenerrorch"malformed import group name"inmatchinput_bytechwith|0x7F->group_name_must_be_empty();letitems=Array.to_list(vec(funch->letname=namechin(name,importdescch(input_bytech)))ch)inWax_utils.Feature.mark_usedch.featuresCompact_import_section;Group1{module_;items}|0x7E->group_name_must_be_empty();letdesc=importdescch(input_bytech)inletnames=Array.to_list(vec(funch->namech)ch)inWax_utils.Feature.mark_usedch.featuresCompact_import_section;Group2{module_;desc;names}|d->Single{module_;name=nm;desc=importdescchd}letexportable_kindd:exportable=matchdwith|0->Func|1->Table|2->Memory|3->Global|4->Tag|_->assertfalseletexportch=letexport_name=namechin(* A single byte, like the import kind above. *)letd=input_bytechinifd>4thenerrorch"unknown export description 0x%02x"d;letidx=uintchinletkind=exportable_kinddin{name=export_name;kind;index=idx}letmemargch=(* Binary order is align, then (when align's bit 6 is set) the explicit memory
index, then the offset — read the offset last, after the memory index. *)leta=uintchinletm,a=ifaland0x40<>0then(uintch,alxor0x40)else(0,a)inifa>=64thenerrorch"malformed memop flags";leto=uint64chin(m,{align=Wax_utils.Uint64.of_int(1lsla);offset=o})(* The cast flags byte of a branching cast ([br_on_cast] and its variants)
carries the nullability of the two reference types in bits 0 and 1; the spec
production [castflags] admits only 0..3, so every other bit is reserved and a
nonzero one is malformed (silently masking it would drop information the
encoding states). Returns the two nullability bits, source type first. *)letcastflagsch=letflags=input_bytechinifflagsland0xFC<>0thenerrorch"malformed br_on_cast flags";(flagsland1<>0,flagsland2<>0)(* An instruction, located at the byte range it was decoded from: its
[loc_start.pos_cnum] is the absolute file offset of its opcode, which is what
lets the [metadata.code.…] attach passes match a hint's body-relative offset.
The hints start empty and those passes fill them in. *)letwith_locchposdesc={desc;info={Ast.loc_start=positionchpos;loc_end=positionchch.pos};hints=Hints.none;}(* Consume the [end] opcode (0x0B) that terminates a block or expression. *)letexpect_endch=ifinput_bytech<>0x0Bthenerrorch"END opcode expected"leton_clausech=matchinput_bytechwith|0x00->lettag=uintchinletlabel=uintchinOnLabel(tag,label)|0x01->lettag=uintchinOnSwitchtag|c->errorch"invalid on clause 0x%02x"cletresumetablech=letn=uintchinList.initn(fun_->on_clausech)(*** Instruction decoding ***)letrecinstructionschacc=ifpos_inch=ch.limitthenList.revaccelsematchpeek_bytechwith|0x0B|0x05|0x07|0x18|0x19->List.revacc|_->instructionsch(instructionch::acc)andinstructionch=letpos=ch.posinletop=input_bytechinletdesc=matchopwith|0x00->Unreachable|0x01->Nop|0x02->lettyp=blocktypechinletblock=instructionsch[]inexpect_endch;Block{label=();typ;block=Ast.no_locblock}|0x03->lettyp=blocktypechinletblock=instructionsch[]inexpect_endch;Loop{label=();typ;block=Ast.no_locblock}|0x04->lettyp=blocktypechin(* Give each arm its own byte-offset span (like any decoded
instruction), so a per-arm diagnostic anchors at that arm rather
than at the whole [if] — two arms failing identically would
otherwise render as duplicate reports. An absent [else] keeps
[no_loc]; the validator then falls back to the instruction's span. *)letarm_start=ch.posinletif_block=instructionsch[]inletif_info={Ast.loc_start=positioncharm_start;loc_end=positionchch.pos;}inletelse_block=ifinput_bytech=0x05then(letarm_start=ch.posinletb=instructionsch[]inletinfo={Ast.loc_start=positioncharm_start;loc_end=positionchch.pos;}inexpect_endch;{Ast.desc=b;info})elseAst.no_loc[]inIf{label=();typ;if_block={Ast.desc=if_block;info=if_info};else_block;}|0x06->lettyp=blocktypechinletblock=instructionsch[]inletrecloop_catchescatches=matchinput_bytechwith|0x0B->(List.revcatches,None)|0x07->lettag=uintchinletbody=instructionsch[]inloop_catches((tag,body)::catches)|0x19->letbody=instructionsch[]inexpect_endch;(List.revcatches,Somebody)|0x18->errorch"delegate is not supported"|c->errorch"unexpected opcode 0x%02x in try block"cinletcatches,catch_all=loop_catches[]inTry{label=();typ;block=Ast.no_locblock;catches=List.map(fun(t,b)->(t,Ast.no_locb))catches;catch_all=Option.mapAst.no_loccatch_all;}|0x08->Throw(uintch)|0x0A->ThrowRef|0xE0->ContNew(uintch)|0xE1->leti=uintchinletj=uintchinContBind(i,j)|0xE2->Suspend(uintch)|0xE3->leti=uintchinletclauses=resumetablechinResume(i,clauses)|0xE4->leti=uintchinletj=uintchinletclauses=resumetablechinResumeThrow(i,j,clauses)|0xE5->leti=uintchinletclauses=resumetablechinResumeThrowRef(i,clauses)|0xE6->leti=uintchinletj=uintchinSwitch(i,j)|0x0C->Br(uintch)|0x0D->Br_if(uintch)|0x0E->lettargets=vecuintchinletdefault=uintchinBr_table(Array.to_listtargets,default)|0x0F->Return|0x10->Call(uintch)|0x11->(* Binary order is (type, table); the AST holds (table, type). *)lettype_idx=uintchinlettable=uintchinCallIndirect(table,type_idx)|0x12->ReturnCall(uintch)|0x13->(* Binary order is (type, table); the AST holds (table, type). *)lettype_idx=uintchinlettable=uintchinReturnCallIndirect(table,type_idx)|0x14->CallRef(uintch)|0x15->ReturnCallRef(uintch)|0x1A->Drop|0x1B->SelectNone|0x1C->Select(Some(Array.to_list(vecvaltype_first_bytech)))|0x1F->lettyp=blocktypechinletn=uintchinletcatches=List.initn(fun_->matchinput_bytechwith|0->lett=uintchinletl=uintchinCatch(t,l)|1->lett=uintchinletl=uintchinCatchRef(t,l)|2->letl=uintchinCatchAlll|3->letl=uintchinCatchAllRefl|_->errorch"invalid catch clause")inletblock=instructionsch[]inexpect_endch;TryTable{label=();typ;catches;block=Ast.no_locblock}|0x20->LocalGet(uintch)|0x21->LocalSet(uintch)|0x22->LocalTee(uintch)|0x23->GlobalGet(uintch)|0x24->GlobalSet(uintch)|0x25->TableGet(uintch)|0x26->TableSet(uintch)|0x28->letm,arg=memargchinLoad(m,arg,NumI32)|0x29->letm,arg=memargchinLoad(m,arg,NumI64)|0x2A->letm,arg=memargchinLoad(m,arg,NumF32)|0x2B->letm,arg=memargchinLoad(m,arg,NumF64)|0x2C->letm,arg=memargchinLoadS(m,arg,`I32,`I8,Signed)|0x2D->letm,arg=memargchinLoadS(m,arg,`I32,`I8,Unsigned)|0x2E->letm,arg=memargchinLoadS(m,arg,`I32,`I16,Signed)|0x2F->letm,arg=memargchinLoadS(m,arg,`I32,`I16,Unsigned)|0x30->letm,arg=memargchinLoadS(m,arg,`I64,`I8,Signed)|0x31->letm,arg=memargchinLoadS(m,arg,`I64,`I8,Unsigned)|0x32->letm,arg=memargchinLoadS(m,arg,`I64,`I16,Signed)|0x33->letm,arg=memargchinLoadS(m,arg,`I64,`I16,Unsigned)|0x34->letm,arg=memargchinLoadS(m,arg,`I64,`I32,Signed)|0x35->letm,arg=memargchinLoadS(m,arg,`I64,`I32,Unsigned)|0x36->letm,arg=memargchinStore(m,arg,NumI32)|0x37->letm,arg=memargchinStore(m,arg,NumI64)|0x38->letm,arg=memargchinStore(m,arg,NumF32)|0x39->letm,arg=memargchinStore(m,arg,NumF64)|0x3A->letm,arg=memargchinStoreS(m,arg,`I32,`I8)|0x3B->letm,arg=memargchinStoreS(m,arg,`I32,`I16)|0x3C->letm,arg=memargchinStoreS(m,arg,`I64,`I8)|0x3D->letm,arg=memargchinStoreS(m,arg,`I64,`I16)|0x3E->letm,arg=memargchinStoreS(m,arg,`I64,`I32)|0x3F->MemorySize(uintch)|0x40->MemoryGrow(uintch)|0x41->Const(I32(sint32ch))|0x42->Const(I64(sint64ch))|0x43->Const(F32(float32_bitsch))|0x44->Const(F64(float64ch))|0x45->UnOp(I32Eqz)|0x46->BinOp(I32Eq)|0x47->BinOp(I32Ne)|0x48->BinOp(I32(LtSigned))|0x49->BinOp(I32(LtUnsigned))|0x4A->BinOp(I32(GtSigned))|0x4B->BinOp(I32(GtUnsigned))|0x4C->BinOp(I32(LeSigned))|0x4D->BinOp(I32(LeUnsigned))|0x4E->BinOp(I32(GeSigned))|0x4F->BinOp(I32(GeUnsigned))|0x50->UnOp(I64Eqz)|0x51->BinOp(I64Eq)|0x52->BinOp(I64Ne)|0x53->BinOp(I64(LtSigned))|0x54->BinOp(I64(LtUnsigned))|0x55->BinOp(I64(GtSigned))|0x56->BinOp(I64(GtUnsigned))|0x57->BinOp(I64(LeSigned))|0x58->BinOp(I64(LeUnsigned))|0x59->BinOp(I64(GeSigned))|0x5A->BinOp(I64(GeUnsigned))|0x5B->BinOp(F32Eq)|0x5C->BinOp(F32Ne)|0x5D->BinOp(F32Lt)|0x5E->BinOp(F32Gt)|0x5F->BinOp(F32Le)|0x60->BinOp(F32Ge)|0x61->BinOp(F64Eq)|0x62->BinOp(F64Ne)|0x63->BinOp(F64Lt)|0x64->BinOp(F64Gt)|0x65->BinOp(F64Le)|0x66->BinOp(F64Ge)|0x67->UnOp(I32Clz)|0x68->UnOp(I32Ctz)|0x69->UnOp(I32Popcnt)|0x6A->BinOp(I32Add)|0x6B->BinOp(I32Sub)|0x6C->BinOp(I32Mul)|0x6D->BinOp(I32(DivSigned))|0x6E->BinOp(I32(DivUnsigned))|0x6F->BinOp(I32(RemSigned))|0x70->BinOp(I32(RemUnsigned))|0x71->BinOp(I32And)|0x72->BinOp(I32Or)|0x73->BinOp(I32Xor)|0x74->BinOp(I32Shl)|0x75->BinOp(I32(ShrSigned))|0x76->BinOp(I32(ShrUnsigned))|0x77->BinOp(I32Rotl)|0x78->BinOp(I32Rotr)|0x79->UnOp(I64Clz)|0x7A->UnOp(I64Ctz)|0x7B->UnOp(I64Popcnt)|0x7C->BinOp(I64Add)|0x7D->BinOp(I64Sub)|0x7E->BinOp(I64Mul)|0x7F->BinOp(I64(DivSigned))|0x80->BinOp(I64(DivUnsigned))|0x81->BinOp(I64(RemSigned))|0x82->BinOp(I64(RemUnsigned))|0x83->BinOp(I64And)|0x84->BinOp(I64Or)|0x85->BinOp(I64Xor)|0x86->BinOp(I64Shl)|0x87->BinOp(I64(ShrSigned))|0x88->BinOp(I64(ShrUnsigned))|0x89->BinOp(I64Rotl)|0x8A->BinOp(I64Rotr)|0x8B->UnOp(F32Abs)|0x8C->UnOp(F32Neg)|0x8D->UnOp(F32Ceil)|0x8E->UnOp(F32Floor)|0x8F->UnOp(F32Trunc)|0x90->UnOp(F32Nearest)|0x91->UnOp(F32Sqrt)|0x92->BinOp(F32Add)|0x93->BinOp(F32Sub)|0x94->BinOp(F32Mul)|0x95->BinOp(F32Div)|0x96->BinOp(F32Min)|0x97->BinOp(F32Max)|0x98->BinOp(F32CopySign)|0x99->UnOp(F64Abs)|0x9A->UnOp(F64Neg)|0x9B->UnOp(F64Ceil)|0x9C->UnOp(F64Floor)|0x9D->UnOp(F64Trunc)|0x9E->UnOp(F64Nearest)|0x9F->UnOp(F64Sqrt)|0xA0->BinOp(F64Add)|0xA1->BinOp(F64Sub)|0xA2->BinOp(F64Mul)|0xA3->BinOp(F64Div)|0xA4->BinOp(F64Min)|0xA5->BinOp(F64Max)|0xA6->BinOp(F64CopySign)|0xA7->I32WrapI64|0xA8->UnOp(I32(Trunc(`F32,Signed)))|0xA9->UnOp(I32(Trunc(`F32,Unsigned)))|0xAA->UnOp(I32(Trunc(`F64,Signed)))|0xAB->UnOp(I32(Trunc(`F64,Unsigned)))|0xAC->I64ExtendI32Signed|0xAD->I64ExtendI32Unsigned|0xAE->UnOp(I64(Trunc(`F32,Signed)))|0xAF->UnOp(I64(Trunc(`F32,Unsigned)))|0xB0->UnOp(I64(Trunc(`F64,Signed)))|0xB1->UnOp(I64(Trunc(`F64,Unsigned)))|0xB2->UnOp(F32(Convert(`I32,Signed)))|0xB3->UnOp(F32(Convert(`I32,Unsigned)))|0xB4->UnOp(F32(Convert(`I64,Signed)))|0xB5->UnOp(F32(Convert(`I64,Unsigned)))|0xB6->F32DemoteF64|0xB7->UnOp(F64(Convert(`I32,Signed)))|0xB8->UnOp(F64(Convert(`I32,Unsigned)))|0xB9->UnOp(F64(Convert(`I64,Signed)))|0xBA->UnOp(F64(Convert(`I64,Unsigned)))|0xBB->F64PromoteF32|0xBC->UnOp(I32Reinterpret)|0xBD->UnOp(I64Reinterpret)|0xBE->UnOp(F32Reinterpret)|0xBF->UnOp(F64Reinterpret)|0xC0->UnOp(I32(ExtendS`_8))|0xC1->UnOp(I32(ExtendS`_16))|0xC2->UnOp(I64(ExtendS`_8))|0xC3->UnOp(I64(ExtendS`_16))|0xC4->UnOp(I64(ExtendS`_32))|0xD0->RefNull(heaptypech)|0xD1->RefIsNull|0xD2->RefFunc(uintch)|0xD3->RefEq|0xD4->RefAsNonNull|0xD5->Br_on_null(uintch)|0xD6->Br_on_non_null(uintch)|0xFB->(matchuintchwith|0->StructNew(uintch)|1->StructNewDefault(uintch)|2->leti=uintchinStructGet(None,i,uintch)|3->leti=uintchinStructGet(SomeSigned,i,uintch)|4->leti=uintchinStructGet(SomeUnsigned,i,uintch)|5->leti=uintchinStructSet(i,uintch)|6->ArrayNew(uintch)|7->ArrayNewDefault(uintch)|8->leti=uintchinArrayNewFixed(i,Wax_utils.Uint32.of_int(uintch))|9->(* Like [memory.init]/[data.drop], [array.new_data] references a data
segment, so the data section (which follows the code section)
must be sized ahead of time by a data count section. *)ifnotch.has_data_countthenerrorch"data count section required";leti=uintchinArrayNewData(i,uintch)|10->leti=uintchinArrayNewElem(i,uintch)|11->ArrayGet(None,uintch)|12->ArrayGet(SomeSigned,uintch)|13->ArrayGet(SomeUnsigned,uintch)|14->ArraySet(uintch)|15->ArrayLen|16->ArrayFill(uintch)|17->leti=uintchinArrayCopy(i,uintch)|18->leti=uintchinArrayInitData(i,uintch)|19->leti=uintchinArrayInitElem(i,uintch)|20->RefTest{nullable=false;typ=heaptypech}|21->RefTest(nullable(heaptypech))|22->RefCast{nullable=false;typ=heaptypech}|23->RefCast(nullable(heaptypech))|24->letn1,n2=castflagschinletlabel=uintchinletht1=heaptypechinletht2=heaptypechinletrt1={nullable=n1;typ=ht1}inletrt2={nullable=n2;typ=ht2}inBr_on_cast(label,rt1,rt2)|25->letn1,n2=castflagschinletlabel=uintchinletht1=heaptypechinletht2=heaptypechinletrt1={nullable=n1;typ=ht1}inletrt2={nullable=n2;typ=ht2}inBr_on_cast_fail(label,rt1,rt2)|26->AnyConvertExtern|27->ExternConvertAny|28->RefI31|29->I31GetSigned|30->I31GetUnsigned|32->StructNewDesc(uintch)|33->StructNewDefaultDesc(uintch)|34->RefGetDesc(uintch)|35->RefCastDescEq{nullable=false;typ=heaptypech}|36->RefCastDescEq(nullable(heaptypech))|37->letn1,n2=castflagschinletlabel=uintchinletht1=heaptypechinletht2=heaptypechinletrt1={nullable=n1;typ=ht1}inletrt2={nullable=n2;typ=ht2}inBr_on_cast_desc_eq(label,rt1,rt2)|38->letn1,n2=castflagschinletlabel=uintchinletht1=heaptypechinletht2=heaptypechinletrt1={nullable=n1;typ=ht1}inletrt2={nullable=n2;typ=ht2}inBr_on_cast_desc_eq_fail(label,rt1,rt2)|c->errorch"unknown GC opcode %d"c)|0xFC->(matchuintchwith|0->UnOp(I32(TruncSat(`F32,Signed)))|1->UnOp(I32(TruncSat(`F32,Unsigned)))|2->UnOp(I32(TruncSat(`F64,Signed)))|3->UnOp(I32(TruncSat(`F64,Unsigned)))|4->UnOp(I64(TruncSat(`F32,Signed)))|5->UnOp(I64(TruncSat(`F32,Unsigned)))|6->UnOp(I64(TruncSat(`F64,Signed)))|7->UnOp(I64(TruncSat(`F64,Unsigned)))|8->ifnotch.has_data_countthenerrorch"data count section required";leti=uintchinletm=uintchinMemoryInit(i,m)|9->ifnotch.has_data_countthenerrorch"data count section required";DataDrop(uintch)|10->letm_dst=uintchinletm_src=uintchinMemoryCopy(m_dst,m_src)|11->letm=uintchinMemoryFillm|12->leti=uintchinTableInit(i,uintch)|13->ElemDrop(uintch)|14->leti=uintchinTableCopy(i,uintch)|15->TableGrow(uintch)|16->TableSize(uintch)|17->TableFill(uintch)|19->Add128|20->Sub128|21->MulWideSigned|22->MulWideUnsigned|c->errorch"unknown 0xfc opcode %d"c)|0x05->errorch"unexpected else opcode"|0x07->errorch"unexpected catch opcode"|0x09->errorch"unknown opcode 0x09"|0x0B->errorch"unexpected end opcode"|0xFE->(letcode=uintchinifcode=0x03then((* atomic.fence: a reserved consistency-model byte follows; it must
be zero — no memory-order value is defined. *)letb=uintchinifb<>0thenerrorch"nonzero byte after `atomic.fence`";AtomicFence)elsematchAtomics.of_opcodecodewith|Someop->letm,arg=memargchinAtomic(m,op,arg)|None->errorch"unknown atomic opcode %d"code)|0xFD->(matchuintchwith|0->letm,arg=memargchinVecLoad(m,Load128,arg)|1->letm,arg=memargchinVecLoad(m,Load8x8S,arg)|2->letm,arg=memargchinVecLoad(m,Load8x8U,arg)|3->letm,arg=memargchinVecLoad(m,Load16x4S,arg)|4->letm,arg=memargchinVecLoad(m,Load16x4U,arg)|5->letm,arg=memargchinVecLoad(m,Load32x2S,arg)|6->letm,arg=memargchinVecLoad(m,Load32x2U,arg)|7->letm,arg=memargchinVecLoadSplat(m,`I8,arg)|8->letm,arg=memargchinVecLoadSplat(m,`I16,arg)|9->letm,arg=memargchinVecLoadSplat(m,`I32,arg)|10->letm,arg=memargchinVecLoadSplat(m,`I64,arg)|11->letm,arg=memargchinVecStore(m,arg)|12->VecConst(v128ch)|13->VecShuffle(v128ch)|14->VecBinOpVecSwizzle|15->VecSplatI8x16|16->VecSplatI16x8|17->VecSplatI32x4|18->VecSplatI64x2|19->VecSplatF32x4|20->VecSplatF64x2|21->VecExtract(I8x16,SomeSigned,uintch)|22->VecExtract(I8x16,SomeUnsigned,uintch)|23->VecReplace(I8x16,uintch)|24->VecExtract(I16x8,SomeSigned,uintch)|25->VecExtract(I16x8,SomeUnsigned,uintch)|26->VecReplace(I16x8,uintch)|27->VecExtract(I32x4,None,uintch)|28->VecReplace(I32x4,uintch)|29->VecExtract(I64x2,None,uintch)|30->VecReplace(I64x2,uintch)|31->VecExtract(F32x4,None,uintch)|32->VecReplace(F32x4,uintch)|33->VecExtract(F64x2,None,uintch)|34->VecReplace(F64x2,uintch)|35->VecBinOp(VecEqI8x16)|36->VecBinOp(VecNeI8x16)|37->VecBinOp(VecLt(SomeSigned,I8x16))|38->VecBinOp(VecLt(SomeUnsigned,I8x16))|39->VecBinOp(VecGt(SomeSigned,I8x16))|40->VecBinOp(VecGt(SomeUnsigned,I8x16))|41->VecBinOp(VecLe(SomeSigned,I8x16))|42->VecBinOp(VecLe(SomeUnsigned,I8x16))|43->VecBinOp(VecGe(SomeSigned,I8x16))|44->VecBinOp(VecGe(SomeUnsigned,I8x16))|45->VecBinOp(VecEqI16x8)|46->VecBinOp(VecNeI16x8)|47->VecBinOp(VecLt(SomeSigned,I16x8))|48->VecBinOp(VecLt(SomeUnsigned,I16x8))|49->VecBinOp(VecGt(SomeSigned,I16x8))|50->VecBinOp(VecGt(SomeUnsigned,I16x8))|51->VecBinOp(VecLe(SomeSigned,I16x8))|52->VecBinOp(VecLe(SomeUnsigned,I16x8))|53->VecBinOp(VecGe(SomeSigned,I16x8))|54->VecBinOp(VecGe(SomeUnsigned,I16x8))|55->VecBinOp(VecEqI32x4)|56->VecBinOp(VecNeI32x4)|57->VecBinOp(VecLt(SomeSigned,I32x4))|58->VecBinOp(VecLt(SomeUnsigned,I32x4))|59->VecBinOp(VecGt(SomeSigned,I32x4))|60->VecBinOp(VecGt(SomeUnsigned,I32x4))|61->VecBinOp(VecLe(SomeSigned,I32x4))|62->VecBinOp(VecLe(SomeUnsigned,I32x4))|63->VecBinOp(VecGe(SomeSigned,I32x4))|64->VecBinOp(VecGe(SomeUnsigned,I32x4))|65->VecBinOp(VecEqF32x4)|66->VecBinOp(VecNeF32x4)|67->VecBinOp(VecLt(None,F32x4))|68->VecBinOp(VecGt(None,F32x4))|69->VecBinOp(VecLe(None,F32x4))|70->VecBinOp(VecGe(None,F32x4))|71->VecBinOp(VecEqF64x2)|72->VecBinOp(VecNeF64x2)|73->VecBinOp(VecLt(None,F64x2))|74->VecBinOp(VecGt(None,F64x2))|75->VecBinOp(VecLe(None,F64x2))|76->VecBinOp(VecGe(None,F64x2))|77->VecUnOpVecNot|78->VecBinOpVecAnd|79->VecBinOpVecAndNot|80->VecBinOpVecOr|81->VecBinOpVecXor|82->VecBitselect|83->VecTestAnyTrue|84->letm_idx,m=memargchinletl=input_bytechinVecLoadLane(m_idx,`I8,m,l)|85->letm_idx,m=memargchinletl=input_bytechinVecLoadLane(m_idx,`I16,m,l)|86->letm_idx,m=memargchinletl=input_bytechinVecLoadLane(m_idx,`I32,m,l)|87->letm_idx,m=memargchinletl=input_bytechinVecLoadLane(m_idx,`I64,m,l)|88->letm_idx,m=memargchinletl=input_bytechinVecStoreLane(m_idx,`I8,m,l)|89->letm_idx,m=memargchinletl=input_bytechinVecStoreLane(m_idx,`I16,m,l)|90->letm_idx,m=memargchinletl=input_bytechinVecStoreLane(m_idx,`I32,m,l)|91->letm_idx,m=memargchinletl=input_bytechinVecStoreLane(m_idx,`I64,m,l)|92->letm,arg=memargchinVecLoad(m,Load32Zero,arg)|93->letm,arg=memargchinVecLoad(m,Load64Zero,arg)|94->VecUnOpVecDemote|95->VecUnOpVecPromote|96->VecUnOp(VecAbsI8x16)|97->VecUnOp(VecNegI8x16)|98->VecUnOpVecPopcnt|99->VecTest(AllTrueI8x16)|100->VecBitmask(BitmaskI8x16)|101->VecBinOp(VecNarrow(Signed,`I8))|102->VecBinOp(VecNarrow(Unsigned,`I8))|103->VecUnOp(VecCeil`F32)|104->VecUnOp(VecFloor`F32)|105->VecUnOp(VecTrunc`F32)|106->VecUnOp(VecNearest`F32)|107->VecShift(ShlI8x16)|108->VecShift(Shr(Signed,I8x16))|109->VecShift(Shr(Unsigned,I8x16))|110->VecBinOp(VecAddI8x16)|111->VecBinOp(VecAddSat(Signed,`I8))|112->VecBinOp(VecAddSat(Unsigned,`I8))|113->VecBinOp(VecSubI8x16)|114->VecBinOp(VecSubSat(Signed,`I8))|115->VecBinOp(VecSubSat(Unsigned,`I8))|116->VecUnOp(VecCeil`F64)|117->VecUnOp(VecFloor`F64)|118->VecBinOp(VecMin(SomeSigned,I8x16))|119->VecBinOp(VecMin(SomeUnsigned,I8x16))|120->VecBinOp(VecMax(SomeSigned,I8x16))|121->VecBinOp(VecMax(SomeUnsigned,I8x16))|122->VecUnOp(VecTrunc`F64)|123->VecBinOp(VecAvgr`I8)|124->VecUnOp(VecExtAddPairwise(Signed,`I8))|125->VecUnOp(VecExtAddPairwise(Unsigned,`I8))|126->VecUnOp(VecExtAddPairwise(Signed,`I16))|127->VecUnOp(VecExtAddPairwise(Unsigned,`I16))|128->VecUnOp(VecAbsI16x8)|129->VecUnOp(VecNegI16x8)|130->VecBinOpVecQ15MulrSat|131->VecTest(AllTrueI16x8)|132->VecBitmask(BitmaskI16x8)|133->VecBinOp(VecNarrow(Signed,`I16))|134->VecBinOp(VecNarrow(Unsigned,`I16))|135->VecUnOp(VecExtend(`Low,`_8,Signed))|136->VecUnOp(VecExtend(`High,`_8,Signed))|137->VecUnOp(VecExtend(`Low,`_8,Unsigned))|138->VecUnOp(VecExtend(`High,`_8,Unsigned))|139->VecShift(ShlI16x8)|140->VecShift(Shr(Signed,I16x8))|141->VecShift(Shr(Unsigned,I16x8))|142->VecBinOp(VecAddI16x8)|143->VecBinOp(VecAddSat(Signed,`I16))|144->VecBinOp(VecAddSat(Unsigned,`I16))|145->VecBinOp(VecSubI16x8)|146->VecBinOp(VecSubSat(Signed,`I16))|147->VecBinOp(VecSubSat(Unsigned,`I16))|148->VecUnOp(VecNearest`F64)|149->VecBinOp(VecMulI16x8)|150->VecBinOp(VecMin(SomeSigned,I16x8))|151->VecBinOp(VecMin(SomeUnsigned,I16x8))|152->VecBinOp(VecMax(SomeSigned,I16x8))|153->VecBinOp(VecMax(SomeUnsigned,I16x8))|155->VecBinOp(VecAvgr`I16)|156->VecBinOp(VecExtMulLow(Signed,`_8))|157->VecBinOp(VecExtMulHigh(Signed,`_8))|158->VecBinOp(VecExtMulLow(Unsigned,`_8))|159->VecBinOp(VecExtMulHigh(Unsigned,`_8))|160->VecUnOp(VecAbsI32x4)|161->VecUnOp(VecNegI32x4)|163->VecTest(AllTrueI32x4)|164->VecBitmask(BitmaskI32x4)|167->VecUnOp(VecExtend(`Low,`_16,Signed))|168->VecUnOp(VecExtend(`High,`_16,Signed))|169->VecUnOp(VecExtend(`Low,`_16,Unsigned))|170->VecUnOp(VecExtend(`High,`_16,Unsigned))|171->VecShift(ShlI32x4)|172->VecShift(Shr(Signed,I32x4))|173->VecShift(Shr(Unsigned,I32x4))|174->VecBinOp(VecAddI32x4)|177->VecBinOp(VecSubI32x4)|181->VecBinOp(VecMulI32x4)|182->VecBinOp(VecMin(SomeSigned,I32x4))|183->VecBinOp(VecMin(SomeUnsigned,I32x4))|184->VecBinOp(VecMax(SomeSigned,I32x4))|185->VecBinOp(VecMax(SomeUnsigned,I32x4))|186->VecBinOpVecDot|188->VecBinOp(VecExtMulLow(Signed,`_16))|189->VecBinOp(VecExtMulHigh(Signed,`_16))|190->VecBinOp(VecExtMulLow(Unsigned,`_16))|191->VecBinOp(VecExtMulHigh(Unsigned,`_16))|192->VecUnOp(VecAbsI64x2)|193->VecUnOp(VecNegI64x2)|195->VecTest(AllTrueI64x2)|196->VecBitmask(BitmaskI64x2)|199->VecUnOp(VecExtend(`Low,`_32,Signed))|200->VecUnOp(VecExtend(`High,`_32,Signed))|201->VecUnOp(VecExtend(`Low,`_32,Unsigned))|202->VecUnOp(VecExtend(`High,`_32,Unsigned))|203->VecShift(ShlI64x2)|204->VecShift(Shr(Signed,I64x2))|205->VecShift(Shr(Unsigned,I64x2))|206->VecBinOp(VecAddI64x2)|209->VecBinOp(VecSubI64x2)|213->VecBinOp(VecMulI64x2)|214->VecBinOp(VecEqI64x2)|215->VecBinOp(VecNeI64x2)|216->VecBinOp(VecLt(SomeSigned,I64x2))|217->VecBinOp(VecGt(SomeSigned,I64x2))|218->VecBinOp(VecLe(SomeSigned,I64x2))|219->VecBinOp(VecGe(SomeSigned,I64x2))|220->VecBinOp(VecExtMulLow(Signed,`_32))|221->VecBinOp(VecExtMulHigh(Signed,`_32))|222->VecBinOp(VecExtMulLow(Unsigned,`_32))|223->VecBinOp(VecExtMulHigh(Unsigned,`_32))|224->VecUnOp(VecAbsF32x4)|225->VecUnOp(VecNegF32x4)|227->VecUnOp(VecSqrt`F32)|228->VecBinOp(VecAddF32x4)|229->VecBinOp(VecSubF32x4)|230->VecBinOp(VecMulF32x4)|231->VecBinOp(VecDiv`F32)|232->VecBinOp(VecMin(None,F32x4))|233->VecBinOp(VecMax(None,F32x4))|234->VecBinOp(VecPMin`F32)|235->VecBinOp(VecPMax`F32)|236->VecUnOp(VecAbsF64x2)|237->VecUnOp(VecNegF64x2)|239->VecUnOp(VecSqrt`F64)|240->VecBinOp(VecAddF64x2)|241->VecBinOp(VecSubF64x2)|242->VecBinOp(VecMulF64x2)|243->VecBinOp(VecDiv`F64)|244->VecBinOp(VecMin(None,F64x2))|245->VecBinOp(VecMax(None,F64x2))|246->VecBinOp(VecPMin`F64)|247->VecBinOp(VecPMax`F64)|248->VecUnOp(VecTruncSat(`F32,Signed))|249->VecUnOp(VecTruncSat(`F32,Unsigned))|250->VecUnOp(VecConvert(`F32,Signed))|251->VecUnOp(VecConvert(`F32,Unsigned))|252->VecUnOp(VecTruncSat(`F64,Signed))|253->VecUnOp(VecTruncSat(`F64,Unsigned))|254->VecUnOp(VecConvert(`F64,Signed))|255->VecUnOp(VecConvert(`F64,Unsigned))(* Relaxed SIMD *)|0x100->VecBinOpVecRelaxedSwizzle|0x101->VecUnOp(VecRelaxedTruncSigned)|0x102->VecUnOp(VecRelaxedTruncUnsigned)|0x103->VecUnOp(VecRelaxedTruncZeroSigned)|0x104->VecUnOp(VecRelaxedTruncZeroUnsigned)|0x105->VecTernOp(VecRelaxedMAdd`F32)|0x106->VecTernOp(VecRelaxedNMAdd`F32)|0x107->VecTernOp(VecRelaxedMAdd`F64)|0x108->VecTernOp(VecRelaxedNMAdd`F64)|0x109->VecTernOp(VecRelaxedLaneSelectI8x16)|0x10a->VecTernOp(VecRelaxedLaneSelectI16x8)|0x10b->VecTernOp(VecRelaxedLaneSelectI32x4)|0x10c->VecTernOp(VecRelaxedLaneSelectI64x2)|0x10d->VecBinOp(VecRelaxedMinF32x4)|0x10e->VecBinOp(VecRelaxedMaxF32x4)|0x10f->VecBinOp(VecRelaxedMinF64x2)|0x110->VecBinOp(VecRelaxedMaxF64x2)|0x111->VecBinOpVecRelaxedQ15Mulr|0x112->VecBinOpVecRelaxedDot|0x113->VecTernOpVecRelaxedDotAdd|c->errorch"unknown SIMD opcode 0x%02x"c)|c->errorch"illegal opcode %02x"cinwith_locchposdesc(*** Section readers ***)letexprch=letinstrs=instructionsch[]inexpect_endch;instrsletelemch=letmode_byte=uintchinletfunc(ch:ch)=letpos=ch.posinletdesc=RefFunc(uintch)in[with_locchposdesc]inmatchmode_bytewith|0x00->(* Active, table 0, vec(funcidx) *)letoffset_expr=exprchinletinit=Array.to_list(vecfuncch)in{typ={nullable=false;typ=Func};init;mode=Active(0,offset_expr);}|0x01->(* Passive, elemkind=0, vec(funcidx) *)letelemkind=input_bytechinifelemkind<>0thenerrorch"element kind must be 0x00, got 0x%02x"elemkind;letinit=Array.to_list(vecfuncch)in{typ={nullable=false;typ=Func};init;mode=Passive}|0x02->(* Active, tableidx, offset, elemkind=0, vec(funcidx) *)lettable_idx=uintchinletoffset_expr=exprchinletelemkind=input_bytechinifelemkind<>0thenerrorch"element kind must be 0x00, got 0x%02x"elemkind;letinit=Array.to_list(vecfuncch)in{typ={nullable=false;typ=Func};init;mode=Active(table_idx,offset_expr);}|0x03->(* Declarative, elemkind=0, vec(funcidx) *)letelemkind=input_bytechinifelemkind<>0thenerrorch"element kind must be 0x00, got 0x%02x"elemkind;letinit=Array.to_list(vecfuncch)in{typ={nullable=false;typ=Func};init;mode=Declare}|0x04->(* Active, table 0, vec(expr) *)letoffset_expr=exprchinletinit=Array.to_list(vecexprch)in{typ={nullable=true;typ=Func};init;mode=Active(0,offset_expr);}|0x05->(* Passive, reftype, vec(expr) *)lettyp=reftype_first_bytechinletinit=Array.to_list(vecexprch)in{typ;init;mode=Passive}|0x06->(* Active, tableidx, offset, reftype, vec(expr) *)lettable_idx=uintchinletoffset_expr=exprchinlettyp=reftype_first_bytechinletinit=Array.to_list(vecexprch)in{typ;init;mode=Active(table_idx,offset_expr)}|0x07->(* Declarative, reftype, vec(expr) *)lettyp=reftype_first_bytechinletinit=Array.to_list(vecexprch)in{typ;init;mode=Declare}|_->errorch"unknown element segment kind 0x%02x"mode_bytelettablech=letnext_byte=peek_bytechinifnext_byte=0x40then((* Case 2: 0x40 0x00 tabletype expr *)letmarker=input_bytechinletattribute=input_bytechinifmarker<>0x40||attribute<>0x00thenerrorch"malformed table definition";lettyp=tabletypechinletexpr=exprchin{typ;expr=Someexpr})else(* Case 1: tabletype *)lettyp=tabletypechin{typ;expr=None}letcodech=letsize=uintchinletstart_pos=pos_inchinletlocals=letn=uintchinletread_groupch=letn=uintchinlett=valtype_first_bytechin(n,t)inletgroups=Array.to_list(repeatnread_groupch)in(* The spec's only bound on locals is that a function declare at most
2^32-1 of them. Check the accumulated total before materialising, so an
over-limit function is a diagnostic rather than a huge allocation.
Accumulate in [Int64], matching the reference interpreter: a group count
is a u32, so the sum can exceed [max_int] on a 32-bit / js_of_ocaml
[int] (where 0xffff_ffff is not even representable). *)lettotal=List.fold_left(funacc(n,_)->Int64.addacc(Int64.of_intn))0LgroupsinifInt64.comparetotal0xffff_ffffL>0thenerrorch"too many locals";List.concat_map(fun(n,t)->List.initn(fun_->t))groupsinletinstrs=exprchin(* Compare bytes consumed against the declared body [size] rather than
[start_pos + size]: [size] is untrusted and the sum could overflow the
OCaml [int] on a 32-bit / js_of_ocaml build. [pos_in ch >= start_pos]. *)ifpos_inch-start_pos<>sizethenerrorch"function body size mismatch";(* [start_pos] is where this function's locals declaration begins — the origin
for branch-hint offsets (branch-hinting proposal). *)(start_pos,{locals;instrs;loc=Ast.dummy_loc;priority=None})letdatach=letmode_byte=uintchinlet(mode:Ast.locationAst.Binary.datamode)=matchmode_bytewith|0x00->(* Active, memory 0 *)letoffset_expr=exprchinActive(0,offset_expr)|0x01->Passive|0x02->(* Active, explicit memory index *)letmem_idx=uintchinletoffset_expr=exprchinActive(mem_idx,offset_expr)|_->errorch"unknown data segment kind 0x%02x"mode_byteinletinit_len=uintchinletinit_str=really_input_stringchinit_lenin{Ast.Binary.init=init_str;mode}lettagch=letb=input_bytechinifb<>0thenerrorch"malformed tag attribute";typeidxchletempty_names={module_=None;functions=IntMap.empty;locals=IntMap.empty;labels=IntMap.empty;types=IntMap.empty;fields=IntMap.empty;tags=IntMap.empty;globals=IntMap.empty;tables=IntMap.empty;memories=IntMap.empty;data=IntMap.empty;elem=IntMap.empty;}letname_map'fch=letarr=vecfchinlet_=Array.fold_left(funlast_idx(idx,_)->(matchlast_idxwith|Somelastwhenidx<=last->errorch"name map not sorted"|_->());Someidx)NonearrinArray.fold_left(funacc(idx,n)->IntMap.addidxnacc)IntMap.emptyarrletname_assocch=leti=uintchin(i,namech)(* An EMPTY name is dropped. The name section may carry one (it is a custom
section of arbitrary byte strings), but no text identifier denotes it: [$]
is not an identifier and the quoted form [$""] is rejected outright ("an
identifier cannot be the empty string"), so emitting it produced WAT wax
could not read back — a mutate-wasm FALSE_ACCEPT/VALIDATION_PARITY finding,
wax accepting the binary and then rejecting its own rendering. Dropping
leaves the entity anonymous (printed by index), which is what the name
conveyed anyway, and matches wasm-tools, which also prints no name for it. *)letname_mapch=IntMap.filter(fun_n->n<>"")(name_map'name_assocch)letindirect_name_mapch=name_map'(funch->leti=uintchin(i,name_mapch))ch(* Branch-hinting / compilation-hints proposals. [sections] holds the parsed
[metadata.code.*] entries from every such section: for each (absolute) function
index, a list of (body-relative offset, setter). [code_starts] gives, in
defined-function order, the byte offset where each function body (its locals
declaration) begins — the origin for those offsets. Apply the setters to the
instruction whose opcode sits at the matching offset (its source location
records that absolute offset). Whether that instruction is a legal target is a
validation concern, not a decoding one, so a hint is attached wherever its
offset lands and [validation] rejects a bad placement — matching the text path.
Our own encoder always records the hinted opcode's offset, so a round-tripped
valid module lands on one; only an externally-produced, malformed section can
point elsewhere, and then the placement is diagnosed rather than silently
dropped. An offset falling between opcodes (matching no instruction start)
still cannot attach. *)letattach_code_metadata~num_func_imports~code_starts~sections(code:Ast.locationcodelist)=ifsections=[]thencodeelseletby_func:(int,(int,Ast.location->intHints.t->intHints.t)Hashtbl.t)Hashtbl.t=Hashtbl.create16inList.iter(fun(funcidx,hints)->lettbl=matchHashtbl.find_optby_funcfuncidxwith|Somet->t|None->lett=Hashtbl.create8inHashtbl.addby_funcfuncidxt;tinList.iter(fun(off,f)->(* Two sections may hint the same instruction, so compose rather than
replace; within one section a repeated offset still lets the last
entry win, since each setter overwrites its own field. *)matchHashtbl.find_opttbloffwith|None->Hashtbl.replacetblofff|Someg->Hashtbl.replacetbloff(funloch->floc(gloch)))hints)sections;letrecgostart_postbl(i:Ast.locationinstr)=letlst=List.map(gostart_postbl)inletdesc=matchi.descwith|Blockb->Block{bwithblock={b.blockwithdesc=lstb.block.desc}}|Loopb->Loop{bwithblock={b.blockwithdesc=lstb.block.desc}}|Ifb->If{bwithif_block={b.if_blockwithdesc=lstb.if_block.desc};else_block={b.else_blockwithdesc=lstb.else_block.desc};}|TryTableb->TryTable{bwithblock={b.blockwithdesc=lstb.block.desc}}|Tryb->Try{bwithblock={b.blockwithdesc=lstb.block.desc};catches=List.map(fun(t,bl)->(t,{blwithAst.desc=lstbl.Ast.desc}))b.catches;catch_all=Option.map(funbl->{blwithAst.desc=lstbl.Ast.desc})b.catch_all;}|d->dinleti={iwithdesc}inletrel=i.info.Wax_utils.Ast.loc_start.Lexing.pos_cnum-start_posinmatchHashtbl.find_opttblrelwith|Somef->{iwithhints=fi.infoi.hints}|None->iinList.mapi(funci(c:Ast.locationcode)->matchHashtbl.find_optby_func(num_func_imports+ci)with|None->c|Sometbl->letstart_pos=List.nthcode_startsciin{cwithinstrs=List.map(gostart_postbl)c.instrs})code(*** The module reader ***)letmodule_diagnostics?(features=Wax_utils.Feature.default())?filenamebuf=Wax_utils.Debug.timed"parse"@@fun()->letch={filename;buf;pos=0;limit=String.lengthbuf;has_data_count=false;diagnostics;features;}incheck_headerch;letdata_count=refNonein(* Branch-hinting / compilation-hints proposals: the parsed [metadata.code.*]
entries and the byte offset at which each function body begins, applied
together after the whole module is read (a section may sit before or after
the code section). *)letcode_metadata_sections=ref[]inletcode_priorities=ref[]inletcode_body_starts=ref[]inch.pos<-8;letrecloopmlast_section_order=matchnext_sectionchwith|None->m|Somesect->letcurrent_order=matchsect.idwith|12->11|10->12|11->13|13->6|iwheni>=6&&i<=9->i+1|i->iinifsect.id<>0&¤t_order<=last_section_orderthenerrorch"unexpected content after last section";letnext_section_order=ifsect.id=0thenlast_section_orderelsecurrent_orderinletm=matchsect.idwith|1->(* Type section *){mwithtypes=Array.to_list(type_sectionch)}|2->(* Import section — each entry kept as an [import_entry] so a
compact-import-section group survives the round-trip. *){mwithimports=Array.to_list(vecimport_entrych)}|3->(* Function section *){mwithfunctions=Array.to_list(vectypeidxch)}|4->(* Table section *)lettables=Array.to_list(vectablech)in{mwithtables}|5->(* Memory section *){mwithmemories=Array.to_list(vecmemtypech)}|6->(* Global section *)letglobals=Array.to_list(vec(funch->lettyp=globaltypechin{typ;init=exprch})ch)in{mwithglobals}|7->(* Export section *){mwithexports=Array.to_list(vecexportch)}|8->(* Start section *){mwithstart=Some(uintch)}|9->(* Element section *){mwithelem=Array.to_list(vecelemch)}|10->(* Code section *)letentries=Array.to_list(veccodech)incode_body_starts:=List.mapfstentries;{mwithcode=List.mapsndentries}|11->(* Data section *){mwithdata=Array.to_list(vecdatach)}|12->(* DataCount section *)data_count:=Some(uintch);ch.has_data_count<-true;m|13->(* Tag section *)lettags=Array.to_list(vectagch)in{mwithAst.Binary.tags}|0->((* Custom section *)letstart_pos=pos_inchinletcustom_name=namechinmatchcustom_namewith|"name"->letrecparse_name_subsectionscurrent_names=ifpos_inch=start_pos+sect.sizethencurrent_nameselseletsubsection_id=uintchinletsubsection_size=uintchinletsubsection_start_pos=pos_inchinletupdated_names=matchsubsection_idwith|0->(* Module name; empty means anonymous (see
[name_map]). *)letmodule_name=namechinifmodule_name=""thencurrent_nameselse{current_nameswithAst.Binary.module_=Somemodule_name;}|1->(* Function names *){current_nameswithfunctions=name_mapch}|2->(* Local names *){current_nameswithlocals=indirect_name_mapch}|3->(* Label names *){current_nameswithlabels=indirect_name_mapch}|4->(* Type names *){current_nameswithtypes=name_mapch}|5->(* Table names *){current_nameswithtables=name_mapch}|6->(* Memory names *){current_nameswithmemories=name_mapch}|7->(* Global names *){current_nameswithglobals=name_mapch}|8->(* Elem names *){current_nameswithelem=name_mapch}|9->(* Data names *){current_nameswithdata=name_mapch}|10->(* Field names *){current_nameswithfields=indirect_name_mapch}|11->(* Tag names *){current_nameswithtags=name_mapch}|_->current_names(* Skip unknown subsections *)inseek_inch(subsection_start_pos+subsection_size);parse_name_subsectionsupdated_namesinletnames=parse_name_subsectionsm.namesin{mwithAst.Binary.names}|"target_features"->(* The tool-conventions feature-detection section: a vector
of (prefix byte, name) entries. Kept verbatim — including
other producers' entries — so the section survives a
round-trip; ['+'] entries with a name we know restore the
module's feature declarations (in [Binary_to_text]). The
convention allows the section at most once; be lenient on
input and concatenate. *)letentries=vec(funch->letprefix=Char.chr(input_bytech)in(prefix,namech))chin{mwithtarget_features=m.target_features@Array.to_listentries;}|"metadata.code.compilation_priority"->(* Compilation-hints proposal, the function-level section. It
shares the family's shape — funcidx, then (offset, payload)
entries — but the offset is always 0, meaning "the function
itself", so it needs no instruction matching and is kept apart
from the offset-keyed setters. A nonzero offset addresses no
instruction here, so the entry is ignored rather than
misapplied to the body. Must still precede the code section,
which is where its functions are. *)iflast_section_order>=12thenerrorch"metadata.code.compilation_priority must appear before \
the code section";letentries=vec(funch->letfuncidx=uintchinletps=vec(funch->letoffset=uintchinletlen=uintchiniflen=0thenerrorch"empty compilation_priority entry";lets=String.initlen(fun_->Char.chr(input_bytech))inmatchHints.priority_of_payloadswith|Okp->(offset,p)|Errormsg->errorch"%s"msg)chin(funcidx,Array.to_listps))chincode_priorities:=!code_priorities@List.filter_map(fun(funcidx,ps)->Option.map(fun(_,p)->(funcidx,p))(List.find_opt(fun(off,_)->off=0)ps))(Array.to_listentries);m|("metadata.code.branch_hint"|"metadata.code.instr_freq"|"metadata.code.call_targets")assname->(* Branch-hinting / compilation-hints proposals. These sections
address instructions by their offset from the start of the
function body, so they must appear before the code section.
Buffer them as setters; they are matched to instructions once
the code section is parsed. The trailing section-size check
verifies the whole content was consumed. *)iflast_section_order>=12thenerrorch"%s must appear before the code section"sname;letpayloadch=letlen=uintchiniflen=0thenerrorch"empty %s hint"sname;String.initlen(fun_->Char.chr(input_bytech))inletsetterchs=matchsnamewith|"metadata.code.branch_hint"->(* One byte; a longer payload keeps the leading value and
ignores the rest, per the proposal's extension rule. *)letv=s.[0]<>'\000'infunloch->Hints.branchlocvh|"metadata.code.instr_freq"->letv=Char.codes.[0]infunloch->Hints.freqlocvh|_->(matchHints.call_targets_of_payloadswith|Okl->funloch->Hints.targetsloclh|Errormsg->errorch"%s"msg)inletentries=vec(funch->letfuncidx=uintchinlethints=vec(funch->letoffset=uintchinlets=payloadchin(offset,setterchs))chin(funcidx,Array.to_listhints))chincode_metadata_sections:=!code_metadata_sections@Array.to_listentries;m|_->(* Skip other custom sections *)skip_sectionchsect;m)|_->errorch"malformed section id %d"sect.idin(* The section body must be exactly its declared length: reject a section
whose content parses to fewer bytes (trailing data in the section) or
more (it ran into the next section), rather than resuming from wherever
the content parser happened to stop. [next_section] already rejected a
length that runs past the end of the module. *)ifch.pos<>sect.pos+sect.sizethenerrorch"section size mismatch";loopmnext_section_orderinletres=loop{Ast.Binary.types=[];imports=[];functions=[];tables=[];memories=[];tags=[];globals=[];exports=[];start=None;elem=[];code=[];data=[];names=empty_names;target_features=[];}0in(match!data_countwith|Somenwhenn<>List.lengthres.data->errorch"data count and data section have inconsistent lengths"|_->());ifList.lengthres.functions<>List.lengthres.codethenerrorch"function and code section have inconsistent lengths";(* Branch-hinting proposal: attach the buffered hints to their instructions. *)letnum_func_imports=List.fold_left(funn(i:import)->matchi.descwithFunc_->n+1|_->n)0(Ast_utils.flatten_binary_importsres.imports)inletcode=attach_code_metadata~num_func_imports~code_starts:!code_body_starts~sections:!code_metadata_sectionsres.codein(* The function-level priorities, indexed like the sections state them: absolute
function indices, so the imports come first. An entry naming an imported or
out-of-range function has no body to carry it and is dropped. *)letcode=if!code_priorities=[]thencodeelseList.mapi(funi(c:Ast.locationcode)->matchList.assoc_opt(num_func_imports+i)!code_prioritieswith|None->c|Somep->{cwithpriority=Somep})codein{reswithcode}