wasm-module-builder.js (53833B)
1 // Copyright 2016 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Used for encoding f32 and double constants to bits. 6 let byte_view = new Uint8Array(8); 7 let data_view = new DataView(byte_view.buffer); 8 9 // The bytes function receives one of 10 // - several arguments, each of which is either a number or a string of length 11 // 1; if it's a string, the charcode of the contained character is used. 12 // - a single array argument containing the actual arguments 13 // - a single string; the returned buffer will contain the char codes of all 14 // contained characters. 15 function bytes(...input) { 16 if (input.length == 1 && typeof input[0] == 'array') input = input[0]; 17 if (input.length == 1 && typeof input[0] == 'string') { 18 let len = input[0].length; 19 let view = new Uint8Array(len); 20 for (let i = 0; i < len; i++) view[i] = input[0].charCodeAt(i); 21 return view.buffer; 22 } 23 let view = new Uint8Array(input.length); 24 for (let i = 0; i < input.length; i++) { 25 let val = input[i]; 26 if (typeof val == 'string') { 27 assertEquals(1, val.length, 'string inputs must have length 1'); 28 val = val.charCodeAt(0); 29 } 30 view[i] = val | 0; 31 } 32 return view.buffer; 33 } 34 35 // Header declaration constants 36 var kWasmH0 = 0; 37 var kWasmH1 = 0x61; 38 var kWasmH2 = 0x73; 39 var kWasmH3 = 0x6d; 40 41 var kWasmV0 = 0x1; 42 var kWasmV1 = 0; 43 var kWasmV2 = 0; 44 var kWasmV3 = 0; 45 46 var kHeaderSize = 8; 47 var kPageSize = 65536; 48 var kSpecMaxPages = 65536; 49 var kMaxVarInt32Size = 5; 50 var kMaxVarInt64Size = 10; 51 52 let kDeclNoLocals = 0; 53 54 // Section declaration constants 55 let kUnknownSectionCode = 0; 56 let kTypeSectionCode = 1; // Function signature declarations 57 let kImportSectionCode = 2; // Import declarations 58 let kFunctionSectionCode = 3; // Function declarations 59 let kTableSectionCode = 4; // Indirect function table and other tables 60 let kMemorySectionCode = 5; // Memory attributes 61 let kGlobalSectionCode = 6; // Global declarations 62 let kExportSectionCode = 7; // Exports 63 let kStartSectionCode = 8; // Start function declaration 64 let kElementSectionCode = 9; // Elements section 65 let kCodeSectionCode = 10; // Function code 66 let kDataSectionCode = 11; // Data segments 67 let kDataCountSectionCode = 12; // Data segment count (between Element & Code) 68 let kTagSectionCode = 13; // Tag section (between Memory & Global) 69 70 // Name section types 71 let kModuleNameCode = 0; 72 let kFunctionNamesCode = 1; 73 let kLocalNamesCode = 2; 74 75 let kWasmFunctionTypeForm = 0x60; 76 let kWasmAnyFunctionTypeForm = 0x70; 77 let kWasmStructTypeForm = 0x5f; 78 let kWasmArrayTypeForm = 0x5e; 79 let kWasmSubtypeForm = 0x50; 80 let kWasmSubtypeFinalForm = 0x4f; 81 let kWasmRecursiveTypeGroupForm = 0x4e; 82 83 let kNoSuperType = 0xFFFFFFFF; 84 globalThis.kNoSuperType = kNoSuperType; 85 86 let kHasMaximumFlag = 1; 87 let kSharedHasMaximumFlag = 3; 88 89 // Segment flags 90 let kActiveNoIndex = 0; 91 let kPassive = 1; 92 let kActiveWithIndex = 2; 93 let kPassiveWithElements = 5; 94 95 // Function declaration flags 96 let kDeclFunctionName = 0x01; 97 let kDeclFunctionImport = 0x02; 98 let kDeclFunctionLocals = 0x04; 99 let kDeclFunctionExport = 0x08; 100 101 // Local types 102 let kWasmStmt = 0x40; 103 let kWasmI32 = 0x7f; 104 let kWasmI64 = 0x7e; 105 let kWasmF32 = 0x7d; 106 let kWasmF64 = 0x7c; 107 let kWasmS128 = 0x7b; 108 109 // Packed storage types 110 let kWasmI8 = 0x78; 111 let kWasmI16 = 0x77; 112 113 // These are defined as negative integers to distinguish them from positive type 114 // indices. 115 let kWasmNullFuncRef = -0x0d; 116 let kWasmNullExternRef = -0x0e; 117 let kWasmNullRef = -0x0f; 118 let kWasmFuncRef = -0x10; 119 let kWasmAnyFunc = kWasmFuncRef; // Alias named as in the JS API spec 120 let kWasmExternRef = -0x11; 121 let kWasmAnyRef = -0x12; 122 let kWasmEqRef = -0x13; 123 let kWasmI31Ref = -0x14; 124 let kWasmStructRef = -0x15; 125 let kWasmArrayRef = -0x16; 126 127 // Use the positive-byte versions inside function bodies. 128 let kLeb128Mask = 0x7f; 129 let kFuncRefCode = kWasmFuncRef & kLeb128Mask; 130 let kAnyFuncCode = kFuncRefCode; // Alias named as in the JS API spec 131 let kExternRefCode = kWasmExternRef & kLeb128Mask; 132 let kAnyRefCode = kWasmAnyRef & kLeb128Mask; 133 let kEqRefCode = kWasmEqRef & kLeb128Mask; 134 let kI31RefCode = kWasmI31Ref & kLeb128Mask; 135 let kNullExternRefCode = kWasmNullExternRef & kLeb128Mask; 136 let kNullFuncRefCode = kWasmNullFuncRef & kLeb128Mask; 137 let kStructRefCode = kWasmStructRef & kLeb128Mask; 138 let kArrayRefCode = kWasmArrayRef & kLeb128Mask; 139 let kNullRefCode = kWasmNullRef & kLeb128Mask; 140 141 let kWasmRefNull = 0x63; 142 let kWasmRef = 0x64; 143 function wasmRefNullType(heap_type) { 144 return {opcode: kWasmRefNull, heap_type: heap_type}; 145 } 146 function wasmRefType(heap_type) { 147 return {opcode: kWasmRef, heap_type: heap_type}; 148 } 149 150 Object.assign(globalThis, { 151 kWasmStmt, kWasmI32, kWasmI64, kWasmF32, kWasmF64, kWasmS128, kWasmI8, 152 kWasmI16, kWasmNullFuncRef, kWasmNullExternRef, kWasmNullRef, kWasmFuncRef, 153 kWasmAnyFunc, kWasmExternRef, kWasmAnyRef, kWasmEqRef, kWasmI31Ref, 154 kWasmStructRef, kWasmArrayRef, kFuncRefCode, kAnyFuncCode, kExternRefCode, 155 kAnyRefCode, kEqRefCode, kI31RefCode, kNullExternRefCode, kNullFuncRefCode, 156 kStructRefCode, kArrayRefCode, kNullRefCode, kWasmRefNull, kWasmRef, 157 wasmRefNullType, wasmRefType 158 }); 159 160 let kExternalFunction = 0; 161 let kExternalTable = 1; 162 let kExternalMemory = 2; 163 let kExternalGlobal = 3; 164 let kExternalTag = 4; 165 166 Object.assign(globalThis, { 167 kExternalFunction, kExternalTable, kExternalMemory, kExternalGlobal, 168 kExternalTag 169 }); 170 171 let kTableZero = 0; 172 let kMemoryZero = 0; 173 let kSegmentZero = 0; 174 175 let kTagAttribute = 0; 176 177 // Useful signatures 178 let kSig_i_i = makeSig([kWasmI32], [kWasmI32]); 179 let kSig_l_l = makeSig([kWasmI64], [kWasmI64]); 180 let kSig_i_l = makeSig([kWasmI64], [kWasmI32]); 181 let kSig_i_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32]); 182 let kSig_i_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], [kWasmI32]); 183 let kSig_v_iiii = makeSig([kWasmI32, kWasmI32, kWasmI32, kWasmI32], []); 184 let kSig_f_ff = makeSig([kWasmF32, kWasmF32], [kWasmF32]); 185 let kSig_d_dd = makeSig([kWasmF64, kWasmF64], [kWasmF64]); 186 let kSig_l_ll = makeSig([kWasmI64, kWasmI64], [kWasmI64]); 187 let kSig_i_dd = makeSig([kWasmF64, kWasmF64], [kWasmI32]); 188 let kSig_v_v = makeSig([], []); 189 let kSig_i_v = makeSig([], [kWasmI32]); 190 let kSig_l_v = makeSig([], [kWasmI64]); 191 let kSig_f_v = makeSig([], [kWasmF32]); 192 let kSig_d_v = makeSig([], [kWasmF64]); 193 let kSig_v_i = makeSig([kWasmI32], []); 194 let kSig_v_ii = makeSig([kWasmI32, kWasmI32], []); 195 let kSig_v_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], []); 196 let kSig_v_l = makeSig([kWasmI64], []); 197 let kSig_v_d = makeSig([kWasmF64], []); 198 let kSig_v_dd = makeSig([kWasmF64, kWasmF64], []); 199 let kSig_v_ddi = makeSig([kWasmF64, kWasmF64, kWasmI32], []); 200 let kSig_ii_v = makeSig([], [kWasmI32, kWasmI32]); 201 let kSig_iii_v = makeSig([], [kWasmI32, kWasmI32, kWasmI32]); 202 let kSig_ii_i = makeSig([kWasmI32], [kWasmI32, kWasmI32]); 203 let kSig_iii_i = makeSig([kWasmI32], [kWasmI32, kWasmI32, kWasmI32]); 204 let kSig_ii_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32, kWasmI32]); 205 let kSig_iii_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32, kWasmI32, kWasmI32]); 206 207 let kSig_v_f = makeSig([kWasmF32], []); 208 let kSig_f_f = makeSig([kWasmF32], [kWasmF32]); 209 let kSig_f_d = makeSig([kWasmF64], [kWasmF32]); 210 let kSig_d_d = makeSig([kWasmF64], [kWasmF64]); 211 let kSig_r_r = makeSig([kWasmExternRef], [kWasmExternRef]); 212 let kSig_a_a = makeSig([kWasmAnyFunc], [kWasmAnyFunc]); 213 let kSig_i_r = makeSig([kWasmExternRef], [kWasmI32]); 214 let kSig_v_r = makeSig([kWasmExternRef], []); 215 let kSig_v_a = makeSig([kWasmAnyFunc], []); 216 let kSig_v_rr = makeSig([kWasmExternRef, kWasmExternRef], []); 217 let kSig_v_aa = makeSig([kWasmAnyFunc, kWasmAnyFunc], []); 218 let kSig_r_v = makeSig([], [kWasmExternRef]); 219 let kSig_a_v = makeSig([], [kWasmAnyFunc]); 220 let kSig_a_i = makeSig([kWasmI32], [kWasmAnyFunc]); 221 222 function makeSig(params, results) { 223 return {params: params, results: results}; 224 } 225 226 function makeSig_v_x(x) { 227 return makeSig([x], []); 228 } 229 230 function makeSig_v_xx(x) { 231 return makeSig([x, x], []); 232 } 233 234 function makeSig_r_v(r) { 235 return makeSig([], [r]); 236 } 237 238 function makeSig_r_x(r, x) { 239 return makeSig([x], [r]); 240 } 241 242 function makeSig_r_xx(r, x) { 243 return makeSig([x, x], [r]); 244 } 245 246 Object.assign(globalThis, { 247 kSig_i_i, kSig_l_l, kSig_i_l, kSig_i_ii, kSig_i_iii, kSig_v_iiii, kSig_f_ff, 248 kSig_d_dd, kSig_l_ll, kSig_i_dd, kSig_v_v, kSig_i_v, kSig_l_v, kSig_f_v, 249 kSig_d_v, kSig_v_i, kSig_v_ii, kSig_v_iii, kSig_v_l, kSig_v_d, kSig_v_dd, 250 kSig_v_ddi, kSig_ii_v, kSig_iii_v, kSig_ii_i, kSig_iii_i, kSig_ii_ii, 251 kSig_iii_ii, kSig_v_f, kSig_f_f, kSig_f_d, kSig_d_d, kSig_r_r, kSig_a_a, 252 kSig_i_r, kSig_v_r, kSig_v_a, kSig_v_rr, kSig_v_aa, kSig_r_v, kSig_a_v, 253 kSig_a_i, 254 makeSig, makeSig_v_x, makeSig_v_xx, makeSig_r_v, makeSig_r_x, makeSig_r_xx 255 }); 256 257 // Opcodes 258 let kExprUnreachable = 0x00; 259 let kExprNop = 0x01; 260 let kExprBlock = 0x02; 261 let kExprLoop = 0x03; 262 let kExprIf = 0x04; 263 let kExprElse = 0x05; 264 let kExprTry = 0x06; 265 let kExprCatch = 0x07; 266 let kExprCatchAll = 0x19; 267 let kExprThrow = 0x08; 268 let kExprRethrow = 0x09; 269 let kExprBrOnExn = 0x0a; 270 let kExprEnd = 0x0b; 271 let kExprBr = 0x0c; 272 let kExprBrIf = 0x0d; 273 let kExprBrTable = 0x0e; 274 let kExprReturn = 0x0f; 275 let kExprCallFunction = 0x10; 276 let kExprCallIndirect = 0x11; 277 let kExprReturnCall = 0x12; 278 let kExprReturnCallIndirect = 0x13; 279 let kExprDrop = 0x1a; 280 let kExprSelect = 0x1b; 281 let kExprLocalGet = 0x20; 282 let kExprLocalSet = 0x21; 283 let kExprLocalTee = 0x22; 284 let kExprGlobalGet = 0x23; 285 let kExprGlobalSet = 0x24; 286 let kExprTableGet = 0x25; 287 let kExprTableSet = 0x26; 288 let kExprI32LoadMem = 0x28; 289 let kExprI64LoadMem = 0x29; 290 let kExprF32LoadMem = 0x2a; 291 let kExprF64LoadMem = 0x2b; 292 let kExprI32LoadMem8S = 0x2c; 293 let kExprI32LoadMem8U = 0x2d; 294 let kExprI32LoadMem16S = 0x2e; 295 let kExprI32LoadMem16U = 0x2f; 296 let kExprI64LoadMem8S = 0x30; 297 let kExprI64LoadMem8U = 0x31; 298 let kExprI64LoadMem16S = 0x32; 299 let kExprI64LoadMem16U = 0x33; 300 let kExprI64LoadMem32S = 0x34; 301 let kExprI64LoadMem32U = 0x35; 302 let kExprI32StoreMem = 0x36; 303 let kExprI64StoreMem = 0x37; 304 let kExprF32StoreMem = 0x38; 305 let kExprF64StoreMem = 0x39; 306 let kExprI32StoreMem8 = 0x3a; 307 let kExprI32StoreMem16 = 0x3b; 308 let kExprI64StoreMem8 = 0x3c; 309 let kExprI64StoreMem16 = 0x3d; 310 let kExprI64StoreMem32 = 0x3e; 311 let kExprMemorySize = 0x3f; 312 let kExprMemoryGrow = 0x40; 313 let kExprI32Const = 0x41; 314 let kExprI64Const = 0x42; 315 let kExprF32Const = 0x43; 316 let kExprF64Const = 0x44; 317 let kExprI32Eqz = 0x45; 318 let kExprI32Eq = 0x46; 319 let kExprI32Ne = 0x47; 320 let kExprI32LtS = 0x48; 321 let kExprI32LtU = 0x49; 322 let kExprI32GtS = 0x4a; 323 let kExprI32GtU = 0x4b; 324 let kExprI32LeS = 0x4c; 325 let kExprI32LeU = 0x4d; 326 let kExprI32GeS = 0x4e; 327 let kExprI32GeU = 0x4f; 328 let kExprI64Eqz = 0x50; 329 let kExprI64Eq = 0x51; 330 let kExprI64Ne = 0x52; 331 let kExprI64LtS = 0x53; 332 let kExprI64LtU = 0x54; 333 let kExprI64GtS = 0x55; 334 let kExprI64GtU = 0x56; 335 let kExprI64LeS = 0x57; 336 let kExprI64LeU = 0x58; 337 let kExprI64GeS = 0x59; 338 let kExprI64GeU = 0x5a; 339 let kExprF32Eq = 0x5b; 340 let kExprF32Ne = 0x5c; 341 let kExprF32Lt = 0x5d; 342 let kExprF32Gt = 0x5e; 343 let kExprF32Le = 0x5f; 344 let kExprF32Ge = 0x60; 345 let kExprF64Eq = 0x61; 346 let kExprF64Ne = 0x62; 347 let kExprF64Lt = 0x63; 348 let kExprF64Gt = 0x64; 349 let kExprF64Le = 0x65; 350 let kExprF64Ge = 0x66; 351 let kExprI32Clz = 0x67; 352 let kExprI32Ctz = 0x68; 353 let kExprI32Popcnt = 0x69; 354 let kExprI32Add = 0x6a; 355 let kExprI32Sub = 0x6b; 356 let kExprI32Mul = 0x6c; 357 let kExprI32DivS = 0x6d; 358 let kExprI32DivU = 0x6e; 359 let kExprI32RemS = 0x6f; 360 let kExprI32RemU = 0x70; 361 let kExprI32And = 0x71; 362 let kExprI32Ior = 0x72; 363 let kExprI32Xor = 0x73; 364 let kExprI32Shl = 0x74; 365 let kExprI32ShrS = 0x75; 366 let kExprI32ShrU = 0x76; 367 let kExprI32Rol = 0x77; 368 let kExprI32Ror = 0x78; 369 let kExprI64Clz = 0x79; 370 let kExprI64Ctz = 0x7a; 371 let kExprI64Popcnt = 0x7b; 372 let kExprI64Add = 0x7c; 373 let kExprI64Sub = 0x7d; 374 let kExprI64Mul = 0x7e; 375 let kExprI64DivS = 0x7f; 376 let kExprI64DivU = 0x80; 377 let kExprI64RemS = 0x81; 378 let kExprI64RemU = 0x82; 379 let kExprI64And = 0x83; 380 let kExprI64Ior = 0x84; 381 let kExprI64Xor = 0x85; 382 let kExprI64Shl = 0x86; 383 let kExprI64ShrS = 0x87; 384 let kExprI64ShrU = 0x88; 385 let kExprI64Rol = 0x89; 386 let kExprI64Ror = 0x8a; 387 let kExprF32Abs = 0x8b; 388 let kExprF32Neg = 0x8c; 389 let kExprF32Ceil = 0x8d; 390 let kExprF32Floor = 0x8e; 391 let kExprF32Trunc = 0x8f; 392 let kExprF32NearestInt = 0x90; 393 let kExprF32Sqrt = 0x91; 394 let kExprF32Add = 0x92; 395 let kExprF32Sub = 0x93; 396 let kExprF32Mul = 0x94; 397 let kExprF32Div = 0x95; 398 let kExprF32Min = 0x96; 399 let kExprF32Max = 0x97; 400 let kExprF32CopySign = 0x98; 401 let kExprF64Abs = 0x99; 402 let kExprF64Neg = 0x9a; 403 let kExprF64Ceil = 0x9b; 404 let kExprF64Floor = 0x9c; 405 let kExprF64Trunc = 0x9d; 406 let kExprF64NearestInt = 0x9e; 407 let kExprF64Sqrt = 0x9f; 408 let kExprF64Add = 0xa0; 409 let kExprF64Sub = 0xa1; 410 let kExprF64Mul = 0xa2; 411 let kExprF64Div = 0xa3; 412 let kExprF64Min = 0xa4; 413 let kExprF64Max = 0xa5; 414 let kExprF64CopySign = 0xa6; 415 let kExprI32ConvertI64 = 0xa7; 416 let kExprI32SConvertF32 = 0xa8; 417 let kExprI32UConvertF32 = 0xa9; 418 let kExprI32SConvertF64 = 0xaa; 419 let kExprI32UConvertF64 = 0xab; 420 let kExprI64SConvertI32 = 0xac; 421 let kExprI64UConvertI32 = 0xad; 422 let kExprI64SConvertF32 = 0xae; 423 let kExprI64UConvertF32 = 0xaf; 424 let kExprI64SConvertF64 = 0xb0; 425 let kExprI64UConvertF64 = 0xb1; 426 let kExprF32SConvertI32 = 0xb2; 427 let kExprF32UConvertI32 = 0xb3; 428 let kExprF32SConvertI64 = 0xb4; 429 let kExprF32UConvertI64 = 0xb5; 430 let kExprF32ConvertF64 = 0xb6; 431 let kExprF64SConvertI32 = 0xb7; 432 let kExprF64UConvertI32 = 0xb8; 433 let kExprF64SConvertI64 = 0xb9; 434 let kExprF64UConvertI64 = 0xba; 435 let kExprF64ConvertF32 = 0xbb; 436 let kExprI32ReinterpretF32 = 0xbc; 437 let kExprI64ReinterpretF64 = 0xbd; 438 let kExprF32ReinterpretI32 = 0xbe; 439 let kExprF64ReinterpretI64 = 0xbf; 440 let kExprI32SExtendI8 = 0xc0; 441 let kExprI32SExtendI16 = 0xc1; 442 let kExprI64SExtendI8 = 0xc2; 443 let kExprI64SExtendI16 = 0xc3; 444 let kExprI64SExtendI32 = 0xc4; 445 let kExprRefNull = 0xd0; 446 let kExprRefIsNull = 0xd1; 447 let kExprRefFunc = 0xd2; 448 449 // Prefix opcodes 450 let kGCPrefix = 0xfb; 451 let kNumericPrefix = 0xfc; 452 let kSimdPrefix = 0xfd; 453 let kAtomicPrefix = 0xfe; 454 455 // Use these for multi-byte instructions (opcode > 0x7F needing two LEB bytes): 456 function GCInstr(opcode) { 457 if (opcode <= 0x7F) return [kGCPrefix, opcode]; 458 return [kGCPrefix, 0x80 | (opcode & 0x7F), opcode >> 7]; 459 } 460 461 // GC opcodes 462 let kExprStructNew = 0x00; 463 let kExprStructNewDefault = 0x01; 464 let kExprStructGet = 0x02; 465 let kExprStructGetS = 0x03; 466 let kExprStructGetU = 0x04; 467 let kExprStructSet = 0x05; 468 let kExprArrayNew = 0x06; 469 let kExprArrayNewDefault = 0x07; 470 let kExprArrayNewFixed = 0x08; 471 let kExprArrayNewData = 0x09; 472 let kExprArrayNewElem = 0x0a; 473 let kExprArrayGet = 0x0b; 474 let kExprArrayGetS = 0x0c; 475 let kExprArrayGetU = 0x0d; 476 let kExprArraySet = 0x0e; 477 let kExprArrayLen = 0x0f; 478 let kExprArrayFill = 0x10; 479 let kExprArrayCopy = 0x11; 480 let kExprArrayInitData = 0x12; 481 let kExprArrayInitElem = 0x13; 482 let kExprRefTest = 0x14; 483 let kExprRefTestNull = 0x15; 484 let kExprRefCast = 0x16; 485 let kExprRefCastNull = 0x17; 486 let kExprBrOnCast = 0x18; 487 let kExprBrOnCastFail = 0x19; 488 let kExprExternInternalize = 0x1a; 489 let kExprExternExternalize = 0x1b; 490 let kExprI31New = 0x1c; 491 let kExprI31GetS = 0x1d; 492 let kExprI31GetU = 0x1e; 493 494 // Numeric opcodes. 495 let kExprMemoryInit = 0x08; 496 let kExprDataDrop = 0x09; 497 let kExprMemoryCopy = 0x0a; 498 let kExprMemoryFill = 0x0b; 499 let kExprTableInit = 0x0c; 500 let kExprElemDrop = 0x0d; 501 let kExprTableCopy = 0x0e; 502 let kExprTableGrow = 0x0f; 503 let kExprTableSize = 0x10; 504 let kExprTableFill = 0x11; 505 506 // Atomic opcodes. 507 let kExprAtomicNotify = 0x00; 508 let kExprI32AtomicWait = 0x01; 509 let kExprI64AtomicWait = 0x02; 510 let kExprI32AtomicLoad = 0x10; 511 let kExprI32AtomicLoad8U = 0x12; 512 let kExprI32AtomicLoad16U = 0x13; 513 let kExprI32AtomicStore = 0x17; 514 let kExprI32AtomicStore8U = 0x19; 515 let kExprI32AtomicStore16U = 0x1a; 516 let kExprI32AtomicAdd = 0x1e; 517 let kExprI32AtomicAdd8U = 0x20; 518 let kExprI32AtomicAdd16U = 0x21; 519 let kExprI32AtomicSub = 0x25; 520 let kExprI32AtomicSub8U = 0x27; 521 let kExprI32AtomicSub16U = 0x28; 522 let kExprI32AtomicAnd = 0x2c; 523 let kExprI32AtomicAnd8U = 0x2e; 524 let kExprI32AtomicAnd16U = 0x2f; 525 let kExprI32AtomicOr = 0x33; 526 let kExprI32AtomicOr8U = 0x35; 527 let kExprI32AtomicOr16U = 0x36; 528 let kExprI32AtomicXor = 0x3a; 529 let kExprI32AtomicXor8U = 0x3c; 530 let kExprI32AtomicXor16U = 0x3d; 531 let kExprI32AtomicExchange = 0x41; 532 let kExprI32AtomicExchange8U = 0x43; 533 let kExprI32AtomicExchange16U = 0x44; 534 let kExprI32AtomicCompareExchange = 0x48; 535 let kExprI32AtomicCompareExchange8U = 0x4a; 536 let kExprI32AtomicCompareExchange16U = 0x4b; 537 538 let kExprI64AtomicLoad = 0x11; 539 let kExprI64AtomicLoad8U = 0x14; 540 let kExprI64AtomicLoad16U = 0x15; 541 let kExprI64AtomicLoad32U = 0x16; 542 let kExprI64AtomicStore = 0x18; 543 let kExprI64AtomicStore8U = 0x1b; 544 let kExprI64AtomicStore16U = 0x1c; 545 let kExprI64AtomicStore32U = 0x1d; 546 let kExprI64AtomicAdd = 0x1f; 547 let kExprI64AtomicAdd8U = 0x22; 548 let kExprI64AtomicAdd16U = 0x23; 549 let kExprI64AtomicAdd32U = 0x24; 550 let kExprI64AtomicSub = 0x26; 551 let kExprI64AtomicSub8U = 0x29; 552 let kExprI64AtomicSub16U = 0x2a; 553 let kExprI64AtomicSub32U = 0x2b; 554 let kExprI64AtomicAnd = 0x2d; 555 let kExprI64AtomicAnd8U = 0x30; 556 let kExprI64AtomicAnd16U = 0x31; 557 let kExprI64AtomicAnd32U = 0x32; 558 let kExprI64AtomicOr = 0x34; 559 let kExprI64AtomicOr8U = 0x37; 560 let kExprI64AtomicOr16U = 0x38; 561 let kExprI64AtomicOr32U = 0x39; 562 let kExprI64AtomicXor = 0x3b; 563 let kExprI64AtomicXor8U = 0x3e; 564 let kExprI64AtomicXor16U = 0x3f; 565 let kExprI64AtomicXor32U = 0x40; 566 let kExprI64AtomicExchange = 0x42; 567 let kExprI64AtomicExchange8U = 0x45; 568 let kExprI64AtomicExchange16U = 0x46; 569 let kExprI64AtomicExchange32U = 0x47; 570 let kExprI64AtomicCompareExchange = 0x49 571 let kExprI64AtomicCompareExchange8U = 0x4c; 572 let kExprI64AtomicCompareExchange16U = 0x4d; 573 let kExprI64AtomicCompareExchange32U = 0x4e; 574 575 // Simd opcodes. 576 let kExprS128LoadMem = 0x00; 577 let kExprS128StoreMem = 0x01; 578 let kExprI32x4Splat = 0x0c; 579 let kExprI32x4Eq = 0x2c; 580 let kExprS1x4AllTrue = 0x75; 581 let kExprF32x4Min = 0x9e; 582 583 Object.assign(globalThis, { 584 kExprUnreachable, kExprNop, kExprBlock, kExprLoop, kExprIf, kExprElse, 585 kExprTry, kExprCatch, kExprCatchAll, kExprThrow, kExprRethrow, kExprBrOnExn, 586 kExprEnd, kExprBr, kExprBrIf, kExprBrTable, kExprReturn, kExprCallFunction, 587 kExprCallIndirect, kExprReturnCall, kExprReturnCallIndirect, kExprDrop, 588 kExprSelect, kExprLocalGet, kExprLocalSet, kExprLocalTee, kExprGlobalGet, 589 kExprGlobalSet, kExprTableGet, kExprTableSet, kExprI32LoadMem, 590 kExprI64LoadMem, kExprF32LoadMem, kExprF64LoadMem, kExprI32LoadMem8S, 591 kExprI32LoadMem8U, kExprI32LoadMem16S, kExprI32LoadMem16U, kExprI64LoadMem8S, 592 kExprI64LoadMem8U, kExprI64LoadMem16S, kExprI64LoadMem16U, kExprI64LoadMem32S, 593 kExprI64LoadMem32U, kExprI32StoreMem, kExprI64StoreMem, kExprF32StoreMem, 594 kExprF64StoreMem, kExprI32StoreMem8, kExprI32StoreMem16, kExprI64StoreMem8, 595 kExprI64StoreMem16, kExprI64StoreMem32, kExprMemorySize, kExprMemoryGrow, 596 kExprI32Const, kExprI64Const, kExprF32Const, kExprF64Const, kExprI32Eqz, 597 kExprI32Eq, kExprI32Ne, kExprI32LtS, kExprI32LtU, kExprI32GtS, kExprI32GtU, 598 kExprI32LeS, kExprI32LeU, kExprI32GeS, kExprI32GeU, kExprI64Eqz, kExprI64Eq, 599 kExprI64Ne, kExprI64LtS, kExprI64LtU, kExprI64GtS, kExprI64GtU, kExprI64LeS, 600 kExprI64LeU, kExprI64GeS, kExprI64GeU, kExprF32Eq, kExprF32Ne, kExprF32Lt, 601 kExprF32Gt, kExprF32Le, kExprF32Ge, kExprF64Eq, kExprF64Ne, kExprF64Lt, 602 kExprF64Gt, kExprF64Le, kExprF64Ge, kExprI32Clz, kExprI32Ctz, kExprI32Popcnt, 603 kExprI32Add, kExprI32Sub, kExprI32Mul, kExprI32DivS, kExprI32DivU, 604 kExprI32RemS, kExprI32RemU, kExprI32And, kExprI32Ior, kExprI32Xor, 605 kExprI32Shl, kExprI32ShrS, kExprI32ShrU, kExprI32Rol, kExprI32Ror, 606 kExprI64Clz, kExprI64Ctz, kExprI64Popcnt, kExprI64Add, kExprI64Sub, 607 kExprI64Mul, kExprI64DivS, kExprI64DivU, kExprI64RemS, kExprI64RemU, 608 kExprI64And, kExprI64Ior, kExprI64Xor, kExprI64Shl, kExprI64ShrS, 609 kExprI64ShrU, kExprI64Rol, kExprI64Ror, kExprF32Abs, kExprF32Neg, 610 kExprF32Ceil, kExprF32Floor, kExprF32Trunc, kExprF32NearestInt, kExprF32Sqrt, 611 kExprF32Add, kExprF32Sub, kExprF32Mul, kExprF32Div, kExprF32Min, kExprF32Max, 612 kExprF32CopySign, kExprF64Abs, kExprF64Neg, kExprF64Ceil, kExprF64Floor, 613 kExprF64Trunc, kExprF64NearestInt, kExprF64Sqrt, kExprF64Add, kExprF64Sub, 614 kExprF64Mul, kExprF64Div, kExprF64Min, kExprF64Max, kExprF64CopySign, 615 kExprI32ConvertI64, kExprI32SConvertF32, kExprI32UConvertF32, 616 kExprI32SConvertF64, kExprI32UConvertF64, kExprI64SConvertI32, 617 kExprI64UConvertI32, kExprI64SConvertF32, kExprI64UConvertF32, 618 kExprI64SConvertF64, kExprI64UConvertF64, kExprF32SConvertI32, 619 kExprF32UConvertI32, kExprF32SConvertI64, kExprF32UConvertI64, 620 kExprF32ConvertF64, kExprF64SConvertI32, kExprF64UConvertI32, 621 kExprF64SConvertI64, kExprF64UConvertI64, kExprF64ConvertF32, 622 kExprI32ReinterpretF32, kExprI64ReinterpretF64, kExprF32ReinterpretI32, 623 kExprF64ReinterpretI64, kExprI32SExtendI8, kExprI32SExtendI16, 624 kExprI64SExtendI8, kExprI64SExtendI16, kExprI64SExtendI32, kExprRefNull, 625 kExprRefIsNull, kExprRefFunc, 626 GCInstr, 627 kExprStructNew, kExprStructNewDefault, kExprStructGet, kExprStructGetS, 628 kExprStructGetU, kExprStructSet, kExprArrayNew, kExprArrayNewDefault, 629 kExprArrayNewFixed, kExprArrayNewData, kExprArrayNewElem, kExprArrayGet, 630 kExprArrayGetS, kExprArrayGetU, kExprArraySet, kExprArrayLen, kExprArrayFill, 631 kExprArrayCopy, kExprArrayInitData, kExprArrayInitElem, kExprRefTest, 632 kExprRefTestNull, kExprRefCast, kExprRefCastNull, kExprBrOnCast, 633 kExprBrOnCastFail, kExprExternInternalize, kExprExternExternalize, 634 kExprI31New, kExprI31GetS, kExprI31GetU, 635 kExprMemoryInit, kExprDataDrop, kExprMemoryCopy, kExprMemoryFill, 636 kExprTableInit, kExprElemDrop, kExprTableCopy, kExprTableGrow, kExprTableSize, 637 kExprTableFill, 638 kExprAtomicNotify, kExprI32AtomicWait, kExprI64AtomicWait, kExprI32AtomicLoad, 639 kExprI32AtomicLoad8U, kExprI32AtomicLoad16U, kExprI32AtomicStore, 640 kExprI32AtomicStore8U, kExprI32AtomicStore16U, kExprI32AtomicAdd, 641 kExprI32AtomicAdd8U, kExprI32AtomicAdd16U, kExprI32AtomicSub, 642 kExprI32AtomicSub8U, kExprI32AtomicSub16U, kExprI32AtomicAnd, 643 kExprI32AtomicAnd8U, kExprI32AtomicAnd16U, kExprI32AtomicOr, 644 kExprI32AtomicOr8U, kExprI32AtomicOr16U, kExprI32AtomicXor, 645 kExprI32AtomicXor8U, kExprI32AtomicXor16U, kExprI32AtomicExchange, 646 kExprI32AtomicExchange8U, kExprI32AtomicExchange16U, 647 kExprI32AtomicCompareExchange, kExprI32AtomicCompareExchange8U, 648 kExprI32AtomicCompareExchange16U, kExprI64AtomicLoad, kExprI64AtomicLoad8U, 649 kExprI64AtomicLoad16U, kExprI64AtomicLoad32U, kExprI64AtomicStore, 650 kExprI64AtomicStore8U, kExprI64AtomicStore16U, kExprI64AtomicStore32U, 651 kExprI64AtomicAdd, kExprI64AtomicAdd8U, kExprI64AtomicAdd16U, 652 kExprI64AtomicAdd32U, kExprI64AtomicSub, kExprI64AtomicSub8U, 653 kExprI64AtomicSub16U, kExprI64AtomicSub32U, kExprI64AtomicAnd, 654 kExprI64AtomicAnd8U, kExprI64AtomicAnd16U, kExprI64AtomicAnd32U, 655 kExprI64AtomicOr, kExprI64AtomicOr8U, kExprI64AtomicOr16U, 656 kExprI64AtomicOr32U, kExprI64AtomicXor, kExprI64AtomicXor8U, 657 kExprI64AtomicXor16U, kExprI64AtomicXor32U, kExprI64AtomicExchange, 658 kExprI64AtomicExchange8U, kExprI64AtomicExchange16U, 659 kExprI64AtomicExchange32U, kExprI64AtomicCompareExchange, 660 kExprI64AtomicCompareExchange8U, kExprI64AtomicCompareExchange16U, 661 kExprI64AtomicCompareExchange32U, 662 kExprS128LoadMem, kExprS128StoreMem, kExprI32x4Splat, kExprI32x4Eq, 663 kExprS1x4AllTrue, kExprF32x4Min 664 }); 665 666 class Binary { 667 constructor() { 668 this.length = 0; 669 this.buffer = new Uint8Array(8192); 670 } 671 672 ensure_space(needed) { 673 if (this.buffer.length - this.length >= needed) return; 674 let new_capacity = this.buffer.length * 2; 675 while (new_capacity - this.length < needed) new_capacity *= 2; 676 let new_buffer = new Uint8Array(new_capacity); 677 new_buffer.set(this.buffer); 678 this.buffer = new_buffer; 679 } 680 681 trunc_buffer() { 682 return new Uint8Array(this.buffer.buffer, 0, this.length); 683 } 684 685 reset() { 686 this.length = 0; 687 } 688 689 emit_u8(val) { 690 this.ensure_space(1); 691 this.buffer[this.length++] = val; 692 } 693 694 emit_u16(val) { 695 this.ensure_space(2); 696 this.buffer[this.length++] = val; 697 this.buffer[this.length++] = val >> 8; 698 } 699 700 emit_u32(val) { 701 this.ensure_space(4); 702 this.buffer[this.length++] = val; 703 this.buffer[this.length++] = val >> 8; 704 this.buffer[this.length++] = val >> 16; 705 this.buffer[this.length++] = val >> 24; 706 } 707 708 emit_leb_u(val, max_len) { 709 this.ensure_space(max_len); 710 for (let i = 0; i < max_len; ++i) { 711 let v = val & 0xff; 712 val = val >>> 7; 713 if (val == 0) { 714 this.buffer[this.length++] = v; 715 return; 716 } 717 this.buffer[this.length++] = v | 0x80; 718 } 719 throw new Error("Leb value exceeds maximum length of " + max_len); 720 } 721 722 emit_u32v(val) { 723 this.emit_leb_u(val, kMaxVarInt32Size); 724 } 725 726 emit_u64v(val) { 727 this.emit_leb_u(val, kMaxVarInt64Size); 728 } 729 730 emit_bytes(data) { 731 this.ensure_space(data.length); 732 this.buffer.set(data, this.length); 733 this.length += data.length; 734 } 735 736 emit_string(string) { 737 // When testing illegal names, we pass a byte array directly. 738 if (string instanceof Array) { 739 this.emit_u32v(string.length); 740 this.emit_bytes(string); 741 return; 742 } 743 744 // This is the hacky way to convert a JavaScript string to a UTF8 encoded 745 // string only containing single-byte characters. 746 let string_utf8 = unescape(encodeURIComponent(string)); 747 this.emit_u32v(string_utf8.length); 748 for (let i = 0; i < string_utf8.length; i++) { 749 this.emit_u8(string_utf8.charCodeAt(i)); 750 } 751 } 752 753 emit_heap_type(heap_type) { 754 this.emit_bytes(wasmSignedLeb(heap_type, kMaxVarInt32Size)); 755 } 756 757 emit_type(type) { 758 if ((typeof type) == 'number') { 759 this.emit_u8(type >= 0 ? type : type & kLeb128Mask); 760 } else { 761 this.emit_u8(type.opcode); 762 if ('depth' in type) this.emit_u8(type.depth); 763 this.emit_heap_type(type.heap_type); 764 } 765 } 766 767 emit_init_expr(expr) { 768 this.emit_bytes(expr); 769 this.emit_u8(kExprEnd); 770 } 771 772 emit_header() { 773 this.emit_bytes([ 774 kWasmH0, kWasmH1, kWasmH2, kWasmH3, kWasmV0, kWasmV1, kWasmV2, kWasmV3 775 ]); 776 } 777 778 emit_section(section_code, content_generator) { 779 // Emit section name. 780 this.emit_u8(section_code); 781 // Emit the section to a temporary buffer: its full length isn't know yet. 782 const section = new Binary; 783 content_generator(section); 784 // Emit section length. 785 this.emit_u32v(section.length); 786 // Copy the temporary buffer. 787 // Avoid spread because {section} can be huge. 788 this.emit_bytes(section.trunc_buffer()); 789 } 790 } 791 792 class WasmFunctionBuilder { 793 constructor(module, name, type_index) { 794 this.module = module; 795 this.name = name; 796 this.type_index = type_index; 797 this.body = []; 798 this.locals = []; 799 this.local_names = []; 800 } 801 802 numLocalNames() { 803 let num_local_names = 0; 804 for (let loc_name of this.local_names) { 805 if (loc_name !== undefined) ++num_local_names; 806 } 807 return num_local_names; 808 } 809 810 exportAs(name) { 811 this.module.addExport(name, this.index); 812 return this; 813 } 814 815 exportFunc() { 816 this.exportAs(this.name); 817 return this; 818 } 819 820 addBody(body) { 821 for (let b of body) { 822 if (typeof b !== 'number' || (b & (~0xFF)) !== 0 ) 823 throw new Error('invalid body (entries must be 8 bit numbers): ' + body); 824 } 825 this.body = body.slice(); 826 // Automatically add the end for the function block to the body. 827 this.body.push(kExprEnd); 828 return this; 829 } 830 831 addBodyWithEnd(body) { 832 this.body = body; 833 return this; 834 } 835 836 getNumLocals() { 837 let total_locals = 0; 838 for (let l of this.locals) { 839 for (let type of ["i32", "i64", "f32", "f64", "s128"]) { 840 total_locals += l[type + "_count"] || 0; 841 } 842 } 843 return total_locals; 844 } 845 846 addLocals(locals, names) { 847 const old_num_locals = this.getNumLocals(); 848 this.locals.push(locals); 849 if (names) { 850 const missing_names = old_num_locals - this.local_names.length; 851 this.local_names.push(...new Array(missing_names), ...names); 852 } 853 return this; 854 } 855 856 end() { 857 return this.module; 858 } 859 } 860 861 class WasmGlobalBuilder { 862 constructor(module, type, mutable, init) { 863 this.module = module; 864 this.type = type; 865 this.mutable = mutable; 866 this.init = init; 867 } 868 869 exportAs(name) { 870 this.module.exports.push({name: name, kind: kExternalGlobal, 871 index: this.index}); 872 return this; 873 } 874 } 875 876 function checkExpr(expr) { 877 for (let b of expr) { 878 if (typeof b !== 'number' || (b & (~0xFF)) !== 0) { 879 throw new Error( 880 'invalid body (entries must be 8 bit numbers): ' + expr); 881 } 882 } 883 } 884 885 class WasmTableBuilder { 886 constructor(module, type, initial_size, max_size, init_expr) { 887 this.module = module; 888 this.type = type; 889 this.initial_size = initial_size; 890 this.has_max = max_size != undefined; 891 this.max_size = max_size; 892 this.init_expr = init_expr; 893 this.has_init = init_expr !== undefined; 894 } 895 896 exportAs(name) { 897 this.module.exports.push({name: name, kind: kExternalTable, 898 index: this.index}); 899 return this; 900 } 901 } 902 903 function makeField(type, mutability) { 904 if ((typeof mutability) != 'boolean') { 905 throw new Error('field mutability must be boolean'); 906 } 907 return {type: type, mutability: mutability}; 908 } 909 910 class WasmStruct { 911 constructor(fields, is_final, supertype_idx) { 912 if (!Array.isArray(fields)) { 913 throw new Error('struct fields must be an array'); 914 } 915 this.fields = fields; 916 this.type_form = kWasmStructTypeForm; 917 this.is_final = is_final; 918 this.supertype = supertype_idx; 919 } 920 } 921 922 class WasmArray { 923 constructor(type, mutability, is_final, supertype_idx) { 924 this.type = type; 925 this.mutability = mutability; 926 this.type_form = kWasmArrayTypeForm; 927 this.is_final = is_final; 928 this.supertype = supertype_idx; 929 } 930 } 931 932 class WasmModuleBuilder { 933 constructor() { 934 this.types = []; 935 this.imports = []; 936 this.exports = []; 937 this.globals = []; 938 this.tables = []; 939 this.tags = []; 940 this.functions = []; 941 this.element_segments = []; 942 this.data_segments = []; 943 this.explicit = []; 944 this.rec_groups = []; 945 this.num_imported_funcs = 0; 946 this.num_imported_globals = 0; 947 this.num_imported_tables = 0; 948 this.num_imported_tags = 0; 949 return this; 950 } 951 952 addStart(start_index) { 953 this.start_index = start_index; 954 return this; 955 } 956 957 addMemory(min, max, exp, shared) { 958 this.memory = {min: min, max: max, exp: exp, shared: shared}; 959 return this; 960 } 961 962 addExplicitSection(bytes) { 963 this.explicit.push(bytes); 964 return this; 965 } 966 967 stringToBytes(name) { 968 var result = new Binary(); 969 result.emit_string(name); 970 return result.trunc_buffer() 971 } 972 973 createCustomSection(name, bytes) { 974 name = this.stringToBytes(name); 975 var section = new Binary(); 976 section.emit_u8(kUnknownSectionCode); 977 section.emit_u32v(name.length + bytes.length); 978 section.emit_bytes(name); 979 section.emit_bytes(bytes); 980 return section.trunc_buffer(); 981 } 982 983 addCustomSection(name, bytes) { 984 this.explicit.push(this.createCustomSection(name, bytes)); 985 } 986 987 // We use {is_final = true} so that the MVP syntax is generated for 988 // signatures. 989 addType(type, supertype_idx = kNoSuperType, is_final = true) { 990 var pl = type.params.length; // should have params 991 var rl = type.results.length; // should have results 992 var type_copy = {params: type.params, results: type.results, 993 is_final: is_final, supertype: supertype_idx}; 994 this.types.push(type_copy); 995 return this.types.length - 1; 996 } 997 998 addStruct(fields, supertype_idx = kNoSuperType, is_final = false) { 999 this.types.push(new WasmStruct(fields, is_final, supertype_idx)); 1000 return this.types.length - 1; 1001 } 1002 1003 addArray(type, mutability, supertype_idx = kNoSuperType, is_final = false) { 1004 this.types.push(new WasmArray(type, mutability, is_final, supertype_idx)); 1005 return this.types.length - 1; 1006 } 1007 1008 static defaultFor(type) { 1009 switch (type) { 1010 case kWasmI32: 1011 return wasmI32Const(0); 1012 case kWasmI64: 1013 return wasmI64Const(0); 1014 case kWasmF32: 1015 return wasmF32Const(0.0); 1016 case kWasmF64: 1017 return wasmF64Const(0.0); 1018 case kWasmS128: 1019 return [kSimdPrefix, kExprS128Const, ...(new Array(16).fill(0))]; 1020 default: 1021 if ((typeof type) != 'number' && type.opcode != kWasmRefNull) { 1022 throw new Error("Non-defaultable type"); 1023 } 1024 let heap_type = (typeof type) == 'number' ? type : type.heap_type; 1025 return [kExprRefNull, ...wasmSignedLeb(heap_type, kMaxVarInt32Size)]; 1026 } 1027 } 1028 1029 addGlobal(type, mutable, init) { 1030 if (init === undefined) init = WasmModuleBuilder.defaultFor(type); 1031 checkExpr(init); 1032 let glob = new WasmGlobalBuilder(this, type, mutable, init); 1033 glob.index = this.globals.length + this.num_imported_globals; 1034 this.globals.push(glob); 1035 return glob; 1036 } 1037 1038 addTable(type, initial_size, max_size = undefined, init_expr = undefined) { 1039 if (type == kWasmI32 || type == kWasmI64 || type == kWasmF32 || 1040 type == kWasmF64 || type == kWasmS128 || type == kWasmStmt) { 1041 throw new Error('Tables must be of a reference type'); 1042 } 1043 if (init_expr != undefined) checkExpr(init_expr); 1044 let table = new WasmTableBuilder( 1045 this, type, initial_size, max_size, init_expr); 1046 table.index = this.tables.length + this.num_imported_tables; 1047 this.tables.push(table); 1048 return table; 1049 } 1050 1051 addTag(type) { 1052 let type_index = (typeof type) == "number" ? type : this.addType(type); 1053 let tag_index = this.tags.length + this.num_imported_tags; 1054 this.tags.push(type_index); 1055 return tag_index; 1056 } 1057 1058 addFunction(name, type) { 1059 let type_index = (typeof type) == "number" ? type : this.addType(type); 1060 let func = new WasmFunctionBuilder(this, name, type_index); 1061 func.index = this.functions.length + this.num_imported_funcs; 1062 this.functions.push(func); 1063 return func; 1064 } 1065 1066 addImport(module, name, type) { 1067 if (this.functions.length != 0) { 1068 throw new Error('Imported functions must be declared before local ones'); 1069 } 1070 let type_index = (typeof type) == "number" ? type : this.addType(type); 1071 this.imports.push({module: module, name: name, kind: kExternalFunction, 1072 type: type_index}); 1073 return this.num_imported_funcs++; 1074 } 1075 1076 addImportedGlobal(module, name, type, mutable = false) { 1077 if (this.globals.length != 0) { 1078 throw new Error('Imported globals must be declared before local ones'); 1079 } 1080 let o = {module: module, name: name, kind: kExternalGlobal, type: type, 1081 mutable: mutable}; 1082 this.imports.push(o); 1083 return this.num_imported_globals++; 1084 } 1085 1086 addImportedMemory(module, name, initial = 0, maximum, shared) { 1087 let o = {module: module, name: name, kind: kExternalMemory, 1088 initial: initial, maximum: maximum, shared: shared}; 1089 this.imports.push(o); 1090 return this; 1091 } 1092 1093 addImportedTable(module, name, initial, maximum, type) { 1094 if (this.tables.length != 0) { 1095 throw new Error('Imported tables must be declared before local ones'); 1096 } 1097 let o = {module: module, name: name, kind: kExternalTable, initial: initial, 1098 maximum: maximum, type: type || kWasmAnyFunctionTypeForm}; 1099 this.imports.push(o); 1100 return this.num_imported_tables++; 1101 } 1102 1103 addImportedTag(module, name, type) { 1104 if (this.tags.length != 0) { 1105 throw new Error('Imported tags must be declared before local ones'); 1106 } 1107 let type_index = (typeof type) == "number" ? type : this.addType(type); 1108 let o = {module: module, name: name, kind: kExternalTag, type: type_index}; 1109 this.imports.push(o); 1110 return this.num_imported_tags++; 1111 } 1112 1113 addExport(name, index) { 1114 this.exports.push({name: name, kind: kExternalFunction, index: index}); 1115 return this; 1116 } 1117 1118 addExportOfKind(name, kind, index) { 1119 this.exports.push({name: name, kind: kind, index: index}); 1120 return this; 1121 } 1122 1123 addDataSegment(addr, data, is_global = false) { 1124 this.data_segments.push( 1125 {addr: addr, data: data, is_global: is_global, is_active: true}); 1126 return this.data_segments.length - 1; 1127 } 1128 1129 addPassiveDataSegment(data) { 1130 this.data_segments.push({data: data, is_active: false}); 1131 return this.data_segments.length - 1; 1132 } 1133 1134 exportMemoryAs(name) { 1135 this.exports.push({name: name, kind: kExternalMemory, index: 0}); 1136 } 1137 1138 addElementSegment(table, base, is_global, array) { 1139 this.element_segments.push({table: table, base: base, is_global: is_global, 1140 array: array, is_active: true}); 1141 return this; 1142 } 1143 1144 addPassiveElementSegment(array, is_import = false) { 1145 this.element_segments.push({array: array, is_active: false}); 1146 return this; 1147 } 1148 1149 appendToTable(array) { 1150 for (let n of array) { 1151 if (typeof n != 'number') 1152 throw new Error('invalid table (entries have to be numbers): ' + array); 1153 } 1154 if (this.tables.length == 0) { 1155 this.addTable(kWasmAnyFunc, 0); 1156 } 1157 // Adjust the table to the correct size. 1158 let table = this.tables[0]; 1159 const base = table.initial_size; 1160 const table_size = base + array.length; 1161 table.initial_size = table_size; 1162 if (table.has_max && table_size > table.max_size) { 1163 table.max_size = table_size; 1164 } 1165 return this.addElementSegment(0, base, false, array); 1166 } 1167 1168 setTableBounds(min, max = undefined) { 1169 if (this.tables.length != 0) { 1170 throw new Error("The table bounds of table '0' have already been set."); 1171 } 1172 this.addTable(kWasmAnyFunc, min, max); 1173 return this; 1174 } 1175 1176 startRecGroup() { 1177 this.rec_groups.push({start: this.types.length, size: 0}); 1178 } 1179 1180 endRecGroup() { 1181 if (this.rec_groups.length == 0) { 1182 throw new Error("Did not start a recursive group before ending one") 1183 } 1184 let last_element = this.rec_groups[this.rec_groups.length - 1] 1185 if (last_element.size != 0) { 1186 throw new Error("Did not start a recursive group before ending one") 1187 } 1188 last_element.size = this.types.length - last_element.start; 1189 } 1190 1191 setName(name) { 1192 this.name = name; 1193 return this; 1194 } 1195 1196 toBuffer(debug = false) { 1197 let binary = new Binary; 1198 let wasm = this; 1199 1200 // Add header 1201 binary.emit_header(); 1202 1203 // Add type section 1204 if (wasm.types.length > 0) { 1205 if (debug) print('emitting types @ ' + binary.length); 1206 binary.emit_section(kTypeSectionCode, section => { 1207 let length_with_groups = wasm.types.length; 1208 for (let group of wasm.rec_groups) { 1209 length_with_groups -= group.size - 1; 1210 } 1211 section.emit_u32v(length_with_groups); 1212 1213 let rec_group_index = 0; 1214 1215 for (let i = 0; i < wasm.types.length; i++) { 1216 if (rec_group_index < wasm.rec_groups.length && 1217 wasm.rec_groups[rec_group_index].start == i) { 1218 section.emit_u8(kWasmRecursiveTypeGroupForm); 1219 section.emit_u32v(wasm.rec_groups[rec_group_index].size); 1220 rec_group_index++; 1221 } 1222 1223 let type = wasm.types[i]; 1224 if (type.supertype != kNoSuperType) { 1225 section.emit_u8(type.is_final ? kWasmSubtypeFinalForm 1226 : kWasmSubtypeForm); 1227 section.emit_u8(1); // supertype count 1228 section.emit_u32v(type.supertype); 1229 } else if (!type.is_final) { 1230 section.emit_u8(kWasmSubtypeForm); 1231 section.emit_u8(0); // no supertypes 1232 } 1233 if (type instanceof WasmStruct) { 1234 section.emit_u8(kWasmStructTypeForm); 1235 section.emit_u32v(type.fields.length); 1236 for (let field of type.fields) { 1237 section.emit_type(field.type); 1238 section.emit_u8(field.mutability ? 1 : 0); 1239 } 1240 } else if (type instanceof WasmArray) { 1241 section.emit_u8(kWasmArrayTypeForm); 1242 section.emit_type(type.type); 1243 section.emit_u8(type.mutability ? 1 : 0); 1244 } else { 1245 section.emit_u8(kWasmFunctionTypeForm); 1246 section.emit_u32v(type.params.length); 1247 for (let param of type.params) { 1248 section.emit_type(param); 1249 } 1250 section.emit_u32v(type.results.length); 1251 for (let result of type.results) { 1252 section.emit_type(result); 1253 } 1254 } 1255 } 1256 }); 1257 } 1258 1259 // Add imports section 1260 if (wasm.imports.length > 0) { 1261 if (debug) print("emitting imports @ " + binary.length); 1262 binary.emit_section(kImportSectionCode, section => { 1263 section.emit_u32v(wasm.imports.length); 1264 for (let imp of wasm.imports) { 1265 section.emit_string(imp.module); 1266 section.emit_string(imp.name || ''); 1267 section.emit_u8(imp.kind); 1268 if (imp.kind == kExternalFunction) { 1269 section.emit_u32v(imp.type); 1270 } else if (imp.kind == kExternalGlobal) { 1271 section.emit_type(imp.type); 1272 section.emit_u8(imp.mutable); 1273 } else if (imp.kind == kExternalMemory) { 1274 var has_max = (typeof imp.maximum) != "undefined"; 1275 var is_shared = (typeof imp.shared) != "undefined"; 1276 if (is_shared) { 1277 section.emit_u8(has_max ? 3 : 2); // flags 1278 } else { 1279 section.emit_u8(has_max ? 1 : 0); // flags 1280 } 1281 section.emit_u32v(imp.initial); // initial 1282 if (has_max) section.emit_u32v(imp.maximum); // maximum 1283 } else if (imp.kind == kExternalTable) { 1284 section.emit_type(imp.type); 1285 var has_max = (typeof imp.maximum) != "undefined"; 1286 section.emit_u8(has_max ? 1 : 0); // flags 1287 section.emit_u32v(imp.initial); // initial 1288 if (has_max) section.emit_u32v(imp.maximum); // maximum 1289 } else if (imp.kind == kExternalTag) { 1290 section.emit_u32v(kTagAttribute); 1291 section.emit_u32v(imp.type); 1292 } else { 1293 throw new Error("unknown/unsupported import kind " + imp.kind); 1294 } 1295 } 1296 }); 1297 } 1298 1299 // Add functions declarations 1300 if (wasm.functions.length > 0) { 1301 if (debug) print("emitting function decls @ " + binary.length); 1302 binary.emit_section(kFunctionSectionCode, section => { 1303 section.emit_u32v(wasm.functions.length); 1304 for (let func of wasm.functions) { 1305 section.emit_u32v(func.type_index); 1306 } 1307 }); 1308 } 1309 1310 // Add table section 1311 if (wasm.tables.length > 0) { 1312 if (debug) print ("emitting tables @ " + binary.length); 1313 binary.emit_section(kTableSectionCode, section => { 1314 section.emit_u32v(wasm.tables.length); 1315 for (let table of wasm.tables) { 1316 section.emit_type(table.type); 1317 section.emit_u8(table.has_max); 1318 section.emit_u32v(table.initial_size); 1319 if (table.has_max) section.emit_u32v(table.max_size); 1320 if (table.has_init) section.emit_init_expr(table.init_expr); 1321 } 1322 }); 1323 } 1324 1325 // Add memory section 1326 if (wasm.memory !== undefined) { 1327 if (debug) print("emitting memory @ " + binary.length); 1328 binary.emit_section(kMemorySectionCode, section => { 1329 section.emit_u8(1); // one memory entry 1330 const has_max = wasm.memory.max !== undefined; 1331 const is_shared = wasm.memory.shared !== undefined; 1332 // Emit flags (bit 0: reszeable max, bit 1: shared memory) 1333 if (is_shared) { 1334 section.emit_u8(has_max ? kSharedHasMaximumFlag : 2); 1335 } else { 1336 section.emit_u8(has_max ? kHasMaximumFlag : 0); 1337 } 1338 section.emit_u32v(wasm.memory.min); 1339 if (has_max) section.emit_u32v(wasm.memory.max); 1340 }); 1341 } 1342 1343 // Add global section. 1344 if (wasm.globals.length > 0) { 1345 if (debug) print ("emitting globals @ " + binary.length); 1346 binary.emit_section(kGlobalSectionCode, section => { 1347 section.emit_u32v(wasm.globals.length); 1348 for (let global of wasm.globals) { 1349 section.emit_type(global.type); 1350 section.emit_u8(global.mutable); 1351 section.emit_init_expr(global.init); 1352 } 1353 }); 1354 } 1355 1356 // Add tags. 1357 if (wasm.tags.length > 0) { 1358 if (debug) print("emitting tags @ " + binary.length); 1359 binary.emit_section(kTagSectionCode, section => { 1360 section.emit_u32v(wasm.tags.length); 1361 for (let type of wasm.tags) { 1362 section.emit_u32v(kTagAttribute); 1363 section.emit_u32v(type); 1364 } 1365 }); 1366 } 1367 1368 // Add export table. 1369 var mem_export = (wasm.memory !== undefined && wasm.memory.exp); 1370 var exports_count = wasm.exports.length + (mem_export ? 1 : 0); 1371 if (exports_count > 0) { 1372 if (debug) print("emitting exports @ " + binary.length); 1373 binary.emit_section(kExportSectionCode, section => { 1374 section.emit_u32v(exports_count); 1375 for (let exp of wasm.exports) { 1376 section.emit_string(exp.name); 1377 section.emit_u8(exp.kind); 1378 section.emit_u32v(exp.index); 1379 } 1380 if (mem_export) { 1381 section.emit_string("memory"); 1382 section.emit_u8(kExternalMemory); 1383 section.emit_u8(0); 1384 } 1385 }); 1386 } 1387 1388 // Add start function section. 1389 if (wasm.start_index !== undefined) { 1390 if (debug) print("emitting start function @ " + binary.length); 1391 binary.emit_section(kStartSectionCode, section => { 1392 section.emit_u32v(wasm.start_index); 1393 }); 1394 } 1395 1396 // Add element segments 1397 if (wasm.element_segments.length > 0) { 1398 if (debug) print("emitting element segments @ " + binary.length); 1399 binary.emit_section(kElementSectionCode, section => { 1400 var inits = wasm.element_segments; 1401 section.emit_u32v(inits.length); 1402 1403 for (let init of inits) { 1404 if (init.is_active) { 1405 // Active segment. 1406 if (init.table == 0) { 1407 section.emit_u32v(kActiveNoIndex); 1408 } else { 1409 section.emit_u32v(kActiveWithIndex); 1410 section.emit_u32v(init.table); 1411 } 1412 if (init.is_global) { 1413 section.emit_u8(kExprGlobalGet); 1414 } else { 1415 section.emit_u8(kExprI32Const); 1416 } 1417 section.emit_u32v(init.base); 1418 section.emit_u8(kExprEnd); 1419 if (init.table != 0) { 1420 section.emit_u8(kExternalFunction); 1421 } 1422 section.emit_u32v(init.array.length); 1423 for (let index of init.array) { 1424 section.emit_u32v(index); 1425 } 1426 } else { 1427 // Passive segment. 1428 section.emit_u8(kPassiveWithElements); // flags 1429 section.emit_u8(kWasmAnyFunc); 1430 section.emit_u32v(init.array.length); 1431 for (let index of init.array) { 1432 if (index === null) { 1433 section.emit_u8(kExprRefNull); 1434 section.emit_u8(kExprEnd); 1435 } else { 1436 section.emit_u8(kExprRefFunc); 1437 section.emit_u32v(index); 1438 section.emit_u8(kExprEnd); 1439 } 1440 } 1441 } 1442 } 1443 }); 1444 } 1445 1446 // If there are any passive data segments, add the DataCount section. 1447 if (wasm.data_segments.some(seg => !seg.is_active)) { 1448 binary.emit_section(kDataCountSectionCode, section => { 1449 section.emit_u32v(wasm.data_segments.length); 1450 }); 1451 } 1452 1453 // Add function bodies. 1454 if (wasm.functions.length > 0) { 1455 // emit function bodies 1456 if (debug) print("emitting code @ " + binary.length); 1457 binary.emit_section(kCodeSectionCode, section => { 1458 section.emit_u32v(wasm.functions.length); 1459 let header = new Binary; 1460 for (let func of wasm.functions) { 1461 header.reset(); 1462 // Function body length will be patched later. 1463 let local_decls = []; 1464 for (let l of func.locals || []) { 1465 if (l.i32_count > 0) { 1466 local_decls.push({count: l.i32_count, type: kWasmI32}); 1467 } 1468 if (l.i64_count > 0) { 1469 local_decls.push({count: l.i64_count, type: kWasmI64}); 1470 } 1471 if (l.f32_count > 0) { 1472 local_decls.push({count: l.f32_count, type: kWasmF32}); 1473 } 1474 if (l.f64_count > 0) { 1475 local_decls.push({count: l.f64_count, type: kWasmF64}); 1476 } 1477 if (l.s128_count > 0) { 1478 local_decls.push({count: l.s128_count, type: kWasmS128}); 1479 } 1480 if (l.anyref_count > 0) { 1481 local_decls.push({count: l.anyref_count, type: kWasmExternRef}); 1482 } 1483 if (l.anyfunc_count > 0) { 1484 local_decls.push({count: l.anyfunc_count, type: kWasmAnyFunc}); 1485 } 1486 } 1487 1488 header.emit_u32v(local_decls.length); 1489 for (let decl of local_decls) { 1490 header.emit_u32v(decl.count); 1491 header.emit_type(decl.type); 1492 } 1493 1494 section.emit_u32v(header.length + func.body.length); 1495 section.emit_bytes(header.trunc_buffer()); 1496 section.emit_bytes(func.body); 1497 } 1498 }); 1499 } 1500 1501 // Add data segments. 1502 if (wasm.data_segments.length > 0) { 1503 if (debug) print("emitting data segments @ " + binary.length); 1504 binary.emit_section(kDataSectionCode, section => { 1505 section.emit_u32v(wasm.data_segments.length); 1506 for (let seg of wasm.data_segments) { 1507 if (seg.is_active) { 1508 section.emit_u8(0); // linear memory index 0 / flags 1509 if (seg.is_global) { 1510 // initializer is a global variable 1511 section.emit_u8(kExprGlobalGet); 1512 section.emit_u32v(seg.addr); 1513 } else { 1514 // initializer is a constant 1515 section.emit_u8(kExprI32Const); 1516 section.emit_u32v(seg.addr); 1517 } 1518 section.emit_u8(kExprEnd); 1519 } else { 1520 section.emit_u8(kPassive); // flags 1521 } 1522 section.emit_u32v(seg.data.length); 1523 section.emit_bytes(seg.data); 1524 } 1525 }); 1526 } 1527 1528 // Add any explicitly added sections 1529 for (let exp of wasm.explicit) { 1530 if (debug) print("emitting explicit @ " + binary.length); 1531 binary.emit_bytes(exp); 1532 } 1533 1534 // Add names. 1535 let num_function_names = 0; 1536 let num_functions_with_local_names = 0; 1537 for (let func of wasm.functions) { 1538 if (func.name !== undefined) ++num_function_names; 1539 if (func.numLocalNames() > 0) ++num_functions_with_local_names; 1540 } 1541 if (num_function_names > 0 || num_functions_with_local_names > 0 || 1542 wasm.name !== undefined) { 1543 if (debug) print('emitting names @ ' + binary.length); 1544 binary.emit_section(kUnknownSectionCode, section => { 1545 section.emit_string('name'); 1546 // Emit module name. 1547 if (wasm.name !== undefined) { 1548 section.emit_section(kModuleNameCode, name_section => { 1549 name_section.emit_string(wasm.name); 1550 }); 1551 } 1552 // Emit function names. 1553 if (num_function_names > 0) { 1554 section.emit_section(kFunctionNamesCode, name_section => { 1555 name_section.emit_u32v(num_function_names); 1556 for (let func of wasm.functions) { 1557 if (func.name === undefined) continue; 1558 name_section.emit_u32v(func.index); 1559 name_section.emit_string(func.name); 1560 } 1561 }); 1562 } 1563 // Emit local names. 1564 if (num_functions_with_local_names > 0) { 1565 section.emit_section(kLocalNamesCode, name_section => { 1566 name_section.emit_u32v(num_functions_with_local_names); 1567 for (let func of wasm.functions) { 1568 if (func.numLocalNames() == 0) continue; 1569 name_section.emit_u32v(func.index); 1570 name_section.emit_u32v(func.numLocalNames()); 1571 for (let i = 0; i < func.local_names.length; ++i) { 1572 if (func.local_names[i] === undefined) continue; 1573 name_section.emit_u32v(i); 1574 name_section.emit_string(func.local_names[i]); 1575 } 1576 } 1577 }); 1578 } 1579 }); 1580 } 1581 1582 return binary.trunc_buffer(); 1583 } 1584 1585 toArray(debug = false) { 1586 return Array.from(this.toBuffer(debug)); 1587 } 1588 1589 instantiate(ffi) { 1590 let module = this.toModule(); 1591 let instance = new WebAssembly.Instance(module, ffi); 1592 return instance; 1593 } 1594 1595 asyncInstantiate(ffi) { 1596 return WebAssembly.instantiate(this.toBuffer(), ffi) 1597 .then(({module, instance}) => instance); 1598 } 1599 1600 toModule(debug = false) { 1601 return new WebAssembly.Module(this.toBuffer(debug)); 1602 } 1603 } 1604 globalThis.WasmModuleBuilder = WasmModuleBuilder; 1605 1606 function wasmSignedLeb(val, max_len = 5) { 1607 let res = []; 1608 for (let i = 0; i < max_len; ++i) { 1609 let v = val & 0x7f; 1610 // If {v} sign-extended from 7 to 32 bits is equal to val, we are done. 1611 if (((v << 25) >> 25) == val) { 1612 res.push(v); 1613 return res; 1614 } 1615 res.push(v | 0x80); 1616 val = val >> 7; 1617 } 1618 throw new Error( 1619 'Leb value <' + val + '> exceeds maximum length of ' + max_len); 1620 } 1621 globalThis.wasmSignedLeb = wasmSignedLeb; 1622 1623 function wasmI32Const(val) { 1624 return [kExprI32Const, ...wasmSignedLeb(val, 5)]; 1625 } 1626 globalThis.wasmI32Const = wasmI32Const; 1627 1628 function wasmF32Const(f) { 1629 // Write in little-endian order at offset 0. 1630 data_view.setFloat32(0, f, true); 1631 return [ 1632 kExprF32Const, byte_view[0], byte_view[1], byte_view[2], byte_view[3] 1633 ]; 1634 } 1635 globalThis.wasmI32Const = wasmI32Const; 1636 1637 function wasmF64Const(f) { 1638 // Write in little-endian order at offset 0. 1639 data_view.setFloat64(0, f, true); 1640 return [ 1641 kExprF64Const, byte_view[0], byte_view[1], byte_view[2], 1642 byte_view[3], byte_view[4], byte_view[5], byte_view[6], byte_view[7] 1643 ]; 1644 } 1645 globalThis.wasmF64Const = wasmF64Const;