Index: gobject/valadbusservermodule.vala
===================================================================
--- gobject/valadbusservermodule.vala	(revision 2023)
+++ gobject/valadbusservermodule.vala	(working copy)
@@ -29,6 +29,32 @@
  * The link between a dynamic method and generated code.
  */
 public class Vala.DBusServerModule : DBusClientModule {
+	struct BasicTypeInfo {
+		public weak string signature;
+		public weak string type_name;
+		public weak string cname;
+		public weak string gtype;
+		public weak string? get_value_function;
+		public weak string set_value_function;
+	}
+
+	const BasicTypeInfo[] basic_types = {
+		{ "y", "BYTE", "guint8", "G_TYPE_UCHAR", "g_value_get_uchar", "g_value_set_uchar" },
+		{ "b", "BOOLEAN", "dbus_bool_t", "G_TYPE_BOOLEAN", "g_value_get_boolean", "g_value_set_boolean" },
+		{ "n", "INT16", "dbus_int16_t", "G_TYPE_INT", null, "g_value_set_int" },
+		{ "q", "UINT16", "dbus_uint16_t", "G_TYPE_UINT", null, "g_value_set_uint" },
+		{ "i", "INT32", "dbus_int32_t", "G_TYPE_INT", "g_value_get_int", "g_value_set_int" },
+		{ "u", "UINT32", "dbus_uint32_t", "G_TYPE_UINT", "g_value_get_uint", "g_value_set_uint" },
+		{ "x", "INT64", "dbus_int64_t", "G_TYPE_INT64", "g_value_get_int64", "g_value_set_int64" },
+		{ "t", "UINT64", "dbus_uint64_t", "G_TYPE_UINT64", "g_value_get_uint64", "g_value_set_uint64" },
+		{ "d", "DOUBLE", "double", "G_TYPE_DOUBLE", "g_value_get_double", "g_value_set_double" },
+		{ "s", "STRING", "const char*", "G_TYPE_STRING", "g_value_get_string", "g_value_set_string" },
+		{ "o", "OBJECT_PATH", "const char*", "G_TYPE_STRING", null, "g_value_set_string" },
+		{ "g", "SIGNATURE", "const char*", "G_TYPE_STRING", null, "g_value_set_string" }
+	};
+
+	int loopindex;
+
 	public DBusServerModule (CCodeGenerator codegen, CCodeModule? next) {
 		base (codegen, next);
 	}
@@ -56,30 +82,50 @@
 		return "result";
 	}
 
-	public override CCodeFragment register_dbus_info (ObjectTypeSymbol bindable) {
+	void generate_unregister_function (ObjectType object_type) {
+		var sym = object_type.type_symbol;
 
-		CCodeFragment fragment = new CCodeFragment ();
+		var cfunc = new CCodeFunction ("_dbus_" + sym.get_lower_case_cprefix () + "unregister", "void");
+		cfunc.add_parameter (new CCodeFormalParameter ("connection", "DBusConnection*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("user_data", "void*"));
 
-		var dbus = bindable.get_attribute ("DBus");
+		source_type_member_declaration.append (cfunc.copy ());
+
+		var block = new CCodeBlock ();
+		cfunc.block = block;
+
+		source_type_member_definition.append (cfunc);
+	}
+
+	void generate_message_function (ObjectType object_type) {
+		var sym = object_type.type_symbol;
+
+		var dbus = sym.get_attribute ("DBus");
 		if (dbus == null) {
-			return fragment;
+			Report.error (sym.source_reference, "`%s' does not specify a D-Bus interface name");
+			return;
 		}
-		var dbus_iface_name = dbus.get_string ("name");
+		string dbus_iface_name = dbus.get_string ("name");
 		if (dbus_iface_name == null) {
-			return fragment;
+			Report.error (sym.source_reference, "`%s' does not specify a D-Bus interface name");
+			return;
 		}
 
 		dbus_glib_h_needed = true;
 
-		var dbus_methods = new StringBuilder ();
-		dbus_methods.append ("{\n");
+		var cfunc = new CCodeFunction ("_dbus_" + sym.get_lower_case_cprefix () + "message", "DBusHandlerResult");
+		cfunc.add_parameter (new CCodeFormalParameter ("connection", "DBusConnection*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("message", "DBusMessage*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("user_data", "void*"));
 
-		var blob = new StringBuilder ();
-		blob.append_c ('"');
+		source_type_member_declaration.append (cfunc.copy ());
 
-		int method_count = 0;
-		long blob_len = 0;
-		foreach (Method m in bindable.get_methods ()) {
+		var block = new CCodeBlock ();
+		cfunc.block = block;
+
+		CCodeIfStatement clastif = null;
+
+		foreach (Method m in sym.get_methods ()) {
 			if (m is CreationMethod || m.binding != MemberBinding.INSTANCE
 			    || m.overrides || m.access != SymbolAccessibility.PUBLIC) {
 				continue;
@@ -88,562 +134,661 @@
 				continue;
 			}
 
-			var parameters = new Gee.ArrayList<FormalParameter> ();
-			foreach (FormalParameter param in m.get_parameters ()) {
-				parameters.add (param);
-			}
-			if (!(m.return_type is VoidType)) {
-				parameters.add (new FormalParameter ("result", new PointerType (new VoidType ())));
-			}
-			parameters.add (new FormalParameter ("error", gerror_type));
+			var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_is_method_call"));
+			ccheck.add_argument (new CCodeIdentifier ("message"));
+			ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
+			ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (Symbol.lower_case_to_camel_case (m.name))));
 
-			dbus_methods.append ("{ (GCallback) ");
-			dbus_methods.append (generate_dbus_wrapper (m, bindable));
-			dbus_methods.append (", ");
-			dbus_methods.append (head.get_marshaller_function (parameters, bool_type, null, true));
-			dbus_methods.append (", ");
-			dbus_methods.append (blob_len.to_string ());
-			dbus_methods.append (" },\n");
+			var callblock = new CCodeBlock ();
+			var cdecl = new CCodeDeclaration ("DBusMessage*");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("reply"));
 
-			head.generate_marshaller (parameters, bool_type, true);
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_wrapper (m, sym)));
+			ccall.add_argument (new CCodeIdentifier ("user_data"));
+			ccall.add_argument (new CCodeIdentifier ("message"));
 
-			long start = blob.len;
+			callblock.add_statement (cdecl);
+			callblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("reply"), ccall)));
 
-			blob.append (dbus_iface_name);
-			blob.append ("\\0");
-			start++;
+			ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_send"));
+			ccall.add_argument (new CCodeIdentifier ("connection"));
+			ccall.add_argument (new CCodeIdentifier ("reply"));
+			ccall.add_argument (new CCodeConstant ("NULL"));
+			callblock.add_statement (new CCodeExpressionStatement (ccall));
 
