Index: src/org/armedbear/lisp/CharHashMap.java
===================================================================
--- src/org/armedbear/lisp/CharHashMap.java	(revision 0)
+++ src/org/armedbear/lisp/CharHashMap.java	(revision 0)
@@ -0,0 +1,72 @@
+package org.armedbear.lisp;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class CharHashMap<T> {
+
+	final public T[] constants;
+	final public T NULL;
+	final static int CACHE_SIZE = 256; 
+	final HashMap<Character, T> backing;
+	public CharHashMap(Class componentType, T def) {
+		NULL = def;
+		constants = (T[]) Array.newInstance(componentType, CACHE_SIZE);
+		Arrays.fill(constants, NULL);
+		backing = new HashMap<Character, T>();
+	}
+	
+	@Override
+	public Object clone() {
+		CharHashMap<T> n = new CharHashMap<T>(constants.getClass().getComponentType(),NULL);
+		System.arraycopy(constants,0, n.constants,0,CACHE_SIZE);
+		n.backing.putAll(backing);
+		return n;
+	}
+	
+	public T get(char key) {
+		if (key<CACHE_SIZE) return constants[key];
+		T value = backing.get(key);
+		return (value==null) ? NULL:value;
+	}
+
+	public void clear() {
+		Arrays.fill(constants,NULL);
+		backing.clear();
+	}
+
+	public T put(char key, T value) {
+		if (key<CACHE_SIZE) {
+			T old = constants[key];
+			constants[key] = value;
+			return old;
+		}
+		else return backing.put(key, value);
+	}
+
+	public Iterator<Character> getCharIterator() {
+		return new Iterator<Character>() {			
+			final Iterator<Character> carIt =  backing.keySet().iterator();
+			int charNum = -1;
+			public boolean hasNext() {
+				if ( charNum<CACHE_SIZE) return true;
+				return carIt.hasNext();
+			}
+			public Character next() {
+				if ( charNum<CACHE_SIZE) return (char)++charNum;
+				return carIt.next();
+			}
+			public void remove() {
+				throw new UnsupportedOperationException();			
+			}
+			
+		};
+	}
+}
Index: src/org/armedbear/lisp/FaslReadtable.java
===================================================================
--- src/org/armedbear/lisp/FaslReadtable.java	(revision 12173)
+++ src/org/armedbear/lisp/FaslReadtable.java	(working copy)
@@ -43,6 +43,7 @@
     @Override
     protected void initialize()
     {
+    	Byte[] syntax = this.syntax.constants;
         syntax[9]    = SYNTAX_TYPE_WHITESPACE; // tab
         syntax[10]   = SYNTAX_TYPE_WHITESPACE; // linefeed
         syntax[12]   = SYNTAX_TYPE_WHITESPACE; // form feed
@@ -62,6 +63,7 @@
         syntax['\\'] = SYNTAX_TYPE_SINGLE_ESCAPE;
         syntax['|']  = SYNTAX_TYPE_MULTIPLE_ESCAPE;
 
+        LispObject[] readerMacroFunctions = this.readerMacroFunctions.constants;
         readerMacroFunctions[';']  = FaslReader.FASL_READ_COMMENT;
         readerMacroFunctions['"']  = FaslReader.FASL_READ_STRING;
         readerMacroFunctions['(']  = FaslReader.FASL_READ_LIST;
@@ -74,30 +76,31 @@
         readerMacroFunctions[',']  = Symbol.COMMA_MACRO;
 
         DispatchTable dt = new DispatchTable();
-        dt.functions['(']  = FaslReader.FASL_SHARP_LEFT_PAREN;
-        dt.functions['*']  = FaslReader.FASL_SHARP_STAR;
-        dt.functions['.']  = FaslReader.FASL_SHARP_DOT;
-        dt.functions[':']  = FaslReader.FASL_SHARP_COLON;
-        dt.functions['A']  = FaslReader.FASL_SHARP_A;
-        dt.functions['B']  = FaslReader.FASL_SHARP_B;
-        dt.functions['C']  = FaslReader.FASL_SHARP_C;
-        dt.functions['O']  = FaslReader.FASL_SHARP_O;
-        dt.functions['P']  = FaslReader.FASL_SHARP_P;
-        dt.functions['R']  = FaslReader.FASL_SHARP_R;
-        dt.functions['S']  = FaslReader.FASL_SHARP_S;
-        dt.functions['X']  = FaslReader.FASL_SHARP_X;
-        dt.functions['\''] = FaslReader.FASL_SHARP_QUOTE;
-        dt.functions['\\'] = FaslReader.FASL_SHARP_BACKSLASH;
-        dt.functions['|']  = FaslReader.FASL_SHARP_VERTICAL_BAR;
-        dt.functions[')']  = FaslReader.FASL_SHARP_ILLEGAL;
-        dt.functions['<']  = FaslReader.FASL_SHARP_ILLEGAL;
-        dt.functions[' ']  = FaslReader.FASL_SHARP_ILLEGAL;
-        dt.functions[8]    = FaslReader.FASL_SHARP_ILLEGAL; // backspace
-        dt.functions[9]    = FaslReader.FASL_SHARP_ILLEGAL; // tab
-        dt.functions[10]   = FaslReader.FASL_SHARP_ILLEGAL; // newline, linefeed
-        dt.functions[12]   = FaslReader.FASL_SHARP_ILLEGAL; // page
-        dt.functions[13]   = FaslReader.FASL_SHARP_ILLEGAL; // return
-        dispatchTables['#'] = dt;
+        LispObject[] dtfunctions = dt.functions.constants;
+        dtfunctions['(']  = FaslReader.FASL_SHARP_LEFT_PAREN;
+        dtfunctions['*']  = FaslReader.FASL_SHARP_STAR;
+        dtfunctions['.']  = FaslReader.FASL_SHARP_DOT;
+        dtfunctions[':']  = FaslReader.FASL_SHARP_COLON;
+        dtfunctions['A']  = FaslReader.FASL_SHARP_A;
+        dtfunctions['B']  = FaslReader.FASL_SHARP_B;
+        dtfunctions['C']  = FaslReader.FASL_SHARP_C;
+        dtfunctions['O']  = FaslReader.FASL_SHARP_O;
+        dtfunctions['P']  = FaslReader.FASL_SHARP_P;
+        dtfunctions['R']  = FaslReader.FASL_SHARP_R;
+        dtfunctions['S']  = FaslReader.FASL_SHARP_S;
+        dtfunctions['X']  = FaslReader.FASL_SHARP_X;
+        dtfunctions['\''] = FaslReader.FASL_SHARP_QUOTE;
+        dtfunctions['\\'] = FaslReader.FASL_SHARP_BACKSLASH;
+        dtfunctions['|']  = FaslReader.FASL_SHARP_VERTICAL_BAR;
+        dtfunctions[')']  = FaslReader.FASL_SHARP_ILLEGAL;
+        dtfunctions['<']  = FaslReader.FASL_SHARP_ILLEGAL;
+        dtfunctions[' ']  = FaslReader.FASL_SHARP_ILLEGAL;
+        dtfunctions[8]    = FaslReader.FASL_SHARP_ILLEGAL; // backspace
+        dtfunctions[9]    = FaslReader.FASL_SHARP_ILLEGAL; // tab
+        dtfunctions[10]   = FaslReader.FASL_SHARP_ILLEGAL; // newline, linefeed
+        dtfunctions[12]   = FaslReader.FASL_SHARP_ILLEGAL; // page
+        dtfunctions[13]   = FaslReader.FASL_SHARP_ILLEGAL; // return
+        dispatchTables.constants['#'] = dt;
 
         readtableCase = Keyword.UPCASE;
     }
