1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870openAst.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)inFormat.kasprintf(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=leti=uintchinmatchiwith|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->letb=uintchinifb<>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. *)letimport_entrych=letmodule_=namechinletnm=namechinmatchuintchwith|0x7F->letitems=Array.to_list(vec(funch->letname=namechin(name,importdescch(uintch)))ch)inWax_utils.Feature.mark_usedch.featuresCompact_import_section;Group1{module_;items}|0x7E->letdesc=importdescch(uintch)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=namechinletd=uintchinifd>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})letwith_locchposdesc={Ast.desc;info={Ast.loc_start=positionchpos;loc_end=positionchch.pos};}(* 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=blocktypechinletif_block=instructionsch[]inletelse_block=ifinput_bytech=0x05then(letb=instructionsch[]inexpect_endch;b)else[]inIf{label=();typ;if_block=Ast.no_locif_block;else_block=Ast.no_locelse_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->letflags=input_bytechinletlabel=uintchinletht1=heaptypechinletht2=heaptypechinletrt1={nullable=flagsland1<>0;typ=ht1}inletrt2={nullable=flagsland2<>0;typ=ht2}inBr_on_cast(label,rt1,rt2)|25->letflags=input_bytechinletlabel=uintchinletht1=heaptypechinletht2=heaptypechinletrt1={nullable=flagsland1<>0;typ=ht1}inletrt2={nullable=flagsland2<>0;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->letflags=input_bytechinletlabel=uintchinletht1=heaptypechinletht2=heaptypechinletrt1={nullable=flagsland1<>0;typ=ht1}inletrt2={nullable=flagsland2<>0;typ=ht2}inBr_on_cast_desc_eq(label,rt1,rt2)|38->letflags=input_bytechinletlabel=uintchinletht1=heaptypechinletht2=heaptypechinletrt1={nullable=flagsland1<>0;typ=ht1}inletrt2={nullable=flagsland2<>0;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 *)let(_:int)=uintchinAtomicFenceelsematchAtomics.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})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)letname_mapch=name_map'name_assocchletindirect_name_mapch=name_map'(funch->leti=uintchin(i,name_mapch))ch(* Branch-hinting proposal. [sections] holds the parsed [metadata.code.branch_hint]
entries: for each (absolute) function index, a list of (body-relative offset,
hint). [code_starts] gives, in defined-function order, the byte offset where
each function body (its locals declaration) begins — the origin for those
offsets. Wrap in [Hinted] 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
the hint is attached wherever its offset lands and [validation] rejects a
non-branch placement — matching the text path. Our own encoder always records
the branch opcode's offset, so a round-tripped valid module lands on a branch;
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_branch_hints~num_func_imports~code_starts~sections(code:Ast.locationcodelist)=ifsections=[]thencodeelseletby_func:(int,(int,bool)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,h)->Hashtbl.replacetbloffh)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|Someh->{iwithdesc=Hinted(h,i)}|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 proposal: parsed [metadata.code.branch_hint] entries and the
byte offset at which each function body begins, applied together after the
whole module is read (the section may sit before or after the code section). *)letbranch_hint_sections=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 *)letmodule_name=namechin{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.branch_hint"->(* Branch-hinting proposal. The section must appear before the
code section. Buffer the entries; they are matched
to instructions after the code section is parsed. The trailing
section-size check verifies the whole content was consumed. *)iflast_section_order>=12thenerrorch"metadata.code.branch_hint must appear before the code \
section";letentries=vec(funch->letfuncidx=uintchinlethints=vec(funch->letoffset=uintchinletlen=uintchin(* The payload is [len] bytes (always 1 in practice:
a single 0x00/0x01 hint byte); read them all and
take the first as the hint value. *)iflen=0thenerrorch"empty branch hint";letv=input_bytech<>0infor_=2tolendoignore(input_bytech)done;(offset,v))chin(funcidx,Array.to_listhints))chinbranch_hint_sections:=!branch_hint_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)in{reswithcode=attach_branch_hints~num_func_imports~code_starts:!code_body_starts~sections:!branch_hint_sectionsres.code;}