-			blob.append (Symbol.lower_case_to_camel_case (m.name));
-			blob.append ("\\0");
-			start++;
+			ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
+			ccall.add_argument (new CCodeIdentifier ("reply"));
+			callblock.add_statement (new CCodeExpressionStatement (ccall));
 
-			// synchronous
-			blob.append ("S\\0");
-			start++;
+			var cif = new CCodeIfStatement (ccheck, callblock);
+			if (clastif == null) {
+				block.add_statement (cif);
+			} else {
+				clastif.false_statement = cif;
+			}
 
-			foreach (FormalParameter param in m.get_parameters ()) {
-				blob.append (param.name);
-				blob.append ("\\0");
-				start++;
+			clastif = cif;
+		}
 
-				if (param.direction == ParameterDirection.IN) {
-					blob.append ("I\\0");
-					start++;
-				} else if (param.direction == ParameterDirection.OUT) {
-					blob.append ("O\\0");
-					start++;
-					blob.append ("F\\0");
-					start++;
-					blob.append ("N\\0");
-					start++;
-				} else {
-					Report.error (param.source_reference, "unsupported parameter direction for D-Bus method");
-				}
+		var retblock = new CCodeBlock ();
+		retblock.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("DBUS_HANDLER_RESULT_NOT_YET_HANDLED")));
+		if (clastif == null) {
+			block.add_statement (retblock);
+		} else {
+			clastif.false_statement = retblock;
+		}
+		
 
-				blob.append (param.parameter_type.get_type_signature ());
-				blob.append ("\\0");
-				start++;
-			}
+		source_type_member_definition.append (cfunc);
+	}
 
-			if (!(m.return_type is VoidType)) {
-				blob.append (dbus_result_name (m));
-				blob.append ("\\0");
-				start++;
+	CCodeExpression get_vtable (ObjectType object_type) {
+		var sym = object_type.type_symbol;
 
-				blob.append ("O\\0");
-				start++;
-				blob.append ("F\\0");
-				start++;
-				blob.append ("N\\0");
-				start++;
+		var vtable = new CCodeInitializerList ();
+		vtable.append (new CCodeIdentifier ("_dbus_" + sym.get_lower_case_cprefix () + "unregister"));
+		vtable.append (new CCodeIdentifier ("_dbus_" + sym.get_lower_case_cprefix () + "message"));
 
-				blob.append (m.return_type.get_type_signature ());
-				blob.append ("\\0");
-				start++;
-			}
+		generate_unregister_function (object_type);
+		generate_message_function (object_type);
 
-			blob.append ("\\0");
-			start++;
+		var cdecl = new CCodeDeclaration ("const DBusObjectPathVTable");
+		cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("_dbus_" + sym.get_lower_case_cprefix () + "vtable", vtable));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_constant_declaration.append (cdecl);
 
-			blob_len += blob.len - start;
+		return new CCodeIdentifier ("_dbus_" + sym.get_lower_case_cprefix () + "vtable");
+	}
 
-			method_count++;
+	public override void visit_invocation_expression (InvocationExpression expr) {
+		var mtype = expr.call.value_type as MethodType;
+		if (mtype == null || mtype.method_symbol.get_cname () != "dbus_g_connection_register_g_object") {
+			base.visit_invocation_expression (expr);
+			return;
 		}
 
-		blob.append_c ('"');
+		expr.accept_children (codegen);
 
-		dbus_methods.append ("}\n");
+		var ma = (MemberAccess) expr.call;
 
-		var dbus_signals = new StringBuilder ();
-		dbus_signals.append_c ('"');
-		foreach (Signal sig in bindable.get_signals ()) {
-			if (sig.access != SymbolAccessibility.PUBLIC) {
-				continue;
-			}
-			if (!is_dbus_visible (sig)) {
-				continue;
-			}
+		var raw_conn = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_get_connection"));
+		raw_conn.add_argument ((CCodeExpression) ma.inner.ccodenode);
 
-			dbus_signals.append (dbus_iface_name);
-			dbus_signals.append ("\\0");
-			dbus_signals.append (Symbol.lower_case_to_camel_case (sig.name));
-			dbus_signals.append ("\\0");
+		var args_it = expr.get_argument_list ().iterator ();
+		args_it.next ();
+		var path_arg = args_it.get ();
+		args_it.next ();
+		var obj_arg = args_it.get ();
+
+		var object_type = (ObjectType) obj_arg.value_type;
+
+		var cregister = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_register_object_path"));
+		cregister.add_argument (raw_conn);
+		cregister.add_argument ((CCodeExpression) path_arg.ccodenode);
+		cregister.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_vtable (object_type)));
+		cregister.add_argument ((CCodeExpression) obj_arg.ccodenode);
+		expr.ccodenode = cregister;
+	}
+
+	public override CCodeFragment register_dbus_info (ObjectTypeSymbol bindable) {
+		return new CCodeFragment ();
+	}
+
+	CCodeExpression? get_array_length (CCodeExpression expr) {
+		var id = expr as CCodeIdentifier;
+		var ma = expr as CCodeMemberAccess;
+		if (id != null) {
+			return new CCodeIdentifier (id.name + "_length1");
+		} else if (ma != null) {
+			return new CCodeMemberAccess.pointer (ma.inner, ma.member_name + "_length1");
 		}
-		dbus_signals.append_c('"');
+		return null;
+	}
 
-		var dbus_props = new StringBuilder();
-		dbus_props.append_c ('"');
-		foreach (Property prop in bindable.get_properties ()) {
-			if (prop.access != SymbolAccessibility.PUBLIC) {
-				continue;
+	bool get_basic_type_info (string signature, out BasicTypeInfo basic_type) {
+		foreach (BasicTypeInfo info in basic_types) {
+			if (info.signature == signature) {
+				basic_type = info;
+				return true;
 			}
-			if (!is_dbus_visible (prop)) {
-				continue;
-			}
-
-			dbus_props.append (dbus_iface_name);
-			dbus_props.append ("\\0");
-			dbus_props.append (Symbol.lower_case_to_camel_case (prop.name));
-			dbus_props.append ("\\0");
 		}
-		dbus_props.append_c ('"');
+		return false;
+	}
 
-		var dbus_methods_decl = new CCodeDeclaration ("const DBusGMethodInfo");
-		dbus_methods_decl.modifiers = CCodeModifiers.STATIC;
-		dbus_methods_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("%s_dbus_methods[]".printf (bindable.get_lower_case_cname ()), new CCodeConstant (dbus_methods.str)));
+	CCodeExpression read_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression iter_expr) {
+		string temp_name = "_tmp%d".printf (next_temp_var_id++);
 
-		fragment.append (dbus_methods_decl);
+		var cdecl = new CCodeDeclaration (basic_type.cname);
+		cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
+		fragment.append (cdecl);
 
-		var dbus_object_info = new CCodeDeclaration ("const DBusGObjectInfo");
-		dbus_object_info.modifiers = CCodeModifiers.STATIC;
-		dbus_object_info.add_declarator (new CCodeVariableDeclarator.with_initializer ("%s_dbus_object_info".printf (bindable.get_lower_case_cname ()), new CCodeConstant ("{ 0, %s_dbus_methods, %d, %s, %s, %s }".printf (bindable.get_lower_case_cname (), method_count, blob.str, dbus_signals.str, dbus_props.str))));
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_basic"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
+		fragment.append (new CCodeExpressionStatement (iter_call));
+		return new CCodeIdentifier (temp_name);
+	}
 
