Index: src/org/jruby/RubyHash.java
===================================================================
RCS file: /cvsroot/jruby/jruby/src/org/jruby/RubyHash.java,v
retrieving revision 1.33
diff -u -r1.33 RubyHash.java
--- src/org/jruby/RubyHash.java	25 Mar 2006 06:25:36 -0000	1.33
+++ src/org/jruby/RubyHash.java	15 Apr 2006 01:43:07 -0000
@@ -35,6 +35,7 @@
  ***** END LICENSE BLOCK *****/
 package org.jruby;
 
+import java.io.IOException;
 import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -503,7 +504,9 @@
         return result;
     }
 
-	public void marshalTo(MarshalStream output) throws java.io.IOException {
+	public void marshalTo(MarshalStream output) throws IOException {
+		output.writeUserClass(this, getRuntime().getClass("Hash"), output);
+		
 		output.write('{');
 		output.dumpInt(getValueMap().size());
 		
@@ -515,7 +518,7 @@
 		}
 	}
 
-    public static RubyHash unmarshalFrom(UnmarshalStream input) throws java.io.IOException {
+    public static RubyHash unmarshalFrom(UnmarshalStream input) throws IOException {
         RubyHash result = newHash(input.getRuntime());
         input.registerLinkTarget(result);
         int size = input.unmarshalInt();
Index: src/org/jruby/runtime/marshal/MarshalStream.java
===================================================================
RCS file: /cvsroot/jruby/jruby/src/org/jruby/runtime/marshal/MarshalStream.java,v
retrieving revision 1.15
diff -u -r1.15 MarshalStream.java
--- src/org/jruby/runtime/marshal/MarshalStream.java	9 Apr 2006 20:58:30 -0000	1.15
+++ src/org/jruby/runtime/marshal/MarshalStream.java	15 Apr 2006 01:43:07 -0000
@@ -38,6 +38,7 @@
 
 import org.jruby.IRuby;
 import org.jruby.RubyBoolean;
+import org.jruby.RubyClass;
 import org.jruby.RubyFixnum;
 import org.jruby.RubyString;
 import org.jruby.RubySymbol;
@@ -57,7 +58,8 @@
 
     private final static char TYPE_USRMARSHAL = 'U';
     private final static char TYPE_USERDEF = 'u';
-
+    
+    protected static char TYPE_UCLASS = 'C';
 
     public MarshalStream(IRuby runtime, OutputStream out, int depthLimit) throws IOException {
         super(out);
@@ -89,6 +91,26 @@
         	out.flush(); // flush afer whole dump is complete
         }
     }
+    
+    public void writeUserClass(IRubyObject obj, RubyClass baseClass, MarshalStream output) throws IOException {
+    	// TODO: handle w_extended code here
+    	
+    	if (obj.getMetaClass().equals(baseClass)) {
+    		// do nothing, simple builtin type marshalling
+    		return;
+    	}
+    	
+    	output.write(TYPE_UCLASS);
+    	
+    	// w_unique
+    	if (obj.getMetaClass().getName().charAt(0) == '#') {
+    		throw obj.getRuntime().newTypeError("Can't dump anonymous class");
+    	}
+    	
+    	// w_symbol
+    	// TODO: handle symlink?
+    	RubySymbol.newSymbol(obj.getRuntime(), obj.getMetaClass().getName()).marshalTo(output);
+    }
 
     private void writeDirectly(IRubyObject value) throws IOException {
         if (value.isNil()) {
Index: src/org/jruby/runtime/marshal/UnmarshalStream.java
===================================================================
RCS file: /cvsroot/jruby/jruby/src/org/jruby/runtime/marshal/UnmarshalStream.java,v
retrieving revision 1.16
diff -u -r1.16 UnmarshalStream.java
--- src/org/jruby/runtime/marshal/UnmarshalStream.java	8 Apr 2006 00:55:20 -0000	1.16
+++ src/org/jruby/runtime/marshal/UnmarshalStream.java	15 Apr 2006 01:43:07 -0000
@@ -138,6 +138,9 @@
             case 'U' :
                 rubyObj = userNewUnmarshal();
                 break;
+            case 'C' :
+            	rubyObj = uclassUnmarshall();
+            	break;
             default :
                 throw getRuntime().newArgumentError("dump format error(" + type + ")");
         }
@@ -223,6 +226,18 @@
 
         return result;
     }
+    
+    private IRubyObject uclassUnmarshall() throws IOException {
+    	RubySymbol className = (RubySymbol)unmarshalObject();
+    	
+    	RubyClass type = (RubyClass)runtime.getClassFromPath(className.asSymbol());
+    	
+    	IRubyObject result = unmarshalObject();
+    	
+    	result.setMetaClass(type);
+    	
+    	return result;
+    }
 
     private IRubyObject userUnmarshal() throws IOException {
         String className = unmarshalObject().asSymbol();
Index: test/testMarshal.rb
===================================================================
RCS file: /cvsroot/jruby/jruby/test/testMarshal.rb,v
retrieving revision 1.24
diff -u -r1.24 testMarshal.rb
--- test/testMarshal.rb	11 Dec 2004 05:55:50 -0000	1.24
+++ test/testMarshal.rb	15 Apr 2006 01:43:07 -0000
@@ -148,3 +148,13 @@
 a = Marshal.load(Marshal.dump([:hi, :hi, :hi, :hi]))
 test_ok(a[0] == :hi)
 test_ok(a[1] == :hi)
+
+# simple extensions of builtins should retain their types
+class MyHash < Hash
+  def foo; end
+end
+
+x = MyHash.new
+
+test_equal(MyHash, Marshal.load(Marshal.dump(x)).class)
+test_equal(x, Marshal.load(Marshal.dump(x)))