Index: src/org/armedbear/lisp/LispCharacter.java
===================================================================
--- src/org/armedbear/lisp/LispCharacter.java	(revision 12173)
+++ src/org/armedbear/lisp/LispCharacter.java	(working copy)
@@ -37,10 +37,22 @@
 
 public final class LispCharacter extends LispObject
 {
-  public static final LispCharacter[] constants = new LispCharacter[CHAR_MAX];
+  public static final LispCharacter[] constants;
+  public static final CharHashMap<LispCharacter> lispChars;
 
   static
   {
+    lispChars = new CharHashMap<LispCharacter>(LispCharacter.class,null){
+      public LispCharacter get(char c) {
+        LispCharacter lc = super.get(c);
+        if (lc==null) {
+          lc = new LispCharacter(c);
+          put(c, lc);
+        }
+        return lc;
+      }
+    };
+    constants = lispChars.constants;
     for (int i = constants.length; i-- > 0;)
       constants[i] = new LispCharacter((char)i);
   }
@@ -51,7 +63,7 @@
   {
     try
       {
-        return constants[c];
+        return lispChars.get(c);
       }
     catch (ArrayIndexOutOfBoundsException e)
       {
@@ -341,7 +353,7 @@
       {
           int n = Fixnum.getValue(arg);
           if (n < CHAR_MAX)
-            return constants[n];
+            return lispChars.get((char)n);
           else if (n <= Character.MAX_VALUE)
             return new LispCharacter((char)n);
               // SBCL signals a type-error here: "not of type (UNSIGNED-BYTE 8)"
@@ -613,7 +625,7 @@
         return "Rubout";
       }
     if (c<0 || c>255) return null;
-    return constants[c].name;
+    return lispChars.get(c).name;
   }
 
   // ### char-name
@@ -651,8 +663,7 @@
   } 
   
   static void setCharName(int settingChar, String string) { 
-    if (settingChar>=CHAR_MAX) return; 
-    LispCharacter c = constants[settingChar]; 
+    LispCharacter c = lispChars.get((char)settingChar); 
     c.name = string; 
     namedToChar.put(string.toLowerCase(), c); 
   } 
Index: src/org/armedbear/lisp/Readtable.java
===================================================================
--- src/org/armedbear/lisp/Readtable.java	(revision 12173)
+++ src/org/armedbear/lisp/Readtable.java	(working copy)
@@ -32,6 +32,7 @@
  */
 
 package org.armedbear.lisp;
+import java.util.Iterator;
 
 public class Readtable extends LispObject
 {
@@ -42,9 +43,9 @@
   public static final byte SYNTAX_TYPE_SINGLE_ESCAPE         = 4;
   public static final byte SYNTAX_TYPE_MULTIPLE_ESCAPE       = 5;
 
-  protected final byte[]          syntax               = new byte[CHAR_MAX];
-  protected final LispObject[]    readerMacroFunctions = new LispObject[CHAR_MAX];
-  protected final DispatchTable[] dispatchTables       = new DispatchTable[CHAR_MAX];
+  protected final CharHashMap<Byte> syntax = new CharHashMap<Byte>(Byte.class,SYNTAX_TYPE_CONSTITUENT);
+  protected final CharHashMap<LispObject> readerMacroFunctions = new CharHashMap<LispObject>(LispObject.class,null);
+  protected final CharHashMap<DispatchTable> dispatchTables = new CharHashMap<DispatchTable>(DispatchTable.class,null);
 
   protected LispObject readtableCase;
 
@@ -55,6 +56,7 @@
 
   protected void initialize()
   {
+    Byte[] syntax = this.syntax.constants;
     syntax[9]    = SYNTAX_TYPE_WHITESPACE; // tab
     syntax[10]   = SYNTAX_TYPE_WHITESPACE; // linefeed
     syntax[12]   = SYNTAX_TYPE_WHITESPACE; // form feed
@@ -74,6 +76,7 @@
     syntax['\\'] = SYNTAX_TYPE_SINGLE_ESCAPE;
     syntax['|']  = SYNTAX_TYPE_MULTIPLE_ESCAPE;
 
+    LispObject[] readerMacroFunctions = this.readerMacroFunctions.constants;
     readerMacroFunctions[';']  = LispReader.READ_COMMENT;
     readerMacroFunctions['"']  = LispReader.READ_STRING;
     readerMacroFunctions['(']  = LispReader.READ_LIST;
@@ -86,33 +89,33 @@
     readerMacroFunctions[',']  = Symbol.COMMA_MACRO;
 
     DispatchTable dt = new DispatchTable();
+    LispObject[] dtfunctions = dt.functions.constants;
+    dtfunctions['(']  = LispReader.SHARP_LEFT_PAREN;
+    dtfunctions['*']  = LispReader.SHARP_STAR;
+    dtfunctions['.']  = LispReader.SHARP_DOT;
+    dtfunctions[':']  = LispReader.SHARP_COLON;
+    dtfunctions['A']  = LispReader.SHARP_A;
+    dtfunctions['B']  = LispReader.SHARP_B;
+    dtfunctions['C']  = LispReader.SHARP_C;
+    dtfunctions['O']  = LispReader.SHARP_O;
+    dtfunctions['P']  = LispReader.SHARP_P;
+    dtfunctions['R']  = LispReader.SHARP_R;
+    dtfunctions['S']  = LispReader.SHARP_S;
+    dtfunctions['X']  = LispReader.SHARP_X;
+    dtfunctions['\''] = LispReader.SHARP_QUOTE;
+    dtfunctions['\\'] = LispReader.SHARP_BACKSLASH;
+    dtfunctions['|']  = LispReader.SHARP_VERTICAL_BAR;
+    dtfunctions[')']  = LispReader.SHARP_ILLEGAL;
+    dtfunctions['<']  = LispReader.SHARP_ILLEGAL;
+    dtfunctions[' ']  = LispReader.SHARP_ILLEGAL;
+    dtfunctions[8]    = LispReader.SHARP_ILLEGAL; // backspace
+    dtfunctions[9]    = LispReader.SHARP_ILLEGAL; // tab
+    dtfunctions[10]   = LispReader.SHARP_ILLEGAL; // newline, linefeed
+    dtfunctions[12]   = LispReader.SHARP_ILLEGAL; // page
+    dtfunctions[13]   = LispReader.SHARP_ILLEGAL; // return
 
-    dt.functions['(']  = LispReader.SHARP_LEFT_PAREN;
-    dt.functions['*']  = LispReader.SHARP_STAR;
-    dt.functions['.']  = LispReader.SHARP_DOT;
-    dt.functions[':']  = LispReader.SHARP_COLON;
-    dt.functions['A']  = LispReader.SHARP_A;
-    dt.functions['B']  = LispReader.SHARP_B;
-    dt.functions['C']  = LispReader.SHARP_C;
-    dt.functions['O']  = LispReader.SHARP_O;
-    dt.functions['P']  = LispReader.SHARP_P;
-    dt.functions['R']  = LispReader.SHARP_R;
-    dt.functions['S']  = LispReader.SHARP_S;
-    dt.functions['X']  = LispReader.SHARP_X;
-    dt.functions['\''] = LispReader.SHARP_QUOTE;
-    dt.functions['\\'] = LispReader.SHARP_BACKSLASH;
-    dt.functions['|']  = LispReader.SHARP_VERTICAL_BAR;
-    dt.functions[')']  = LispReader.SHARP_ILLEGAL;
-    dt.functions['<']  = LispReader.SHARP_ILLEGAL;
-    dt.functions[' ']  = LispReader.SHARP_ILLEGAL;
-    dt.functions[8]    = LispReader.SHARP_ILLEGAL; // backspace
-    dt.functions[9]    = LispReader.SHARP_ILLEGAL; // tab
-    dt.functions[10]   = LispReader.SHARP_ILLEGAL; // newline, linefeed
-    dt.functions[12]   = LispReader.SHARP_ILLEGAL; // page
-    dt.functions[13]   = LispReader.SHARP_ILLEGAL; // return
+    dispatchTables.constants['#'] = dt;
 
-    dispatchTables['#'] = dt;
-
     readtableCase = Keyword.UPCASE;
   }
 
@@ -125,35 +128,44 @@
       rt = checkReadtable(obj);
     synchronized (rt)
       {
-        System.arraycopy(rt.syntax, 0, syntax, 0, CHAR_MAX);
-        System.arraycopy(rt.readerMacroFunctions, 0, readerMacroFunctions, 0,
-                         CHAR_MAX);
-        // Deep copy.
-        for (int i = dispatchTables.length; i-- > 0;)
-          {
-            DispatchTable dt = rt.dispatchTables[i];
-            if (dt != null)
-              dispatchTables[i] = new DispatchTable(dt);
-          }
-        readtableCase = rt.readtableCase;
+        copyReadtable(rt, this);
       }
   }
 
   // FIXME synchronization
   private static void copyReadtable(Readtable from, Readtable to)
   {
-    System.arraycopy(from.syntax, 0, to.syntax, 0, CHAR_MAX);
-    System.arraycopy(from.readerMacroFunctions, 0, to.readerMacroFunctions, 0,
-                     CHAR_MAX);
-    for (int i = from.dispatchTables.length; i-- > 0;)
-      {
-        DispatchTable dt = from.dispatchTables[i];
-        if (dt != null)
-          to.dispatchTables[i] = new DispatchTable(dt);
-        else
-          to.dispatchTables[i] = null;
+    Iterator<Character> charIterator = from.syntax.getCharIterator();
+      while (charIterator.hasNext()) {
+        char c = charIterator.next();
+          Byte dt = from.syntax.get(c);
+          if (dt!=null) {
+              to.syntax.put(c, dt);          
+          } else {
+              to.syntax.put(c, null);          
+          }      
+      }      
+      charIterator = from.readerMacroFunctions.getCharIterator();
+      while (charIterator.hasNext()) {
+        char c = charIterator.next();
+          LispObject dt = from.readerMacroFunctions.get(c);
+          if (dt!=null) {
+              to.readerMacroFunctions.put(c, dt);          
+          } else {
+              to.readerMacroFunctions.put(c, null);          
+          }      
       }
-    to.readtableCase = from.readtableCase;
+      charIterator = from.dispatchTables.getCharIterator();
+      while (charIterator.hasNext()) {
+        char c = charIterator.next();
+          DispatchTable dt = from.dispatchTables.get(c);
+          if (dt!=null) {
+              to.dispatchTables.put(c, new DispatchTable(dt));          
+          } else {
+              to.dispatchTables.put(c, null);          
+          }      
+      }
+      to.readtableCase = from.readtableCase;
   }
 
   @Override
@@ -191,16 +203,12 @@
 
   public boolean isWhitespace(char c)
   {
-    if (c < CHAR_MAX)
-      return syntax[c] == SYNTAX_TYPE_WHITESPACE;
-    return false;
+    return getSyntaxType(c) == SYNTAX_TYPE_WHITESPACE;
   }
 
   public byte getSyntaxType(char c)
   {
-    if (c < CHAR_MAX)
-      return syntax[c];
-    return SYNTAX_TYPE_CONSTITUENT;
+    return syntax.get(c);
   }
 
   public boolean isInvalid(char c)
@@ -239,10 +247,7 @@
 
   public LispObject getReaderMacroFunction(char c)
   {
-    if (c < CHAR_MAX)
-      return readerMacroFunctions[c];
-    else
-      return null;
+    return readerMacroFunctions.get(c);
   }
 
   private LispObject getMacroCharacter(char c) throws ConditionThrowable
@@ -251,7 +256,7 @@
     LispObject non_terminating_p;
     if (function != null)
       {
-        if (syntax[c] == SYNTAX_TYPE_NON_TERMINATING_MACRO)
+        if (syntax.get(c) == SYNTAX_TYPE_NON_TERMINATING_MACRO)
           non_terminating_p = T;
         else
           non_terminating_p = NIL;
@@ -272,15 +277,15 @@
     else
       syntaxType = SYNTAX_TYPE_TERMINATING_MACRO;
     // FIXME synchronization
-    syntax[dispChar] = syntaxType;
-    readerMacroFunctions[dispChar] = LispReader.READ_DISPATCH_CHAR;
-    dispatchTables[dispChar] = new DispatchTable();
+    syntax.put(dispChar,syntaxType);
+    readerMacroFunctions.put(dispChar, LispReader.READ_DISPATCH_CHAR);
+    dispatchTables.put(dispChar, new DispatchTable());
   }
 
   public LispObject getDispatchMacroCharacter(char dispChar, char subChar)
     throws ConditionThrowable
   {
-    DispatchTable dispatchTable = dispatchTables[dispChar];
+    DispatchTable dispatchTable = dispatchTables.get(dispChar);
     if (dispatchTable == null)
       {
         LispCharacter c = LispCharacter.getInstance(dispChar);
@@ -288,7 +293,7 @@
                                     " is not a dispatch character."));
       }
     LispObject function =
-      dispatchTable.functions[LispCharacter.toUpperCase(subChar)];
+      dispatchTable.functions.get(LispCharacter.toUpperCase(subChar));
     return (function != null) ? function : NIL;
   }
 