-		fragment.append (dbus_object_info);
+	CCodeExpression read_array (CCodeFragment fragment, ArrayType array_type, CCodeExpression iter_expr, CCodeExpression? expr) {
+		string temp_name = "_tmp%d".printf (next_temp_var_id++);
 
-		var install_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_object_type_install_info"));
-		install_call.add_argument (new CCodeIdentifier (bindable.get_type_id ()));
-		install_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("%s_dbus_object_info".printf (bindable.get_lower_case_cname ()))));
+		var cdecl = new CCodeDeclaration (array_type.get_cname ());
+		cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (temp_name, new CCodeConstant ("NULL")));
+		fragment.append (cdecl);
 
-		fragment.append (new CCodeExpressionStatement (install_call));
+		cdecl = new CCodeDeclaration ("int");
+		cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (temp_name + "_length1", new CCodeConstant ("0")));
+		fragment.append (cdecl);
 
-		return fragment;
+		cdecl = new CCodeDeclaration ("int");
+		cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (temp_name + "_size", new CCodeConstant ("0")));
+		fragment.append (cdecl);
+
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		fragment.append (new CCodeExpressionStatement (iter_call));
+
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+
+		var cforblock = new CCodeBlock ();
+		var cforfragment = new CCodeFragment ();
+		cforblock.add_statement (cforfragment);
+		var cfor = new CCodeForStatement (iter_call, cforblock);
+		cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (temp_name + "_length1")));
+
+		var size_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (temp_name + "_size"), new CCodeIdentifier (temp_name + "_length1"));
+		var init_check = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, new CCodeIdentifier (temp_name + "_size"), new CCodeConstant ("0"));
+		var new_size = new CCodeConditionalExpression (init_check, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), new CCodeIdentifier (temp_name + "_size")), new CCodeConstant ("4"));
+		var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
+		renew_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+		renew_call.add_argument (new CCodeIdentifier (temp_name));
+		renew_call.add_argument (new_size);
+		var renew_stmt = new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), renew_call));
+		var renew_block = new CCodeBlock ();
+		renew_block.add_statement (renew_stmt);
+
+		var cif = new CCodeIfStatement (size_check, renew_block);
+		cforfragment.append (cif);
+
+		var element_expr = read_expression (cforfragment, array_type.element_type, new CCodeIdentifier ("subiter"), null);
+		cforfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeElementAccess (new CCodeIdentifier (temp_name), new CCodeIdentifier (temp_name + "_length1")), element_expr)));
+
+		fragment.append (cfor);
+
+		if (expr != null) {
+			fragment.append (new CCodeExpressionStatement (new CCodeAssignment (get_array_length (expr), new CCodeIdentifier (temp_name + "_length1"))));
+		}
+
+		return new CCodeIdentifier (temp_name);
 	}
 
-	void transform_struct_to_value_array (CCodeBlock block, Struct st, CCodeExpression target, CCodeExpression st_expr, string name) {
-		var array_construct = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_new"));
-		array_construct.add_argument (new CCodeConstant ("0"));
+	CCodeExpression read_struct (CCodeFragment fragment, Struct st, CCodeExpression iter_expr) {
+		string temp_name = "_tmp%d".printf (next_temp_var_id++);
 
-		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (target, array_construct)));
+		var cdecl = new CCodeDeclaration (st.get_cname ());
+		cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
+		fragment.append (cdecl);
 
-		var type_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_struct"));
-		type_call.add_argument (new CCodeConstant ("\"GValueArray\""));
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		fragment.append (new CCodeExpressionStatement (iter_call));
 
 		foreach (Field f in st.get_fields ()) {
 			if (f.binding != MemberBinding.INSTANCE) {
 				continue;
 			}
 
-			string val_name = "val_%s_%s".printf (name, f.name);
+			var field_expr = read_expression (fragment, f.field_type, new CCodeIdentifier ("subiter"), new CCodeMemberAccess (new CCodeIdentifier (temp_name), f.get_cname ()));
+			fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess (new CCodeIdentifier (temp_name), f.get_cname ()), field_expr)));
+		}
 
-			// 0-initialize struct with struct initializer { 0 }
-			var cvalinit = new CCodeInitializerList ();
-			cvalinit.append (new CCodeConstant ("0"));
+		return new CCodeIdentifier (temp_name);
+	}
 
-			var cval_decl = new CCodeDeclaration ("GValue");
-			cval_decl.add_declarator (new CCodeVariableDeclarator.with_initializer (val_name, cvalinit));
-			block.add_statement (cval_decl);
+	CCodeExpression read_value (CCodeFragment fragment, CCodeExpression iter_expr) {
+		string temp_name = "_tmp%d".printf (next_temp_var_id++);
 
-			var val_ptr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (val_name));
+		// 0-initialize struct with struct initializer { 0 }
+		var cvalinit = new CCodeInitializerList ();
+		cvalinit.append (new CCodeConstant ("0"));
 
-			string type_id = f.field_type.data_type.get_type_id ();
-			string set_value_function = f.field_type.data_type.get_set_value_function ();
+		var cdecl = new CCodeDeclaration ("GValue");
+		cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (temp_name, cvalinit));
+		fragment.append (cdecl);
 
-			if (f.field_type.data_type is Enum) {
-				// dbus-glib does not support enums
-				var en = (Enum) f.field_type.data_type;
-				if (!en.is_flags) {
-					type_id = "G_TYPE_INT";
-					set_value_function = "g_value_set_int";
-				} else {
-					type_id = "G_TYPE_UINT";
-					set_value_function = "g_value_set_uint";
-				}
-			}
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		fragment.append (new CCodeExpressionStatement (iter_call));
 
