#include <bits/stdc++.h>
#include <cassert>
#include <cstddef>
#include <limits>
#include <queue>
#include <unordered_map>
#include <utility>
#include <vector>

// lib/dijkstra.hpp
#ifndef DIJKSTRA_HPP
#define DIJKSTRA_HPP


/*
usage:

tools::dijkstra<int> calculator(node_count);
calculator.add_edge(from_node, to_node, cost);
std::vector<int> distances = calculator.calc(start_node);
*/

namespace tools {
  template <typename T>
  class dijkstra {
  private:
    std::vector<T> distances;
    std::vector<std::size_t> prev_nodes;
    std::priority_queue<std::pair<T, std::size_t>, std::vector<std::pair<T, std::size_t>>, std::greater<std::pair<T, std::size_t>>> tasks;
    std::vector<std::unordered_map<std::size_t, T>> edges;

  public:
    static constexpr std::size_t NONE = std::numeric_limits<std::size_t>::max();

    dijkstra(const std::size_t node_count) :
      distances(node_count),
      prev_nodes(node_count),
      tasks(),
      edges(node_count) {
    }

    void add_edge(const std::size_t from, const std::size_t to, const T distance) {
      this->edges[from].insert(std::make_pair(to, distance));
    }

    std::vector<T> calc(const std::size_t start_node) {
      assert(start_node < this->distances.size());
      this->distances.assign(this->distances.size(), std::numeric_limits<T>::max());
      this->prev_nodes.assign(this->prev_nodes.size(), std::size_t(NONE));
      this->tasks.push(std::make_pair(0, start_node));
      while (!this->tasks.empty()) {
        const std::pair<T, std::size_t> task = this->tasks.top();
        this->tasks.pop();
        const T& distance = std::get<0>(task);
        const std::size_t& target_node = std::get<1>(task);
        if (this->distances[target_node] != std::numeric_limits<T>::max()) {
          // old task for already visited node
          continue;
        }
        this->distances[target_node] = distance;
        for (const std::pair<std::size_t, T>& edge : this->edges[target_node]) {
          const std::size_t& next_node = std::get<0>(edge);
          const T new_distance = distance + std::get<1>(edge);
          if (new_distance < this->distances[next_node]) {
            this->prev_nodes[next_node] = target_node;
            this->tasks.push(std::make_pair(new_distance, next_node));
          }
        }
      }
      return this->distances;
    }
  };
}

#endif

// main.cpp

int main() {
  std::int_fast64_t h, w;
  std::cin >> h >> w;
  std::vector<std::string> s;
  s.reserve(h);
  std::copy_n(std::istream_iterator<std::string>(std::cin), h, std::back_inserter(s));

  std::int_fast64_t white = 0;
  tools::dijkstra<std::int_fast64_t> dijkstra(h * w);
  for (std::int_fast64_t i = 0; i < h; ++i) {
    for (std::int_fast64_t j = 0; j < w; ++j) {
      if (s[i][j] == '.') {
        if (j > 0 && s[i][j - 1] == '.') dijkstra.add_edge(i * w + j, i * w + (j - 1), 1);
        if (j < w - 1 && s[i][j + 1] == '.') dijkstra.add_edge(i * w + j, i * w + (j + 1), 1);
        if (i > 0 && s[i - 1][j] == '.') dijkstra.add_edge(i * w + j, (i - 1) * w + j, 1);
        if (i < h - 1 && s[i + 1][j] == '.') dijkstra.add_edge(i * w + j, (i + 1) * w + j, 1);
        ++white;
      }
    }
  }

  const std::int_fast64_t min_distance = dijkstra.calc(0)[h * w - 1];
  std::cout << (min_distance < std::numeric_limits<std::int_fast64_t>::max() ? white - (min_distance + 1) : -1) << std::endl;
  return 0;
}

Measured memory_bytes: 896