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