-			var cinit_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
-			cinit_call.add_argument (val_ptr);
-			cinit_call.add_argument (new CCodeIdentifier (type_id));
-			block.add_statement (new CCodeExpressionStatement (cinit_call));
+		CCodeIfStatement clastif = null;
 
-			var cset_call = new CCodeFunctionCall (new CCodeIdentifier (set_value_function));
-			cset_call.add_argument (val_ptr);
-			if (f.field_type.data_type is Struct) {
-				cset_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess (st_expr, f.name)));
+		foreach (BasicTypeInfo basic_type in basic_types) {
+			var type_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
+			type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+			var type_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, type_call, new CCodeIdentifier ("DBUS_TYPE_" + basic_type.type_name));
+
+			var type_block = new CCodeBlock ();
+			var type_fragment = new CCodeFragment ();
+			type_block.add_statement (type_fragment);
+			var result = read_basic (type_fragment, basic_type, new CCodeIdentifier ("subiter"));
+
+			var value_init = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
+			value_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
+			value_init.add_argument (new CCodeIdentifier (basic_type.gtype));
+			type_fragment.append (new CCodeExpressionStatement (value_init));
+
+			var value_set = new CCodeFunctionCall (new CCodeIdentifier (basic_type.set_value_function));
+			value_set.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
+			value_set.add_argument (result);
+			type_fragment.append (new CCodeExpressionStatement (value_set));
+
+			var cif = new CCodeIfStatement (type_check, type_block);
+			if (clastif == null) {
+				fragment.append (cif);
 			} else {
-				cset_call.add_argument (new CCodeMemberAccess (st_expr, f.name));
+				clastif.false_statement = cif;
 			}
-			block.add_statement (new CCodeExpressionStatement (cset_call));
 
-			var cappend_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_append"));
-			cappend_call.add_argument (target);
-			cappend_call.add_argument (val_ptr);
-			block.add_statement (new CCodeExpressionStatement (cappend_call));
+			clastif = cif;
+		}
 
-			type_call.add_argument (new CCodeIdentifier (f.field_type.data_type.get_type_id ()));
-		}
+		return new CCodeIdentifier (temp_name);
 	}
 
-	void transform_struct_hash_table_to_value_array_hash_table (CCodeBlock block, Struct st, CCodeExpression target, CCodeExpression table_expr, string name) {
-		// FIXME take care of memory management
-		var table_construct = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_new"));
-		table_construct.add_argument (new CCodeIdentifier ("g_direct_hash"));
-		table_construct.add_argument (new CCodeIdentifier ("g_direct_equal"));
-		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (target, table_construct)));
+	CCodeExpression read_hash_table (CCodeFragment fragment, ObjectType type, CCodeExpression iter_expr) {
+		var type_args = type.get_type_arguments ();
+		assert (type_args.size == 2);
+		var key_type = type_args.get (0);
+		var value_type = type_args.get (1);
 
-		var cdecl = new CCodeDeclaration ("GList");
-		cdecl.add_declarator (new CCodeVariableDeclarator ("*%s_keys".printf (name)));
-		cdecl.add_declarator (new CCodeVariableDeclarator ("*%s_keys_it".printf (name)));
-		cdecl.add_declarator (new CCodeVariableDeclarator ("*%s_values".printf (name)));
-		cdecl.add_declarator (new CCodeVariableDeclarator ("*%s_values_it".printf (name)));
-		block.add_statement (cdecl);
+		string temp_name = "_tmp%d".printf (next_temp_var_id++);
 
-		var get_keys = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_get_keys"));
-		get_keys.add_argument (table_expr);
-		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("%s_keys".printf (name)), get_keys)));
+		var cdecl = new CCodeDeclaration ("GHashTable*");
+		cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
+		fragment.append (cdecl);
 
-		var get_values = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_get_values"));
-		get_values.add_argument (table_expr);
-		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("%s_values".printf (name)), get_values)));
+		var hash_table_new = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_new"));
+		hash_table_new.add_argument (new CCodeIdentifier ("g_direct_hash"));
+		hash_table_new.add_argument (new CCodeIdentifier ("g_direct_equal"));
+		fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), hash_table_new)));
 
-		var loop_body = new CCodeBlock ();
-		var for_stmt = new CCodeForStatement (new CCodeIdentifier ("%s_keys_it".printf (name)), loop_body);
-		block.add_statement (for_stmt);
-		for_stmt.add_initializer (new CCodeAssignment (new CCodeIdentifier ("%s_keys_it".printf (name)), new CCodeIdentifier ("%s_keys".printf (name))));
-		for_stmt.add_initializer (new CCodeAssignment (new CCodeIdentifier ("%s_values_it".printf (name)), new CCodeIdentifier ("%s_values".printf (name))));
-		for_stmt.add_iterator (new CCodeAssignment (new CCodeIdentifier ("%s_keys_it".printf (name)), new CCodeMemberAccess.pointer (new CCodeIdentifier ("%s_keys_it".printf (name)), "next")));
-		for_stmt.add_iterator (new CCodeAssignment (new CCodeIdentifier ("%s_values_it".printf (name)), new CCodeMemberAccess.pointer (new CCodeIdentifier ("%s_values_it".printf (name)), "next")));
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		fragment.append (new CCodeExpressionStatement (iter_call));
 
-		cdecl = new CCodeDeclaration (st.get_cname () + "*");
-		cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("%s_value".printf (name), new CCodeMemberAccess.pointer (new CCodeIdentifier ("%s_values_it".printf (name)), "data")));
-		loop_body.add_statement (cdecl);
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
 
-		cdecl = new CCodeDeclaration ("GValueArray*");
-		cdecl.add_declarator (new CCodeVariableDeclarator ("%s_value_array".printf (name)));
-		loop_body.add_statement (cdecl);
+		var cwhileblock = new CCodeBlock ();
+		var cwhilefragment = new CCodeFragment ();
+		cwhileblock.add_statement (cwhilefragment);
+		var cwhile = new CCodeWhileStatement (iter_call, cwhileblock);
 
-		transform_struct_to_value_array (loop_body, st, new CCodeIdentifier ("%s_value_array".printf (name)), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("%s_value".printf (name))), name);
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("entryiter")));
+		cwhilefragment.append (new CCodeExpressionStatement (iter_call));
 
-		var insert_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_insert"));
-		insert_call.add_argument (target);
-		insert_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("%s_keys_it".printf (name)), "data"));
-		insert_call.add_argument (new CCodeIdentifier ("%s_value_array".printf (name)));
-		loop_body.add_statement (new CCodeExpressionStatement (insert_call));
-	}
+		cdecl = new CCodeDeclaration (key_type.get_cname ());
+		cdecl.add_declarator (new CCodeVariableDeclarator ("entry_key"));
+		cwhilefragment.append (cdecl);
 
