فهرست منبع

2009-11-24 Marek Safar <[email protected]>

	* StreamReader.cs, FileStream.cs: Use recycle buffer to avoid
	repeated underlying buffer initialization (saves hefty 10MB
	during corlib compilation).
	
	* Path.cs (InsecureGetFullPath): Avoid CanonicalizePath in common
	path.


svn path=/trunk/mcs/; revision=146841
Marek Safar 16 سال پیش
والد
کامیت
6bec77af06

+ 13 - 0
mcs/class/corlib/System.IO/ChangeLog

@@ -1,3 +1,12 @@
+2009-11-24  Marek Safar <[email protected]>
+
+	* StreamReader.cs, FileStream.cs: Use recycle buffer to avoid
+	repeated underlying buffer initialization (saves hefty 10MB
+	during corlib compilation).
+	
+	* Path.cs (InsecureGetFullPath): Avoid CanonicalizePath in common
+	path.
+
 2009-11-23  Miguel de Icaza  <[email protected]>
 
 	* DirectoryInfo.cs: Added the new overloads.
@@ -18,6 +27,10 @@
 
 	* UnmanagedMemoryAccessor.cs: Finished.
 
+2009-11-13  Marek Safar <[email protected]>
+
+	* UnmanagedMemoryAccessor.cs: Finished.
+
 2009-11-08  Miguel de Icaza  <[email protected]>
 
 	* FileInfo.cs: Partially implement.

+ 45 - 21
mcs/class/corlib/System.IO/FileStream.cs

@@ -5,6 +5,7 @@
 // 	Dietmar Maurer ([email protected])
 // 	Dan Lewis ([email protected])
 //	Gonzalo Paniagua Javier ([email protected])
+//  Marek Safar ([email protected])
 //
 // (C) 2001-2003 Ximian, Inc.  http://www.ximian.com
 // Copyright (C) 2004-2005, 2008 Novell, Inc (http://www.novell.com)
@@ -69,7 +70,7 @@ namespace System.IO
 			: this (handle, access, ownsHandle, bufferSize, isAsync, false) {}
 
 		[SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
-		internal FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync, bool noBuffering)
+		internal FileStream (IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync, bool isZeroSize)
 		{
 			this.handle = MonoIO.InvalidHandle;
 			if (handle == this.handle)
@@ -104,8 +105,10 @@ namespace System.IO
 #else
 			this.anonymous = false;
 #endif
+			if (isZeroSize)
+				bufferSize = 1;
 
-			InitBuffer (bufferSize, noBuffering);
+			InitBuffer (bufferSize);
 
 			if (canseek) {
 				buf_start = MonoIO.Seek (handle, 0, SeekOrigin.Current, out error);
@@ -326,7 +329,7 @@ namespace System.IO
 				}
 			}
 
-			InitBuffer (bufferSize, false);
+			InitBuffer (bufferSize);
 
 			if (mode==FileMode.Append) {
 				this.Seek (0, SeekOrigin.End);
@@ -918,11 +921,19 @@ namespace System.IO
 
 			canseek = false;
 			access = 0;
-			if (disposing) {
+			
+			if (disposing && buf != null) {
+				if (buf.Length == DefaultBufferSize && buf_recycle == null) {
+					lock (buf_recycle_lock) {
+						if (buf_recycle == null) {
+							buf_recycle = buf;
+						}
+					}
+				}
+				
 				buf = null;
-			}
-			if (disposing)
 				GC.SuppressFinalize (this);
+			}
 		}
 
 #if !NET_2_1
@@ -1061,26 +1072,35 @@ namespace System.IO
 			return(amount);
 		}
 				
