/** * @fileoverview A thin wrapper around Binaryen's C-API. * * The AssemblyScript compiler utilizes Binaryen's C-API directly. Even * though it currently imports binaryen.js, none of the JS APIs it * provides are used. * * @license Apache-2.0 */ import { Target } from "./common"; import * as binaryen from "./glue/binaryen"; export type ModuleRef = usize; export type FunctionRef = usize; export type ExpressionRef = usize; export type GlobalRef = usize; export type EventRef = usize; export type ImportRef = usize; export type ExportRef = usize; export type RelooperRef = usize; export type RelooperBlockRef = usize; export type Index = u32; // The following constants must be updated by running scripts/update-constants. // This is necessary because the functions are not yet callable with Binaryen // compiled to WebAssembly, requiring awaiting the ready promise first. Note // that this essentially fixes the compiler to specific versions of Binaryen // sometimes, because these constants can differ between Binaryen versions. export type NativeType = usize; export namespace NativeType { export const None: NativeType = 0 /* _BinaryenTypeNone */; export const Unreachable: NativeType = 1 /* _BinaryenTypeUnreachable */; export const I32: NativeType = 2 /* _BinaryenTypeInt32 */; export const I64: NativeType = 3 /* _BinaryenTypeInt64 */; export const F32: NativeType = 4 /* _BinaryenTypeFloat32 */; export const F64: NativeType = 5 /* _BinaryenTypeFloat64 */; export const V128: NativeType = 6 /* _BinaryenTypeVec128 */; export const Funcref: NativeType = 7 /* _BinaryenTypeFuncref */; export const Anyref: NativeType = 8 /* _BinaryenTypeAnyref */; export const Nullref: NativeType = 9 /* _BinaryenTypeNullref */; export const Exnref: NativeType = 10 /* _BinaryenTypeExnref */; export const Auto: NativeType = -1 /* _BinaryenTypeAuto */; } export enum FeatureFlags { MVP = 0 /* _BinaryenFeatureMVP */, Atomics = 1 /* _BinaryenFeatureAtomics */, MutableGloabls = 2 /* _BinaryenFeatureMutableGlobals */, NontrappingFPToInt = 4 /* _BinaryenFeatureNontrappingFPToInt */, SIMD128 = 8 /* _BinaryenFeatureSIMD128 */, BulkMemory = 16 /* _BinaryenFeatureBulkMemory */, SignExt = 32 /* _BinaryenFeatureSignExt */, ExceptionHandling = 64 /* _BinaryenFeatureExceptionHandling */, TailCall = 128 /* _BinaryenFeatureTailCall */, ReferenceTypes = 256 /* _BinaryenFeatureReferenceTypes */, MultiValue = 512 /* _BinaryenFeatureMultivalue */, All = 1023 /* _BinaryenFeatureAll */ } export enum ExpressionId { Invalid = 0 /* _BinaryenInvalidId */, Block = 1 /* _BinaryenBlockId */, If = 2 /* _BinaryenIfId */, Loop = 3 /* _BinaryenLoopId */, Break = 4 /* _BinaryenBreakId */, Switch = 5 /* _BinaryenSwitchId */, Call = 6 /* _BinaryenCallId */, CallIndirect = 7 /* _BinaryenCallIndirectId */, LocalGet = 8 /* _BinaryenLocalGetId */, LocalSet = 9 /* _BinaryenLocalSetId */, GlobalGet = 10 /* _BinaryenGlobalGetId */, GlobalSet = 11 /* _BinaryenGlobalSetId */, Load = 12 /* _BinaryenLoadId */, Store = 13 /* _BinaryenStoreId */, Const = 14 /* _BinaryenConstId */, Unary = 15 /* _BinaryenUnaryId */, Binary = 16 /* _BinaryenBinaryId */, Select = 17 /* _BinaryenSelectId */, Drop = 18 /* _BinaryenDropId */, Return = 19 /* _BinaryenReturnId */, Host = 20 /* _BinaryenHostId */, Nop = 21 /* _BinaryenNopId */, Unreachable = 22 /* _BinaryenUnreachableId */, AtomicCmpxchg = 24 /* _BinaryenAtomicCmpxchgId */, AtomicRMW = 23 /* _BinaryenAtomicRMWId */, AtomicWait = 25 /* _BinaryenAtomicWaitId */, AtomicNotify = 26 /* _BinaryenAtomicNotifyId */, AtomicFence = 27 /* _BinaryenAtomicFenceId */, SIMDExtract = 28 /* _BinaryenSIMDExtractId */, SIMDReplace = 29 /* _BinaryenSIMDReplaceId */, SIMDShuffle = 30 /* _BinaryenSIMDShuffleId */, SIMDTernary = 31 /* _BinaryenSIMDTernaryId */, SIMDShift = 32 /* _BinaryenSIMDShiftId */, SIMDLoad = 33 /* _BinaryenSIMDLoadId */, MemoryInit = 34 /* _BinaryenMemoryInitId */, DataDrop = 35 /* _BinaryenDataDropId */, MemoryCopy = 36 /* _BinaryenMemoryCopyId */, MemoryFill = 37 /* _BinaryenMemoryFillId */, Push = 38 /* _BinaryenPushId */, Pop = 39 /* _BinaryenPopId */, RefNull = 40 /* _BinaryenRefNullId */, RefIsNull = 41 /* _BinaryenRefIsNullId */, RefFunc = 42 /* _BinaryenRefFuncId */, Try = 43 /* _BinaryenTryId */, Throw = 44 /* _BinaryenThrowId */, Rethrow = 45 /* _BinaryenRethrowId */, BrOnExn = 46 /* _BinaryenBrOnExnId */, TupleMake = 47 /* _BinaryenTupleMakeId */, TupleExtract = 48 /* _BinaryenTupleExtractId */ } export enum UnaryOp { ClzI32 = 0 /* _BinaryenClzInt32 */, ClzI64 = 1 /* _BinaryenClzInt64 */, CtzI32 = 2 /* _BinaryenCtzInt32 */, CtzI64 = 3 /* _BinaryenCtzInt64 */, PopcntI32 = 4 /* _BinaryenPopcntInt32 */, PopcntI64 = 5 /* _BinaryenPopcntInt64 */, NegF32 = 6 /* _BinaryenNegFloat32 */, NegF64 = 7 /* _BinaryenNegFloat64 */, AbsF32 = 8 /* _BinaryenAbsFloat32 */, AbsF64 = 9 /* _BinaryenAbsFloat64 */, CeilF32 = 10 /* _BinaryenCeilFloat32 */, CeilF64 = 11 /* _BinaryenCeilFloat64 */, FloorF32 = 12 /* _BinaryenFloorFloat32 */, FloorF64 = 13 /* _BinaryenFloorFloat64 */, TruncF32 = 14 /* _BinaryenTruncFloat32 */, TruncF64 = 15 /* _BinaryenTruncFloat64 */, NearestF32 = 16 /* _BinaryenNearestFloat32 */, NearestF64 = 17 /* _BinaryenNearestFloat64 */, SqrtF32 = 18 /* _BinaryenSqrtFloat32 */, SqrtF64 = 19 /* _BinaryenSqrtFloat64 */, EqzI32 = 20 /* _BinaryenEqZInt32 */, EqzI64 = 21 /* _BinaryenEqZInt64 */, ExtendI32 = 22 /* _BinaryenExtendSInt32 */, ExtendU32 = 23 /* _BinaryenExtendUInt32 */, WrapI64 = 24 /* _BinaryenWrapInt64 */, TruncF32ToI32 = 25 /* _BinaryenTruncSFloat32ToInt32 */, TruncF32ToI64 = 26 /* _BinaryenTruncSFloat32ToInt64 */, TruncF32ToU32 = 27 /* _BinaryenTruncUFloat32ToInt32 */, TruncF32ToU64 = 28 /* _BinaryenTruncUFloat32ToInt64 */, TruncF64ToI32 = 29 /* _BinaryenTruncSFloat64ToInt32 */, TruncF64ToI64 = 30 /* _BinaryenTruncSFloat64ToInt64 */, TruncF64ToU32 = 31 /* _BinaryenTruncUFloat64ToInt32 */, TruncF64ToU64 = 32 /* _BinaryenTruncUFloat64ToInt64 */, ReinterpretF32 = 33 /* _BinaryenReinterpretFloat32 */, ReinterpretF64 = 34 /* _BinaryenReinterpretFloat64 */, ConvertI32ToF32 = 35 /* _BinaryenConvertSInt32ToFloat32 */, ConvertI32ToF64 = 36 /* _BinaryenConvertSInt32ToFloat64 */, ConvertU32ToF32 = 37 /* _BinaryenConvertUInt32ToFloat32 */, ConvertU32ToF64 = 38 /* _BinaryenConvertUInt32ToFloat64 */, ConvertI64ToF32 = 39 /* _BinaryenConvertSInt64ToFloat32 */, ConvertI64ToF64 = 40 /* _BinaryenConvertSInt64ToFloat64 */, ConvertU64ToF32 = 41 /* _BinaryenConvertUInt64ToFloat32 */, ConvertU64ToF64 = 42 /* _BinaryenConvertUInt64ToFloat64 */, PromoteF32 = 43 /* _BinaryenPromoteFloat32 */, DemoteF64 = 44 /* _BinaryenDemoteFloat64 */, ReinterpretI32 = 45 /* _BinaryenReinterpretInt32 */, ReinterpretI64 = 46 /* _BinaryenReinterpretInt64 */, // see: https://github.com/WebAssembly/sign-extension-ops ExtendI8ToI32 = 47 /* _BinaryenExtendS8Int32 */, ExtendI16ToI32 = 48 /* _BinaryenExtendS16Int32 */, ExtendI8ToI64 = 49 /* _BinaryenExtendS8Int64 */, ExtendI16ToI64 = 50 /* _BinaryenExtendS16Int64 */, ExtendI32ToI64 = 51 /* _BinaryenExtendS32Int64 */, // see: https://github.com/WebAssembly/nontrapping-float-to-int-conversions TruncF32ToI32Sat = 52 /* _BinaryenTruncSatSFloat32ToInt32 */, TruncF32ToU32Sat = 53 /* _BinaryenTruncSatUFloat32ToInt32 */, TruncF64ToI32Sat = 54 /* _BinaryenTruncSatSFloat64ToInt32 */, TruncF64ToU32Sat = 55 /* _BinaryenTruncSatUFloat64ToInt32 */, TruncF32ToI64Sat = 56 /* _BinaryenTruncSatSFloat32ToInt64 */, TruncF32ToU64Sat = 57 /* _BinaryenTruncSatUFloat32ToInt64 */, TruncF64ToI64Sat = 58 /* _BinaryenTruncSatSFloat64ToInt64 */, TruncF64ToU64Sat = 59 /* _BinaryenTruncSatUFloat64ToInt64 */, // see: https://github.com/WebAssembly/simd SplatI8x16 = 60 /* _BinaryenSplatVecI8x16 */, SplatI16x8 = 61 /* _BinaryenSplatVecI16x8 */, SplatI32x4 = 62 /* _BinaryenSplatVecI32x4 */, SplatI64x2 = 63 /* _BinaryenSplatVecI64x2 */, SplatF32x4 = 64 /* _BinaryenSplatVecF32x4 */, SplatF64x2 = 65 /* _BinaryenSplatVecF64x2 */, NotV128 = 66 /* _BinaryenNotVec128 */, AbsI8x16 = 67 /* __BinaryenAbsVecI8x16 */, NegI8x16 = 68 /* _BinaryenNegVecI8x16 */, AnyTrueI8x16 = 69 /* _BinaryenAnyTrueVecI8x16 */, AllTrueI8x16 = 70 /* _BinaryenAllTrueVecI8x16 */, BitmaskI8x16 = 71 /* __BinaryenBitmaskVecI8x16 */, AbsI16x8 = 72 /* __BinaryenAbsVecI16x8 */, NegI16x8 = 73 /* _BinaryenNegVecI16x8 */, AnyTrueI16x8 = 74 /* _BinaryenAnyTrueVecI16x8 */, AllTrueI16x8 = 75 /* _BinaryenAllTrueVecI16x8 */, BitmaskI16x8 = 76 /* _BinaryenBitmaskVecI16x8 */, AbsI32x4 = 77 /* _BinaryenAbsVecI32x4 */, NegI32x4 = 78 /* _BinaryenNegVecI32x4 */, AnyTrueI32x4 = 79 /* _BinaryenAnyTrueVecI32x4 */, AllTrueI32x4 = 80 /* _BinaryenAllTrueVecI32x4 */, BitmaskI32x4 = 81 /* _BinaryenBitmaskVecI32x4 */, NegI64x2 = 82 /* _BinaryenNegVecI64x2 */, AnyTrueI64x2 = 83 /* _BinaryenAnyTrueVecI64x2 */, AllTrueI64x2 = 84 /* _BinaryenAllTrueVecI64x2 */, AbsF32x4 = 85 /* _BinaryenAbsVecF32x4 */, NegF32x4 = 86 /* _BinaryenNegVecF32x4 */, SqrtF32x4 = 87 /* _BinaryenSqrtVecF32x4 */, AbsF64x2 = 88 /* _BinaryenAbsVecF64x2 */, NegF64x2 = 89 /* _BinaryenNegVecF64x2 */, SqrtF64x2 = 90 /* _BinaryenSqrtVecF64x2 */, TruncSatF32x4ToI32x4 = 91 /* _BinaryenTruncSatSVecF32x4ToVecI32x4 */, TruncSatF32x4ToU32x4 = 92 /* _BinaryenTruncSatUVecF32x4ToVecI32x4 */, TruncSatF64x2ToI64x2 = 93 /* _BinaryenTruncSatSVecF64x2ToVecI64x2 */, TruncSatF64x2ToU64x2 = 94 /* _BinaryenTruncSatUVecF64x2ToVecI64x2 */, ConvertI32x4ToF32x4 = 95 /* _BinaryenConvertSVecI32x4ToVecF32x4 */, ConvertU32x4ToF32x4 = 96 /* _BinaryenConvertUVecI32x4ToVecF32x4 */, ConvertI64x2ToF64x2 = 97 /* _BinaryenConvertSVecI64x2ToVecF64x2 */, ConvertU64x2ToF64x2 = 98 /* _BinaryenConvertUVecI64x2ToVecF64x2 */, WidenLowI8x16ToI16x8 = 99 /* _BinaryenWidenLowSVecI8x16ToVecI16x8 */, WidenHighI8x16ToI16x8 = 100 /* _BinaryenWidenHighSVecI8x16ToVecI16x8 */, WidenLowU8x16ToU16x8 = 101 /* _BinaryenWidenLowUVecI8x16ToVecI16x8 */, WidenHighU8x16ToU16x8 = 102 /* _BinaryenWidenHighUVecI8x16ToVecI16x8 */, WidenLowI16x8ToI32x4 = 103 /* _BinaryenWidenLowSVecI16x8ToVecI32x4 */, WidenHighI16x8ToI32x4 = 104 /* _BinaryenWidenHighSVecI16x8ToVecI32x4 */, WidenLowU16x8ToU32x4 = 105 /* _BinaryenWidenLowUVecI16x8ToVecI32x4 */, WidenHighU16x8ToU32x4 = 106 /* _BinaryenWidenHighUVecI16x8ToVecI32x4 */ } export enum BinaryOp { AddI32 = 0 /* _BinaryenAddInt32 */, SubI32 = 1 /* _BinaryenSubInt32 */, MulI32 = 2 /* _BinaryenMulInt32 */, DivI32 = 3 /* _BinaryenDivSInt32 */, DivU32 = 4 /* _BinaryenDivUInt32 */, RemI32 = 5 /* _BinaryenRemSInt32 */, RemU32 = 6 /* _BinaryenRemUInt32 */, AndI32 = 7 /* _BinaryenAndInt32 */, OrI32 = 8 /* _BinaryenOrInt32 */, XorI32 = 9 /* _BinaryenXorInt32 */, ShlI32 = 10 /* _BinaryenShlInt32 */, ShrU32 = 11 /* _BinaryenShrUInt32 */, ShrI32 = 12 /* _BinaryenShrSInt32 */, RotlI32 = 13 /* _BinaryenRotLInt32 */, RotrI32 = 14 /* _BinaryenRotRInt32 */, EqI32 = 15 /* _BinaryenEqInt32 */, NeI32 = 16 /* _BinaryenNeInt32 */, LtI32 = 17 /* _BinaryenLtSInt32 */, LtU32 = 18 /* _BinaryenLtUInt32 */, LeI32 = 19 /* _BinaryenLeSInt32 */, LeU32 = 20 /* _BinaryenLeUInt32 */, GtI32 = 21 /* _BinaryenGtSInt32 */, GtU32 = 22 /* _BinaryenGtUInt32 */, GeI32 = 23 /* _BinaryenGeSInt32 */, GeU32 = 24 /* _BinaryenGeUInt32 */, AddI64 = 25 /* _BinaryenAddInt64 */, SubI64 = 26 /* _BinaryenSubInt64 */, MulI64 = 27 /* _BinaryenMulInt64 */, DivI64 = 28 /* _BinaryenDivSInt64 */, DivU64 = 29 /* _BinaryenDivUInt64 */, RemI64 = 30 /* _BinaryenRemSInt64 */, RemU64 = 31 /* _BinaryenRemUInt64 */, AndI64 = 32 /* _BinaryenAndInt64 */, OrI64 = 33 /* _BinaryenOrInt64 */, XorI64 = 34 /* _BinaryenXorInt64 */, ShlI64 = 35 /* _BinaryenShlInt64 */, ShrU64 = 36 /* _BinaryenShrUInt64 */, ShrI64 = 37 /* _BinaryenShrSInt64 */, RotlI64 = 38 /* _BinaryenRotLInt64 */, RotrI64 = 39 /* _BinaryenRotRInt64 */, EqI64 = 40 /* _BinaryenEqInt64 */, NeI64 = 41 /* _BinaryenNeInt64 */, LtI64 = 42 /* _BinaryenLtSInt64 */, LtU64 = 43 /* _BinaryenLtUInt64 */, LeI64 = 44 /* _BinaryenLeSInt64 */, LeU64 = 45 /* _BinaryenLeUInt64 */, GtI64 = 46 /* _BinaryenGtSInt64 */, GtU64 = 47 /* _BinaryenGtUInt64 */, GeI64 = 48 /* _BinaryenGeSInt64 */, GeU64 = 49 /* _BinaryenGeUInt64 */, AddF32 = 50 /* _BinaryenAddFloat32 */, SubF32 = 51 /* _BinaryenSubFloat32 */, MulF32 = 52 /* _BinaryenMulFloat32 */, DivF32 = 53 /* _BinaryenDivFloat32 */, CopysignF32 = 54 /* _BinaryenCopySignFloat32 */, MinF32 = 55 /* _BinaryenMinFloat32 */, MaxF32 = 56 /* _BinaryenMaxFloat32 */, EqF32 = 57 /* _BinaryenEqFloat32 */, NeF32 = 58 /* _BinaryenNeFloat32 */, LtF32 = 59 /* _BinaryenLtFloat32 */, LeF32 = 60 /* _BinaryenLeFloat32 */, GtF32 = 61 /* _BinaryenGtFloat32 */, GeF32 = 62 /* _BinaryenGeFloat32 */, AddF64 = 63 /* _BinaryenAddFloat64 */, SubF64 = 64 /* _BinaryenSubFloat64 */, MulF64 = 65 /* _BinaryenMulFloat64 */, DivF64 = 66 /* _BinaryenDivFloat64 */, CopysignF64 = 67 /* _BinaryenCopySignFloat64 */, MinF64 = 68 /* _BinaryenMinFloat64 */, MaxF64 = 69 /* _BinaryenMaxFloat64 */, EqF64 = 70 /* _BinaryenEqFloat64 */, NeF64 = 71 /* _BinaryenNeFloat64 */, LtF64 = 72 /* _BinaryenLtFloat64 */, LeF64 = 73 /* _BinaryenLeFloat64 */, GtF64 = 74 /* _BinaryenGtFloat64 */, GeF64 = 75 /* _BinaryenGeFloat64 */, // see: https://github.com/WebAssembly/simd EqI8x16 = 76 /* _BinaryenEqVecI8x16 */, NeI8x16 = 77 /* _BinaryenNeVecI8x16 */, LtI8x16 = 78 /* _BinaryenLtSVecI8x16 */, LtU8x16 = 79 /* _BinaryenLtUVecI8x16 */, GtI8x16 = 80 /* _BinaryenGtSVecI8x16 */, GtU8x16 = 81 /* _BinaryenGtUVecI8x16 */, LeI8x16 = 82 /* _BinaryenLeSVecI8x16 */, LeU8x16 = 83 /* _BinaryenLeUVecI8x16 */, GeI8x16 = 84 /* _BinaryenGeSVecI8x16 */, GeU8x16 = 85 /* _BinaryenGeUVecI8x16 */, EqI16x8 = 86 /* _BinaryenEqVecI16x8 */, NeI16x8 = 87 /* _BinaryenNeVecI16x8 */, LtI16x8 = 88 /* _BinaryenLtSVecI16x8 */, LtU16x8 = 89 /* _BinaryenLtUVecI16x8 */, GtI16x8 = 90 /* _BinaryenGtSVecI16x8 */, GtU16x8 = 91 /* _BinaryenGtUVecI16x8 */, LeI16x8 = 92 /* _BinaryenLeSVecI16x8 */, LeU16x8 = 93 /* _BinaryenLeUVecI16x8 */, GeI16x8 = 94 /* _BinaryenGeSVecI16x8 */, GeU16x8 = 95 /* _BinaryenGeUVecI16x8 */, EqI32x4 = 96 /* _BinaryenEqVecI32x4 */, NeI32x4 = 97 /* _BinaryenNeVecI32x4 */, LtI32x4 = 98 /* _BinaryenLtSVecI32x4 */, LtU32x4 = 99 /* _BinaryenLtUVecI32x4 */, GtI32x4 = 100 /* _BinaryenGtSVecI32x4 */, GtU32x4 = 101 /* _BinaryenGtUVecI32x4 */, LeI32x4 = 102 /* _BinaryenLeSVecI32x4 */, LeU32x4 = 103 /* _BinaryenLeUVecI32x4 */, GeI32x4 = 104 /* _BinaryenGeSVecI32x4 */, GeU32x4 = 105 /* _BinaryenGeUVecI32x4 */, EqF32x4 = 106 /* _BinaryenEqVecF32x4 */, NeF32x4 = 107 /* _BinaryenNeVecF32x4 */, LtF32x4 = 108 /* _BinaryenLtVecF32x4 */, GtF32x4 = 109 /* _BinaryenGtVecF32x4 */, LeF32x4 = 110 /* _BinaryenLeVecF32x4 */, GeF32x4 = 111 /* _BinaryenGeVecF32x4 */, EqF64x2 = 112 /* _BinaryenEqVecF64x2 */, NeF64x2 = 113 /* _BinaryenNeVecF64x2 */, LtF64x2 = 114 /* _BinaryenLtVecF64x2 */, GtF64x2 = 115 /* _BinaryenGtVecF64x2 */, LeF64x2 = 116 /* _BinaryenLeVecF64x2 */, GeF64x2 = 117 /* _BinaryenGeVecF64x2 */, AndV128 = 118 /* _BinaryenAndVec128 */, OrV128 = 119 /* _BinaryenOrVec128 */, XorV128 = 120 /* _BinaryenXorVec128 */, AndNotV128 = 121 /* _BinaryenAndNotVec128 */, AddI8x16 = 122 /* _BinaryenAddVecI8x16 */, AddSatI8x16 = 123 /* _BinaryenAddSatSVecI8x16 */, AddSatU8x16 = 124 /* _BinaryenAddSatUVecI8x16 */, SubI8x16 = 125 /* _BinaryenSubVecI8x16 */, SubSatI8x16 = 126 /* _BinaryenSubSatSVecI8x16 */, SubSatU8x16 = 127 /* _BinaryenSubSatUVecI8x16 */, MulI8x16 = 128 /* _BinaryenMulVecI8x16 */, MinI8x16 = 129 /* _BinaryenMinSVecI8x16 */, MinU8x16 = 130 /* _BinaryenMinUVecI8x16 */, MaxI8x16 = 131 /* _BinaryenMaxSVecI8x16 */, MaxU8x16 = 132 /* _BinaryenMaxUVecI8x16 */, AvgrU8x16 = 133 /* _BinaryenAvgrUVecI8x16 */, AddI16x8 = 134 /* _BinaryenAddVecI16x8 */, AddSatI16x8 = 135 /* _BinaryenAddSatSVecI16x8 */, AddSatU16x8 = 136 /* _BinaryenAddSatUVecI16x8 */, SubI16x8 = 137 /* _BinaryenSubVecI16x8 */, SubSatI16x8 = 138 /* _BinaryenSubSatSVecI16x8 */, SubSatU16x8 = 139 /* _BinaryenSubSatUVecI16x8 */, MulI16x8 = 140 /* _BinaryenMulVecI16x8 */, MinI16x8 = 141 /* _BinaryenMinSVecI16x8 */, MinU16x8 = 142 /* _BinaryenMinUVecI16x8 */, MaxI16x8 = 143 /* _BinaryenMaxSVecI16x8 */, MaxU16x8 = 144 /* _BinaryenMaxUVecI16x8 */, AvgrU16x8 = 145 /* _BinaryenAvgrUVecI16x8 */, AddI32x4 = 146 /* _BinaryenAddVecI32x4 */, SubI32x4 = 147 /* _BinaryenSubVecI32x4 */, MulI32x4 = 148 /* _BinaryenMulVecI32x4 */, MinI32x4 = 149 /* _BinaryenMinSVecI32x4 */, MinU32x4 = 150 /* _BinaryenMinUVecI32x4 */, MaxI32x4 = 151 /* _BinaryenMaxSVecI32x4 */, MaxU32x4 = 152 /* _BinaryenMaxUVecI32x4 */, DotI16x8 = 153 /* _BinaryenDotSVecI16x8ToVecI32x4 */, AddI64x2 = 154 /* _BinaryenAddVecI64x2 */, SubI64x2 = 155 /* _BinaryenSubVecI64x2 */, AddF32x4 = 156 /* _BinaryenAddVecF32x4 */, SubF32x4 = 157 /* _BinaryenSubVecF32x4 */, MulF32x4 = 158 /* _BinaryenMulVecF32x4 */, DivF32x4 = 159 /* _BinaryenDivVecF32x4 */, MinF32x4 = 160 /* _BinaryenMinVecF32x4 */, MaxF32x4 = 161 /* _BinaryenMaxVecF32x4 */, PminF32x4 = 162 /* _BinaryenPMinVecF32x4 */, PmaxF32x4 = 163 /* _BinaryenPMaxVecF32x4 */, AddF64x2 = 164 /* _BinaryenAddVecF64x2 */, SubF64x2 = 165 /* _BinaryenSubVecF64x2 */, MulF64x2 = 166 /* _BinaryenMulVecF64x2 */, DivF64x2 = 167 /* _BinaryenDivVecF64x2 */, MinF64x2 = 168 /* _BinaryenMinVecF64x2 */, MaxF64x2 = 169 /* _BinaryenMaxVecF64x2 */, PminF64x2 = 170 /* _BinaryenPMinVecF64x2 */, PmaxF64x2 = 171 /* _BinaryenPMaxVecF64x2 */, NarrowI16x8ToI8x16 = 172 /* _BinaryenNarrowSVecI16x8ToVecI8x16 */, NarrowU16x8ToU8x16 = 173 /* _BinaryenNarrowUVecI16x8ToVecI8x16 */, NarrowI32x4ToI16x8 = 174 /* _BinaryenNarrowSVecI32x4ToVecI16x8 */, NarrowU32x4ToU16x8 = 175 /* _BinaryenNarrowUVecI32x4ToVecI16x8 */, SwizzleV8x16 = 176 /* _BinaryenSwizzleVec8x16 */ } export enum HostOp { MemorySize = 0 /* _BinaryenMemorySize */, MemoryGrow = 1 /* _BinaryenMemoryGrow */, } export enum AtomicRMWOp { Add = 0 /* _BinaryenAtomicRMWAdd */, Sub = 1 /* _BinaryenAtomicRMWSub */, And = 2 /* _BinaryenAtomicRMWAnd */, Or = 3 /* _BinaryenAtomicRMWOr */, Xor = 4 /* _BinaryenAtomicRMWXor */, Xchg = 5 /* _BinaryenAtomicRMWXchg */ } export enum SIMDExtractOp { ExtractLaneI8x16 = 0 /* _BinaryenExtractLaneSVecI8x16 */, ExtractLaneU8x16 = 1 /* _BinaryenExtractLaneUVecI8x16 */, ExtractLaneI16x8 = 2 /* _BinaryenExtractLaneSVecI16x8 */, ExtractLaneU16x8 = 3 /* _BinaryenExtractLaneUVecI16x8 */, ExtractLaneI32x4 = 4 /* _BinaryenExtractLaneVecI32x4 */, ExtractLaneI64x2 = 5 /* _BinaryenExtractLaneVecI64x2 */, ExtractLaneF32x4 = 6 /* _BinaryenExtractLaneVecF32x4 */, ExtractLaneF64x2 = 7 /* _BinaryenExtractLaneVecF64x2 */, } export enum SIMDReplaceOp { ReplaceLaneI8x16 = 0 /* _BinaryenReplaceLaneVecI8x16 */, ReplaceLaneI16x8 = 1 /* _BinaryenReplaceLaneVecI16x8 */, ReplaceLaneI32x4 = 2 /* _BinaryenReplaceLaneVecI32x4 */, ReplaceLaneI64x2 = 3 /* _BinaryenReplaceLaneVecI64x2 */, ReplaceLaneF32x4 = 4 /* _BinaryenReplaceLaneVecF32x4 */, ReplaceLaneF64x2 = 5 /* _BinaryenReplaceLaneVecF64x2 */ } export enum SIMDShiftOp { ShlI8x16 = 0 /* _BinaryenShlVecI8x16 */, ShrI8x16 = 1 /* _BinaryenShrSVecI8x16 */, ShrU8x16 = 2 /* _BinaryenShrUVecI8x16 */, ShlI16x8 = 3 /* _BinaryenShlVecI16x8 */, ShrI16x8 = 4 /* _BinaryenShrSVecI16x8 */, ShrU16x8 = 5 /* _BinaryenShrUVecI16x8 */, ShlI32x4 = 6 /* _BinaryenShlVecI32x4 */, ShrI32x4 = 7 /* _BinaryenShrSVecI32x4 */, ShrU32x4 = 8 /* _BinaryenShrUVecI32x4 */, ShlI64x2 = 9 /* _BinaryenShlVecI64x2 */, ShrI64x2 = 10 /* _BinaryenShrSVecI64x2 */, ShrU64x2 = 11 /* _BinaryenShrUVecI64x2 */ } export enum SIMDTernaryOp { Bitselect = 0 /* _BinaryenBitselectVec128 */, QFMAF32x4 = 1 /* _BinaryenQFMAVecF32x4 */, QFMSF32x4 = 2 /* _BinaryenQFMSVecF32x4 */, QFMAF64x2 = 3 /* _BinaryenQFMAVecF64x2 */, QFMSF64x2 = 4 /* _BinaryenQFMSVecF64x2 */ } export enum SIMDLoadOp { LoadSplatV8x16 = 0 /* _BinaryenLoadSplatVec8x16 */, LoadSplatV16x8 = 1 /* _BinaryenLoadSplatVec16x8 */, LoadSplatV32x4 = 2 /* _BinaryenLoadSplatVec32x4 */, LoadSplatV64x2 = 3 /* _BinaryenLoadSplatVec64x2 */, LoadI8ToI16x8 = 4 /* _BinaryenLoadExtSVec8x8ToVecI16x8 */, LoadU8ToU16x8 = 5 /* _BinaryenLoadExtUVec8x8ToVecI16x8 */, LoadI16ToI32x4 = 6 /* _BinaryenLoadExtSVec16x4ToVecI32x4 */, LoadU16ToU32x4 = 7 /* _BinaryenLoadExtUVec16x4ToVecI32x4 */, LoadI32ToI64x2 = 8 /* _BinaryenLoadExtSVec32x2ToVecI64x2 */, LoadU32ToU64x2 = 9 /* _BinaryenLoadExtUVec32x2ToVecI64x2 */ } export enum ExpressionRunnerFlags { Default = 0 /* _ExpressionRunnerFlagsDefault */, PreserveSideeffects = 1 /* _ExpressionRunnerFlagsPreserveSideeffects */, TraverseCalls = 2 /* _ExpressionRunnerFlagsTraverseCalls */ } export class MemorySegment { buffer: Uint8Array; offset: i64; static create(buffer: Uint8Array, offset: i64): MemorySegment { var segment = new MemorySegment(); segment.buffer = buffer; segment.offset = offset; return segment; } } export class Module { ref: ModuleRef; private lit: usize; static create(): Module { var module = new Module(); module.ref = binaryen._BinaryenModuleCreate(); module.lit = binaryen._malloc(binaryen._BinaryenSizeofLiteral()); return module; } static createFrom(buffer: Uint8Array): Module { var module = new Module(); var cArr = allocU8Array(buffer); module.ref = binaryen._BinaryenModuleRead(cArr, buffer.length); binaryen._free(changetype(cArr)); module.lit = binaryen._malloc(binaryen._BinaryenSizeofLiteral()); return module; } private constructor() { } // constants i32(value: i32): ExpressionRef { var out = this.lit; binaryen._BinaryenLiteralInt32(out, value); return binaryen._BinaryenConst(this.ref, out); } i64(valueLow: i32, valueHigh: i32 = 0): ExpressionRef { var out = this.lit; binaryen._BinaryenLiteralInt64(out, valueLow, valueHigh); return binaryen._BinaryenConst(this.ref, out); } f32(value: f32): ExpressionRef { var out = this.lit; binaryen._BinaryenLiteralFloat32(out, value); return binaryen._BinaryenConst(this.ref, out); } f64(value: f64): ExpressionRef { var out = this.lit; binaryen._BinaryenLiteralFloat64(out, value); return binaryen._BinaryenConst(this.ref, out); } v128(bytes: Uint8Array): ExpressionRef { assert(bytes.length == 16); var out = this.lit; for (let i = 0; i < 16; ++i) binaryen.__i32_store8(out + i, bytes[i]); binaryen._BinaryenLiteralVec128(out, out); return binaryen._BinaryenConst(this.ref, out); } ref_null(): ExpressionRef { return binaryen._BinaryenRefNull(this.ref); } // expressions unary( op: UnaryOp, expr: ExpressionRef ): ExpressionRef { return binaryen._BinaryenUnary(this.ref, op, expr); } binary( op: BinaryOp, left: ExpressionRef, right: ExpressionRef ): ExpressionRef { return binaryen._BinaryenBinary(this.ref, op, left, right); } host( op: HostOp, name: string | null = null, operands: ExpressionRef[] | null = null ): ExpressionRef { var cStr = this.allocStringCached(name); var cArr = allocPtrArray(operands); var ret = binaryen._BinaryenHost(this.ref, op, cStr, cArr, operands ? (operands).length : 0); binaryen._free(cArr); return ret; } local_get( index: i32, type: NativeType ): ExpressionRef { return binaryen._BinaryenLocalGet(this.ref, index, type); } local_tee( index: i32, value: ExpressionRef, type: NativeType = NativeType.Auto ): ExpressionRef { if (type == NativeType.Auto) type = binaryen._BinaryenExpressionGetType(value); return binaryen._BinaryenLocalTee(this.ref, index, value, type); } global_get( name: string, type: NativeType ): ExpressionRef { var cStr = this.allocStringCached(name); return binaryen._BinaryenGlobalGet(this.ref, cStr, type); } load( bytes: Index, signed: bool, ptr: ExpressionRef, type: NativeType, offset: Index = 0, align: Index = bytes // naturally aligned by default ): ExpressionRef { return binaryen._BinaryenLoad(this.ref, bytes, signed ? 1 : 0, offset, align, type, ptr); } store( bytes: Index, ptr: ExpressionRef, value: ExpressionRef, type: NativeType, offset: Index = 0, align: Index = bytes // naturally aligned by default ): ExpressionRef { return binaryen._BinaryenStore(this.ref, bytes, offset, align, ptr, value, type); } atomic_load( bytes: Index, ptr: ExpressionRef, type: NativeType, offset: Index = 0 ): ExpressionRef { return binaryen._BinaryenAtomicLoad(this.ref, bytes, offset, type, ptr); } atomic_store( bytes: Index, ptr: ExpressionRef, value: ExpressionRef, type: NativeType, offset: Index = 0 ): ExpressionRef { return binaryen._BinaryenAtomicStore(this.ref, bytes, offset, ptr, value, type); } atomic_rmw( op: AtomicRMWOp, bytes: Index, offset: Index, ptr: ExpressionRef, value: ExpressionRef, type: NativeType ): ExpressionRef { return binaryen._BinaryenAtomicRMW(this.ref, op, bytes, offset, ptr, value, type); } atomic_cmpxchg( bytes: Index, offset: Index, ptr: ExpressionRef, expected: ExpressionRef, replacement: ExpressionRef, type: NativeType ): ExpressionRef { return binaryen._BinaryenAtomicCmpxchg(this.ref, bytes, offset, ptr, expected, replacement, type); } atomic_wait( ptr: ExpressionRef, expected: ExpressionRef, timeout: ExpressionRef, expectedType: NativeType ): ExpressionRef { return binaryen._BinaryenAtomicWait(this.ref, ptr, expected, timeout, expectedType); } atomic_notify( ptr: ExpressionRef, notifyCount: ExpressionRef ): ExpressionRef { return binaryen._BinaryenAtomicNotify(this.ref, ptr, notifyCount); } atomic_fence(): ExpressionRef { return binaryen._BinaryenAtomicFence(this.ref); } // statements local_set( index: Index, value: ExpressionRef ): ExpressionRef { return binaryen._BinaryenLocalSet(this.ref, index, value); } global_set( name: string, value: ExpressionRef ): ExpressionRef { var cStr = this.allocStringCached(name); return binaryen._BinaryenGlobalSet(this.ref, cStr, value); } block( label: string | null, children: ExpressionRef[], type: NativeType = NativeType.None ): ExpressionRef { var cStr = this.allocStringCached(label); var cArr = allocPtrArray(children); var ret = binaryen._BinaryenBlock(this.ref, cStr, cArr, children.length, type); binaryen._free(cArr); return ret; } /** Attempts to trivially flatten a series of expressions instead of emitting a block. */ flatten( stmts: ExpressionRef[], type: NativeType = NativeType.None ): ExpressionRef { var length = stmts.length; if (length == 0) return this.nop(); // usually filtered out again if (length == 1) { let single = stmts[0]; switch (getExpressionId(single)) { case ExpressionId.Return: case ExpressionId.Throw: case ExpressionId.Unreachable: { // type does no matter, terminates anyway return single; } } let singleType = getExpressionType(single); assert(singleType == NativeType.Unreachable || singleType == type); return single; } return this.block(null, stmts, type); } br( label: string | null, condition: ExpressionRef = 0, value: ExpressionRef = 0 ): ExpressionRef { var cStr = this.allocStringCached(label); return binaryen._BinaryenBreak(this.ref, cStr, condition, value); } drop( expression: ExpressionRef ): ExpressionRef { return binaryen._BinaryenDrop(this.ref, expression); } maybeDropCondition(condition: ExpressionRef, result: ExpressionRef): ExpressionRef { // FIXME: This is necessary because Binaryen's ExpressionRunner bails early // when encountering a local with an unknown value. This helper only drops // the pre-evaluated condition if it has relevant side effects. // see WebAssembly/binaryen#1237 if ((getSideEffects(condition) & ~(SideEffects.ReadsLocal | SideEffects.ReadsGlobal)) != 0) { return this.block(null, [ this.drop(condition), result ], getExpressionType(result)); } return result; } loop( label: string | null, body: ExpressionRef ): ExpressionRef { var cStr = this.allocStringCached(label); return binaryen._BinaryenLoop(this.ref, cStr, body); } if( condition: ExpressionRef, ifTrue: ExpressionRef, ifFalse: ExpressionRef = 0 ): ExpressionRef { return binaryen._BinaryenIf(this.ref, condition, ifTrue, ifFalse); } nop(): ExpressionRef { return binaryen._BinaryenNop(this.ref); } return( expression: ExpressionRef = 0 ): ExpressionRef { return binaryen._BinaryenReturn(this.ref, expression); } select( ifTrue: ExpressionRef, ifFalse: ExpressionRef, condition: ExpressionRef, type: NativeType = NativeType.Auto ): ExpressionRef { if (type == NativeType.Auto) { type = binaryen._BinaryenExpressionGetType(ifTrue); assert(type == binaryen._BinaryenExpressionGetType(ifFalse)); } return binaryen._BinaryenSelect(this.ref, condition, ifTrue, ifFalse, type); } switch( names: string[], defaultName: string | null, condition: ExpressionRef, value: ExpressionRef = 0 ): ExpressionRef { var numNames = names.length; var strs = new Array(numNames); for (let i = 0; i < numNames; ++i) { strs[i] = this.allocStringCached(names[i]); } var cArr = allocPtrArray(strs); var cStr = this.allocStringCached(defaultName); var ret = binaryen._BinaryenSwitch(this.ref, cArr, numNames, cStr, condition, value); binaryen._free(cArr); return ret; } call( target: string, operands: ExpressionRef[] | null, returnType: NativeType, isReturn: bool = false ): ExpressionRef { var cStr = this.allocStringCached(target); var cArr = allocPtrArray(operands); var ret = isReturn ? binaryen._BinaryenReturnCall(this.ref, cStr, cArr, operands ? operands.length : 0, returnType) : binaryen._BinaryenCall(this.ref, cStr, cArr, operands ? operands.length : 0, returnType); binaryen._free(cArr); return ret; } return_call( target: string, operands: ExpressionRef[] | null, returnType: NativeType ): ExpressionRef { return this.call(target, operands, returnType, true); } call_indirect( index: ExpressionRef, operands: ExpressionRef[] | null, params: NativeType, results: NativeType, isReturn: bool = false ): ExpressionRef { var cArr = allocPtrArray(operands); var ret = isReturn ? binaryen._BinaryenReturnCallIndirect(this.ref, index, cArr, operands ? operands.length : 0, params, results) : binaryen._BinaryenCallIndirect(this.ref, index, cArr, operands ? operands.length : 0, params, results); binaryen._free(cArr); return ret; } return_call_indirect( index: ExpressionRef, operands: ExpressionRef[] | null, params: NativeType, results: NativeType ): ExpressionRef { return this.call_indirect(index, operands, params, results, true); } unreachable(): ExpressionRef { return binaryen._BinaryenUnreachable(this.ref); } // bulk memory memory_copy( dest: ExpressionRef, source: ExpressionRef, size: ExpressionRef ): ExpressionRef { return binaryen._BinaryenMemoryCopy(this.ref, dest, source, size); } memory_fill( dest: ExpressionRef, value: ExpressionRef, size: ExpressionRef ): ExpressionRef { return binaryen._BinaryenMemoryFill(this.ref, dest, value, size); } // exception handling try( body: ExpressionRef, catchBody: ExpressionRef ): ExpressionRef { return binaryen._BinaryenTry(this.ref, body, catchBody); } throw( eventName: string, operands: ExpressionRef[] ): ExpressionRef { var cStr = this.allocStringCached(eventName); var cArr = allocPtrArray(operands); var ret = binaryen._BinaryenThrow(this.ref, cStr, cArr, operands.length); binaryen._free(cArr); return ret; } rethrow( exnref: ExpressionRef ): ExpressionRef { return binaryen._BinaryenRethrow(this.ref, exnref); } br_on_exn( name: string, eventName: string, exnref: ExpressionRef ): ExpressionRef { var cStr1 = this.allocStringCached(name); var cStr2 = this.allocStringCached(eventName); return binaryen._BinaryenBrOnExn(this.ref, cStr1, cStr2, exnref); } // push / pop (multi value?) push( value: ExpressionRef ): ExpressionRef { return binaryen._BinaryenPush(this.ref, value); } pop( type: NativeType ): ExpressionRef { return binaryen._BinaryenPop(this.ref, type); } // simd simd_extract( op: SIMDExtractOp, vec: ExpressionRef, idx: u8 ): ExpressionRef { return binaryen._BinaryenSIMDExtract(this.ref, op, vec, idx); } simd_replace( op: SIMDReplaceOp, vec: ExpressionRef, idx: u8, value: ExpressionRef ): ExpressionRef { return binaryen._BinaryenSIMDReplace(this.ref, op, vec, idx, value); } simd_shuffle( vec1: ExpressionRef, vec2: ExpressionRef, mask: Uint8Array ): ExpressionRef { assert(mask.length == 16); var cArr = allocU8Array(mask); var ret = binaryen._BinaryenSIMDShuffle(this.ref, vec1, vec2, cArr); binaryen._free(cArr); return ret; } simd_ternary( op: SIMDTernaryOp, a: ExpressionRef, b: ExpressionRef, c: ExpressionRef ): ExpressionRef { return binaryen._BinaryenSIMDTernary(this.ref, op, a, b, c); } simd_shift( op: SIMDShiftOp, vec: ExpressionRef, shift: ExpressionRef ): ExpressionRef { return binaryen._BinaryenSIMDShift(this.ref, op, vec, shift); } simd_load( op: SIMDLoadOp, ptr: ExpressionRef, offset: u32, align: u32 ): ExpressionRef { return binaryen._BinaryenSIMDLoad(this.ref, op, offset, align, ptr); } // reference types ref_is_null( expr: ExpressionRef ): ExpressionRef { return binaryen._BinaryenRefIsNull(this.ref, expr); } ref_func( name: string ): ExpressionRef { var cStr = this.allocStringCached(name); return binaryen._BinaryenRefFunc(this.ref, cStr); } // tuples (pseudo instructions) tuple_make(operands: ExpressionRef[]): ExpressionRef { var cArr = allocPtrArray(operands); var ret = binaryen._BinaryenTupleMake(this.ref, cArr, operands.length); binaryen._free(cArr); return ret; } tuple_extract(tuple: ExpressionRef, index: Index): ExpressionRef { return binaryen._BinaryenTupleExtract(this.ref, tuple, index); } // globals addGlobal( name: string, type: NativeType, mutable: bool, initializer: ExpressionRef ): GlobalRef { var cStr = this.allocStringCached(name); return binaryen._BinaryenAddGlobal(this.ref, cStr, type, mutable, initializer); } getGlobal( name: string ): GlobalRef { var cStr = this.allocStringCached(name); return binaryen._BinaryenGetGlobal(this.ref, cStr); } removeGlobal( name: string ): void { var cStr = this.allocStringCached(name); binaryen._BinaryenRemoveGlobal(this.ref, cStr); } // events addEvent( name: string, attribute: u32, params: NativeType, results: NativeType ): EventRef { var cStr = this.allocStringCached(name); return binaryen._BinaryenAddEvent(this.ref, cStr, attribute, params, results); } getEvent( name: string ): EventRef { var cStr = this.allocStringCached(name); return binaryen._BinaryenGetEvent(this.ref, cStr); } removeEvent( name: string ): void { var cStr = this.allocStringCached(name); binaryen._BinaryenRemoveEvent(this.ref, cStr); } // functions addFunction( name: string, params: NativeType, results: NativeType, varTypes: NativeType[] | null, body: ExpressionRef ): FunctionRef { var cStr = this.allocStringCached(name); var cArr = allocPtrArray(varTypes); var ret = binaryen._BinaryenAddFunction(this.ref, cStr, params, results, cArr, varTypes ? varTypes.length : 0, body); binaryen._free(cArr); return ret; } getFunction( name: string ): FunctionRef { var cStr = this.allocStringCached(name); return binaryen._BinaryenGetFunction(this.ref, cStr); } removeFunction(name: string): void { var cStr = this.allocStringCached(name); binaryen._BinaryenRemoveFunction(this.ref, cStr); } private hasTemporaryFunction: bool = false; addTemporaryFunction(result: NativeType, paramTypes: NativeType[] | null, body: ExpressionRef): FunctionRef { this.hasTemporaryFunction = assert(!this.hasTemporaryFunction); var tempName = this.allocStringCached(""); var cArr = allocPtrArray(paramTypes); var ret = binaryen._BinaryenAddFunction(this.ref, tempName, createType(paramTypes), result, 0, 0, body ); binaryen._free(cArr); return ret; } removeTemporaryFunction(): void { this.hasTemporaryFunction = !assert(this.hasTemporaryFunction); var tempName = this.allocStringCached(""); binaryen._BinaryenRemoveFunction(this.ref, tempName); } setStart(func: FunctionRef): void { binaryen._BinaryenSetStart(this.ref, func); } // exports addFunctionExport( internalName: string, externalName: string ): ExportRef { var cStr1 = this.allocStringCached(internalName); var cStr2 = this.allocStringCached(externalName); return binaryen._BinaryenAddFunctionExport(this.ref, cStr1, cStr2); } addTableExport( internalName: string, externalName: string ): ExportRef { var cStr1 = this.allocStringCached(internalName); var cStr2 = this.allocStringCached(externalName); return binaryen._BinaryenAddTableExport(this.ref, cStr1, cStr2); } addMemoryExport( internalName: string, externalName: string ): ExportRef { var cStr1 = this.allocStringCached(internalName); var cStr2 = this.allocStringCached(externalName); return binaryen._BinaryenAddMemoryExport(this.ref, cStr1, cStr2); } addGlobalExport( internalName: string, externalName: string ): ExportRef { var cStr1 = this.allocStringCached(internalName); var cStr2 = this.allocStringCached(externalName); return binaryen._BinaryenAddGlobalExport(this.ref, cStr1, cStr2); } addEventExport( internalName: string, externalName: string ): ExportRef { var cStr1 = this.allocStringCached(internalName); var cStr2 = this.allocStringCached(externalName); return binaryen._BinaryenAddEventExport(this.ref, cStr1, cStr2); } removeExport(externalName: string): void { var cStr = this.allocStringCached(externalName); binaryen._BinaryenRemoveExport(this.ref, cStr); } // imports addFunctionImport( internalName: string, externalModuleName: string, externalBaseName: string, params: NativeType, results: NativeType ): void { var cStr1 = this.allocStringCached(internalName); var cStr2 = this.allocStringCached(externalModuleName); var cStr3 = this.allocStringCached(externalBaseName); binaryen._BinaryenAddFunctionImport(this.ref, cStr1, cStr2, cStr3, params, results); } addTableImport( internalName: string, externalModuleName: string, externalBaseName: string ): void { var cStr1 = this.allocStringCached(internalName); var cStr2 = this.allocStringCached(externalModuleName); var cStr3 = this.allocStringCached(externalBaseName); binaryen._BinaryenAddTableImport(this.ref, cStr1, cStr2, cStr3); } addMemoryImport( internalName: string, externalModuleName: string, externalBaseName: string, shared: bool = false, ): void { var cStr1 = this.allocStringCached(internalName); var cStr2 = this.allocStringCached(externalModuleName); var cStr3 = this.allocStringCached(externalBaseName); binaryen._BinaryenAddMemoryImport(this.ref, cStr1, cStr2, cStr3, shared); } addGlobalImport( internalName: string, externalModuleName: string, externalBaseName: string, globalType: NativeType, mutable: bool = false ): void { var cStr1 = this.allocStringCached(internalName); var cStr2 = this.allocStringCached(externalModuleName); var cStr3 = this.allocStringCached(externalBaseName); binaryen._BinaryenAddGlobalImport(this.ref, cStr1, cStr2, cStr3, globalType, mutable); } addEventImport( internalName: string, externalModuleName: string, externalBaseName: string, attribute: u32, params: NativeType, results: NativeType ): void { var cStr1 = this.allocStringCached(internalName); var cStr2 = this.allocStringCached(externalModuleName); var cStr3 = this.allocStringCached(externalBaseName); binaryen._BinaryenAddEventImport(this.ref, cStr1, cStr2, cStr3, attribute, params, results); } // memory /** Unlimited memory constant. */ static readonly UNLIMITED_MEMORY: Index = -1; setMemory( initial: Index, maximum: Index, segments: MemorySegment[], target: Target, exportName: string | null = null, shared: bool = false ): void { var cStr = this.allocStringCached(exportName); var k = segments.length; var segs = new Array(k); var psvs = new Uint8Array(k); var offs = new Array(k); var sizs = new Array(k); for (let i = 0; i < k; ++i) { let buffer = segments[i].buffer; let offset = segments[i].offset; segs[i] = allocU8Array(buffer); psvs[i] = 0; // no passive segments currently offs[i] = target == Target.WASM64 ? this.i64(i64_low(offset), i64_high(offset)) : this.i32(i64_low(offset)); sizs[i] = buffer.length; } var cArr1 = allocPtrArray(segs); var cArr2 = allocU8Array(psvs); var cArr3 = allocPtrArray(offs); var cArr4 = allocU32Array(sizs); binaryen._BinaryenSetMemory(this.ref, initial, maximum, cStr, cArr1, cArr2, cArr3, cArr4, k, shared); binaryen._free(cArr4); binaryen._free(cArr3); binaryen._free(cArr2); binaryen._free(cArr1); for (let i = k - 1; i >= 0; --i) binaryen._free(segs[i]); } // table /** Unlimited table constant. */ static readonly UNLIMITED_TABLE: Index = -1; setFunctionTable( initial: Index, maximum: Index, funcs: string[], offset: ExpressionRef ): void { var numNames = funcs.length; var names = new Array(numNames); for (let i = 0; i < numNames; ++i) { names[i] = this.allocStringCached(funcs[i]); } var cArr = allocPtrArray(names); binaryen._BinaryenSetFunctionTable(this.ref, initial, maximum, cArr, numNames, offset); binaryen._free(cArr); } // sections addCustomSection(name: string, contents: Uint8Array): void { var cStr = this.allocStringCached(name); var cArr = allocU8Array(contents); binaryen._BinaryenAddCustomSection(this.ref, cStr, cArr, contents.length); binaryen._free(cArr); } // meta (global) getOptimizeLevel(): i32 { return binaryen._BinaryenGetOptimizeLevel(); } setOptimizeLevel(level: i32): void { binaryen._BinaryenSetOptimizeLevel(level); } getShrinkLevel(): i32 { return binaryen._BinaryenGetShrinkLevel(); } setShrinkLevel(level: i32): void { binaryen._BinaryenSetShrinkLevel(level); } getDebugInfo(): boolean { return binaryen._BinaryenGetDebugInfo(); } setDebugInfo(on: bool): void { binaryen._BinaryenSetDebugInfo(on); } getLowMemoryUnused(): bool { return binaryen._BinaryenGetLowMemoryUnused(); } setLowMemoryUnused(on: bool): void { binaryen._BinaryenSetLowMemoryUnused(on); } getPassArgument(key: string): string | null { var cStr = this.allocStringCached(key); var ptr = binaryen._BinaryenGetPassArgument(cStr); return ptr ? readString(ptr) : null; } setPassArgument(key: string, value: string | null): void { var cStr1 = this.allocStringCached(key); var cStr2 = this.allocStringCached(value); binaryen._BinaryenSetPassArgument(cStr1, cStr2); } clearPassArguments(): void { binaryen._BinaryenClearPassArguments(); } getAlwaysInlineMaxSize(): Index { return binaryen._BinaryenGetAlwaysInlineMaxSize(); } setAlwaysInlineMaxSize(size: Index): void { binaryen._BinaryenSetAlwaysInlineMaxSize(size); } getFlexibleInlineMaxSize(): Index { return binaryen._BinaryenGetFlexibleInlineMaxSize(); } setFlexibleInlineMaxSize(size: Index): void { binaryen._BinaryenSetFlexibleInlineMaxSize(size); } getOneCallerInlineMaxSize(): Index { return binaryen._BinaryenGetOneCallerInlineMaxSize(); } setOneCallerInlineMaxSize(size: Index): void { binaryen._BinaryenSetOneCallerInlineMaxSize(size); } // meta (module) getFeatures(): FeatureFlags { return binaryen._BinaryenModuleGetFeatures(this.ref); } setFeatures(featureFlags: FeatureFlags): void { binaryen._BinaryenModuleSetFeatures(this.ref, featureFlags); } runPass(pass: string, func: FunctionRef = 0): void { var cStr = allocString(pass); if (func) { binaryen._BinaryenFunctionRunPasses(func, this.ref, cStr, 1); } else { binaryen._BinaryenModuleRunPasses(this.ref, cStr, 1); } binaryen._free(cStr); } runPasses(passes: string[], func: FunctionRef = 0): void { var numNames = passes.length; var cStrs = new Array(numNames); for (let i = 0; i < numNames; ++i) { cStrs[i] = allocString(passes[i]); } var cArr = allocPtrArray(cStrs); if (func) { binaryen._BinaryenFunctionRunPasses(func, this.ref, cArr, numNames); } else { binaryen._BinaryenModuleRunPasses(this.ref, cArr, numNames); } binaryen._free(cArr); for (let i = numNames; i >= 0; --i) binaryen._free(cStrs[i]); } optimize(optimizeLevel: i32, shrinkLevel: i32, debugInfo: bool = false, usesARC: bool = true): void { // Implicitly run costly non-LLVM optimizations on -O3 or -Oz if (optimizeLevel >= 3 || shrinkLevel >= 2) optimizeLevel = 4; binaryen._BinaryenSetOptimizeLevel(optimizeLevel); binaryen._BinaryenSetShrinkLevel(shrinkLevel); binaryen._BinaryenSetDebugInfo(debugInfo); // Tweak inlining limits based on optimization levels if (optimizeLevel >= 2 && shrinkLevel === 0) { binaryen._BinaryenSetAlwaysInlineMaxSize(12); binaryen._BinaryenSetFlexibleInlineMaxSize(70); binaryen._BinaryenSetOneCallerInlineMaxSize(200); } else { binaryen._BinaryenSetAlwaysInlineMaxSize( optimizeLevel == 0 && shrinkLevel >= 0 ? 2 : 4 ); binaryen._BinaryenSetFlexibleInlineMaxSize(65); binaryen._BinaryenSetOneCallerInlineMaxSize(80); } // Pass order here differs substantially from Binaryen's defaults // see: Binaryen/src/pass.cpp if (optimizeLevel > 0 || shrinkLevel > 0) { let passes = new Array(); // --- PassRunner::addDefaultGlobalOptimizationPrePasses --- passes.push("duplicate-function-elimination"); passes.push("remove-unused-module-elements"); // + // --- PassRunner::addDefaultFunctionOptimizationPasses --- if (optimizeLevel >= 3 || shrinkLevel >= 1) { passes.push("ssa-nomerge"); } if (optimizeLevel >= 3) { passes.push("flatten"); passes.push("simplify-locals-notee-nostructure"); passes.push("vacuum"); passes.push("code-folding"); passes.push("flatten"); passes.push("local-cse"); passes.push("reorder-locals"); } if (optimizeLevel >= 2 || shrinkLevel >= 1) { passes.push("rse"); passes.push("vacuum"); } if (usesARC) { if (optimizeLevel < 3) { passes.push("flatten"); } passes.push("post-assemblyscript"); } passes.push("optimize-instructions"); passes.push("inlining"); passes.push("dce"); passes.push("remove-unused-brs"); passes.push("remove-unused-names"); passes.push("inlining-optimizing"); if (optimizeLevel >= 2 || shrinkLevel >= 1) { passes.push("pick-load-signs"); passes.push("simplify-globals-optimizing"); } if (optimizeLevel >= 3 || shrinkLevel >= 2) { passes.push("precompute-propagate"); } else { passes.push("precompute"); } passes.push("vacuum"); if (optimizeLevel >= 3 && shrinkLevel <= 1) { passes.push("licm"); } passes.push("simplify-locals-nostructure"); passes.push("vacuum"); passes.push("reorder-locals"); passes.push("remove-unused-brs"); passes.push("coalesce-locals"); passes.push("simplify-locals"); passes.push("vacuum"); passes.push("reorder-locals"); passes.push("coalesce-locals"); passes.push("reorder-locals"); if (optimizeLevel >= 3 || shrinkLevel >= 1) { passes.push("merge-locals"); } passes.push("vacuum"); if (optimizeLevel >= 3 || shrinkLevel >= 1) { passes.push("code-folding"); } if (optimizeLevel >= 2 || shrinkLevel >= 1) { passes.push("simplify-globals-optimizing"); } passes.push("merge-blocks"); passes.push("remove-unused-brs"); passes.push("remove-unused-names"); passes.push("merge-blocks"); if (optimizeLevel >= 3) { passes.push("optimize-instructions"); } if (optimizeLevel >= 2 || shrinkLevel >= 1) { passes.push("rse"); } passes.push("vacuum"); // --- PassRunner::addDefaultGlobalOptimizationPostPasses --- if (optimizeLevel >= 2 || shrinkLevel >= 1) { passes.push("simplify-globals-optimizing"); passes.push("dae-optimizing"); } if (optimizeLevel >= 2 || shrinkLevel >= 2) { passes.push("inlining-optimizing"); } if (binaryen._BinaryenGetLowMemoryUnused()) { if (optimizeLevel >= 3 || shrinkLevel >= 1) { passes.push("optimize-added-constants-propagate"); } else { passes.push("optimize-added-constants"); } } passes.push("duplicate-import-elimination"); if (optimizeLevel >= 2 || shrinkLevel >= 2) { passes.push("simplify-globals-optimizing"); } else { passes.push("simplify-globals"); passes.push("vacuum"); } // precompute works best after global optimizations if (optimizeLevel >= 2 || shrinkLevel >= 1) { passes.push("precompute-propagate"); } else { passes.push("precompute"); } passes.push("directize"); // replace indirect with direct calls passes.push("dae-optimizing"); // reduce arity passes.push("inlining-optimizing"); // and inline if possible if (usesARC) { // works best after inlining to cover most retains/releases passes.push("post-assemblyscript-finalize"); } if (optimizeLevel >= 2 || shrinkLevel >= 1) { passes.push("rse"); // move code on early return (after CFG cleanup) passes.push("code-pushing"); if (optimizeLevel >= 3) { // very expensive, so O3 only passes.push("simplify-globals"); passes.push("vacuum"); // replace indirect with direct calls again and inline passes.push("inlining-optimizing"); passes.push("directize"); passes.push("dae-optimizing"); passes.push("precompute-propagate"); passes.push("vacuum"); passes.push("merge-locals"); passes.push("coalesce-locals"); passes.push("simplify-locals-nostructure"); passes.push("vacuum"); passes.push("inlining-optimizing"); passes.push("precompute-propagate"); } passes.push("remove-unused-brs"); passes.push("remove-unused-names"); passes.push("vacuum"); passes.push("optimize-instructions"); passes.push("simplify-globals-optimizing"); } // clean up passes.push("duplicate-function-elimination"); passes.push("remove-unused-nonfunction-module-elements"); passes.push("memory-packing"); passes.push("remove-unused-module-elements"); this.runPasses(passes); } } validate(): bool { return binaryen._BinaryenModuleValidate(this.ref) == 1; } interpret(): void { binaryen._BinaryenModuleInterpret(this.ref); } toBinary(sourceMapUrl: string | null = null): BinaryModule { var out = this.lit; // safe to reuse as long as.. assert(binaryen._BinaryenSizeofLiteral() >= 12); var cStr = allocString(sourceMapUrl); var binaryPtr: usize = 0; var sourceMapPtr: usize = 0; binaryen._BinaryenModuleAllocateAndWrite(out, this.ref, cStr); binaryPtr = assert(binaryen.__i32_load(out)); var binaryLen = binaryen.__i32_load(out + 4); sourceMapPtr = binaryen.__i32_load(out + 8); // may be NULL var ret = new BinaryModule(); ret.output = readBuffer(binaryPtr, binaryLen); ret.sourceMap = readString(sourceMapPtr); if (cStr) binaryen._free(cStr); binaryen._free(binaryPtr); if (sourceMapPtr) binaryen._free(sourceMapPtr); return ret; } toText(): string { throw new Error("not implemented"); // JS glue overrides this } toAsmjs(): string { throw new Error("not implemented"); // JS glue overrides this } private cachedStrings: Map = new Map(); private allocStringCached(str: string | null): usize { if (str === null) return 0; var cachedStrings = this.cachedStrings; if (cachedStrings.has(str)) return cachedStrings.get(str); var ptr = allocString(str); cachedStrings.set(str, ptr); return ptr; } dispose(): void { assert(this.ref); // TODO: for (let ptr of this.cachedStrings.values()) { for (let _values = Map_values(this.cachedStrings), i = 0, k = _values.length; i < k; ++i) { let ptr = unchecked(_values[i]); binaryen._free(ptr); } this.cachedStrings = new Map(); binaryen._free(this.lit); binaryen._BinaryenModuleDispose(this.ref); this.ref = 0; } createRelooper(): Relooper { return Relooper.create(this); } cloneExpression( expr: ExpressionRef, noSideEffects: bool = false, maxDepth: i32 = i32.MAX_VALUE ): ExpressionRef { // currently supports side effect free expressions only if (maxDepth < 0) return 0; maxDepth -= 1; var nested1: ExpressionRef, nested2: ExpressionRef; switch (binaryen._BinaryenExpressionGetId(expr)) { case ExpressionId.Const: { switch (binaryen._BinaryenExpressionGetType(expr)) { case NativeType.I32: { return this.i32(binaryen._BinaryenConstGetValueI32(expr)); } case NativeType.I64: { return this.i64( binaryen._BinaryenConstGetValueI64Low(expr), binaryen._BinaryenConstGetValueI64High(expr) ); } case NativeType.F32: { return this.f32(binaryen._BinaryenConstGetValueF32(expr)); } case NativeType.F64: { return this.f64(binaryen._BinaryenConstGetValueF64(expr)); } case NativeType.V128: { // TODO return 0; } // Not possible to clone an anyref as it is opaque case NativeType.Anyref: { return 0; } default: { throw new Error("concrete type expected"); } } } case ExpressionId.LocalGet: { return binaryen._BinaryenLocalGet(this.ref, binaryen._BinaryenLocalGetGetIndex(expr), binaryen._BinaryenExpressionGetType(expr) ); } case ExpressionId.GlobalGet: { let globalName = binaryen._BinaryenGlobalGetGetName(expr); if (!globalName) break; return binaryen._BinaryenGlobalGet(this.ref, globalName, binaryen._BinaryenExpressionGetType(expr)); } case ExpressionId.Load: { if (!(nested1 = this.cloneExpression(binaryen._BinaryenLoadGetPtr(expr), noSideEffects, maxDepth))) { break; } return ( binaryen._BinaryenLoadIsAtomic(expr) ? binaryen._BinaryenAtomicLoad(this.ref, binaryen._BinaryenLoadGetBytes(expr), binaryen._BinaryenLoadGetOffset(expr), binaryen._BinaryenExpressionGetType(expr), nested1 ) : binaryen._BinaryenLoad(this.ref, binaryen._BinaryenLoadGetBytes(expr), binaryen._BinaryenLoadIsSigned(expr) ? 1 : 0, binaryen._BinaryenLoadGetOffset(expr), binaryen._BinaryenLoadGetAlign(expr), binaryen._BinaryenExpressionGetType(expr), nested1 ) ); } case ExpressionId.Unary: { if (!(nested1 = this.cloneExpression(binaryen._BinaryenUnaryGetValue(expr), noSideEffects, maxDepth))) { break; } return binaryen._BinaryenUnary(this.ref, binaryen._BinaryenUnaryGetOp(expr), nested1); } case ExpressionId.Binary: { if (!(nested1 = this.cloneExpression(binaryen._BinaryenBinaryGetLeft(expr), noSideEffects, maxDepth))) { break; } if (!(nested2 = this.cloneExpression(binaryen._BinaryenBinaryGetRight(expr), noSideEffects, maxDepth))) { break; } return binaryen._BinaryenBinary(this.ref, binaryen._BinaryenBinaryGetOp(expr), nested1, nested2); } } return 0; } copyExpression(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenExpressionCopy(expr, this.ref); } runExpression(expr: ExpressionRef, flags: ExpressionRunnerFlags, maxDepth: i32 = 50, maxLoopIterations: i32 = 1): ExpressionRef { var runner = binaryen._ExpressionRunnerCreate(this.ref, flags, maxDepth, maxLoopIterations); var precomp = binaryen._ExpressionRunnerRunAndDispose(runner, expr); if (precomp) { assert(getExpressionId(precomp) == ExpressionId.Const); assert(getExpressionType(precomp) == getExpressionType(expr)); } return precomp; } // source map generation addDebugInfoFile(name: string): Index { var cStr = allocString(name); var ret = binaryen._BinaryenModuleAddDebugInfoFileName(this.ref, cStr); binaryen._free(cStr); return ret; } getDebugInfoFile(index: Index): string | null { return readString(binaryen._BinaryenModuleGetDebugInfoFileName(this.ref, index)); } setDebugLocation( func: FunctionRef, expr: ExpressionRef, fileIndex: Index, lineNumber: Index, columnNumber: Index ): void { binaryen._BinaryenFunctionSetDebugLocation(func, expr, fileIndex, lineNumber, columnNumber); } } // types export function createType(types: NativeType[] | null): NativeType { if (!types) return NativeType.None; switch (types.length) { case 0: return NativeType.None; case 1: return types[0]; } var cArr = allocPtrArray(types); var ret = binaryen._BinaryenTypeCreate(cArr, types.length); binaryen._free(cArr); return ret; } export function expandType(type: NativeType): NativeType[] { var arity = binaryen._BinaryenTypeArity(type); var cArr = binaryen._malloc(arity << 2); binaryen._BinaryenTypeExpand(type, cArr); var types = new Array(arity); for (let i: u32 = 0; i < arity; ++i) { types[i] = binaryen.__i32_load(cArr + (i << 2)); } binaryen._free(cArr); return types; } // expressions export function getExpressionId(expr: ExpressionRef): ExpressionId { return binaryen._BinaryenExpressionGetId(expr); } export function getExpressionType(expr: ExpressionRef): NativeType { return binaryen._BinaryenExpressionGetType(expr); } export function getConstValueI32(expr: ExpressionRef): i32 { return binaryen._BinaryenConstGetValueI32(expr); } export function getConstValueI64Low(expr: ExpressionRef): i32 { return binaryen._BinaryenConstGetValueI64Low(expr); } export function getConstValueI64High(expr: ExpressionRef): i32 { return binaryen._BinaryenConstGetValueI64High(expr); } export function getConstValueF32(expr: ExpressionRef): f32 { return binaryen._BinaryenConstGetValueF32(expr); } export function getConstValueF64(expr: ExpressionRef): f64 { return binaryen._BinaryenConstGetValueF64(expr); } export function getLocalGetIndex(expr: ExpressionRef): Index { return binaryen._BinaryenLocalGetGetIndex(expr); } export function getLocalSetIndex(expr: ExpressionRef): Index { return binaryen._BinaryenLocalSetGetIndex(expr); } export function getLocalSetValue(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenLocalSetGetValue(expr); } export function isLocalTee(expr: ExpressionRef): bool { return binaryen._BinaryenLocalSetIsTee(expr); } export function getGlobalGetName(expr: ExpressionRef): string | null { return readString(binaryen._BinaryenGlobalGetGetName(expr)); } export function getBinaryOp(expr: ExpressionRef): BinaryOp { return binaryen._BinaryenBinaryGetOp(expr); } export function getBinaryLeft(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenBinaryGetLeft(expr); } export function getBinaryRight(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenBinaryGetRight(expr); } export function getUnaryOp(expr: ExpressionRef): UnaryOp { return binaryen._BinaryenUnaryGetOp(expr); } export function getUnaryValue(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenUnaryGetValue(expr); } export function getLoadBytes(expr: ExpressionRef): u32 { return binaryen._BinaryenLoadGetBytes(expr); } export function getLoadOffset(expr: ExpressionRef): u32 { return binaryen._BinaryenLoadGetOffset(expr); } export function getLoadPtr(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenLoadGetPtr(expr); } export function isLoadSigned(expr: ExpressionRef): bool { return binaryen._BinaryenLoadIsSigned(expr); } export function getStoreBytes(expr: ExpressionRef): u32 { return binaryen._BinaryenStoreGetBytes(expr); } export function getStoreOffset(expr: ExpressionRef): u32 { return binaryen._BinaryenStoreGetOffset(expr); } export function getStorePtr(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenStoreGetPtr(expr); } export function getStoreValue(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenStoreGetValue(expr); } export function getBlockName(expr: ExpressionRef): string | null { return readString(binaryen._BinaryenBlockGetName(expr)); } export function getBlockChildCount(expr: ExpressionRef): Index { return binaryen._BinaryenBlockGetNumChildren(expr); } export function getBlockChild(expr: ExpressionRef, index: Index): ExpressionRef { return binaryen._BinaryenBlockGetChild(expr, index); } export function getIfCondition(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenIfGetCondition(expr); } export function getIfTrue(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenIfGetIfTrue(expr); } export function getIfFalse(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenIfGetIfFalse(expr); } export function getLoopName(expr: ExpressionRef): string | null { return readString(binaryen._BinaryenLoopGetName(expr)); } export function getLoopBody(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenLoopGetBody(expr); } export function getBreakName(expr: ExpressionRef): string | null { return readString(binaryen._BinaryenBreakGetName(expr)); } export function getBreakCondition(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenBreakGetCondition(expr); } export function getSelectThen(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenSelectGetIfTrue(expr); } export function getSelectElse(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenSelectGetIfFalse(expr); } export function getSelectCondition(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenSelectGetCondition(expr); } export function getDropValue(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenDropGetValue(expr); } export function getReturnValue(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenReturnGetValue(expr); } export function getCallTarget(expr: ExpressionRef): string | null { return readString(binaryen._BinaryenCallGetTarget(expr)); } export function getCallOperandCount(expr: ExpressionRef): i32 { return binaryen._BinaryenCallGetNumOperands(expr); } export function getCallOperand(expr: ExpressionRef, index: Index): ExpressionRef { return binaryen._BinaryenCallGetOperand(expr, index); } export function getHostOp(expr: ExpressionRef): ExpressionRef { return binaryen._BinaryenHostGetOp(expr); } export function getHostOperandCount(expr: ExpressionRef): Index { return binaryen._BinaryenHostGetNumOperands(expr); } export function getHostOperand(expr: ExpressionRef, index: Index): ExpressionRef { return binaryen._BinaryenHostGetOperand(expr, index); } export function getHostName(expr: ExpressionRef): string | null { return readString(binaryen._BinaryenHostGetNameOperand(expr)); } // functions export function getFunctionBody(func: FunctionRef): ExpressionRef { return binaryen._BinaryenFunctionGetBody(func); } export function getFunctionName(func: FunctionRef): string | null { return readString(binaryen._BinaryenFunctionGetName(func)); } export function getFunctionParams(func: FunctionRef): NativeType { return binaryen._BinaryenFunctionGetParams(func); } export function getFunctionResults(func: FunctionRef): NativeType { return binaryen._BinaryenFunctionGetResults(func); } export function getFunctionVars(func: FunctionRef): NativeType[] { var count = binaryen._BinaryenFunctionGetNumVars(func); var types = new Array(count); for (let i: Index = 0; i < count; ++i) { types[i] = binaryen._BinaryenFunctionGetVar(func, i); } return types; } // globals export function getGlobalName(global: GlobalRef): string | null { return readString(binaryen._BinaryenGlobalGetName(global)); } export function getGlobalType(global: GlobalRef): NativeType { return binaryen._BinaryenGlobalGetType(global); } export function isGlobalMutable(global: GlobalRef): bool { return binaryen._BinaryenGlobalIsMutable(global); } export function getGlobalInit(global: GlobalRef): ExpressionRef { return binaryen._BinaryenGlobalGetInitExpr(global); } // events export function getEventName(event: EventRef): string | null { return readString(binaryen._BinaryenEventGetName(event)); } export function getEventAttribute(event: EventRef): u32 { return binaryen._BinaryenEventGetAttribute(event); } export function getEventParams(event: EventRef): NativeType { return binaryen._BinaryenEventGetParams(event); } export function getEventResults(event: EventRef): NativeType { return binaryen._BinaryenEventGetResults(event); } export class Relooper { module: Module; ref: RelooperRef; static create(module: Module): Relooper { var relooper = new Relooper(); relooper.module = module; relooper.ref = binaryen._RelooperCreate(module.ref); return relooper; } private constructor() {} addBlock(code: ExpressionRef): RelooperBlockRef { return binaryen._RelooperAddBlock(this.ref, code); } addBranch( from: RelooperBlockRef, to: RelooperBlockRef, condition: ExpressionRef = 0, code: ExpressionRef = 0 ): void { binaryen._RelooperAddBranch(from, to, condition, code); } addBlockWithSwitch(code: ExpressionRef, condition: ExpressionRef): RelooperBlockRef { return binaryen._RelooperAddBlockWithSwitch(this.ref, code, condition); } addBranchForSwitch( from: RelooperBlockRef, to: RelooperBlockRef, indexes: i32[], code: ExpressionRef = 0 ): void { var cArr = allocI32Array(indexes); binaryen._RelooperAddBranchForSwitch(from, to, cArr, indexes.length, code); binaryen._free(cArr); } renderAndDispose(entry: RelooperBlockRef, labelHelper: Index): ExpressionRef { return binaryen._RelooperRenderAndDispose(this.ref, entry, labelHelper); } } /** Builds a switch using a sequence of `br_if`s. */ export class SwitchBuilder { // This is useful because Binaryen understands sequences of `br_if`s and // knows how to make a `br_table` from such a sequence if switched over // values are considered dense enough, respectively a size-efficient sequence // of `if`s if not, depending on optimization levels. private module: Module; private condition: ExpressionRef; private values: i32[] = new Array(); private indexes: i32[] = new Array(); private cases: ExpressionRef[][] = new Array(); private defaultIndex: i32 = -1; /** Creates a new builder using the specified i32 condition. */ constructor(module: Module, condition: ExpressionRef) { this.module = module; this.condition = condition; } /** Links a case to the specified branch. */ addCase(value: i32, code: ExpressionRef[]): void { var cases = this.cases; var index = cases.indexOf(code); if (index < 0) { index = cases.length; cases.push(code); } this.values.push(value); this.indexes.push(index); } /** Links the default branch. */ addDefault(code: ExpressionRef[]): void { assert(this.defaultIndex == -1); var cases = this.cases; this.defaultIndex = cases.length; cases.push(code); } /** Renders the switch to a block. */ render(localIndex: i32, labelPostfix: string = ""): ExpressionRef { var module = this.module; var cases = this.cases; var numCases = cases.length; if (!numCases) { return module.drop(this.condition); } var values = this.values; var numValues = values.length; var indexes = this.indexes; var entry = new Array(1 + numValues + 1); var labels = new Array(numCases); for (let i = 0; i < numCases; ++i) { labels[i] = "case" + i.toString() + labelPostfix; } entry[0] = module.local_set(localIndex, this.condition); for (let i = 0; i < numValues; ++i) { let index = indexes[i]; entry[1 + i] = module.br(labels[index], module.binary(BinaryOp.EqI32, module.local_get(localIndex, NativeType.I32), module.i32(values[i]) ) ); } var defaultIndex = this.defaultIndex; var defaultLabel = "default" + labelPostfix; entry[1 + numValues] = module.br( ~defaultIndex ? labels[defaultIndex] : defaultLabel ); var current = module.block(labels[0], entry); for (let i = 1; i < numCases; ++i) { let block = cases[i - 1]; block.unshift(current); current = module.block(labels[i], block); } var lastCase = cases[numCases - 1]; lastCase.unshift(current); return module.block( ~defaultIndex ? null : defaultLabel, lastCase ); } } export enum SideEffects { None = 0 /* _BinaryenSideEffectNone */, Branches = 1 /* _BinaryenSideEffectBranches */, Calls = 2 /* _BinaryenSideEffectCalls */, ReadsLocal = 4 /* _BinaryenSideEffectReadsLocal */, WritesLocal = 8 /* _BinaryenSideEffectWritesLocal */, ReadsGlobal = 16 /* _BinaryenSideEffectReadsGlobal */, WritesGlobal = 32 /* _BinaryenSideEffectWritesGlobal */, ReadsMemory = 64 /* _BinaryenSideEffectReadsMemory */, WritesMemory = 128 /* _BinaryenSideEffectWritesMemory */, ImplicitTrap = 256 /* _BinaryenSideEffectImplicitTrap */, IsAtomic = 512 /* _BinaryenSideEffectIsAtomic */, Throws = 1024 /* _BinaryenSideEffectThrows */, Any = 2047 /* _BinaryenSideEffectAny */ } export function getSideEffects(expr: ExpressionRef, features: FeatureFlags = FeatureFlags.All): SideEffects { return binaryen._BinaryenExpressionGetSideEffects(expr, features); } export function hasSideEffects(expr: ExpressionRef, features: FeatureFlags = FeatureFlags.All): bool { return getSideEffects(expr, features) != SideEffects.None; } // helpers // can't do stack allocation here: STACKTOP is a global in WASM but a hidden variable in asm.js function allocU8Array(u8s: Uint8Array | null): usize { if (!u8s) return 0; var numValues = u8s.length; var ptr = binaryen._malloc(numValues); var idx = ptr; for (let i = 0; i < numValues; ++i) { binaryen.__i32_store8(idx++, u8s[i]); } return ptr; } function allocI32Array(i32s: i32[] | null): usize { if (!i32s) return 0; var ptr = binaryen._malloc(i32s.length << 2); var idx = ptr; for (let i = 0, k = i32s.length; i < k; ++i) { let val = i32s[i]; binaryen.__i32_store(idx, val); idx += 4; } return ptr; } function allocU32Array(u32s: u32[] | null): usize { if (!u32s) return 0; var ptr = binaryen._malloc(u32s.length << 2); var idx = ptr; for (let i = 0, k = u32s.length; i < k; ++i) { let val = u32s[i]; binaryen.__i32_store(idx, val); idx += 4; } return ptr; } function allocPtrArray(ptrs: usize[] | null): usize { if (!ptrs) return 0; // TODO: WASM64 assert(ASC_TARGET != Target.WASM64); var ptr = binaryen._malloc(ptrs.length << 2); var idx = ptr; for (let i = 0, k = ptrs.length; i < k; ++i) { let val = ptrs[i]; binaryen.__i32_store(idx, val); idx += 4; } return ptr; } function stringLengthUTF8(str: string): usize { var len = 0; for (let i = 0, k = str.length; i < k; ++i) { let u = str.charCodeAt(i); if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k) { u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF); } if (u <= 0x7F) { ++len; } else if (u <= 0x7FF) { len += 2; } else if (u <= 0xFFFF) { len += 3; } else if (u <= 0x1FFFFF) { len += 4; } else if (u <= 0x3FFFFFF) { len += 5; } else { len += 6; } } return len; } function allocString(str: string | null): usize { if (str === null) return 0; var ptr = binaryen._malloc(stringLengthUTF8(str) + 1); // the following is based on Emscripten's stringToUTF8Array var idx = ptr; for (let i = 0, k = str.length; i < k; ++i) { let u = str.charCodeAt(i); if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k) { u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF); } if (u <= 0x7F) { binaryen.__i32_store8(idx++, u as u8); } else if (u <= 0x7FF) { binaryen.__i32_store8(idx++, (0xC0 | (u >>> 6) ) as u8); binaryen.__i32_store8(idx++, (0x80 | ( u & 63)) as u8); } else if (u <= 0xFFFF) { binaryen.__i32_store8(idx++, (0xE0 | (u >>> 12) ) as u8); binaryen.__i32_store8(idx++, (0x80 | ((u >>> 6) & 63)) as u8); binaryen.__i32_store8(idx++, (0x80 | ( u & 63)) as u8); } else if (u <= 0x1FFFFF) { binaryen.__i32_store8(idx++, (0xF0 | (u >>> 18) ) as u8); binaryen.__i32_store8(idx++, (0x80 | ((u >>> 12) & 63)) as u8); binaryen.__i32_store8(idx++, (0x80 | ((u >>> 6) & 63)) as u8); binaryen.__i32_store8(idx++, (0x80 | ( u & 63)) as u8); } else if (u <= 0x3FFFFFF) { binaryen.__i32_store8(idx++, (0xF8 | (u >>> 24) ) as u8); binaryen.__i32_store8(idx++, (0x80 | ((u >>> 18) & 63)) as u8); binaryen.__i32_store8(idx++, (0x80 | ((u >>> 12) & 63)) as u8); binaryen.__i32_store8(idx++, (0x80 | ((u >>> 6) & 63)) as u8); binaryen.__i32_store8(idx++, (0x80 | ( u & 63)) as u8); } else { binaryen.__i32_store8(idx++, (0xFC | (u >>> 30) ) as u8); binaryen.__i32_store8(idx++, (0x80 | ((u >>> 24) & 63)) as u8); binaryen.__i32_store8(idx++, (0x80 | ((u >>> 18) & 63)) as u8); binaryen.__i32_store8(idx++, (0x80 | ((u >>> 12) & 63)) as u8); binaryen.__i32_store8(idx++, (0x80 | ((u >>> 6) & 63)) as u8); binaryen.__i32_store8(idx++, (0x80 | ( u & 63)) as u8); } } binaryen.__i32_store8(idx, 0); return ptr; } function readBuffer(ptr: usize, length: i32): Uint8Array { var ret = new Uint8Array(length); for (let i = 0; i < length; ++i) { ret[i] = binaryen.__i32_load8_u(ptr + i); } return ret; } export function readString(ptr: usize): string | null { if (!ptr) return null; var arr = new Array(); // the following is based on Emscripten's UTF8ArrayToString var cp: u32; var u1: u32, u2: u32, u3: u32, u4: u32, u5: u32; while (cp = binaryen.__i32_load8_u(ptr++)) { if (!(cp & 0x80)) { arr.push(cp); continue; } u1 = binaryen.__i32_load8_u(ptr++) & 63; if ((cp & 0xE0) == 0xC0) { arr.push(((cp & 31) << 6) | u1); continue; } u2 = binaryen.__i32_load8_u(ptr++) & 63; if ((cp & 0xF0) == 0xE0) { cp = ((cp & 15) << 12) | (u1 << 6) | u2; } else { u3 = binaryen.__i32_load8_u(ptr++) & 63; if ((cp & 0xF8) == 0xF0) { cp = ((cp & 7) << 18) | (u1 << 12) | (u2 << 6) | u3; } else { u4 = binaryen.__i32_load8_u(ptr++) & 63; if ((cp & 0xFC) == 0xF8) { cp = ((cp & 3) << 24) | (u1 << 18) | (u2 << 12) | (u3 << 6) | u4; } else { u5 = binaryen.__i32_load8_u(ptr++) & 63; cp = ((cp & 1) << 30) | (u1 << 24) | (u2 << 18) | (u3 << 12) | (u4 << 6) | u5; } } } arr.push(cp); if (cp < 0x10000) { arr.push(cp); } else { let ch = cp - 0x10000; arr.push(0xD800 | (ch >> 10)); arr.push(0xDC00 | (ch & 0x3FF)); } } return String.fromCharCodes(arr); // return String.fromCodePoints(arr); } /** Result structure of {@link Module#toBinary}. */ export class BinaryModule { /** WebAssembly binary. */ output: Uint8Array; /** Source map, if generated. */ sourceMap: string | null; } /** Tests if an expression needs an explicit 'unreachable' when it is the terminating statement. */ export function needsExplicitUnreachable(expr: ExpressionRef): bool { // not applicable if pushing a value to the stack if (binaryen._BinaryenExpressionGetType(expr) != NativeType.Unreachable) return false; switch (binaryen._BinaryenExpressionGetId(expr)) { case ExpressionId.Unreachable: case ExpressionId.Return: return false; case ExpressionId.Break: return binaryen._BinaryenBreakGetCondition(expr) != 0; case ExpressionId.Block: { if (!binaryen._BinaryenBlockGetName(expr)) { // can't break out of it let numChildren = binaryen._BinaryenBlockGetNumChildren(expr); // last child needs unreachable return numChildren > 0 && needsExplicitUnreachable(binaryen._BinaryenBlockGetChild(expr, numChildren - 1)); } } } return true; } /** Traverses all expression members of an expression, calling the given visitor. */ export function traverse(expr: ExpressionRef, data: T, visit: (expr: ExpressionRef, data: T) => void): bool { switch (getExpressionId(expr)) { case ExpressionId.Block: { for (let i: Index = 0, n = binaryen._BinaryenBlockGetNumChildren(expr); i < n; ++i) { visit(binaryen._BinaryenBlockGetChild(expr, i), data); } break; } case ExpressionId.If: { visit(binaryen._BinaryenIfGetCondition(expr), data); visit(binaryen._BinaryenIfGetIfTrue(expr), data); let ifFalse = binaryen._BinaryenIfGetIfFalse(expr); if (ifFalse) visit(ifFalse, data); break; } case ExpressionId.Loop: { visit(binaryen._BinaryenLoopGetBody(expr), data); break; } case ExpressionId.Break: { let condition = binaryen._BinaryenBreakGetCondition(expr); if (condition) visit(condition, data); break; } case ExpressionId.Switch: { visit(binaryen._BinaryenSwitchGetCondition(expr), data); break; } case ExpressionId.Call: { for (let i: Index = 0, n = binaryen._BinaryenCallGetNumOperands(expr); i < n; ++i) { visit(binaryen._BinaryenCallGetOperand(expr, i), data); } break; } case ExpressionId.CallIndirect: { for (let i: Index = 0, n = binaryen._BinaryenCallIndirectGetNumOperands(expr); i < n; ++i) { visit(binaryen._BinaryenCallIndirectGetOperand(expr, i), data); } break; } case ExpressionId.LocalGet: { break; } case ExpressionId.LocalSet: { visit(binaryen._BinaryenLocalSetGetValue(expr), data); break; } case ExpressionId.GlobalGet: { break; } case ExpressionId.GlobalSet: { visit(binaryen._BinaryenGlobalSetGetValue(expr), data); break; } case ExpressionId.Load: { visit(binaryen._BinaryenLoadGetPtr(expr), data); break; } case ExpressionId.Store: { visit(binaryen._BinaryenStoreGetPtr(expr), data); visit(binaryen._BinaryenStoreGetValue(expr), data); break; } case ExpressionId.Const: { break; } case ExpressionId.Unary: { visit(binaryen._BinaryenUnaryGetValue(expr), data); break; } case ExpressionId.Binary: { visit(binaryen._BinaryenBinaryGetLeft(expr), data); visit(binaryen._BinaryenBinaryGetRight(expr), data); break; } case ExpressionId.Select: { visit(binaryen._BinaryenSelectGetIfTrue(expr), data); visit(binaryen._BinaryenSelectGetIfFalse(expr), data); visit(binaryen._BinaryenSelectGetCondition(expr), data); break; } case ExpressionId.Drop: { visit(binaryen._BinaryenDropGetValue(expr), data); break; } case ExpressionId.Return: { visit(binaryen._BinaryenReturnGetValue(expr), data); break; } case ExpressionId.Host: { for (let i: Index = 0, n = binaryen._BinaryenHostGetNumOperands(expr); i < n; ++i) { visit(binaryen._BinaryenHostGetOperand(expr, i), data); } break; } case ExpressionId.Nop: { break; } case ExpressionId.Unreachable: { break; } case ExpressionId.AtomicRMW: { visit(binaryen._BinaryenAtomicRMWGetPtr(expr), data); visit(binaryen._BinaryenAtomicRMWGetValue(expr), data); break; } case ExpressionId.AtomicCmpxchg: { visit(binaryen._BinaryenAtomicCmpxchgGetPtr(expr), data); visit(binaryen._BinaryenAtomicCmpxchgGetExpected(expr), data); visit(binaryen._BinaryenAtomicCmpxchgGetReplacement(expr), data); break; } case ExpressionId.AtomicWait: { visit(binaryen._BinaryenAtomicWaitGetPtr(expr), data); visit(binaryen._BinaryenAtomicWaitGetExpected(expr), data); visit(binaryen._BinaryenAtomicWaitGetTimeout(expr), data); break; } case ExpressionId.AtomicNotify: { visit(binaryen._BinaryenAtomicNotifyGetPtr(expr), data); break; } case ExpressionId.AtomicFence: { break; } case ExpressionId.SIMDExtract: { visit(binaryen._BinaryenSIMDExtractGetVec(expr), data); break; } case ExpressionId.SIMDReplace: { visit(binaryen._BinaryenSIMDReplaceGetVec(expr), data); visit(binaryen._BinaryenSIMDReplaceGetValue(expr), data); break; } case ExpressionId.SIMDShuffle: { visit(binaryen._BinaryenSIMDShuffleGetLeft(expr), data); visit(binaryen._BinaryenSIMDShuffleGetRight(expr), data); break; } case ExpressionId.SIMDTernary: { visit(binaryen._BinaryenSIMDTernaryGetA(expr), data); visit(binaryen._BinaryenSIMDTernaryGetB(expr), data); visit(binaryen._BinaryenSIMDTernaryGetC(expr), data); break; } case ExpressionId.SIMDShift: { visit(binaryen._BinaryenSIMDShiftGetVec(expr), data); visit(binaryen._BinaryenSIMDShiftGetShift(expr), data); break; } case ExpressionId.SIMDLoad: { visit(binaryen._BinaryenSIMDLoadGetPtr(expr), data); break; } case ExpressionId.MemoryInit: { visit(binaryen._BinaryenMemoryInitGetDest(expr), data); visit(binaryen._BinaryenMemoryInitGetOffset(expr), data); visit(binaryen._BinaryenMemoryInitGetSize(expr), data); break; } case ExpressionId.DataDrop: { break; } case ExpressionId.MemoryCopy: { visit(binaryen._BinaryenMemoryCopyGetDest(expr), data); visit(binaryen._BinaryenMemoryCopyGetSource(expr), data); visit(binaryen._BinaryenMemoryCopyGetSize(expr), data); break; } case ExpressionId.MemoryFill: { visit(binaryen._BinaryenMemoryFillGetDest(expr), data); visit(binaryen._BinaryenMemoryFillGetValue(expr), data); visit(binaryen._BinaryenMemoryFillGetSize(expr), data); break; } case ExpressionId.Push: { visit(binaryen._BinaryenPushGetValue(expr), data); break; } case ExpressionId.Pop: { break; } case ExpressionId.RefNull: { break; } case ExpressionId.RefIsNull: { visit(binaryen._BinaryenRefIsNullGetValue(expr), data); break; } case ExpressionId.RefFunc: { break; } case ExpressionId.Try: { visit(binaryen._BinaryenTryGetBody(expr), data); visit(binaryen._BinaryenTryGetCatchBody(expr), data); break; } case ExpressionId.Throw: { for (let i: Index = 0, n = binaryen._BinaryenThrowGetNumOperands(expr); i < n; ++i) { visit(binaryen._BinaryenThrowGetOperand(expr, i), data); } break; } case ExpressionId.Rethrow: { visit(binaryen._BinaryenRethrowGetExnref(expr), data); break; } case ExpressionId.BrOnExn: { visit(binaryen._BinaryenBrOnExnGetExnref(expr), data); break; } case ExpressionId.TupleMake: { for (let i: Index = 0, n = binaryen._BinaryenTupleMakeGetNumOperands(expr); i < n; ++i) { visit(binaryen._BinaryenTupleMakeGetOperand(expr, i), data); } break; } case ExpressionId.TupleExtract: { break; } default: assert(false); } return true; }