-	string generate_dbus_wrapper (Method m, ObjectTypeSymbol bindable) {
-		string wrapper_name = "_dbus_%s".printf (m.get_cname ());
+		cdecl = new CCodeDeclaration (value_type.get_cname ());
+		cdecl.add_declarator (new CCodeVariableDeclarator ("entry_value"));
+		cwhilefragment.append (cdecl);
 
-		// declaration
+		var key_expr = read_expression (cwhilefragment, key_type, new CCodeIdentifier ("entryiter"), null);
+		cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("entry_key"), key_expr)));
+		
+		var value_expr = read_expression (cwhilefragment, value_type, new CCodeIdentifier ("entryiter"), null);
+		cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("entry_value"), value_expr)));
 
-		var function = new CCodeFunction (wrapper_name, "gboolean");
-		function.modifiers = CCodeModifiers.STATIC;
-		m.ccodenode = function;
+		var hash_table_insert = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_insert"));
+		hash_table_insert.add_argument (new CCodeIdentifier (temp_name));
+		hash_table_insert.add_argument (convert_to_generic_pointer (key_expr, key_type));
+		hash_table_insert.add_argument (convert_to_generic_pointer (value_expr, value_type));
+		fragment.append (new CCodeExpressionStatement (hash_table_insert));
 
-		function.add_parameter (new CCodeFormalParameter ("self", bindable.get_cname () + "*"));
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		cwhilefragment.append (new CCodeExpressionStatement (iter_call));
 
-		foreach (FormalParameter param in m.get_parameters ()) {
-			string ptr = (param.direction == ParameterDirection.OUT ? "*" : "");
-			var array_type = param.parameter_type as ArrayType;
-			if (array_type != null && array_type.element_type.data_type != string_type.data_type) {
-				if (dbus_use_ptr_array (array_type)) {
-					function.add_parameter (new CCodeFormalParameter ("dbus_%s".printf (param.name), "GPtrArray*" + ptr));
-				} else {
-					function.add_parameter (new CCodeFormalParameter ("dbus_%s".printf (param.name), "GArray*" + ptr));
-				}
-			} else if (param.parameter_type.get_type_signature ().has_prefix ("(")) {
-				function.add_parameter (new CCodeFormalParameter ("dbus_%s".printf (param.name), "GValueArray*" + ptr));
-			} else if (param.parameter_type.get_type_signature ().has_prefix ("a{")) {
-				// hash table output parameter
-				var type_args = param.parameter_type.get_type_arguments ();
-				var value_type = type_args.get (1);
-				if (value_type.get_type_signature ().has_prefix ("(")) {
-					// values are structs
-					function.add_parameter (new CCodeFormalParameter ("dbus_%s".printf (param.name), "GHashTable*" + ptr));
-				} else {
-					function.add_parameter ((CCodeFormalParameter) param.ccodenode);
-				}
-			} else {
-				function.add_parameter ((CCodeFormalParameter) param.ccodenode);
-			}
-		}
+		fragment.append (cwhile);
 
-		if (!(m.return_type is VoidType)) {
-			var array_type = m.return_type as ArrayType;
-			if (array_type != null) {
-				if (array_type.element_type.data_type == string_type.data_type) {
-					function.add_parameter (new CCodeFormalParameter ("result", array_type.get_cname () + "*"));
-				} else if (dbus_use_ptr_array (array_type)) {
-					function.add_parameter (new CCodeFormalParameter ("dbus_result", "GPtrArray**"));
-				} else {
-					function.add_parameter (new CCodeFormalParameter ("dbus_result", "GArray**"));
-				}
-			} else if (m.return_type.get_type_signature ().has_prefix ("(")) {
-				function.add_parameter (new CCodeFormalParameter ("dbus_result", "GValueArray**"));
-			} else if (m.return_type.get_type_signature ().has_prefix ("a{")) {
-				// hash table output parameter
-				var type_args = m.return_type.get_type_arguments ();
-				var value_type = type_args.get (1);
-				if (value_type.get_type_signature ().has_prefix ("(")) {
-					// values are structs
-					function.add_parameter (new CCodeFormalParameter ("dbus_result", "GHashTable**"));
-				} else {
-					function.add_parameter (new CCodeFormalParameter ("result", m.return_type.get_cname () + "*"));
-				}
+		return new CCodeIdentifier (temp_name);
+	}
+
+	CCodeExpression? read_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression? expr) {
+		BasicTypeInfo basic_type;
+		CCodeExpression result = null;
+		if (get_basic_type_info (type.get_type_signature (), out basic_type)) {
+			result = read_basic (fragment, basic_type, iter_expr);
+		} else if (type is ArrayType) {
+			result = read_array (fragment, (ArrayType) type, iter_expr, expr);
+		} else if (type.data_type is Struct) {
+			if (type.data_type.get_full_name () == "GLib.Value") {
+				result = read_value (fragment, iter_expr);
 			} else {
-				function.add_parameter (new CCodeFormalParameter ("result", m.return_type.get_cname () + "*"));
+				result = read_struct (fragment, (Struct) type.data_type, iter_expr);
 			}
+		} else if (type is ObjectType) {
+			if (type.data_type.get_full_name () == "GLib.HashTable") {
+				result = read_hash_table (fragment, (ObjectType) type, iter_expr);
+			}
+		} else {
+			Report.error (type.source_reference, "D-Bus deserialization of type `%s' is not supported".printf (type.to_string ()));
+			return null;
 		}
 
-		function.add_parameter (new CCodeFormalParameter ("error", "GError**"));
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		fragment.append (new CCodeExpressionStatement (iter_call));
 
-		// definition
+		return result;
+	}
 
-		var block = new CCodeBlock ();
+	void write_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression iter_expr, CCodeExpression expr) {
+		string temp_name = "_tmp%d".printf (next_temp_var_id++);
 
-		foreach (FormalParameter param in m.get_parameters ()) {
-			if (param.parameter_type.get_type_signature ().has_prefix ("(")) {
-				var st = (Struct) param.parameter_type.data_type;
+		var cdecl = new CCodeDeclaration (basic_type.cname);
+		cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
+		fragment.append (cdecl);
 
-				var cdecl = new CCodeDeclaration (st.get_cname ());
-				cdecl.add_declarator (new CCodeVariableDeclarator (param.name));
-				block.add_statement (cdecl);
+		fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), expr)));
 
