• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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