@@ -296,28 +301,28 @@
                                         LispObject function)
     throws ConditionThrowable
   {
-    DispatchTable dispatchTable = dispatchTables[dispChar];
+    DispatchTable dispatchTable = dispatchTables.get(dispChar);
     if (dispatchTable == null)
       {
         LispCharacter c = LispCharacter.getInstance(dispChar);
         error(new LispError(c.writeToString() +
                              " is not a dispatch character."));
       }
-    dispatchTable.functions[LispCharacter.toUpperCase(subChar)] = function;
+    dispatchTable.functions.put(LispCharacter.toUpperCase(subChar), function);
   }
 
   protected static class DispatchTable
   {
-    public LispObject[] functions = new LispObject[CHAR_MAX];
+	protected final CharHashMap<LispObject> functions;
 
     public DispatchTable()
     {
+      functions = new CharHashMap<LispObject>(LispObject.class,null);
     }
 
     public DispatchTable(DispatchTable dt)
     {
-      for (int i = 0; i < functions.length; i++)
-        functions[i] = dt.functions[i];
+      functions = (CharHashMap<LispObject>) dt.functions.clone();
     }
   }
 
@@ -427,8 +432,8 @@
           syntaxType = SYNTAX_TYPE_TERMINATING_MACRO;
         Readtable rt = designator_readtable(fourth);
         // REVIEW synchronization
