addFinallyFallThroughDispatches(enclosingFinallyState, tryStates, cases) {
    for (let i = 0; i < tryStates.length; i++) {
      let tryState = tryStates[i];
      if (tryState.kind === TryState.Kind.FINALLY) {
        let finallyState = tryState;

        if (enclosingFinallyState !== null) {
          let caseClauses = [];
          let index = 0;
          // CONSIDER: the actual list is much less than
          // enclosingFinallyState.tryStates
          // CONSIDER: it is actually only jump destinations plus catch starts
          for (let j = 0; j < enclosingFinallyState.tryStates.length; j++) {
            let destination = enclosingFinallyState.tryStates[j];
            index++;
            let statements;
            // all but the last case fallthrough to the last case clause
            if (index < enclosingFinallyState.tryStates.length) {
              statements = [];
            } else {
              statements = parseStatements `
                  $ctx.state = $ctx.finallyFallThrough;
                  $ctx.finallyFallThrough = ${State.INVALID_STATE};
                  break;`
            }
            caseClauses.push(
                createCaseClause(createNumberLiteral(destination), statements));
          }
          caseClauses.push(
              createDefaultClause([
                // $ctx.state = enclosingFinallyState.startState;
                createAssignStateStatement(
                    enclosingFinallyState.finallyState),
                // break;
                createBreakStatement()
              ]));

          // case finally.fallThroughState:
          //   switch ($fallThrough) {
          //   case enclosingFinally.tryStates:
          //   ...
          //     $ctx.state = $fallThrough;
          //     $fallThrough = INVALID_STATE;
          //     break;
          //   default:
          //     $ctx.state = enclosingFinallyBlock.startState;
          //     break;
          //   }
          //   break;
          cases.push(
              createCaseClause(
                  createNumberLiteral(finallyState.fallThroughState),
                  [
                    createSwitchStatement(
                        createMemberExpression('$ctx', 'finallyFallThrough'),
                        caseClauses),
                    createBreakStatement()
                  ]));
        } else {
          // case finally.fallThroughState:
          //   $ctx.state = $fallThrough;
          //   break;
          cases.push(
              createCaseClause(
                  createNumberLiteral(finallyState.fallThroughState),
                  parseStatements `
                      $ctx.state = $ctx.finallyFallThrough;
                      break;`));
        }
        this.addFinallyFallThroughDispatches(finallyState,
                                             finallyState.nestedTrys,
                                             cases);
      } else {
        this.addFinallyFallThroughDispatches(enclosingFinallyState,
                                             tryState.nestedTrys,
                                             cases);
      }
    }
  }
@param {FinallyState} enclosingFinallyState
@param {Array.<TryState>} tryStates
@param {Array.<ParseTree>} cases