internal static void w_ivar(System.Collections.Generic.Dictionary<string, object> tbl, dump_call_arg arg, Frame caller)
 {
     if (tbl != null && tbl.Count > 0)
     {
         w_long(tbl.Count, arg.arg, caller);
         foreach (System.Collections.Generic.KeyValuePair<string, object> IDValuePair in tbl)
         {
             w_symbol((int)Symbol.rb_intern(IDValuePair.Key), arg.arg, caller);
             w_object(IDValuePair.Value, arg.arg, arg.limit, caller);
         }
     }
     else
     {
         w_long(0, arg.arg, caller);
     }                     
 }
        internal static void w_object(object obj, dump_arg arg, int limit, Frame caller)
        {
            dump_call_arg c_arg = new dump_call_arg();
            System.Collections.Generic.Dictionary<string, object> ivtbl = null; 
            //    st_data_t num;

            if (limit == 0)
            {
                throw new ArgumentError("exceed depth limit").raise(caller);
            }

            limit--;
            c_arg.limit = limit;
            c_arg.arg = arg;

            if (obj != null && arg.data.ContainsKey(obj))
            {
                int num = arg.data[obj];
                w_byte(TYPE_LINK, arg, caller);
                w_long(num, arg, caller);
                return;
            }
                               
            ivtbl = Object.get_generic_ivars(obj);
            if (ivtbl != null)
            {
                w_byte(TYPE_IVAR, arg, caller);
            }

            if (obj == null)
            {
                w_byte(TYPE_NIL, arg, caller);
            }
            else if (obj is bool && (bool)obj == true)
            {
                w_byte(TYPE_TRUE, arg, caller);
            }
            else if (obj is bool && (bool)obj == false)
            {
                w_byte(TYPE_FALSE, arg, caller);
            }
            else if (obj is int)
            {
                w_byte((char)TYPE_FIXNUM, arg, caller);
                w_long((int)obj, arg, caller);
            }
            else if (obj is Symbol)
            {
                //FIXME: This code isn't being reached at the moment.
                //should be ok since the latest fixes - haven't tested this though
                w_symbol((int)((Symbol)obj).id_new, arg, caller);
            }
            else
            {
                if (((Basic)obj).Tainted)
                {
                    arg.taint = true;
                }

                arg.data[obj] = arg.data.Count;

                if (Eval.RespondTo(obj, s_mdump))
                {
                    object v;

                    v = Eval.CallPublic0(obj, caller, s_mdump, null);
                    w_class(TYPE_USRMARSHAL, obj, arg, false, caller);
                    w_object(v, arg, limit, caller);
                    if (ivtbl != null) w_ivar(null, c_arg, caller);
                    return;
                }
                if (Eval.RespondTo(obj, s_dump)) //TEST:
                {
                    object v;

                    v = Eval.CallPrivate(obj, caller, s_dump, null, limit);
                    if (!(v is String))
                    {
                        throw new TypeError("_dump() must return string").raise(caller);
                    }

                    if (ivtbl == null && (ivtbl = Object.get_generic_ivars(v)) != null)
                    {
                        w_byte(TYPE_IVAR, arg, caller);
                    }
                    w_class(TYPE_USERDEF, obj, arg, false, caller);
                    w_bytes(((String)v).value, ((String)v).value.Length, arg, caller);
                    if (ivtbl != null)
                    {
                        w_ivar(ivtbl, c_arg, caller);
                    }
                    return;              
                }


                if (obj is Class)
                {
                    if (((Class)obj)._type == Class.Type.Class)
                    {
                        if (((Class)obj)._type == Class.Type.Singleton)
                        {
                            throw new TypeError("singleton class can't be dumped").raise(caller);
                        }
                        w_byte(TYPE_CLASS, arg, caller);
                        {
                            object path = class2path(obj, caller);
                            w_bytes(((String)path).value, ((String)path).value.Length, arg, caller);
                        }
                    }
                    else if (((Class)obj)._type == Class.Type.Module)//TEST:
                    {
                        w_byte(TYPE_MODULE, arg, caller);
                        {
                            object path = class2path(obj, caller);
                            w_bytes(((String)path).value, ((String)path).value.Length, arg, caller);
                        }
                    }
                }
                else if (obj is Float)
                {
                    w_byte((char)TYPE_FLOAT, arg, caller);
                    w_float(((Float)obj).value, arg, caller);
                }
                else if (obj is Bignum)
                {
                    w_byte((char)TYPE_BIGNUM, arg, caller);
                    {
                        char sign = ((Bignum)(obj)).value.Sign < 0 ? '-' : '+';
                        long len = ((Bignum)(obj)).value.length;
                        uint[] d = ((Bignum)(obj)).value.Data;

                        w_byte((char)sign, arg, caller);
                        w_long(shortlen(len, d), arg, caller); /* w_short? */
                        int dIndex = 0;
                        while (len-- > 0)
                        {
                            uint num = d[dIndex];
                            int i;

                            for (i = 0; i < SIZEOF_BDIGITS; i += SIZEOF_SHORT)
                            {
                                w_short((int)num & SHORTMASK, arg, caller);
                                num = num >> BITSPERSHORT;
                                if (len == 0 && num == 0) break;
                            }
                            dIndex++;
                        }
                    }
                }
                else if (obj is Struct)
                {
                    w_class(TYPE_STRUCT, obj, arg, true, caller);
                    {
                        int len;
                        object mem;

                        len = StructLen(obj, caller);
                        mem = rb_struct_members(obj, caller);

                        w_long(len, arg, caller);
                        for (int i = 0; i < len; i++)
                        {
                            string symbolString = (string)((Array)mem).value[i]; //no interning atm
                            w_symbol((int)Symbol.rb_intern(symbolString), arg, caller);
                            w_object(((Struct)obj).instance_vars[symbolString], arg, limit, caller);
                        }
                    }
                }

                else if (obj is String)
                {
                    w_uclass(obj, Ruby.Runtime.Init.rb_cString, arg, caller);
                    w_byte((char)TYPE_STRING, arg, caller);
                    w_bytes(((String)obj).value, ((String)obj).value.Length, arg, caller);
                }
                else if (obj is Regexp)
                {
                    w_uclass(obj, Ruby.Runtime.Init.rb_cRegexp, arg, caller);
                    w_byte(TYPE_REGEXP, arg, caller);
                    string regExpStr = ((Regexp)obj).value.ToString();
                    w_bytes(regExpStr, regExpStr.Length, arg, caller);
                    w_byte((char)Regexp.rb_reg_options(caller, (Regexp)obj), arg, caller);
                }
                else if (obj is Array)
                {
                    w_uclass(obj, Ruby.Runtime.Init.rb_cArray, arg, caller);
                    w_byte((char)TYPE_ARRAY, arg, caller);
                    {
                        int len = ((Array)obj).Count;
                        System.Collections.ArrayList ptr = ((Array)obj).value;
                        w_long(len, arg, caller);
                        foreach (object arrObj in ptr)
                        {
                            w_object(arrObj, arg, limit, caller);
                        }
                    }
                }
                else if (obj is Hash)
                {
                    w_uclass(obj, Ruby.Runtime.Init.rb_cHash, arg, caller);
                    if (((Hash)obj).defaultProc != null)
                        throw new TypeError("cannot dump hash with default proc").raise(caller);
                    else if (((Hash)obj).defaultValue == null)
                        w_byte(TYPE_HASH, arg, caller);
                    else
                        w_byte(TYPE_HASH_DEF, arg, caller);
                    w_long(((Hash)(obj)).value.Count, arg, caller);
                    foreach (HashKeyValuePair pair in ((Hash)obj).value)
                    {
                        w_object(pair.Key.key, c_arg.arg, c_arg.limit, caller);
                        w_object(pair.Value, c_arg.arg, c_arg.limit, caller);
                    }
                    if (((Hash)obj).defaultValue != null)
                        w_object(((Hash)obj).defaultValue, arg, limit, caller);
                }
                else if (obj is Data) //TEST:
                {               
                    object v;
                        
                    w_class(TYPE_DATA, obj, arg, true, caller);
                    if (!Eval.RespondTo(obj, s_dump_data))
                        throw new TypeError(string.Format(CultureInfo.InvariantCulture, "no marshal_dump is defined for class {0}", rb_obj_classname(obj, caller))).raise(caller);

                    v = Eval.CallPrivate0(obj, caller, s_dump_data, null);
                    w_object(v, arg, limit, caller);
                }
                else if (obj is Object)//TEST:
                {
                    w_class(TYPE_OBJECT, obj, arg, true, caller);
                    w_ivar(((Object)obj).instance_vars, c_arg, caller);
                }
                else
                    throw new TypeError(string.Format(CultureInfo.InvariantCulture, "can't dump {0}", ((Basic)obj).my_class.classname())).raise(caller);
            }

            if (ivtbl != null)
            {
                w_ivar(ivtbl, c_arg, caller);
            }
        }
        //----------------------------------------------------------------------------------

        internal static object dump(dump_call_arg arg, Frame caller)
        {
            w_object(arg.obj, arg.arg, arg.limit, caller);
            if (arg.arg.dest != null)
            {
                rb_io_write(arg.arg.dest, arg.arg.str, caller);
                ((String)arg.arg.str).value = "";
            }

            return null; 
        }