-        rt.syntax[c] = syntaxType;
-        rt.readerMacroFunctions[c] = designator;
+        rt.syntax.put(c, syntaxType);
+        rt.readerMacroFunctions.put(c, designator);
         return T;
       }
     };
@@ -530,20 +535,18 @@
         else
           fromReadtable = checkReadtable(STANDARD_READTABLE.symbolValue());
         // REVIEW synchronization
-        toReadtable.syntax[toChar] = fromReadtable.syntax[fromChar];
-        toReadtable.readerMacroFunctions[toChar] =
-          fromReadtable.readerMacroFunctions[fromChar];
+        toReadtable.syntax.put(toChar, fromReadtable.syntax.get(fromChar));
+        toReadtable.readerMacroFunctions.put(toChar,
+        		fromReadtable.readerMacroFunctions.get(fromChar));
         // "If the character is a dispatching macro character, its entire
         // dispatch table of reader macro functions is copied."
-        if (fromReadtable.dispatchTables[fromChar] != null)
-          {
-            toReadtable.dispatchTables[toChar] =
-              new DispatchTable(fromReadtable.dispatchTables[fromChar]);
-          }
+        DispatchTable found = fromReadtable.dispatchTables.get(fromChar);
+        if (found!=null)
+        	toReadtable.dispatchTables.put(toChar, new DispatchTable(found));          
         else
             // Don't leave behind dispatch tables when fromChar
             // doesn't have one
-            toReadtable.dispatchTables[toChar] = null;
+        	toReadtable.dispatchTables.put(toChar, null);
         return T;
       }
     };