-				if (param.direction == ParameterDirection.IN) {
-					// struct input parameter
-					int i = 0;
-					foreach (Field f in st.get_fields ()) {
-						if (f.binding == MemberBinding.INSTANCE) {
-							var cget_call = new CCodeFunctionCall (new CCodeIdentifier (f.field_type.data_type.get_get_value_function ()));
-							cget_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeElementAccess (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "values"), new CCodeConstant (i.to_string ()))));
-							var assign = new CCodeAssignment (new CCodeMemberAccess (new CCodeIdentifier (param.name), f.name), cget_call);
-							block.add_statement (new CCodeExpressionStatement (assign));
-							i++;
-						}
-					}
-				}
-			} else if (param.parameter_type.get_type_signature ().has_prefix ("a{")) {
-				// hash table output parameter
-				var type_args = param.parameter_type.get_type_arguments ();
-				var value_type = type_args.get (1);
-				if (value_type.get_type_signature ().has_prefix ("(")) {
-					// values are structs
-					var cdecl = new CCodeDeclaration ("GHashTable*");
-					cdecl.add_declarator (new CCodeVariableDeclarator (param.name));
-					block.add_statement (cdecl);
-				}
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_append_basic"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_" + basic_type.type_name));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
+		fragment.append (new CCodeExpressionStatement (iter_call));
+	}
+
+	void write_array (CCodeFragment fragment, ArrayType array_type, CCodeExpression iter_expr, CCodeExpression array_expr) {
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_ARRAY"));
+		iter_call.add_argument (new CCodeConstant ("\"%s\"".printf (array_type.element_type.get_type_signature ())));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		fragment.append (new CCodeExpressionStatement (iter_call));
+
+		var cdecl = new CCodeDeclaration ("int");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("i"));
+		fragment.append (cdecl);
+
+		var cforblock = new CCodeBlock ();
+		var cforfragment = new CCodeFragment ();
+		cforblock.add_statement (cforfragment);
+		var cfor = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), get_array_length (array_expr)), cforblock);
+		cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
+		cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
+
+		write_expression (cforfragment, array_type.element_type, new CCodeIdentifier ("subiter"), new CCodeElementAccess (array_expr, new CCodeIdentifier ("i")));
+		fragment.append (cfor);
+
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		fragment.append (new CCodeExpressionStatement (iter_call));
+	}
+
+	void write_struct (CCodeFragment fragment, Struct st, CCodeExpression iter_expr, CCodeExpression struct_expr) {
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_STRUCT"));
+		iter_call.add_argument (new CCodeConstant ("NULL"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		fragment.append (new CCodeExpressionStatement (iter_call));
+
+		foreach (Field f in st.get_fields ()) {
+			if (f.binding != MemberBinding.INSTANCE) {
+				continue;
 			}
+
+			write_expression (fragment, f.field_type, new CCodeIdentifier ("subiter"), new CCodeMemberAccess (struct_expr, f.get_cname ()));
 		}
 
-		if (!(m.return_type is VoidType)) {
-			var array_type = m.return_type as ArrayType;
-			if (array_type != null) {
-				if (array_type.element_type.data_type != string_type.data_type) {
-					var cdecl = new CCodeDeclaration (m.return_type.get_cname ());
-					cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
-					block.add_statement (cdecl);
-				}
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		fragment.append (new CCodeExpressionStatement (iter_call));
+	}
 
-				var len_cdecl = new CCodeDeclaration ("int");
-				len_cdecl.add_declarator (new CCodeVariableDeclarator ("result_length1"));
-				block.add_statement (len_cdecl);
-			} else if (m.return_type.get_type_signature ().has_prefix ("a{")) {
-				// hash table return value
-				var type_args = m.return_type.get_type_arguments ();
-				var value_type = type_args.get (1);
-				if (value_type.get_type_signature ().has_prefix ("(")) {
-					// values are structs
-					var cdecl = new CCodeDeclaration ("GHashTable*");
-					cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
-					block.add_statement (cdecl);
-				}
+	void write_value (CCodeFragment fragment, CCodeExpression iter_expr, CCodeExpression expr) {
+		CCodeIfStatement clastif = null;
+
+		foreach (BasicTypeInfo basic_type in basic_types) {
+			// ensure that there is only one case per GType
+			if (basic_type.get_value_function == null) {
+				continue;
 			}
-		}
 
-		var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
+			var type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
+			type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, expr));
+			var type_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, type_call, new CCodeIdentifier (basic_type.gtype));
 
-		ccall.add_argument (new CCodeIdentifier ("self"));
+			var type_block = new CCodeBlock ();
+			var type_fragment = new CCodeFragment ();
+			type_block.add_statement (type_fragment);
 
-		foreach (FormalParameter param in m.get_parameters ()) {
-			var array_type = param.parameter_type as ArrayType;
-			if (array_type != null) {
-				if (param.direction == ParameterDirection.IN) {
-					if (array_type.element_type.data_type == string_type.data_type) {
-						ccall.add_argument (new CCodeIdentifier (param.name));
-						if (!m.no_array_length) {
-							var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
-							cstrvlen.add_argument (new CCodeIdentifier (param.name));
-							ccall.add_argument (cstrvlen);
-						}
-					} else if (dbus_use_ptr_array (array_type)) {
-						ccall.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "pdata"));
-						if (!m.no_array_length) {
-							ccall.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "len"));
-						}
-					} else {
-						ccall.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "data"));
-						if (!m.no_array_length) {
-							ccall.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "len"));
-						}
-					}
-				} else {
-					if (array_type.element_type.data_type != string_type.data_type) {
-						var cdecl = new CCodeDeclaration (param.parameter_type.get_cname ());
-						cdecl.add_declarator (new CCodeVariableDeclarator (param.name));
-						block.add_statement (cdecl);
+			var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
+			iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+			iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_VARIANT"));
+			iter_call.add_argument (new CCodeConstant ("\"%s\"".printf (basic_type.signature)));
+			iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+			type_fragment.append (new CCodeExpressionStatement (iter_call));
 
-						ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
-					} else {
-						ccall.add_argument (new CCodeIdentifier (param.name));
-					}
+			var value_get = new CCodeFunctionCall (new CCodeIdentifier (basic_type.get_value_function));
+			value_get.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, expr));
 
