All files / src/emitter/section name.js

100% Statements 40/40
100% Branches 0/0
100% Functions 7/7
100% Lines 40/40
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90  21x 21x 21x       21x 42x 42x 42x         21x   42x   42x 42x 90x 90x     42x         21x         42x           42x         42x 50x 50x         50x 21x 21x       42x       21x 42x   42x       42x 42x 42x 42x   42x 42x 42x 42x   42x 42x 42x 42x   42x        
// @flow
import { varuint32, varuint7 } from '../numbers';
import { emitString } from '../string';
import OutputStream from '../../utils/output-stream';
import type { NameSectionType } from '../../generator/flow/types';
 
// Emit Module name subsection
const emitModuleName = (name: string): OutputStream => {
  const moduleSubsection = new OutputStream();
  emitString(moduleSubsection, name, `name_len: ${name}`);
  return moduleSubsection;
};
 
// Emit Functions subsection
const emitFunctionNames = (
  names: Array<{ index: number, name: string }>
): OutputStream => {
  const stream = new OutputStream();
 
  stream.push(varuint32, names.length, `count: ${String(names.length)}`);
  names.forEach(({ index, name }) => {
    stream.push(varuint32, index, `index: ${String(index)}`);
    emitString(stream, name, `name_len: ${name}`);
  });
 
  return stream;
};
 
// Emit Locals subsection
const emitLocals = (
  localsMap: Array<{
    index: number,
    locals: Array<{ index: number, name: string }>,
  }>
): OutputStream => {
  const stream = new OutputStream();
 
  // WebAssembly Binary Encoding docs are not the best on how this should be encoded.
  // This is pretty much lifted from wabt C++ source code. First comes the number
  // or functions, where each function is a header of a u32 function index followed
  // by locals + params count with each local/param encoded as a name_map
  stream.push(
    varuint32,
    localsMap.length,
    `count: ${String(localsMap.length)}`
  );
  localsMap.forEach(({ index: funIndex, locals }) => {
    stream.push(varuint32, funIndex, `function index: ${String(funIndex)}`);
    stream.push(
      varuint32,
      locals.length,
      `number of params and locals ${locals.length}`
    );
    locals.forEach(({ index, name }) => {
      stream.push(varuint32, index, `index: ${String(index)}`);
      emitString(stream, name, `name_len: ${name}`);
    });
  });
 
  return stream;
};
 
// Emit the Name custom section.
const emit = (nameSection: NameSectionType): OutputStream => {
  const stream = new OutputStream();
  // Name identifier/header as this is a custom section which requires a string id
  emitString(stream, 'name', 'name_len: name');
 
  // NOTE: Every subsection header is encoded here, not in the individual subsection
  // logic.
  const moduleSubsection = emitModuleName(nameSection.module);
  stream.push(varuint7, 0, 'name_type: Module');
  stream.push(varuint32, moduleSubsection.size, 'name_payload_len');
  stream.write(moduleSubsection);
 
  const functionSubsection = emitFunctionNames(nameSection.functions);
  stream.push(varuint7, 1, 'name_type: Function');
  stream.push(varuint32, functionSubsection.size, 'name_payload_len');
  stream.write(functionSubsection);
 
  const localsSubsection = emitLocals(nameSection.locals);
  stream.push(varuint7, 2, 'name_type: Locals');
  stream.push(varuint32, localsSubsection.size, 'name_payload_len');
  stream.write(localsSubsection);
 
  return stream;
};
 
export default emit;