-		private void InitBuffer (int size, bool noBuffering)
+		void InitBuffer (int size)
 		{
-			if (noBuffering) {
-				size = 0;
-				// We need a buffer for the ReadByte method. This buffer won't
-				// be used for anything else since buf_size==0.
-				buf = new byte [1];
+			if (size <= 0)
+				throw new ArgumentOutOfRangeException ("bufferSize", "Positive number required.");
+			
+			size = Math.Max (size, 8);
+			
+			//
+			// Instead of allocating a new default buffer use the
+			// last one if there is any available
+			//		
+			if (size <= DefaultBufferSize && buf_recycle != null) {
+				lock (buf_recycle_lock) {
+					if (buf_recycle != null) {
+						buf = buf_recycle;
+						buf_recycle = null;
+					}
+				}
 			}
-			else {
-				if (size <= 0)
-					throw new ArgumentOutOfRangeException ("bufferSize", "Positive number required.");
-				if (size < 8)
-					size = 8;
+			
+			if (buf == null)
 				buf = new byte [size];
-			}
+			else
+				Array.Clear (buf, 0, size);
 					
 			buf_size = size;
-			buf_start = 0;
-			buf_offset = buf_length = 0;
-			buf_dirty = false;
+//			buf_start = 0;
+//			buf_offset = buf_length = 0;
+//			buf_dirty = false;
 		}
 
 		private string GetSecureFileName (string filename)
@@ -1098,6 +1118,10 @@ namespace System.IO
 
 		internal const int DefaultBufferSize = 8192;
 
+		// Input buffer ready for recycling				
+		static byte[] buf_recycle;
+		static readonly object buf_recycle_lock = new object ();
+
 		private FileAccess access;
 		private bool owner;
 		private bool async;

+ 15 - 4
mcs/class/corlib/System.IO/Path.cs

@@ -331,6 +331,7 @@ namespace System.IO {
 			// if the supplied path ends with a separator...
 			char end = path [path.Length - 1];
 
+			var canonicalize = true;
 			if (path.Length >= 2 &&
 				IsDsc (path [0]) &&
 				IsDsc (path [1])) {
@@ -340,11 +341,19 @@ namespace System.IO {
 				if (path [0] != DirectorySeparatorChar)
 					path = path.Replace (AltDirectorySeparatorChar, DirectorySeparatorChar);
 
-				path = CanonicalizePath (path);
 			} else {
-				if (!IsPathRooted (path))
+				if (!IsPathRooted (path)) {
+					
+					// avoid calling expensive CanonicalizePath when possible
+					var start = 0;
+					while ((start = path.IndexOf ('.', start)) != -1) {
+						if (++start == path.Length || path [start] == DirectorySeparatorChar || path [start] == AltDirectorySeparatorChar)
+							break;
+					}
+					canonicalize = start > 0;
+					
 					path = Directory.GetCurrentDirectory () + DirectorySeparatorStr + path;
-				else if (DirectorySeparatorChar == '\\' &&
+				} else if (DirectorySeparatorChar == '\\' &&
 					path.Length >= 2 &&
 					IsDsc (path [0]) &&
 					!IsDsc (path [1])) { // like `\abc\def'
@@ -354,8 +363,10 @@ namespace System.IO {
 					else
 						path = current.Substring (0, current.IndexOf ('\\', current.IndexOf ("\\\\") + 1));
 				}
-				path = CanonicalizePath (path);
 			}
+			
+			if (canonicalize)
+			    path = CanonicalizePath (path);
 
 			// if the original ended with a [Alt]DirectorySeparatorChar then ensure the full path also ends with one
 			if (IsDsc (end) && (path [path.Length - 1] != DirectorySeparatorChar))

+ 53 - 7
mcs/class/corlib/System.IO/StreamReader.cs

@@ -4,6 +4,7 @@
 // Author:
 //   Dietmar Maurer ([email protected])
 //   Miguel de Icaza ([email protected]) 
+//   Marek Safar ([email protected])
 //
 // (C) Ximian, Inc.  http://www.ximian.com
 // Copyright (C) 2004 Novell (http://www.novell.com)
@@ -49,11 +50,16 @@ namespace System.IO {
 		// The input buffer
 		//
 		byte [] input_buffer;
+		
+		// Input buffer ready for recycling
+		static byte [] input_buffer_recycle;
+		static object input_buffer_recycle_lock = new object ();
 
 		//
 		// The decoded buffer from the above input buffer
 		//
 		char [] decoded_buffer;
+		static char[] decoded_buffer_recycle;
 
 		//
 		// Decoded bytes in decoded_buffer.
@@ -116,7 +122,7 @@ namespace System.IO {
 			}
 		}
 
-		public new static readonly StreamReader Null =  (StreamReader)(new NullStreamReader());
+		public new static readonly StreamReader Null =  new NullStreamReader ();
 		
 		internal StreamReader() {}
 
@@ -179,9 +185,41 @@ namespace System.IO {
 
 			if (bufferSize < MinimumBufferSize)
 				bufferSize = MinimumBufferSize;
+			
+			// since GetChars() might add flushed character, it 
+			// should have additional char buffer for extra 1 
+			// (probably 1 is ok, but might be insufficient. I'm not sure)
+			var decoded_buffer_size = encoding.GetMaxCharCount (bufferSize) + 1;
+
+			//
+			// Instead of allocating a new default buffer use the
+			// last one if there is any available
+			//
+			if (bufferSize <= DefaultBufferSize && input_buffer_recycle != null) {
+				lock (input_buffer_recycle_lock) {
+					if (input_buffer_recycle != null) {
+						input_buffer = input_buffer_recycle;
+						input_buffer_recycle = null;
+					}
+					
+					if (decoded_buffer_recycle != null && decoded_buffer_size <= decoded_buffer_recycle.Length) {
+						decoded_buffer = decoded_buffer_recycle;
+						decoded_buffer_recycle = null;
+					}
+				}
+			}
+			
+			if (input_buffer == null)
+				input_buffer = new byte [bufferSize];
+			else
+				Array.Clear (input_buffer, 0, bufferSize);
+			
+			if (decoded_buffer == null)
+				decoded_buffer = new char [decoded_buffer_size];
+			else
+				Array.Clear (decoded_buffer, 0, decoded_buffer_size);
 
-			base_stream = stream;
-			input_buffer = new byte [bufferSize];
+			base_stream = stream;		
 			this.buffer_size = bufferSize;
 			this.encoding = encoding;
 			decoder = encoding.GetDecoder ();
@@ -190,10 +228,6 @@ namespace System.IO {
 			do_checks = detectEncodingFromByteOrderMarks ? 1 : 0;
 			do_checks += (preamble.Length == 0) ? 0 : 2;
 			
-			// since GetChars() might add flushed character, it 
-			// should have additional char buffer for extra 1 
-			// (probably 1 is ok, but might be insufficient. I'm not sure)
-			decoded_buffer = new char [encoding.GetMaxCharCount (bufferSize) + 1];
 			decoded_count = 0;
 			pos = 0;
 		}
@@ -228,6 +262,18 @@ namespace System.IO {
 			if (disposing && base_stream != null)
 				base_stream.Close ();
 			
+			if (input_buffer != null && input_buffer.Length == DefaultBufferSize && input_buffer_recycle == null) {
+				lock (input_buffer_recycle_lock) {
+					if (input_buffer_recycle == null) {
+						input_buffer_recycle = input_buffer;
+					}
+					
+					if (decoded_buffer_recycle == null) {
+						decoded_buffer_recycle = decoded_buffer;
+					}
+				}
+			}
+			
 			input_buffer = null;
 			decoded_buffer = null;
 			encoding = null;