-					if (!m.no_array_length) {
-						var len_cdecl = new CCodeDeclaration ("int");
-						len_cdecl.add_declarator (new CCodeVariableDeclarator ("%s_length1".printf (param.name)));
-						block.add_statement (len_cdecl);
+			write_basic (type_fragment, basic_type, new CCodeIdentifier ("subiter"), value_get);
 
-						ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("%s_length1".printf (param.name))));
-					}
-				}
-			} else if (param.parameter_type.get_type_signature ().has_prefix ("(")) {
-				// struct input or output parameters
-				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
-			} else if (param.parameter_type.get_type_signature ().has_prefix ("a{")) {
-				// hash table output parameter
-				var type_args = param.parameter_type.get_type_arguments ();
-				var value_type = type_args.get (1);
-				if (value_type.get_type_signature ().has_prefix ("(")) {
-					// values are structs
-					ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
-				} else {
-					ccall.add_argument (new CCodeIdentifier (param.name));
-				}
+			iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
+			iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+			iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+			type_fragment.append (new CCodeExpressionStatement (iter_call));
+
+			var cif = new CCodeIfStatement (type_check, type_block);
+			if (clastif == null) {
+				fragment.append (cif);
 			} else {
-				ccall.add_argument (new CCodeIdentifier (param.name));
+				clastif.false_statement = cif;
 			}
+
+			clastif = cif;
 		}
+	}
 
-		CCodeExpression expr;
-		if (m.return_type is VoidType) {
-			expr = ccall;
-		} else {
-			var array_type = m.return_type as ArrayType;
-			if (array_type != null) {
-				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result_length1")));
-				if (array_type.element_type.data_type != string_type.data_type) {
-					expr = new CCodeAssignment (new CCodeIdentifier ("result"), ccall);
-				} else {
-					expr = new CCodeAssignment (new CCodeIdentifier ("*result"), ccall);
-				}
-			} else if (m.return_type.get_type_signature ().has_prefix ("a{")) {
-				// hash table output parameter
-				var type_args = m.return_type.get_type_arguments ();
-				var value_type = type_args.get (1);
-				if (value_type.get_type_signature ().has_prefix ("(")) {
-					// values are structs
-					expr = new CCodeAssignment (new CCodeIdentifier ("result"), ccall);
-				} else {
-					expr = new CCodeAssignment (new CCodeIdentifier ("*result"), ccall);
-				}
+	void write_hash_table (CCodeFragment fragment, ObjectType type, CCodeExpression iter_expr, CCodeExpression hash_table_expr) {
+		var type_args = type.get_type_arguments ();
+		assert (type_args.size == 2);
+		var key_type = type_args.get (0);
+		var value_type = type_args.get (1);
+
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_ARRAY"));
+		iter_call.add_argument (new CCodeConstant ("{%s%s}".printf (key_type.get_type_signature (), value_type.get_type_signature ())));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		fragment.append (new CCodeExpressionStatement (iter_call));
+
+		var cdecl = new CCodeDeclaration ("GHashTableIter");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("iter"));
+		fragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration ("gpointer");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("entry_key_ptr"));
+		cdecl.add_declarator (new CCodeVariableDeclarator ("entry_value_ptr"));
+		fragment.append (cdecl);
+
+		var iter_next_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_next"));
+		iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("iter")));
+		iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("entry_key_ptr")));
+		iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("entry_key_value")));
+
+		var cwhileblock = new CCodeBlock ();
+		var cwhilefragment = new CCodeFragment ();
+		cwhileblock.add_statement (cwhilefragment);
+		var cwhile = new CCodeWhileStatement (iter_next_call, cwhileblock);
+
+		cdecl = new CCodeDeclaration (key_type.get_cname ());
+		cdecl.add_declarator (new CCodeVariableDeclarator ("entry_key"));
+		cwhilefragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration (value_type.get_cname ());
+		cdecl.add_declarator (new CCodeVariableDeclarator ("entry_value"));
+		cwhilefragment.append (cdecl);
+
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_DICT_ENTRY"));
+		iter_call.add_argument (new CCodeConstant ("NULL"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("entryiter")));
+		cwhilefragment.append (new CCodeExpressionStatement (iter_call));
+
+		cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("entry_key"), convert_from_generic_pointer (new CCodeIdentifier ("entry_key_ptr"), key_type))));
+		cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("entry_value"), convert_from_generic_pointer (new CCodeIdentifier ("entry_value_ptr"), value_type))));
+
+		write_expression (cwhilefragment, key_type, new CCodeIdentifier ("entryiter"), new CCodeIdentifier ("entry_key"));
+		write_expression (cwhilefragment, value_type, new CCodeIdentifier ("entryiter"), new CCodeIdentifier ("entry_value"));
+
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("entryiter")));
+		cwhilefragment.append (new CCodeExpressionStatement (iter_call));
+
+		fragment.append (cwhile);
+
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
+		fragment.append (new CCodeExpressionStatement (iter_call));
+	}
+
+	void write_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression expr) {
+		BasicTypeInfo basic_type;
+		if (get_basic_type_info (type.get_type_signature (), out basic_type)) {
+			write_basic (fragment, basic_type, iter_expr, expr);
+		} else if (type is ArrayType) {
+			write_array (fragment, (ArrayType) type, iter_expr, expr);
+		} else if (type.data_type is Struct) {
+			if (type.data_type.get_full_name () == "GLib.Value") {
+				write_value (fragment, iter_expr, expr);
 			} else {
-				expr = new CCodeAssignment (new CCodeIdentifier ("*result"), ccall);
+				write_struct (fragment, (Struct) type.data_type, iter_expr, expr);
 			}
+		} else if (type is ObjectType) {
+			if (type.data_type.get_full_name () == "GLib.HashTable") {
+				write_hash_table (fragment, (ObjectType) type, iter_expr, expr);
+			}
+		} else {
+			Report.error (type.source_reference, "D-Bus serialization of type `%s' is not supported".printf (type.to_string ()));
 		}
+	}
 
-		if (m.get_error_types ().size > 0) {
-			ccall.add_argument (new CCodeIdentifier ("error"));
-		}
+	string generate_dbus_wrapper (Method m, ObjectTypeSymbol sym) {
+		string wrapper_name = "_dbus_%s".printf (m.get_cname ());
 
-		block.add_statement (new CCodeExpressionStatement (expr));
+		// declaration
 
-		foreach (FormalParameter param in m.get_parameters ()) {
-			if (param.direction == ParameterDirection.OUT) {
-				if (param.parameter_type.get_type_signature ().has_prefix ("(")) {
-					// struct output parameter
-					var st = (Struct) param.parameter_type.data_type;
-					var dbus_param = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("dbus_%s".printf (param.name)));
-					var st_expr = new CCodeIdentifier (param.name);
+		CCodeDeclaration cdecl;
 
-					transform_struct_to_value_array (block, st, dbus_param, st_expr, param.name);
-				} else if (param.parameter_type.get_type_signature ().has_prefix ("a{")) {
-					// hash table output parameter
-					var type_args = param.parameter_type.get_type_arguments ();
-					var value_type = type_args.get (1);
-					if (value_type.get_type_signature ().has_prefix ("(")) {
-						// values are structs
-						var st = (Struct) value_type.data_type;
-						var dbus_param = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("dbus_%s".printf (param.name)));
-						var table_expr = new CCodeIdentifier (param.name);
-						transform_struct_hash_table_to_value_array_hash_table (block, st, dbus_param, table_expr, param.name);
-					}
-				}
-			}
-		}
+		var function = new CCodeFunction (wrapper_name, "DBusMessage*");
+		function.modifiers = CCodeModifiers.STATIC;
 
