# All files / src/semantics/map-function map-function-call.js

100% Statements 19/19
100% Branches 10/10
100% Functions 2/2
100% Lines 19/19

    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
    21x
    21x
    21x
    21x

    67x

    67x
    17x

    50x

    5x

    5x

    5x
    5x
    5x

    5x
    3x

    2x

    2x

    45x
    45x

     // @flow
    import Syntax from "../../Syntax";
    import curry from "curry";
    import { expandClosureIdentifier } from "../closure";
    import { FUNCTION_INDEX, TYPE_INDEX, CLOSURE_TYPE } from "../metadata";

    export default curry(function mapFunctonCall(options, call) {
      const { functions, types, locals, mapIdentifier, mapSizeof } = options;

      // sizeof(<target>) calls
      if (call.value === "sizeof") {
        return mapSizeof(call);
      }

      // Function pointer calls aka indirect calls
      if (locals[call.value] != null) {
        // Closures are a special case of indirect function calls where a 64-bit
        // variable is used to encode both the function index and the memory pointer.
        const identifier = {
          ...mapIdentifier(call),
          Type: Syntax.Identifier,
        };
        const meta = { ...identifier.meta };

        const type = (() => {
          const typedef = types[identifier.type];
          return typedef != null ? typedef.type : call.type;
        })();

        // Expand the 64-bit identifier into an additional 32-bit argument for closure
        // base pointer and table index.
        if (identifier.meta[CLOSURE_TYPE] != null) {
          return {
            ...call,
            meta,
            type,
            Type: Syntax.IndirectFunctionCall,
            params: [...expandClosureIdentifier(identifier)],
          };
        }

        const typeIndex = Object.keys(types).indexOf(identifier.type);

        return {
          ...call,
          meta: {
            ...meta,
            [TYPE_INDEX]: typeIndex,
          },
          type,
          params: [...call.params, identifier],
          Type: Syntax.IndirectFunctionCall,
        };
      }

      // Regular function calls
      const index = Object.keys(functions).indexOf(call.value);
      return {
        ...call,
        type: functions[call.value] != null ? functions[call.value].type : null,
        meta: { [FUNCTION_INDEX]: index },
      };
    });