Index: contrib/snowball/src/java/org/apache/lucene/analysis/snowball/SnowballFilter.java
===================================================================
--- contrib/snowball/src/java/org/apache/lucene/analysis/snowball/SnowballFilter.java	(revision 897452)
+++ contrib/snowball/src/java/org/apache/lucene/analysis/snowball/SnowballFilter.java	(working copy)
@@ -76,14 +76,14 @@
     if (input.incrementToken()) {
       char termBuffer[] = termAtt.termBuffer();
       final int length = termAtt.termLength();
-      stemmer.setCurrent(termBuffer, 0, length);
+      stemmer.setCurrent(termBuffer, length);
       stemmer.stem();
-      final StringBuilder finalTerm = stemmer.getCurrentBuffer();
-      final int newLength = finalTerm.length();
-      if (newLength > termBuffer.length)
-        termBuffer = termAtt.resizeTermBuffer(newLength);
-      finalTerm.getChars(0, newLength, termBuffer, 0);
-      termAtt.setTermLength(newLength);
+      final char finalTerm[] = stemmer.getCurrentBuffer();
+      final int newLength = stemmer.getCurrentBufferLength();
+      if (finalTerm != termBuffer)
+        termAtt.setTermBuffer(finalTerm, 0, newLength);
+      else
+        termAtt.setTermLength(newLength); 
       return true;
     } else {
       return false;
Index: contrib/snowball/src/java/org/tartarus/snowball/Among.java
===================================================================
--- contrib/snowball/src/java/org/tartarus/snowball/Among.java	(revision 897452)
+++ contrib/snowball/src/java/org/tartarus/snowball/Among.java	(working copy)
@@ -37,7 +37,7 @@
     public Among (String s, int substring_i, int result,
 		  String methodname, SnowballProgram methodobject) {
         this.s_size = s.length();
-        this.s = s;
+        this.s = s.toCharArray();
         this.substring_i = substring_i;
 	this.result = result;
 	this.methodobject = methodobject;
@@ -55,7 +55,7 @@
     }
 
     public int s_size; /* search string */
-    public String s; /* search string */
+    public char s[]; /* search string */
     public int substring_i; /* index to longest matching substring */
     public int result;      /* result of the lookup */
     public Method method; /* method to use if substring matches */
Index: contrib/snowball/src/java/org/tartarus/snowball/SnowballProgram.java
===================================================================
--- contrib/snowball/src/java/org/tartarus/snowball/SnowballProgram.java	(revision 897453)
+++ contrib/snowball/src/java/org/tartarus/snowball/SnowballProgram.java	(working copy)
@@ -34,6 +34,8 @@
 
 import java.lang.reflect.InvocationTargetException;
 
+import org.apache.lucene.util.ArrayUtil;
+
 /**
  * This is the rev 500 of the Snowball SVN trunk,
  * but modified:
@@ -43,7 +45,7 @@
 public abstract class SnowballProgram {
     protected SnowballProgram()
     {
-	current = new StringBuilder();
+	current = new char[8];
 	setCurrent("");
     }
 
@@ -54,9 +56,9 @@
      */
     public void setCurrent(String value)
     {
-	current.replace(0, current.length(), value);
+	current = value.toCharArray();
 	cursor = 0;
-	limit = current.length();
+	limit = value.length();
 	limit_backward = 0;
 	bra = cursor;
 	ket = limit;
@@ -67,25 +69,16 @@
      */
     public String getCurrent()
     {
-        String result = current.toString();
-        // Make a new StringBuffer.  If we reuse the old one, and a user of
-        // the library keeps a reference to the buffer returned (for example,
-        // by converting it to a String in a way which doesn't force a copy),
-        // the buffer size will not decrease, and we will risk wasting a large
-        // amount of memory.
-        // Thanks to Wolfram Esser for spotting this problem.
-        current = new StringBuilder();
-        return result;
+      return new String(current, 0, limit);
     }
     
     /**
      * Set the current string.
      */
-    public void setCurrent(char text[], int offset, int length) {
-      current.setLength(0);
-      current.append(text, offset, length);
+    public void setCurrent(char text[], int length) {
+      current = text;
       cursor = 0;
-      limit = current.length();
+      limit = length;
       limit_backward = 0;
       bra = cursor;
       ket = limit;
@@ -94,12 +87,16 @@
     /**
      * Get the current buffer containing the stem
      */
-    public StringBuilder getCurrentBuffer() {
+    public char[] getCurrentBuffer() {
       return current;
     }
+    
+    public int getCurrentBufferLength() {
+      return limit;
+    }
 
     // current string
-    protected StringBuilder current;
+    private char current[];
 
     protected int cursor;
     protected int limit;
@@ -120,7 +117,7 @@
     protected boolean in_grouping(char [] s, int min, int max)
     {
 	if (cursor >= limit) return false;
-	char ch = current.charAt(cursor);
+	char ch = current[cursor];
 	if (ch > max || ch < min) return false;
 	ch -= min;
 	if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return false;
@@ -131,7 +128,7 @@
     protected boolean in_grouping_b(char [] s, int min, int max)
     {
 	if (cursor <= limit_backward) return false;
-	char ch = current.charAt(cursor - 1);
+	char ch = current[cursor - 1];
 	if (ch > max || ch < min) return false;
 	ch -= min;
 	if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return false;
@@ -142,7 +139,7 @@
     protected boolean out_grouping(char [] s, int min, int max)
     {
 	if (cursor >= limit) return false;
-	char ch = current.charAt(cursor);
+	char ch = current[cursor];
 	if (ch > max || ch < min) {
 	    cursor++;
 	    return true;
@@ -158,7 +155,7 @@
     protected boolean out_grouping_b(char [] s, int min, int max)
     {
 	if (cursor <= limit_backward) return false;
-	char ch = current.charAt(cursor - 1);
+	char ch = current[cursor - 1];
 	if (ch > max || ch < min) {
 	    cursor--;
 	    return true;
@@ -174,7 +171,7 @@
     protected boolean in_range(int min, int max)
     {
 	if (cursor >= limit) return false;
-	char ch = current.charAt(cursor);
+	char ch = current[cursor];
 	if (ch > max || ch < min) return false;
 	cursor++;
 	return true;
@@ -183,7 +180,7 @@
     protected boolean in_range_b(int min, int max)
     {
 	if (cursor <= limit_backward) return false;
-	char ch = current.charAt(cursor - 1);
+	char ch = current[cursor - 1];
 	if (ch > max || ch < min) return false;
 	cursor--;
 	return true;
@@ -192,7 +189,7 @@
     protected boolean out_range(int min, int max)
     {
 	if (cursor >= limit) return false;
-	char ch = current.charAt(cursor);
+	char ch = current[cursor];
 	if (!(ch > max || ch < min)) return false;
 	cursor++;
 	return true;
@@ -201,41 +198,41 @@
     protected boolean out_range_b(int min, int max)
     {
 	if (cursor <= limit_backward) return false;
-	char ch = current.charAt(cursor - 1);
+	char ch = current[cursor - 1];
 	if(!(ch > max || ch < min)) return false;
 	cursor--;
 	return true;
     }
 
-    protected boolean eq_s(int s_size, String s)
+    protected boolean eq_s(int s_size, CharSequence s)
     {
 	if (limit - cursor < s_size) return false;
 	int i;
 	for (i = 0; i != s_size; i++) {
-	    if (current.charAt(cursor + i) != s.charAt(i)) return false;
+	    if (current[cursor + i] != s.charAt(i)) return false;
 	}
 	cursor += s_size;
 	return true;
     }
 
-    protected boolean eq_s_b(int s_size, String s)
+    protected boolean eq_s_b(int s_size, CharSequence s)
     {
 	if (cursor - limit_backward < s_size) return false;
 	int i;
 	for (i = 0; i != s_size; i++) {
-	    if (current.charAt(cursor - s_size + i) != s.charAt(i)) return false;
+	    if (current[cursor - s_size + i] != s.charAt(i)) return false;
 	}
 	cursor -= s_size;
 	return true;
     }
 
-    protected boolean eq_v(StringBuilder s)
+    protected boolean eq_v(CharSequence s)
     {
-	return eq_s(s.length(), s.toString());
+	return eq_s(s.length(), s);
     }
 
-    protected boolean eq_v_b(StringBuilder s)
-    {   return eq_s_b(s.length(), s.toString());
+    protected boolean eq_v_b(CharSequence s)
+    {   return eq_s_b(s.length(), s);
     }
 
     protected int find_among(Among v[], int v_size)
@@ -262,7 +259,7 @@
 		    diff = -1;
 		    break;
 		}
-		diff = current.charAt(c + common) - w.s.charAt(i2);
+		diff = current[c + common] - w.s[i2];
 		if (diff != 0) break;
 		common++;
 	    }
@@ -335,7 +332,7 @@
 		    diff = -1;
 		    break;
 		}
-		diff = current.charAt(c - 1 - common) - w.s.charAt(i2);
+		diff = current[c - 1 - common] - w.s[i2];
 		if (diff != 0) break;
 		common++;
 	    }
@@ -382,10 +379,28 @@
     /* to replace chars between c_bra and c_ket in current by the
      * chars in s.
      */
-    protected int replace_s(int c_bra, int c_ket, String s)
+    protected int replace_s(int c_bra, int c_ket, CharSequence s)
     {
-	int adjustment = s.length() - (c_ket - c_bra);
-	current.replace(c_bra, c_ket, s);
+	final int adjustment = s.length() - (c_ket - c_bra);
+	final int newLength = limit + adjustment;
+	//resize if necessary
+	if (newLength > current.length) {
+	  char newBuffer[] = new char[ArrayUtil.getNextSize(newLength)];
+	  System.arraycopy(current, 0, newBuffer, 0, limit);
+	  current = newBuffer;
+	}
+	// if the substring being replaced is longer or shorter than the
+	// replacement, need to shift things around
+	if (adjustment != 0 && c_ket < limit) {
+	  System.arraycopy(current, c_ket, current, c_bra + s.length(), 
+	      limit - c_ket);
+	}
+	// insert the replacement text
+	// Note, faster is s.getChars(0, s.length(), current, c_bra);
+	// but would have to duplicate this method for both String and StringBuilder
+	for (int i = 0; i < s.length(); i++)
+	  current[c_bra + i] = s.charAt(i);
+	
 	limit += adjustment;
 	if (cursor >= c_ket) cursor += adjustment;
 	else if (cursor > c_bra) cursor = c_bra;
@@ -396,8 +411,7 @@
     {
 	if (bra < 0 ||
 	    bra > ket ||
-	    ket > limit ||
-	    limit > current.length())   // this line could be removed
+	    ket > limit)
 	{
 	    System.err.println("faulty slice operation");
 	// FIXME: report error somehow.
@@ -417,7 +431,8 @@
 
     protected void slice_from(StringBuilder s)
     {
-        slice_from(s.toString());
+	slice_check();
+	replace_s(bra, ket, s);
     }
 
     protected void slice_del()
@@ -434,7 +449,9 @@
 
     protected void insert(int c_bra, int c_ket, StringBuilder s)
     {
-	insert(c_bra, c_ket, s.toString());
+	int adjustment = replace_s(c_bra, c_ket, s);
+	if (c_bra <= bra) bra += adjustment;
+	if (c_bra <= ket) ket += adjustment;
     }
 
     /* Copy the slice into the supplied StringBuffer */
@@ -442,13 +459,15 @@
     {
 	slice_check();
 	int len = ket - bra;
-	s.replace(0, s.length(), current.substring(bra, ket));
+	s.setLength(0);
+	s.append(current, bra, len);
 	return s;
     }
 
     protected StringBuilder assign_to(StringBuilder s)
     {
-	s.replace(0, s.length(), current.substring(0, limit));
+	s.setLength(0);
+	s.append(current, 0, limit);
 	return s;
     }
 