-		if (!(m.return_type is VoidType)) {
-			var array_type = m.return_type as ArrayType;
-			if (array_type != null && array_type.element_type.data_type != string_type.data_type) {
-				var garray = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("dbus_result"));
+		function.add_parameter (new CCodeFormalParameter ("self", sym.get_cname () + "*"));
+		function.add_parameter (new CCodeFormalParameter ("message", "DBusMessage*"));
 
-				var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
-				sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+		var block = new CCodeBlock ();
+		var prefragment = new CCodeFragment ();
+		var postfragment = new CCodeFragment ();
 
-				if (dbus_use_ptr_array (array_type)) {
-					var array_construct = new CCodeFunctionCall (new CCodeIdentifier ("g_ptr_array_sized_new"));
-					array_construct.add_argument (new CCodeIdentifier ("result_length1"));
+		cdecl = new CCodeDeclaration ("DBusMessageIter");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("iter"));
+		cdecl.add_declarator (new CCodeVariableDeclarator ("subiter"));
+		block.add_statement (cdecl);
 
-					block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (garray, array_construct)));
+		block.add_statement (prefragment);
 
-					var memcpy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
-					memcpy_call.add_argument (new CCodeMemberAccess.pointer (garray, "pdata"));
-					memcpy_call.add_argument (new CCodeIdentifier ("result"));
-					memcpy_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeIdentifier ("result_length1"), sizeof_call));
-					block.add_statement (new CCodeExpressionStatement (memcpy_call));
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init"));
+		iter_call.add_argument (new CCodeIdentifier ("message"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("iter")));
+		prefragment.append (new CCodeExpressionStatement (iter_call));
 
-					var len_assignment = new CCodeAssignment (new CCodeMemberAccess.pointer (garray, "len"), new CCodeIdentifier ("result_length1"));
-					block.add_statement (new CCodeExpressionStatement (len_assignment));
-				} else {
-					var array_construct = new CCodeFunctionCall (new CCodeIdentifier ("g_array_new"));
-					array_construct.add_argument (new CCodeConstant ("TRUE"));
-					array_construct.add_argument (new CCodeConstant ("TRUE"));
-					array_construct.add_argument (sizeof_call);
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init_append"));
+		iter_call.add_argument (new CCodeIdentifier ("reply"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("iter")));
+		postfragment.append (new CCodeExpressionStatement (iter_call));
 
-					block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (garray, array_construct)));
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
 
-					var cappend_call = new CCodeFunctionCall (new CCodeIdentifier ("g_array_append_vals"));
-					cappend_call.add_argument (garray);
-					cappend_call.add_argument (new CCodeIdentifier ("result"));
-					cappend_call.add_argument (new CCodeIdentifier ("result_length1"));
-					block.add_statement (new CCodeExpressionStatement (cappend_call));
+		ccall.add_argument (new CCodeIdentifier ("self"));
+
+		foreach (FormalParameter param in m.get_parameters ()) {
+			cdecl = new CCodeDeclaration (param.parameter_type.get_cname ());
+			cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (param.name, default_value_for_type (param.parameter_type, true)));
+			prefragment.append (cdecl);
+			if (param.direction != ParameterDirection.IN
+			    || param.parameter_type.data_type is Struct) {
+				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
+			} else {
+				ccall.add_argument (new CCodeIdentifier (param.name));
+			}
+
+			if (param.parameter_type is ArrayType) {
+				cdecl = new CCodeDeclaration ("int");
+				cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (param.name + "_length1", new CCodeConstant ("0")));
+				prefragment.append (cdecl);
+				if (param.direction != ParameterDirection.IN) {
+					ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name + "_length1")));
+				} else {
+					ccall.add_argument (new CCodeIdentifier (param.name + "_length1"));
 				}
-			} else if (m.return_type.get_type_signature ().has_prefix ("a{")) {
-				// hash table output parameter
-				var type_args = m.return_type.get_type_arguments ();
-				var value_type = type_args.get (1);
-				if (value_type.get_type_signature ().has_prefix ("(")) {
-					// values are structs
-					var st = (Struct) value_type.data_type;
-					var dbus_param = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("dbus_result"));
-					var table_expr = new CCodeIdentifier ("result");
-					transform_struct_hash_table_to_value_array_hash_table (block, st, dbus_param, table_expr, "result");
-				}
 			}
+
+			if (param.direction == ParameterDirection.IN) {
+				var target = new CCodeIdentifier (param.name);
+				var expr = read_expression (prefragment, param.parameter_type, new CCodeIdentifier ("iter"), target);
+				prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
+			} else {
+				write_expression (postfragment, param.parameter_type, new CCodeIdentifier ("iter"), new CCodeIdentifier (param.name));
+			}
 		}
 
-		var no_error = new CCodeBinaryExpression (CCodeBinaryOperator.OR, new CCodeIdentifier ("!error"), new CCodeIdentifier ("!*error"));
-		block.add_statement (new CCodeReturnStatement (no_error));
+		if (!(m.return_type is VoidType)) {
+			cdecl = new CCodeDeclaration (m.return_type.get_cname ());
+			cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
+			block.add_statement (cdecl);
+			block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), ccall)));
 
-		// append to file
+			if (m.return_type is ArrayType) {
+				cdecl = new CCodeDeclaration ("int");
+				cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("result_length1", new CCodeConstant ("0")));
+				prefragment.append (cdecl);
+				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result_length1")));
+			}
 
+			write_expression (postfragment, m.return_type, new CCodeIdentifier ("iter"), new CCodeIdentifier ("result"));
+		} else {
+			block.add_statement (new CCodeExpressionStatement (ccall));
+		}
+
+		cdecl = new CCodeDeclaration ("DBusMessage*");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("reply"));
+		block.add_statement (cdecl);
+
+		var msgcall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_new_method_return"));
+		msgcall.add_argument (new CCodeIdentifier ("message"));
+		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("reply"), msgcall)));
+
+		block.add_statement (postfragment);
+
+		block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("reply")));
+
 		source_type_member_declaration.append (function.copy ());
 
 		function.block = block;
