All files / src/emitter/section code.js

100% Statements 50/50
100% Branches 11/11
100% Functions 8/8
100% Lines 47/47
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  21x 21x 21x 21x 21x 21x   21x 104x 104x     21x   158x   158x 2573x             2573x     2573x 1967x 1967x     1967x 295x 295x     1672x   13x 13x 13x   35x 35x 35x   706x 706x 706x   21x 21x 21x   897x     1967x         158x 158x     158x 158x   158x 158x 158x     21x   69x 69x 158x   69x        
// @flow
import invariant from 'invariant';
import { u8, i32, f32, f64, i64 } from 'wasm-types';
import { varint32, varuint32, varint7, varint64 } from '../numbers';
import { getTypeString } from '../value_type';
import OutputStream from '../../utils/output-stream';
import opcode from '../opcode';
 
const emitLocal = (stream, local) => {
  stream.push(varuint32, 1, 'number of locals of following type');
  stream.push(varint7, local.type, `${getTypeString(local.type)}`);
};
 
const emitFunctionBody = (stream, { locals, code, debug: functionName }) => {
  // write bytecode into a clean buffer
  const body = new OutputStream();
 
  code.forEach(({ kind, params, debug }) => {
    invariant(
      typeof kind !== 'undefined',
      `Fatal error! Generated undefined opcode. debug code: ${JSON.stringify(
        debug
      )}`
    );
    // There is a much nicer way of doing this
    body.push(u8, kind.code, `${kind.text}  ${debug ? debug : ''}`);
 
    // map over all params, if any and encode each on
    params.filter(p => typeof p !== 'undefined').forEach(p => {
      let type = varuint32;
      let stringType = 'i32.literal';
 
      // Memory opcode?
      if (kind.code >= 0x28 && kind.code <= 0x40) {
        type = varuint32;
        stringType = 'memory_immediate';
      } else {
        // either encode unsigned 32 bit values or floats
        switch (kind.result) {
          case f64:
            type = f64;
            stringType = 'f64.literal';
            break;
          case f32:
            type = f32;
            stringType = 'f32.literal';
            break;
          case i32:
            type = varint32;
            stringType = 'i32.literal';
            break;
          case i64:
            type = varint64;
            stringType = 'i64.literal';
            break;
          default:
            type = varuint32;
        }
      }
      body.push(type, p, `${stringType}`);
    });
  });
 
  // output locals to the stream
  const localsStream = new OutputStream();
  locals.forEach(local => emitLocal(localsStream, local));
 
  // body size is
  stream.push(varuint32, body.size + localsStream.size + 2, functionName);
  stream.push(varuint32, locals.length, 'locals count');
 
  stream.write(localsStream);
  stream.write(body);
  stream.push(u8, opcode.End.code, 'end');
};
 
const emit = (functions: any[]) => {
  // do stuff with ast
  const stream = new OutputStream();
  stream.push(varuint32, functions.length, 'function count');
  functions.forEach(func => emitFunctionBody(stream, func));
 
  return stream;
};
 
export default emit;