using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class MainClass
{
	public const long Giri = 1000000007;
	private static long mincost = 9999999999;
	public struct Pos
	{
		public int X {get;set;}
		public int Y {get;set;}
		public int Cost {get;set;}
		public Pos(int x, int y):this() {X=x; Y=y;}
	}
	public static void Main(string[] args)
	{
		var p = Input().ToInt();
		var h = p[0];
		var w = p[1];
		var goal = new Pos(w-1, h-1);
		var grid = new int[h, w];
		long spaceCount = 0;
		for(int i = 0; i < h; i++)
		{
			var str = Console.ReadLine();
			for(int j = 0; j < w; j++)
			{
				grid[i, j] = -1;
				if(str[j] == '#')
					grid[i, j] = -2;
				else
					spaceCount++;
			}
		}

		var poses = new Queue<Pos>();
		poses.Enqueue(new Pos(0,0));
		for( ;poses.Count > 0; )
		{
			var pos = poses.Dequeue();
			if(pos.X < 0 || pos.Y < 0 || pos.X >= w || pos.Y >= h)
				continue;
			if(grid[pos.Y, pos.X] == -2 || (grid[pos.Y, pos.X] != -1 && grid[pos.Y, pos.X] <= pos.Cost))
				continue;
			
			grid[pos.Y, pos.X] = pos.Cost;
			poses.Enqueue(new Pos(pos.X + 1, pos.Y + 0){Cost = pos.Cost + 1});
			poses.Enqueue(new Pos(pos.X - 1, pos.Y + 0){Cost = pos.Cost + 1});
			poses.Enqueue(new Pos(pos.X + 0, pos.Y + 1){Cost = pos.Cost + 1});
			poses.Enqueue(new Pos(pos.X + 0, pos.Y - 1){Cost = pos.Cost + 1});
		}
		
		if(grid[goal.Y, goal.X] < 0)
		{
			Console.WriteLine(-1);
			return;
		}
		var goalCost = grid[goal.Y, goal.X];
		/*
		
		var curPos = goal;
		
		const Pos[] dir = new Pos[]{ new Pos(1,0),new Pos(-1,0),new Pos(0,1),new Pos(0,-1) };
		for( ; cur;)
		{
			for(int i = 0; i < dir.Length; i++)
			{
				if(Contains(pos.X + dir[i].X, pos.Y + dir[i].Y, w, h))
				{
					if(grid[pos.Y + dir[i].Y, pos.X + dir[i].X] + 1 == goalCost)
					{
						curPos = new Pos(pos.X + dir[i].X, pos.Y + dir[i].Y);
						break;
					}
				}
			}
		}
		*/
		Console.WriteLine(spaceCount - 1 - goalCost);
	}
	
	private static bool Contains(int x, int y, int w, int h)
	{
		return x < 0 || y < 0 || x >= w || y >= h;
	}
	
	public static void Route(Pos pos, int[,] grid, Pos start, Pos goal, int cost)
	{
		if(pos.X < 0 || pos.Y < 0 || pos.Y >= grid.GetLength(0) || pos.X >= grid.GetLength(1))
			return;
		
		if(grid[pos.Y, pos.X] == -2)
			return;
		
		if(grid[pos.Y, pos.X] != -1 && grid[pos.Y, pos.X] <= cost)
			return;
		//Console.WriteLine((pos.X+1) + ","+ (pos.Y+1) + "[cost:" + cost + "]:alt:"+grid[pos.Y, pos.X] );
			
		grid[pos.Y, pos.X] =  cost;
		
		if(pos.X == goal.X && pos.Y == goal.Y)
		{
			mincost = Math.Min(mincost, cost);
		}
		
		Route(new Pos(pos.X + 1, pos.Y + 0), grid, start, goal, cost + 1);
		Route(new Pos(pos.X - 1, pos.Y + 0), grid, start, goal, cost + 1);
		Route(new Pos(pos.X + 0, pos.Y + 1), grid, start, goal, cost + 1);
		Route(new Pos(pos.X + 0, pos.Y - 1), grid, start, goal, cost + 1);
	}
	

	

	static long GCD(long a, long b)
	{
		var v = new[] { a, b };
		while (v[1] != 0) { v = new[] { v[1], v[0] % v[1] }; }
		return v[0];
	}
	public static string[] Input() { return Console.ReadLine().Split(' '); }
	public static int Clamp(int val, int max, int min = 0) { return Math.Min(max, Math.Max(min, val)); }
}

public static class Smarter
{
	public static int ToInt(this string str) { return int.Parse(str); }
	public static long ToLong(this string str) { return long.Parse(str); }
	public static int[] ToInt(this string[] str)
	{
		var r = new int[str.Length];
		for(int i = 0; i < str.Length; i++) r[i] = str[i].ToInt();
		return r;
	 }
}



Measured memory_bytes: 13268