Patchwork [gccgo] Change representation of interfaces

login
register
mail settings
Submitter Ian Taylor
Date July 28, 2010, 4:12 p.m.
Message ID <mcr62zzmvq4.fsf@google.com>
Download mbox | patch
Permalink /patch/60160/
State New
Headers show

Comments

Ian Taylor - July 28, 2010, 4:12 p.m.
This patch changes the representation of interfaces.  Previously an
interface was represented by a pointer to a three word struct in
memory.  That meant that creating an interface value always required a
memory allocation.

This changes the representation of interfaces to be more like that used
by the gc compiler.  An interface is now a struct with two pointers.  If
the interface is empty--has no methods--then the first field points to
the type descriptor of the object stored in the interface.  If the
interface is not empty, the first field points to the method table for
the interface and the type of the object; the type descriptor is now the
first field in the method table.  Either way, the second field of the
interface points to the object.  For a nil interface the first field is
NULL.

This reduces the number of memory allocations.  In the common case of
storing a pointer value in an interface, no memory allocation occurs.

Committed to gccgo branch.

Ian

Patch

diff -r 86c1bd582754 go/expressions.cc
--- a/go/expressions.cc	Wed Jul 28 07:31:16 2010 -0700
+++ b/go/expressions.cc	Wed Jul 28 09:05:23 2010 -0700
@@ -220,238 +220,18 @@ 
 
   if (lhs_type->interface_type() != NULL)
     {
-      Interface_type* lhs_interface_type = lhs_type->interface_type();
-
       if (rhs_type->interface_type() == NULL)
-	{
-	  // Assignment of a non-interface to an interface.  Since
-	  // RHS_TYPE is a static type, we can fill in the interface
-	  // method table at compile time.
-
-	  // When setting an interface to nil, we just use NULL.
-	  if (rhs_type->is_nil_type())
-	    return fold_convert(lhs_type_tree, null_pointer_node);
-
-	  // This should have been checked already.
-	  gcc_assert(lhs_interface_type->implements_interface(rhs_type,
-							      NULL));
-
-	  // Get the decl for the type descriptor that we are going to
-	  // store in the interface value.
-	  tree type_descriptor = rhs_type->type_descriptor(gogo);
-
-	  // Build the interface method table for this interface and
-	  // this object type: a list of function pointers for each
-	  // interface method.
-	  Named_type* rhs_named_type = rhs_type->named_type();
-	  bool is_pointer = false;
-	  if (rhs_named_type == NULL)
-	    {
-	      rhs_named_type = rhs_type->deref()->named_type();
-	      is_pointer = true;
-	    }
-	  tree method_table;
-	  if (rhs_named_type == NULL)
-	    method_table = null_pointer_node;
-	  else
-	    method_table =
-	      rhs_named_type->interface_method_table(gogo,
-						     lhs_interface_type);
-	  method_table = fold_convert(const_ptr_type_node, method_table);
-
-	  // If we are assigning a pointer to the interface, then the
-	  // interface refers to the original value.  If we are
-	  // assigning a value to the interface, then the interface
-	  // takes ownership of the value.
-
-	  if (rhs_type->points_to() != NULL)
-	    {
-	      static tree new_interface_pointer_decl;
-	      tree call = Gogo::call_builtin(&new_interface_pointer_decl,
-					     location,
-					     "__go_new_interface_pointer",
-					     3,
-					     ptr_type_node,
-					     TREE_TYPE(type_descriptor),
-					     type_descriptor,
-					     const_ptr_type_node,
-					     method_table,
-					     ptr_type_node,
-					     rhs_tree);
-	      return fold_convert(lhs_type_tree, call);
-	    }
-	  else
-	    {
-	      // We need an addressable copy of the value.  We are
-	      // going to copy the value into the interface.
-	      tree make_tmp;
-	      tree object;
-	      if (TREE_ADDRESSABLE(TREE_TYPE(rhs_tree))
-		  || (DECL_P(rhs_tree) && TREE_CODE(rhs_tree) != CONST_DECL))
-		{
-		  make_tmp = NULL_TREE;
-		  object = build_fold_addr_expr(rhs_tree);
-		  if (DECL_P(rhs_tree))
-		    TREE_ADDRESSABLE(rhs_tree) = 1;
-		}
-	      else
-		{
-		  tree tmp;
-		  if (current_function_decl != NULL)
-		    {
-		      tmp = create_tmp_var(TREE_TYPE(rhs_tree),
-					   get_name(rhs_tree));
-		      DECL_INITIAL(tmp) = rhs_tree;
-		      make_tmp = build1(DECL_EXPR, void_type_node, tmp);
-		      TREE_ADDRESSABLE(tmp) = 1;
-		    }
-		  else
-		    {
-		      tmp = build_decl(location, VAR_DECL,
-				       create_tmp_var_name("I"),
-				       TREE_TYPE(rhs_tree));
-		      DECL_EXTERNAL(tmp) = 0;
-		      TREE_PUBLIC(tmp) = 0;
-		      TREE_STATIC(tmp) = 1;
-		      DECL_ARTIFICIAL(tmp) = 1;
-		      if (!TREE_CONSTANT(rhs_tree))
-			make_tmp = build2(MODIFY_EXPR, void_type_node,
-					  tmp, rhs_tree);
-		      else
-			{
-			  TREE_READONLY(tmp) = 1;
-			  TREE_CONSTANT(tmp) = 1;
-			  DECL_INITIAL(tmp) = rhs_tree;
-			  make_tmp = NULL_TREE;
-			}
-		      rest_of_decl_compilation(tmp, 1, 0);
-		    }
-		  object = build_fold_addr_expr(tmp);
-		}
-	      object = fold_convert(ptr_type_node, object);
-
-	      tree object_size = TYPE_SIZE_UNIT(TREE_TYPE(rhs_tree));
-
-	      static tree new_interface_object_decl;
-	      tree call = Gogo::call_builtin(&new_interface_object_decl,
-					     location,
-					     "__go_new_interface_object",
-					     4,
-					     ptr_type_node,
-					     TREE_TYPE(type_descriptor),
-					     type_descriptor,
-					     const_ptr_type_node,
-					     method_table,
-					     sizetype,
-					     object_size,
-					     ptr_type_node,
-					     object);
-	      call = fold_convert(lhs_type_tree, call);
-	      if (make_tmp == NULL_TREE)
-		return call;
-	      else
-		return build2(COMPOUND_EXPR, lhs_type_tree, make_tmp, call);
-	    }
-	}
+	return Expression::convert_type_to_interface(context, lhs_type,
+						     rhs_type, rhs_tree,
+						     location);
       else
-	{
-	  // Converting from one interface type to another.  In the
-	  // general case this requires runtime examination of the
-	  // type method table to match it up with the interface
-	  // methods.
-
-	  // FIXME: If the right hand side is a subset of the left
-	  // hand side, we don't need the runtime examination of
-	  // method names.
-
-	  // FIXME: We could do better with some analysis to determine
-	  // the type of the right hand side.
-
-	  // FIXME: What if one interface should be a pointer and the
-	  // other should be an object?
-
-	  // Build the general interface method table for the left
-	  // hand side interface.
-	  tree lhs_type_descriptor = lhs_type->type_descriptor(gogo);
-
-	  gcc_assert(POINTER_TYPE_P(TREE_TYPE(rhs_tree)));
-
-	  static tree convert_interface_decl;
-	  tree call = Gogo::call_builtin(&convert_interface_decl,
-					 location,
-					 "__go_convert_interface",
-					 3,
-					 ptr_type_node,
-					 TREE_TYPE(lhs_type_descriptor),
-					 lhs_type_descriptor,
-					 ptr_type_node,
-					 fold_convert(ptr_type_node, rhs_tree),
-					 build_pointer_type(boolean_type_node),
-					 null_pointer_node);
-	  // This will panic if the interface conversion fails.
-	  TREE_NOTHROW(convert_interface_decl) = 0;
-	  return fold_convert(lhs_type_tree, call);
-	}
+	return Expression::convert_interface_to_interface(context, lhs_type,
+							  rhs_type, rhs_tree,
+							  false, location);
     }
   else if (rhs_type->interface_type() != NULL)
-    {
-      // Converting from an interface type to a non-interface type.
-      // If the object associated with the interface has the right
-      // type, we get the object.  Otherwise we fail at runtime.
-      tree lhs_type_descriptor = lhs_type->type_descriptor(gogo);
-
-      gcc_assert(POINTER_TYPE_P(TREE_TYPE(rhs_tree)));
-
-      if (lhs_type->points_to() != NULL)
-	{
-	  static tree interface_to_pointer_decl;
-	  tree call = Gogo::call_builtin(&interface_to_pointer_decl,
-					 location,
-					 "__go_interface_to_pointer",
-					 2,
-					 ptr_type_node,
-					 TREE_TYPE(lhs_type_descriptor),
-					 lhs_type_descriptor,
-					 const_ptr_type_node,
-					 fold_convert(const_ptr_type_node,
-						      rhs_tree));
-	  // This call will panic if the conversion fails.
-	  TREE_NOTHROW(interface_to_pointer_decl) = 0;
-	  gcc_assert(POINTER_TYPE_P(lhs_type_tree));
-	  return fold_convert(lhs_type_tree, call);
-	}
-      else
-	{
-	  tree tmp = create_tmp_var(lhs_type_tree, NULL);
-	  DECL_IGNORED_P(tmp) = 0;
-	  tree make_tmp = build1(DECL_EXPR, void_type_node, tmp);
-	  tree tmpaddr = build_fold_addr_expr(tmp);
-	  TREE_ADDRESSABLE(tmp) = 1;
-
-	  tree object_size = DECL_SIZE_UNIT(tmp);
-
-	  static tree interface_to_object_decl;
-	  tree call = Gogo::call_builtin(&interface_to_object_decl,
-					 location,
-					 "__go_interface_to_object",
-					 4,
-					 void_type_node,
-					 ptr_type_node,
-					 fold_convert(ptr_type_node,
-						      tmpaddr),
-					 TREE_TYPE(lhs_type_descriptor),
-					 lhs_type_descriptor,
-					 sizetype,
-					 object_size,
-					 ptr_type_node,
-					 fold_convert(ptr_type_node,
-						      rhs_tree));
-	  // This call will panic if the conversion fails.
-	  TREE_NOTHROW(interface_to_object_decl) = 0;
-	  return build2(COMPOUND_EXPR, lhs_type_tree, make_tmp,
-			build2(COMPOUND_EXPR, lhs_type_tree, call, tmp));
-	}
-    }
+    return Expression::convert_interface_to_type(context, lhs_type, rhs_type,
+						 rhs_tree, location);
   else if (lhs_type->is_open_array_type()
 	   && rhs_type->points_to() != NULL
 	   && rhs_type->points_to()->array_type() != NULL
@@ -623,6 +403,331 @@ 
     }
 }
 
+// Return a tree for a conversion from a non-interface type to an
+// interface type.
+
+tree
+Expression::convert_type_to_interface(Translate_context* context,
+				      Type* lhs_type, Type* rhs_type,
+				      tree rhs_tree, source_location location)
+{
+  Gogo* gogo = context->gogo();
+  Interface_type* lhs_interface_type = lhs_type->interface_type();
+  bool lhs_is_empty = lhs_interface_type->is_empty();
+
+  // Since RHS_TYPE is a static type, we can create the interface
+  // method table at compile time.
+
+  // When setting an interface to nil, we just set both fields to
+  // NULL.
+  if (rhs_type->is_nil_type())
+    return lhs_type->get_init_tree(gogo, false);
+
+  // This should have been checked already.
+  gcc_assert(lhs_interface_type->implements_interface(rhs_type, NULL));
+
+  tree lhs_type_tree = lhs_type->get_tree(gogo);
+  if (lhs_type_tree == error_mark_node)
+    return error_mark_node;
+
+  // An interface is a tuple.  If LHS_TYPE is an empty interface type,
+  // then the first field is the type descriptor for RHS_TYPE.
+  // Otherwise it is the interface method table for RHS_TYPE.
+  tree first_field_value;
+  if (lhs_is_empty)
+    first_field_value = rhs_type->type_descriptor(gogo);
+  else
+    {
+      // Build the interface method table for this interface and this
+      // object type: a list of function pointers for each interface
+      // method.
+      Named_type* rhs_named_type = rhs_type->named_type();
+      bool is_pointer = false;
+      if (rhs_named_type == NULL)
+	{
+	  rhs_named_type = rhs_type->deref()->named_type();
+	  is_pointer = true;
+	}
+      tree method_table;
+      if (rhs_named_type == NULL)
+	method_table = null_pointer_node;
+      else
+	method_table =
+	  rhs_named_type->interface_method_table(gogo, lhs_interface_type,
+						 is_pointer);
+      first_field_value = fold_convert_loc(location, const_ptr_type_node,
+					   method_table);
+    }
+
+  // Start building a constructor for the value we will return.
+
+  VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 2);
+
+  constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+  tree field = TYPE_FIELDS(lhs_type_tree);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
+		    (lhs_is_empty ? "__type_descriptor" : "__methods")) == 0);
+  elt->index = field;
+  elt->value = fold_convert_loc(location, TREE_TYPE(field), first_field_value);
+
+  elt = VEC_quick_push(constructor_elt, init, NULL);
+  field = TREE_CHAIN(field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
+  elt->index = field;
+
+  if (rhs_type->points_to() != NULL)
+    {
+      //  We are assigning a pointer to the interface; the interface
+      // holds the pointer itself.
+      elt->value = rhs_tree;
+      return build_constructor(lhs_type_tree, init);
+    }
+
+  // We are assigning a non-pointer value to the interface; the
+  // interface gets a copy of the value in the heap.
+
+  tree object_size = TYPE_SIZE_UNIT(TREE_TYPE(rhs_tree));
+
+  tree space = gogo->allocate_memory(rhs_type, object_size, location);
+  space = fold_convert_loc(location, build_pointer_type(TREE_TYPE(rhs_tree)),
+			   space);
+  space = save_expr(space);
+
+  tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
+			     build_fold_indirect_ref_loc(location, space),
+			     rhs_tree);
+
+  elt->value = fold_convert_loc(location, TREE_TYPE(field), space);
+
+  return build2(COMPOUND_EXPR, lhs_type_tree, set,
+		build_constructor(lhs_type_tree, init));
+}
+
+// Return a tree for the type descriptor of RHS_TREE, which has
+// interface type RHS_TYPE.  If RHS_TREE is nil the result will be
+// NULL.
+
+tree
+Expression::get_interface_type_descriptor(Translate_context*,
+					  Type* rhs_type, tree rhs_tree,
+					  source_location location)
+{
+  tree rhs_type_tree = TREE_TYPE(rhs_tree);
+  gcc_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
+  tree rhs_field = TYPE_FIELDS(rhs_type_tree);
+  tree v = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
+		  NULL_TREE);
+  if (rhs_type->interface_type()->is_empty())
+    {
+      gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)),
+			"__type_descriptor") == 0);
+      return v;
+    }
+
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__methods")
+	     == 0);
+  gcc_assert(POINTER_TYPE_P(TREE_TYPE(v)));
+  v = save_expr(v);
+  tree v1 = build_fold_indirect_ref_loc(location, v);
+  gcc_assert(TREE_CODE(TREE_TYPE(v1)) == RECORD_TYPE);
+  tree f = TYPE_FIELDS(TREE_TYPE(v1));
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(f)), "__type_descriptor")
+	     == 0);
+  v1 = build3(COMPONENT_REF, TREE_TYPE(f), v1, f, NULL_TREE);
+
+  tree eq = fold_build2_loc(location, EQ_EXPR, boolean_type_node, v,
+			    fold_convert_loc(location, TREE_TYPE(v),
+					     null_pointer_node));
+  tree n = fold_convert_loc(location, TREE_TYPE(v1), null_pointer_node);
+  return fold_build3_loc(location, COND_EXPR, TREE_TYPE(v1),
+			 eq, n, v1);
+}
+
+// Return a tree for the conversion of an interface type to an
+// interface type.
+
+tree
+Expression::convert_interface_to_interface(Translate_context* context,
+					   Type *lhs_type, Type *rhs_type,
+					   tree rhs_tree, bool for_type_guard,
+					   source_location location)
+{
+  Gogo* gogo = context->gogo();
+  Interface_type* lhs_interface_type = lhs_type->interface_type();
+  bool lhs_is_empty = lhs_interface_type->is_empty();
+
+  tree lhs_type_tree = lhs_type->get_tree(gogo);
+  if (lhs_type_tree == error_mark_node)
+    return error_mark_node;
+
+  // In the general case this requires runtime examination of the type
+  // method table to match it up with the interface methods.
+
+  // FIXME: If all of the methods in the right hand side interface
+  // also appear in the left hand side interface, then we don't need
+  // to do a runtime check, although we still need to build a new
+  // method table.
+
+  // Get the type descriptor for the right hand side.  This will be
+  // NULL for a nil interface.
+
+  if (!DECL_P(rhs_tree))
+    rhs_tree = save_expr(rhs_tree);
+
+  tree rhs_type_descriptor =
+    Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree,
+					      location);
+
+  // The result is going to be a two element constructor.
+
+  VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 2);
+
+  constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+  tree field = TYPE_FIELDS(lhs_type_tree);
+  elt->index = field;
+
+  if (for_type_guard)
+    {
+      // A type assertion fails when converting a nil interface.
+      tree lhs_type_descriptor = lhs_type->type_descriptor(gogo);
+      static tree assert_interface_decl;
+      tree call = Gogo::call_builtin(&assert_interface_decl,
+				     location,
+				     "__go_assert_interface",
+				     2,
+				     ptr_type_node,
+				     TREE_TYPE(lhs_type_descriptor),
+				     lhs_type_descriptor,
+				     TREE_TYPE(rhs_type_descriptor),
+				     rhs_type_descriptor);
+      // This will panic if the interface conversion fails.
+      TREE_NOTHROW(assert_interface_decl) = 0;
+      elt->value = fold_convert_loc(location, TREE_TYPE(field), call);
+    }
+  else if (lhs_is_empty)
+    {
+      // A convertion to an empty interface always succeeds, and the
+      // first field is just the type descriptor of the object.
+      gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
+			"__type_descriptor") == 0);
+      gcc_assert(TREE_TYPE(field) == TREE_TYPE(rhs_type_descriptor));
+      elt->value = rhs_type_descriptor;
+    }
+  else
+    {
+      // A conversion to a non-empty interface may fail, but unlike a
+      // type assertion converting nil will always succeed.
+      gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods")
+		 == 0);
+      tree lhs_type_descriptor = lhs_type->type_descriptor(gogo);
+      static tree convert_interface_decl;
+      tree call = Gogo::call_builtin(&convert_interface_decl,
+				     location,
+				     "__go_convert_interface",
+				     2,
+				     ptr_type_node,
+				     TREE_TYPE(lhs_type_descriptor),
+				     lhs_type_descriptor,
+				     TREE_TYPE(rhs_type_descriptor),
+				     rhs_type_descriptor);
+      // This will panic if the interface conversion fails.
+      TREE_NOTHROW(convert_interface_decl) = 0;
+      elt->value = fold_convert_loc(location, TREE_TYPE(field), call);
+    }
+
+  // The second field is simply the object pointer.
+
+  elt = VEC_quick_push(constructor_elt, init, NULL);
+  field = TREE_CHAIN(field);
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
+  elt->index = field;
+
+  tree rhs_type_tree = TREE_TYPE(rhs_tree);
+  gcc_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
+  tree rhs_field = TREE_CHAIN(TYPE_FIELDS(rhs_type_tree));
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__object") == 0);
+  elt->value = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
+		      NULL_TREE);
+
+  return build_constructor(lhs_type_tree, init);
+}
+
+// Return a tree for the conversion of an interface type to a
+// non-interface type.
+
+tree
+Expression::convert_interface_to_type(Translate_context* context,
+				      Type *lhs_type, Type* rhs_type,
+				      tree rhs_tree, source_location location)
+{
+  Gogo* gogo = context->gogo();
+  tree rhs_type_tree = TREE_TYPE(rhs_tree);
+
+  tree lhs_type_tree = lhs_type->get_tree(gogo);
+  if (lhs_type_tree == error_mark_node)
+    return error_mark_node;
+
+  // Call a function to check that the type is valid.  The function
+  // will panic with an appropriate runtime type error if the type is
+  // not valid.
+
+  tree lhs_type_descriptor = lhs_type->type_descriptor(gogo);
+
+  if (!DECL_P(rhs_tree))
+    rhs_tree = save_expr(rhs_tree);
+
+  tree rhs_type_descriptor =
+    Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree,
+					      location);
+
+  tree rhs_inter_descriptor = rhs_type->type_descriptor(gogo);
+
+  static tree check_interface_type_decl;
+  tree call = Gogo::call_builtin(&check_interface_type_decl,
+				 location,
+				 "__go_check_interface_type",
+				 3,
+				 void_type_node,
+				 TREE_TYPE(lhs_type_descriptor),
+				 lhs_type_descriptor,
+				 TREE_TYPE(rhs_type_descriptor),
+				 rhs_type_descriptor,
+				 TREE_TYPE(rhs_inter_descriptor),
+				 rhs_inter_descriptor);
+  // This call will panic if the conversion is invalid.
+  TREE_NOTHROW(check_interface_type_decl) = 0;
+
+  tree stmt_list = NULL_TREE;
+  append_to_statement_list(call, &stmt_list);
+
+  // If the call succeeds, pull out the value.
+  gcc_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
+  tree rhs_field = TREE_CHAIN(TYPE_FIELDS(rhs_type_tree));
+  gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__object") == 0);
+  tree val = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
+		    NULL_TREE);
+
+  // If the value is a pointer, then we can just get it from the
+  // interface.  Otherwise we have to make a copy.
+  if (lhs_type->points_to() != NULL)
+    return build2(COMPOUND_EXPR, lhs_type_tree, stmt_list,
+		  fold_convert_loc(location, lhs_type_tree, val));
+
+  tree tmp = create_tmp_var(lhs_type_tree, NULL);
+  DECL_IGNORED_P(tmp) = 0;
+
+  tree make_tmp = fold_build1_loc(location, DECL_EXPR, void_type_node, tmp);
+  append_to_statement_list(make_tmp, &stmt_list);
+
+  val = fold_convert_loc(location, build_pointer_type(lhs_type_tree), val);
+  val = build_fold_indirect_ref_loc(location, val);
+  tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
+			     tmp, val);
+  append_to_statement_list(set, &stmt_list);
+
+  return build2(COMPOUND_EXPR, lhs_type_tree, stmt_list, tmp);
+}
+
 // Convert an expression to a tree.  This is implemented by the child
 // class.  Not that it is not in general safe to call this multiple
 // times for a single expression, but that we don't catch such errors.
@@ -5847,21 +5952,40 @@ 
   if (left_type->interface_type() != NULL
       && right_type->interface_type() != NULL)
     {
-      static tree interface_compare_decl;
-      left_tree = Gogo::call_builtin(&interface_compare_decl,
-				     location,
-				     "__go_interface_compare",
-				     2,
-				     integer_type_node,
-				     const_ptr_type_node,
-				     fold_convert(const_ptr_type_node,
-						  left_tree),
-				     const_ptr_type_node,
-				     fold_convert(const_ptr_type_node,
-						  right_tree));
-      // This can panic if the type is uncomparable.
-      TREE_NOTHROW(interface_compare_decl) = 0;
-      right_tree = build_int_cst_type(integer_type_node, 0);
+      if (left_type->interface_type()->is_empty())
+	{
+	  gcc_assert(right_type->interface_type()->is_empty());
+	  static tree empty_interface_compare_decl;
+	  left_tree = Gogo::call_builtin(&empty_interface_compare_decl,
+					 location,
+					 "__go_empty_interface_compare",
+					 2,
+					 integer_type_node,
+					 TREE_TYPE(left_tree),
+					 left_tree,
+					 TREE_TYPE(right_tree),
+					 right_tree);
+	  // This can panic if the type is uncomparable.
+	  TREE_NOTHROW(empty_interface_compare_decl) = 0;
+	  right_tree = build_int_cst_type(integer_type_node, 0);
+	}
+      else
+	{
+	  gcc_assert(!right_type->interface_type()->is_empty());
+	  static tree interface_compare_decl;
+	  left_tree = Gogo::call_builtin(&interface_compare_decl,
+					 location,
+					 "__go_interface_compare",
+					 2,
+					 integer_type_node,
+					 TREE_TYPE(left_tree),
+					 left_tree,
+					 TREE_TYPE(right_tree),
+					 right_tree);
+	  // This can panic if the type is uncomparable.
+	  TREE_NOTHROW(interface_compare_decl) = 0;
+	  right_tree = build_int_cst_type(integer_type_node, 0);
+	}
     }
 
   if (left_type->is_nil_type()
@@ -5880,6 +6004,16 @@ 
 	  left_tree = at->value_pointer_tree(context->gogo(), left_tree);
 	  right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
 	}
+      else if (left_type->interface_type() != NULL)
+	{
+	  // An interface is nil if the first field is nil.
+	  tree left_type_tree = TREE_TYPE(left_tree);
+	  gcc_assert(TREE_CODE(left_type_tree) == RECORD_TYPE);
+	  tree field = TYPE_FIELDS(left_type_tree);
+	  left_tree = build3(COMPONENT_REF, TREE_TYPE(field), left_tree,
+			     field, NULL_TREE);
+	  right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
+	}
       else
 	{
 	  gcc_assert(POINTER_TYPE_P(TREE_TYPE(left_tree)));
@@ -7141,7 +7275,6 @@ 
 		    fnname = "__go_print_bool";
 		  }
 		else if (type->points_to() != NULL
-			 || type->interface_type() != NULL
 			 || type->channel_type() != NULL
 			 || type->map_type() != NULL
 			 || type->function_type() != NULL)
@@ -7151,6 +7284,21 @@ 
 		    fnname = "__go_print_pointer";
 		    arg = fold_convert_loc(location, ptr_type_node, arg);
 		  }
+		else if (type->interface_type() != NULL)
+		  {
+		    if (type->interface_type()->is_empty())
+		      {
+			static tree print_empty_interface_fndecl;
+			pfndecl = &print_empty_interface_fndecl;
+			fnname = "__go_print_empty_interface";
+		      }
+		    else
+		      {
+			static tree print_interface_fndecl;
+			pfndecl = &print_interface_fndecl;
+			fnname = "__go_print_interface";
+		      }
+		  }
 		else if (type->is_open_array_type())
 		  {
 		    static tree print_slice_fndecl;
@@ -9280,12 +9428,9 @@ 
     expr = build_fold_indirect_ref(expr);
 
   tree expr_type = TREE_TYPE(expr);
-  gcc_assert(POINTER_TYPE_P(expr_type));
-  expr_type = TREE_TYPE(expr_type);
-  expr = build_fold_indirect_ref(expr);
   gcc_assert(TREE_CODE(expr_type) == RECORD_TYPE);
 
-  tree field = TREE_CHAIN(TYPE_FIELDS(expr_type));
+  tree field = TYPE_FIELDS(expr_type);
   gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods") == 0);
 
   tree table = build3(COMPONENT_REF, TREE_TYPE(field), expr, field, NULL_TREE);
@@ -9295,7 +9440,7 @@ 
   gcc_assert(TREE_CODE(TREE_TYPE(table)) == RECORD_TYPE);
 
   std::string name = Gogo::unpack_hidden_name(this->name_);
-  for (field = TYPE_FIELDS(TREE_TYPE(table));
+  for (field = TREE_CHAIN(TYPE_FIELDS(TREE_TYPE(table)));
        field != NULL_TREE;
        field = TREE_CHAIN(field))
     {
@@ -9319,12 +9464,9 @@ 
     expr = build_fold_indirect_ref(expr);
 
   tree expr_type = TREE_TYPE(expr);
-  gcc_assert(POINTER_TYPE_P(expr_type));
-  expr_type = TREE_TYPE(expr_type);
-  expr = build_fold_indirect_ref(expr);
   gcc_assert(TREE_CODE(expr_type) == RECORD_TYPE);
 
-  tree field = TREE_CHAIN(TREE_CHAIN(TYPE_FIELDS(expr_type)));
+  tree field = TREE_CHAIN(TYPE_FIELDS(expr_type));
   gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
 
   return build3(COMPONENT_REF, TREE_TYPE(field), expr, field, NULL_TREE);
@@ -11231,6 +11373,11 @@ 
   else if (expr_type->is_unsafe_pointer_type()
 	   && this->type_->integer_type() != NULL)
     return convert_to_integer(this->type_->get_tree(gogo), expr_tree);
+  else if (this->type_->interface_type() != NULL)
+    return Expression::convert_interface_to_interface(context, this->type_,
+						      this->expr_->type(),
+						      expr_tree, true,
+						      this->location());
   else
     return Expression::convert_for_assignment(context, this->type_,
 					      this->expr_->type(), expr_tree,
diff -r 86c1bd582754 go/expressions.h
--- a/go/expressions.h	Wed Jul 28 07:31:16 2010 -0700
+++ b/go/expressions.h	Wed Jul 28 09:05:23 2010 -0700
@@ -552,6 +552,14 @@ 
   convert_for_assignment(Translate_context*, Type* lhs_type, Type* rhs_type,
 			 tree rhs_tree, source_location location);
 
+  // Return a tree converting a value of one interface type to another
+  // interface type.  If FOR_TYPE_GUARD is true this is for a type
+  // assertion.
+  static tree
+  convert_interface_to_interface(Translate_context*, Type* lhs_type,
+				 Type* rhs_type, tree rhs_tree,
+				 bool for_type_guard, source_location);
+
   // Return a tree implementing the comparison LHS_TREE OP RHS_TREE.
   // TYPE is the type of both sides.
   static tree
@@ -706,6 +714,18 @@ 
 	    : NULL);
   }
 
+  static tree
+  convert_type_to_interface(Translate_context*, Type*, Type*, tree,
+			    source_location);
+
+  static tree
+  get_interface_type_descriptor(Translate_context*, Type*, tree,
+				source_location);
+
+  static tree
+  convert_interface_to_type(Translate_context*, Type*, Type*, tree,
+			    source_location);
+
   // The expression classification.
   Expression_classification classification_;
   // The location in the input file.
diff -r 86c1bd582754 go/gogo-tree.cc
--- a/go/gogo-tree.cc	Wed Jul 28 07:31:16 2010 -0700
+++ b/go/gogo-tree.cc	Wed Jul 28 09:05:23 2010 -0700
@@ -2305,8 +2305,16 @@ 
       break;
 
     case Type::TYPE_INTERFACE:
-      hash_fn_name = "__go_type_hash_interface";
-      equal_fn_name = "__go_type_equal_interface";
+      if (keytype->interface_type()->is_empty())
+	{
+	  hash_fn_name = "__go_type_hash_empty_interface";
+	  equal_fn_name = "__go_type_equal_empty_interface";
+	}
+      else
+	{
+	  hash_fn_name = "__go_type_hash_interface";
+	  equal_fn_name = "__go_type_equal_interface";
+	}
       break;
 
     case Type::TYPE_NAMED:
@@ -3758,12 +3766,13 @@ 
 
 tree
 Gogo::interface_method_table_for_type(const Interface_type* interface,
-				      const Named_type* type)
+				      Named_type* type,
+				      bool is_pointer)
 {
   const Typed_identifier_list* interface_methods = interface->methods();
   gcc_assert(!interface_methods->empty());
 
-  std::string mangled_name = ("__go_imt_"
+  std::string mangled_name = ((is_pointer ? "__go_pimt__" : "__go_imt_")
 			      + interface->mangled_name(this)
 			      + "__"
 			      + type->mangled_name(this));
@@ -3800,9 +3809,21 @@ 
     }
 
   size_t count = interface_methods->size();
-  VEC(constructor_elt, gc)* pointers = VEC_alloc(constructor_elt, gc, count);
-
-  size_t i = 0;
+  VEC(constructor_elt, gc)* pointers = VEC_alloc(constructor_elt, gc,
+						 count + 1);
+
+  // The first element is the type descriptor.
+  constructor_elt* elt = VEC_quick_push(constructor_elt, pointers, NULL);
+  elt->index = size_zero_node;
+  Type* td_type;
+  if (!is_pointer)
+    td_type = type;
+  else
+    td_type = Type::make_pointer_type(type);
+  elt->value = fold_convert(const_ptr_type_node,
+			    td_type->type_descriptor(this));
+
+  size_t i = 1;
   for (Typed_identifier_list::const_iterator p = interface_methods->begin();
        p != interface_methods->end();
        ++p, ++i)
@@ -3825,15 +3846,14 @@ 
 	gcc_unreachable();
       fndecl = build_fold_addr_expr(fndecl);
 
-      constructor_elt* elt = VEC_quick_push(constructor_elt, pointers,
-					    NULL);
+      elt = VEC_quick_push(constructor_elt, pointers, NULL);
       elt->index = size_int(i);
       elt->value = fold_convert(const_ptr_type_node, fndecl);
     }
-  gcc_assert(i == count);
+  gcc_assert(i == count + 1);
 
   tree array_type = build_array_type(const_ptr_type_node,
-				     build_index_type(size_int(count - 1)));
+				     build_index_type(size_int(count)));
   tree constructor = build_constructor(array_type, pointers);
 
   tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type);
diff -r 86c1bd582754 go/gogo.cc
--- a/go/gogo.cc	Wed Jul 28 07:31:16 2010 -0700
+++ b/go/gogo.cc	Wed Jul 28 09:05:23 2010 -0700
@@ -2302,7 +2302,10 @@ 
 	  // interface, because a pointer can implement more methods
 	  // than a value.
 	  if ((*p)->implements_interface(Type::make_pointer_type(nt), NULL))
-	    nt->interface_method_table(this->gogo_, *p);
+	    {
+	      nt->interface_method_table(this->gogo_, *p, false);
+	      nt->interface_method_table(this->gogo_, *p, true);
+	    }
 	}
     }
   return TRAVERSE_CONTINUE;
diff -r 86c1bd582754 go/gogo.h
--- a/go/gogo.h	Wed Jul 28 07:31:16 2010 -0700
+++ b/go/gogo.h	Wed Jul 28 09:05:23 2010 -0700
@@ -509,7 +509,8 @@ 
   // Build an interface method table for a type: a list of function
   // pointers, one for each interface method.  This returns a decl.
   tree
-  interface_method_table_for_type(const Interface_type*, const Named_type*);
+  interface_method_table_for_type(const Interface_type*, Named_type*,
+				  bool is_pointer);
 
   // Return a tree which allocate SIZE bytes to hold values of type
   // TYPE.
diff -r 86c1bd582754 go/statements.cc
--- a/go/statements.cc	Wed Jul 28 07:31:16 2010 -0700
+++ b/go/statements.cc	Wed Jul 28 09:05:23 2010 -0700
@@ -1248,14 +1248,14 @@ 
   { gcc_unreachable(); }
 
  private:
+  Call_expression*
+  lower_to_empty_interface(const char*);
+
+  Call_expression*
+  lower_to_type(const char*);
+
   void
-  lower_to_interface(Block*);
-
-  void
-  lower_to_pointer_type(Block*);
-
-  void
-  lower_to_type(Block*);
+  lower_to_object_type(Block*, const char*);
 
   // The variable which recieves the converted value.
   Expression* val_;
@@ -1286,7 +1286,8 @@ 
 {
   source_location loc = this->location();
 
-  if (this->expr_->type()->interface_type() == NULL)
+  Type* expr_type = this->expr_->type();
+  if (expr_type->interface_type() == NULL)
     {
       this->report_error(_("type assertion only valid for interface types"));
       return Statement::make_error_statement(loc);
@@ -1300,24 +1301,77 @@ 
   this->val_->traverse_subexpressions(&moe);
   this->ok_->traverse_subexpressions(&moe);
 
+  bool expr_is_empty = expr_type->interface_type()->is_empty();
+  Call_expression* call;
   if (this->type_->interface_type() != NULL)
-    this->lower_to_interface(b);
+    {
+      if (this->type_->interface_type()->is_empty())
+	call = this->lower_to_empty_interface(expr_is_empty
+					      ? "ifaceE2E2"
+					      : "ifaceI2E2");
+      else
+	call = this->lower_to_type(expr_is_empty ? "ifaceE2I2" : "ifaceI2I2");
+    }
   else if (this->type_->points_to() != NULL)
-    this->lower_to_pointer_type(b);
+    call = this->lower_to_type(expr_is_empty ? "ifaceE2T2P" : "ifaceI2T2P");
   else
-    this->lower_to_type(b);
+    {
+      this->lower_to_object_type(b, expr_is_empty ? "ifaceE2T2" : "ifaceI2T2");
+      call = NULL;
+    }
+
+  if (call != NULL)
+    {
+      Expression* res = Expression::make_call_result(call, 0);
+      Statement* s = Statement::make_assignment(this->val_, res, loc);
+      b->add_statement(s);
+
+      res = Expression::make_call_result(call, 1);
+      s = Statement::make_assignment(this->ok_, res, loc);
+      b->add_statement(s);
+    }
 
   return Statement::make_block_statement(b, loc);
 }
 
-// Lower a conversion to an interface type.
-
-void
-Tuple_type_guard_assignment_statement::lower_to_interface(Block* b)
+// Lower a conversion to an empty interface type.
+
+Call_expression*
+Tuple_type_guard_assignment_statement::lower_to_empty_interface(
+    const char *fnname)
 {
   source_location loc = this->location();
 
-  // func ifaceI2I2(*descriptor, *interface) (*interface, bool)
+  // func FNNAME(interface) (empty, bool)
+  source_location bloc = BUILTINS_LOCATION;
+  Typed_identifier_list* param_types = new Typed_identifier_list();
+  param_types->push_back(Typed_identifier("i", this->expr_->type(), bloc));
+  Typed_identifier_list* ret_types = new Typed_identifier_list();
+  ret_types->push_back(Typed_identifier("ret", this->type_, bloc));
+  ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc));
+  Function_type* fntype = Type::make_function_type(NULL, param_types,
+						   ret_types, bloc);
+  Named_object* fn =
+    Named_object::make_function_declaration(fnname, NULL, fntype, bloc);
+  std::string asm_name = "runtime.";
+  asm_name += fnname;
+  fn->func_declaration_value()->set_asm_name(asm_name);
+
+  // val, ok = FNNAME(expr)
+  Expression* func = Expression::make_func_reference(fn, NULL, loc);
+  Expression_list* params = new Expression_list();
+  params->push_back(this->expr_);
+  return Expression::make_call(func, params, loc);
+}
+
+// Lower a conversion to a non-empty interface type or a pointer type.
+
+Call_expression*
+Tuple_type_guard_assignment_statement::lower_to_type(const char* fnname)
+{
+  source_location loc = this->location();
+
+  // func FNNAME(*descriptor, interface) (interface, bool)
   source_location bloc = BUILTINS_LOCATION;
   Typed_identifier_list* param_types = new Typed_identifier_list();
   param_types->push_back(Typed_identifier("inter",
@@ -1329,69 +1383,25 @@ 
   ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc));
   Function_type* fntype = Type::make_function_type(NULL, param_types,
 						   ret_types, bloc);
-  Named_object* ifaceI2I2 =
-    Named_object::make_function_declaration("ifaceI2I2", NULL, fntype, bloc);
-  ifaceI2I2->func_declaration_value()->set_asm_name("runtime.ifaceI2I2");
-
-  // val, ok = ifaceI2I2(type_descriptor, expr)
-  Expression* func = Expression::make_func_reference(ifaceI2I2, NULL, loc);
+  Named_object* fn =
+    Named_object::make_function_declaration(fnname, NULL, fntype, bloc);
+  std::string asm_name = "runtime.";
+  asm_name += fnname;
+  fn->func_declaration_value()->set_asm_name(asm_name);
+
+  // val, ok = FNNAME(type_descriptor, expr)
+  Expression* func = Expression::make_func_reference(fn, NULL, loc);
   Expression_list* params = new Expression_list();
   params->push_back(Expression::make_type_descriptor(this->type_, loc));
   params->push_back(this->expr_);
-  Call_expression* call = Expression::make_call(func, params, loc);
-
-  Expression* res = Expression::make_call_result(call, 0);
-  Statement* s = Statement::make_assignment(this->val_, res, loc);
-  b->add_statement(s);
-
-  res = Expression::make_call_result(call, 1);
-  s = Statement::make_assignment(this->ok_, res, loc);
-  b->add_statement(s);
+  return Expression::make_call(func, params, loc);
 }
 
-// Lower a conversion to a pointer type.
+// Lower a conversion to a non-interface non-pointer type.
 
 void
-Tuple_type_guard_assignment_statement::lower_to_pointer_type(Block* b)
-{
-  source_location loc = this->location();
-
-  // func ifaceI2T2P(*descriptor, *interface) (T, bool)
-  source_location bloc = BUILTINS_LOCATION;
-  Typed_identifier_list* param_types = new Typed_identifier_list();
-  param_types->push_back(Typed_identifier("inter",
-					  Type::make_type_descriptor_ptr_type(),
-					  bloc));
-  param_types->push_back(Typed_identifier("i", this->expr_->type(), bloc));
-  Typed_identifier_list* ret_types = new Typed_identifier_list();
-  ret_types->push_back(Typed_identifier("ret", this->type_, bloc));
-  ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc));
-  Function_type* fntype = Type::make_function_type(NULL, param_types,
-						   ret_types, bloc);
-  Named_object* ifaceI2T2P =
-    Named_object::make_function_declaration("ifaceI2T2P", NULL, fntype, bloc);
-  ifaceI2T2P->func_declaration_value()->set_asm_name("runtime.ifaceI2T2P");
-
-  // val, ok = ifaceI2T2P(type_descriptor, expr)
-  Expression* func = Expression::make_func_reference(ifaceI2T2P, NULL, loc);
-  Expression_list* params = new Expression_list();
-  params->push_back(Expression::make_type_descriptor(this->type_, loc));
-  params->push_back(this->expr_);
-  Call_expression* call = Expression::make_call(func, params, loc);
-
-  Expression* res = Expression::make_call_result(call, 0);
-  Statement* s = Statement::make_assignment(this->val_, res, loc);
-  b->add_statement(s);
-
-  res = Expression::make_call_result(call, 1);
-  s = Statement::make_assignment(this->ok_, res, loc);
-  b->add_statement(s);
-}
-
-// Lower a conversion to a non-interface non-pointer type.
-
-void
-Tuple_type_guard_assignment_statement::lower_to_type(Block* b)
+Tuple_type_guard_assignment_statement::lower_to_object_type(Block* b,
+							    const char *fnname)
 {
   source_location loc = this->location();
 
@@ -1400,7 +1410,7 @@ 
 							    NULL, loc);
   b->add_statement(val_temp);
 
-  // func ifaceI2T2(*descriptor, *interface, *T) bool
+  // func FNNAME(*descriptor, interface, *T) bool
   source_location bloc = BUILTINS_LOCATION;
   Typed_identifier_list* param_types = new Typed_identifier_list();
   param_types->push_back(Typed_identifier("inter",
@@ -1413,12 +1423,14 @@ 
   ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc));
   Function_type* fntype = Type::make_function_type(NULL, param_types,
 						   ret_types, bloc);
-  Named_object* ifaceI2T2 =
-    Named_object::make_function_declaration("ifaceI2T2", NULL, fntype, bloc);
-  ifaceI2T2->func_declaration_value()->set_asm_name("runtime.ifaceI2T2");
-
-  // ok = ifaceI2T2(type_descriptor, expr, &val_temp)
-  Expression* func = Expression::make_func_reference(ifaceI2T2, NULL, loc);
+  Named_object* fn =
+    Named_object::make_function_declaration(fnname, NULL, fntype, bloc);
+  std::string asm_name = "runtime.";
+  asm_name += fnname;
+  fn->func_declaration_value()->set_asm_name(asm_name);
+
+  // ok = FNNAME(type_descriptor, expr, &val_temp)
+  Expression* func = Expression::make_func_reference(fn, NULL, loc);
   Expression_list* params = new Expression_list();
   params->push_back(Expression::make_type_descriptor(this->type_, loc));
   params->push_back(this->expr_);
@@ -3792,7 +3804,7 @@ 
     {
       const source_location bloc = BUILTINS_LOCATION;
 
-      // func ifacetype(*interface) *descriptor
+      // func {efacetype,ifacetype}(*interface) *descriptor
       // FIXME: This should be inlined.
       Typed_identifier_list* param_types = new Typed_identifier_list();
       param_types->push_back(Typed_identifier("i", val_type, bloc));
@@ -3800,13 +3812,17 @@ 
       ret_types->push_back(Typed_identifier("", descriptor_type, bloc));
       Function_type* fntype = Type::make_function_type(NULL, param_types,
 						       ret_types, bloc);
-      Named_object* ifacetype =
-	Named_object::make_function_declaration("ifacetype", NULL, fntype,
-						bloc);
-      ifacetype->func_declaration_value()->set_asm_name("runtime.ifacetype");
+      bool is_empty = val_type->interface_type()->is_empty();
+      const char* fnname = is_empty ? "efacetype" : "ifacetype";
+      Named_object* fn =
+	Named_object::make_function_declaration(fnname, NULL, fntype, bloc);
+      const char* asm_name = (is_empty
+			      ? "runtime.efacetype"
+			      : "runtime.ifacetype");
+      fn->func_declaration_value()->set_asm_name(asm_name);
 
       // descriptor_temp = ifacetype(val_temp)
-      Expression* func = Expression::make_func_reference(ifacetype, NULL, loc);
+      Expression* func = Expression::make_func_reference(fn, NULL, loc);
       Expression_list* params = new Expression_list();
       Expression* ref;
       if (this->var_ == NULL)
diff -r 86c1bd582754 go/types.cc
--- a/go/types.cc	Wed Jul 28 07:31:16 2010 -0700
+++ b/go/types.cc	Wed Jul 28 09:05:23 2010 -0700
@@ -4428,7 +4428,7 @@ 
 bool
 Interface_type::implements_interface(const Type* t, std::string* reason) const
 {
-  if (this->methods_ == NULL || this->methods_->empty())
+  if (this->methods_ == NULL)
     return true;
 
   bool is_pointer = false;
@@ -4556,74 +4556,88 @@ 
 tree
 Interface_type::do_get_tree(Gogo* gogo)
 {
-  // Interface types can refer to themselves via pointers.
-  tree ret = make_node(POINTER_TYPE);
-  SET_TYPE_MODE(ret, ptr_mode);
+  tree dtype = gogo->type_descriptor_type_tree();
+  dtype = build_pointer_type(build_qualified_type(dtype, TYPE_QUAL_CONST));
+
+  if (this->methods_ == NULL)
+    {
+      // At the tree level, use the same type for all empty
+      // interfaces.  This lets us assign them to each other directly
+      // without triggering GIMPLE type errors.
+      static tree empty_interface;
+      return Gogo::builtin_struct(&empty_interface, "__go_empty_interface",
+				  NULL_TREE, 2,
+				  "__type_descriptor",
+				  dtype,
+				  "__object",
+				  ptr_type_node);
+    }
+
+  // Interface types can have methods which refer to the interface
+  // type itself, so build the type first and then the method table.
+  tree ret = make_node(RECORD_TYPE);
+
+  tree field_trees = NULL_TREE;
+  tree* pp = &field_trees;
+
+  // Create the pointer to the method table but don't fill it in yet.
+  tree mtype = make_node(POINTER_TYPE);
+  SET_TYPE_MODE(mtype, ptr_mode);
+  layout_type(mtype);
+
+  tree name_tree = get_identifier("__methods");
+  tree field = build_decl(this->location_, FIELD_DECL, name_tree, mtype);
+  DECL_CONTEXT(field) = ret;
+  *pp = field;
+  pp = &TREE_CHAIN(field);
+
+  name_tree = get_identifier("__object");
+  field = build_decl(this->location_, FIELD_DECL, name_tree, ptr_type_node);
+  DECL_CONTEXT(field) = ret;
+  *pp = field;
+
+  TYPE_FIELDS(ret) = field_trees;
+
   layout_type(ret);
+
   this->set_incomplete_type_tree(ret);
 
   // Build the type of the table of methods.
+  tree method_table = make_node(RECORD_TYPE);
+
+  // The first field is a pointer to the type descriptor.
+  name_tree = get_identifier("__type_descriptor");
+  field = build_decl(this->location_, FIELD_DECL, name_tree, dtype);
+  DECL_CONTEXT(field) = method_table;
+  TYPE_FIELDS(method_table) = field;
+
   std::string last_name = "";
-  tree method_table = make_node(RECORD_TYPE);
-  if (this->methods_ != NULL)
-    {
-      tree* pp = &TYPE_FIELDS(method_table);
-      for (Typed_identifier_list::const_iterator p = this->methods_->begin();
-	   p != this->methods_->end();
-	   ++p)
-	{
-	  std::string name = Gogo::unpack_hidden_name(p->name());
-	  tree name_tree = get_identifier_with_length(name.data(),
-						      name.length());
-	  tree field_type = p->type()->get_tree(gogo);
-	  if (field_type == error_mark_node)
-	    return error_mark_node;
-	  tree field = build_decl(this->location_, FIELD_DECL, name_tree,
-				  field_type);
-	  DECL_CONTEXT(field) = method_table;
-	  *pp = field;
-	  pp = &TREE_CHAIN(field);
-	  // Sanity check: the names should be sorted.
-	  gcc_assert(p->name() > last_name);
-	  last_name = p->name();
-	}
+  pp = &TREE_CHAIN(field);
+  for (Typed_identifier_list::const_iterator p = this->methods_->begin();
+       p != this->methods_->end();
+       ++p)
+    {
+      std::string name = Gogo::unpack_hidden_name(p->name());
+      name_tree = get_identifier_with_length(name.data(), name.length());
+      tree field_type = p->type()->get_tree(gogo);
+      if (field_type == error_mark_node)
+	return error_mark_node;
+      field = build_decl(this->location_, FIELD_DECL, name_tree, field_type);
+      DECL_CONTEXT(field) = method_table;
+      *pp = field;
+      pp = &TREE_CHAIN(field);
+      // Sanity check: the names should be sorted.
+      gcc_assert(p->name() > last_name);
+      last_name = p->name();
     }
   layout_type(method_table);
 
-  // Build the type of the struct.  We don't use finish_builtin_struct
-  // because we want to set the name of the interface to the name of
-  // the type, if possible.
-  tree struct_type = make_node(RECORD_TYPE);
-
-  tree id = get_identifier("__type_descriptor");
-  tree dtype = gogo->type_descriptor_type_tree();
-  dtype = build_qualified_type(dtype, TYPE_QUAL_CONST);
-  tree field = build_decl(this->location_, FIELD_DECL, id,
-			  build_pointer_type(dtype));
-  DECL_CONTEXT(field) = struct_type;
-  TYPE_FIELDS(struct_type) = field;
-  tree last_field = field;
-
-  id = get_identifier("__methods");
-  field = build_decl(this->location_, FIELD_DECL, id,
-		     build_pointer_type(method_table));
-  DECL_CONTEXT(field) = struct_type;
-  TREE_CHAIN(last_field) = field;
-  last_field = field;
-
-  id = get_identifier("__object");
-  field = build_decl(this->location_, FIELD_DECL, id, ptr_type_node);
-  DECL_CONTEXT(field) = struct_type;
-  TREE_CHAIN(last_field) = field;
-
-  layout_type(struct_type);
-
-  // We have to do this by hand since we had to create the node
-  // already.
-  TREE_TYPE(ret) = struct_type;
-  TYPE_POINTER_TO(struct_type) = ret;
-  if (TYPE_STRUCTURAL_EQUALITY_P(struct_type))
-    SET_TYPE_STRUCTURAL_EQUALITY(ret);
+  // Finish up the pointer to the method table.
+  TREE_TYPE(mtype) = method_table;
+  TYPE_POINTER_TO(method_table) = mtype;
+  if (TYPE_STRUCTURAL_EQUALITY_P(method_table))
+    SET_TYPE_STRUCTURAL_EQUALITY(mtype);
+
   return ret;
 }
 
@@ -4632,9 +4646,24 @@ 
 tree
 Interface_type::do_init_tree(Gogo* gogo, bool is_clear)
 {
-  return (is_clear
-	  ? NULL
-	  : fold_convert(this->get_tree(gogo), null_pointer_node));
+  if (is_clear)
+    return NULL;
+
+  tree type_tree = this->get_tree(gogo);
+
+  VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 2);
+  for (tree field = TYPE_FIELDS(type_tree);
+       field != NULL_TREE;
+       field = TREE_CHAIN(field))
+    {
+      constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
+      elt->index = field;
+      elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
+    }
+
+  tree ret = build_constructor(type_tree, init);
+  TREE_CONSTANT(ret) = 1;
+  return ret;
 }
 
 // Type descriptor.
@@ -5171,28 +5200,32 @@ 
 }
 
 // Return a pointer to the interface method table for this type for
-// the interface INTERFACE.  IS_POINTER is true if this is for value
-// of pointer type.
+// the interface INTERFACE.  IS_POINTER is true if this is for a
+// pointer to THIS.
 
 tree
-Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface)
-{
-  if (interface->method_count() == 0)
-    return null_pointer_node;
-
-  if (this->interface_method_tables_ == NULL)
-    this->interface_method_tables_ = new Interface_method_tables(5);
+Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface,
+				   bool is_pointer)
+{
+  gcc_assert(!interface->is_empty());
+
+  Interface_method_tables** pimt = (is_pointer
+				    ? &this->interface_method_tables_
+				    : &this->pointer_interface_method_tables_);
+
+  if (*pimt == NULL)
+    *pimt = new Interface_method_tables(5);
 
   std::pair<const Interface_type*, tree> val(interface, NULL_TREE);
-  std::pair<Interface_method_tables::iterator, bool> ins =
-    this->interface_method_tables_->insert(val);
+  std::pair<Interface_method_tables::iterator, bool> ins = (*pimt)->insert(val);
 
   if (ins.second)
     {
       // This is a new entry in the hash table.
       gcc_assert(ins.first->second == NULL_TREE);
       ins.first->second = gogo->interface_method_table_for_type(interface,
-								this);
+								this,
+								is_pointer);
     }
 
   tree decl = ins.first->second;
@@ -5423,11 +5456,7 @@ 
     return error_mark_node;
 
   tree type_tree = this->type_->get_tree(gogo);
-  // If an interface refers to itself recursively, then we may have an
-  // incomplete type here.  It should get filled in somewhere higher
-  // on the call stack.
-  if (type_tree != error_mark_node
-      && (!POINTER_TYPE_P (type_tree) || TREE_TYPE(type_tree) != NULL_TREE))
+  if (type_tree != error_mark_node)
     {
       tree id = this->named_object_->get_id(gogo);
 
@@ -5447,18 +5476,6 @@ 
 
       tree decl = build_decl(this->location_, TYPE_DECL, id, type_tree);
       TYPE_NAME(type_tree) = decl;
-
-      // Interfaces are pointers to structs; give the struct a name so
-      // that the debugging information will be more useful.
-      if (this->type_->interface_type() != NULL)
-	{
-	  gcc_assert(TREE_CODE(type_tree) == POINTER_TYPE);
-	  tree stree = TREE_TYPE(type_tree);
-	  gcc_assert(TREE_CODE(stree) == RECORD_TYPE);
-	  if (TYPE_NAME(stree) != NULL)
-	    stree = build_variant_type_copy(stree);
-	  TYPE_NAME(stree) = decl;
-	}
     }
   return type_tree;
 }
diff -r 86c1bd582754 go/types.h
--- a/go/types.h	Wed Jul 28 07:31:16 2010 -0700
+++ b/go/types.h	Wed Jul 28 09:05:23 2010 -0700
@@ -2184,10 +2184,15 @@ 
   Interface_type(Typed_identifier_list* methods, source_location location)
     : Type(TYPE_INTERFACE),
       methods_(methods), location_(location)
-  { }
-
-  // Return the list of methods.  This can return NULL if there are no
-  // methods.
+  { gcc_assert(methods == NULL || !methods->empty()); }
+
+  // Return whether this is an empty interface.
+  bool
+  is_empty() const
+  { return this->methods_ == NULL; }
+
+  // Return the list of methods.  This will return NULL for an empty
+  // interface.
   const Typed_identifier_list*
   methods() const
   { return this->methods_; }
@@ -2264,7 +2269,7 @@ 
   do_export(Export*) const;
 
  private:
-  // The list of methods associated with the interface.  This can be
+  // The list of methods associated with the interface.  This will be
   // NULL for the empty interface.
   Typed_identifier_list* methods_;
   // The location where the interface was defined.
@@ -2284,8 +2289,8 @@ 
     : Type(TYPE_NAMED),
       named_object_(named_object), in_function_(NULL), type_(type),
       local_methods_(NULL), all_methods_(NULL),
-      interface_method_tables_(NULL), location_(location), is_visible_(true),
-      is_error_(false), seen_(false)
+      interface_method_tables_(NULL), pointer_interface_method_tables_(NULL),
+      location_(location), is_visible_(true), is_error_(false), seen_(false)
   { }
 
   // Return the associated Named_object.  This holds the actual name.
@@ -2410,9 +2415,12 @@ 
   is_unexported_local_method(Gogo*, const std::string& name) const;
 
   // Return a pointer to the interface method table for this type for
-  // the interface INTERFACE.
+  // the interface INTERFACE.  If IS_POINTER is true, set the type
+  // descriptor to a pointer to this type, otherwise set it to this
+  // type.
   tree
-  interface_method_table(Gogo*, const Interface_type* interface);
+  interface_method_table(Gogo*, const Interface_type* interface,
+			 bool is_pointer);
 
   // Whether this type is compatible with T.
   bool
@@ -2496,6 +2504,9 @@ 
   // A mapping from interfaces to the associated interface method
   // tables for this type.
   Interface_method_tables* interface_method_tables_;
+  // A mapping from interfaces to the associated interface method
+  // tables for pointers to this type.
+  Interface_method_tables* pointer_interface_method_tables_;
   // The location where this type was defined.
   source_location location_;
   // Whether this type is visible.  This is false if this type was
diff -r 86c1bd582754 libgo/Makefile.am
--- a/libgo/Makefile.am	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/Makefile.am	Wed Jul 28 09:05:23 2010 -0700
@@ -280,6 +280,7 @@ 
 endif
 
 runtime_files = \
+	runtime/go-assert-interface.c \
 	runtime/go-bad-index.c \
 	runtime/go-byte-array-to-string.c \
 	runtime/go-breakpoint.c \
@@ -287,20 +288,20 @@ 
 	runtime/go-can-convert-interface.c \
 	runtime/go-chan-cap.c \
 	runtime/go-chan-len.c \
+	runtime/go-check-interface.c \
 	runtime/go-close.c \
 	runtime/go-closed.c \
 	runtime/go-construct-map.c \
 	runtime/go-convert-interface.c \
 	runtime/go-defer.c \
 	runtime/go-deferred-recover.c \
+	runtime/go-eface-compare.c \
 	runtime/go-getgoroot.c \
 	runtime/go-go.c \
 	runtime/go-gomaxprocs.c \
 	runtime/go-int-array-to-string.c \
 	runtime/go-int-to-string.c \
 	runtime/go-interface-compare.c \
-	runtime/go-interface-to-object.c \
-	runtime/go-interface-to-pointer.c \
 	runtime/go-lock-os-thread.c \
 	runtime/go-map-delete.c \
 	runtime/go-map-index.c \
@@ -308,8 +309,6 @@ 
 	runtime/go-map-range.c \
 	runtime/go-nanotime.c \
 	runtime/go-new-channel.c \
-	runtime/go-new-interface-object.c \
-	runtime/go-new-interface-pointer.c \
 	runtime/go-new-map.c \
 	runtime/go-new.c \
 	runtime/go-note.c \
@@ -340,6 +339,7 @@ 
 	runtime/go-strplus.c \
 	runtime/go-strslice.c \
 	runtime/go-trampoline.c \
+	runtime/go-type-eface.c \
 	runtime/go-type-error.c \
 	runtime/go-type-identity.c \
 	runtime/go-type-interface.c \
@@ -368,6 +368,7 @@ 
 	malloc.c \
 	map.c \
 	mprof.c \
+	reflect.c \
 	sigqueue.c \
 	string.c
 
@@ -385,6 +386,10 @@ 
 	./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
 	mv -f $@.tmp $@
 
+reflect.c: $(srcdir)/runtime/reflect.goc goc2c
+	./goc2c --gcc --go-prefix libgo_reflect $< > $@.tmp
+	mv -f $@.tmp $@
+
 sigqueue.c: $(srcdir)/runtime/sigqueue.goc goc2c
 	./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
 	mv -f $@.tmp $@
diff -r 86c1bd582754 libgo/go/bytes/indexbyte.c
--- a/libgo/go/bytes/indexbyte.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/go/bytes/indexbyte.c	Wed Jul 28 09:05:23 2010 -0700
@@ -4,6 +4,8 @@ 
    Use of this source code is governed by a BSD-style
    license that can be found in the LICENSE file.  */
 
+#include <stddef.h>
+
 #include "array.h"
 
 /* This is in C so that the compiler can optimize it
diff -r 86c1bd582754 libgo/go/reflect/value.go
--- a/libgo/go/reflect/value.go	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/go/reflect/value.go	Wed Jul 28 09:05:23 2010 -0700
@@ -867,8 +867,7 @@ 
 		// Hard-wired first argument.
 		if fv.isInterface {
 			// v is a single uninterpreted word
-			firstAddr := v.getAddr()
-			params[0] = addr(&firstAddr)
+			params[0] = v.getAddr()
 		} else {
 			// v is a real value
 			tv := v.Type()
@@ -956,44 +955,16 @@ 
 	if !v.canSet {
 		panic(cannotSet)
 	}
-	if x == nil {
-		*(*addr)(v.addr) = nil
+	// Two different representations; see comment in Get.
+	// Empty interface is easy.
+	t := v.typ.(*InterfaceType)
+	if t.NumMethod() == 0 {
+		*(*interface{})(v.addr) = i
 		return
 	}
-	pv := (*[3]addr)(*(*addr)(v.addr))
-	if pv == nil {
-		pv = new([3]addr)
-		*(*addr)(v.addr) = addr(pv)
-	}
-	pi := *(**[3]addr)((unsafe.Pointer)(&i))
-	pv[0] = pi[0]
-	pv[2] = pi[2]
 
-	vt := v.typ.(*InterfaceType)
-	vmc := vt.NumMethod()
-	xt := x.Type()
-	xmc := xt.NumMethod()
-	if vmc == 0 {
-		pv[1] = nil
-	} else {
-		methods := make([]addr, vmc)
-		j := 0
-		for i := 0; i < vmc; i++ {
-			vm := vt.Method(i)
-			for j < xmc {
-				xm := xt.Method(j)
-				if xm.Name == vm.Name && xm.PkgPath == vm.PkgPath {
-					methods[i] = *(*addr)(xm.Func.getAddr())
-					break
-				}
-				j++
-			}
-			if j >= xmc {
-				panic("no method" + vm.Name)
-			}
-		}
-		pv[1] = addr(&methods[0])
-	}
+	// Non-empty interface requires a runtime check.
+	setiface(t, &i, v.addr)
 }
 
 // Set sets v to the value x.
@@ -1010,12 +981,11 @@ 
 	}
 	p := &t.methods[i]
 
-	// gccgo interface is three words: type descriptor, methods,
-	// data pointer.
-	iv := (*[3]addr)(*(*addr)(v.addr))
-	tab := (*[10000]addr)(iv[1])
-	data := &value{Typeof((*byte)(nil)), iv[2], true}
-	fn := tab[i]
+	// Interface is two words: itable, data.
+	tab := *(**[10000]addr)(v.addr)
+	data := &value{Typeof((*byte)(nil)), addr(uintptr(v.addr) + ptrSize), true}
+
+	fn := tab[i+1]
 	fv := &FuncValue{value: value{runtimeToType(p.typ), addr(&fn), true}, first: data, isInterface: true}
 	return fv
 }
diff -r 86c1bd582754 libgo/runtime/array.h
--- a/libgo/runtime/array.h	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/array.h	Wed Jul 28 09:05:23 2010 -0700
@@ -4,7 +4,8 @@ 
    Use of this source code is governed by a BSD-style
    license that can be found in the LICENSE file.  */
 
-#include <stddef.h>
+#ifndef LIBGO_ARRAY_H
+#define LIBGO_ARRAY_H
 
 /* An open array is an instance of this structure.  */
 
@@ -23,3 +24,5 @@ 
      the __VALUES field.  */
   int __capacity;
 };
+
+#endif /* !defined(LIBGO_ARRAY_H) */
diff -r 86c1bd582754 libgo/runtime/go-assert-interface.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/go-assert-interface.c	Wed Jul 28 09:05:23 2010 -0700
@@ -0,0 +1,50 @@ 
+/* go-assert-interface.c -- interface type assertion for Go.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <assert.h>
+
+#include "go-alloc.h"
+#include "go-panic.h"
+#include "interface.h"
+
+/* This is called by the compiler to implement a type assertion from
+   one interface type to another.  This returns the value that should
+   go in the first field of the result tuple.  The result may be an
+   empty or a non-empty interface.  */
+
+const void *
+__go_assert_interface (const struct __go_type_descriptor *lhs_descriptor,
+		       const struct __go_type_descriptor *rhs_descriptor)
+{
+  const struct __go_interface_type *lhs_interface;
+
+  if (rhs_descriptor == NULL)
+    {
+      struct __go_empty_interface panic_arg;
+
+      /* A type assertion is not permitted with a nil interface.  */
+
+      newTypeAssertionError (NULL,
+			     NULL,
+			     lhs_descriptor,
+			     NULL,
+			     NULL,
+			     lhs_descriptor->__reflection,
+			     NULL,
+			     &panic_arg);
+      __go_panic (panic_arg);
+    }
+
+  /* A type assertion to an empty interface just returns the object
+     descriptor.  */
+
+  assert (lhs_descriptor->__code == GO_INTERFACE);
+  lhs_interface = (const struct __go_interface_type *) lhs_descriptor;
+  if (lhs_interface->__methods.__count == 0)
+    return rhs_descriptor;
+
+  return __go_convert_interface_2 (lhs_descriptor, rhs_descriptor, 0);
+}
diff -r 86c1bd582754 libgo/runtime/go-check-interface.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/go-check-interface.c	Wed Jul 28 09:05:23 2010 -0700
@@ -0,0 +1,48 @@ 
+/* go-check-interface.c -- check an interface type for a conversion
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include <assert.h>
+
+#include "go-panic.h"
+#include "interface.h"
+
+/* Check that an interface type matches for a conversion to a
+   non-interface type.  This panics if the types are bad.  The actual
+   extraction of the object is inlined.  */
+
+void
+__go_check_interface_type (
+    const struct __go_type_descriptor *lhs_descriptor,
+    const struct __go_type_descriptor *rhs_descriptor,
+    const struct __go_type_descriptor *rhs_inter_descriptor)
+{
+  if (rhs_descriptor == NULL)
+    {
+      struct __go_empty_interface panic_arg;
+
+      newTypeAssertionError(NULL, NULL, lhs_descriptor, NULL, NULL,
+			    lhs_descriptor->__reflection, NULL, &panic_arg);
+      __go_panic(panic_arg);
+    }
+
+  if (lhs_descriptor != rhs_descriptor
+      && !__go_type_descriptors_equal (lhs_descriptor, rhs_descriptor)
+      && (lhs_descriptor->__code != GO_UNSAFE_POINTER
+	  || !__go_is_pointer_type (rhs_descriptor))
+      && (rhs_descriptor->__code != GO_UNSAFE_POINTER
+	  || !__go_is_pointer_type (lhs_descriptor)))
+    {
+      struct __go_empty_interface panic_arg;
+
+      newTypeAssertionError(rhs_inter_descriptor, rhs_descriptor,
+			    lhs_descriptor,
+			    rhs_inter_descriptor->__reflection,
+			    rhs_descriptor->__reflection,
+			    lhs_descriptor->__reflection,
+			    NULL, &panic_arg);
+      __go_panic(panic_arg);
+    }
+}
diff -r 86c1bd582754 libgo/runtime/go-convert-interface.c
--- a/libgo/runtime/go-convert-interface.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/go-convert-interface.c	Wed Jul 28 09:05:23 2010 -0700
@@ -5,36 +5,37 @@ 
    license that can be found in the LICENSE file.  */
 
 #include <assert.h>
-#include <stdlib.h>
 
 #include "go-alloc.h"
 #include "go-panic.h"
 #include "interface.h"
 
-/* Convert one interface type into another interface type.
-   LHS_DESCRIPTOR is the type descriptor of the resulting interface.
-   RHS is the interface we are converting, a pointer to struct
-   __go_interface.  We need to build a new set of interface method
-   pointers.  If any interface method is not implemented by the
-   object, the conversion fails.  If SUCCESS is not NULL, we set it to
-   whether or not the conversion succeeds.  If SUCCESS is NULL, and
-   the conversion fails, we panic.  */
+/* This is called when converting one interface type into another
+   interface type.  LHS_DESCRIPTOR is the type descriptor of the
+   resulting interface.  RHS_DESCRIPTOR is the type descriptor of the
+   object being converted.  This builds and returns a new interface
+   method table.  If any method in the LHS_DESCRIPTOR interface is not
+   implemented by the object, the conversion fails.  If the conversion
+   fails, then if MAY_FAIL is true this returns NULL; otherwise, it
+   panics.  */
 
-struct __go_interface *
-__go_convert_interface (const struct __go_type_descriptor* lhs_descriptor,
-			const void *rhs_arg, _Bool *success)
+void *
+__go_convert_interface_2 (const struct __go_type_descriptor *lhs_descriptor,
+			  const struct __go_type_descriptor *rhs_descriptor,
+			  _Bool may_fail)
 {
-  const struct __go_interface *rhs = (const struct __go_interface *) rhs_arg;
   const struct __go_interface_type *lhs_interface;
   int lhs_method_count;
   const struct __go_interface_method* lhs_methods;
   const void **methods;
-  struct __go_interface *ret;
+  const struct __go_uncommon_type *rhs_uncommon;
+  int rhs_method_count;
+  const struct __go_method *p_rhs_method;
+  int i;
 
-  if (rhs == NULL)
+  if (rhs_descriptor == NULL)
     {
-      if (success != NULL)
-	*success = 0;
+      /* A nil value always converts to nil.  */
       return NULL;
     }
 
@@ -44,81 +45,95 @@ 
   lhs_methods = ((const struct __go_interface_method *)
 		 lhs_interface->__methods.__values);
 
-  if (lhs_method_count == 0)
-    methods = NULL;
-  else
+  /* This should not be called for an empty interface.  */
+  assert (lhs_method_count > 0);
+
+  rhs_uncommon = rhs_descriptor->__uncommon;
+  if (rhs_uncommon == NULL || rhs_uncommon->__methods.__count == 0)
     {
-      const struct __go_uncommon_type *rhs_uncommon;
-      int rhs_method_count;
-      const struct __go_method *p_rhs_method;
-      int i;
+      struct __go_empty_interface panic_arg;
 
-      methods = (const void **) __go_alloc (lhs_method_count
-					    * sizeof (void *));
+      if (may_fail)
+	return NULL;
 
-      rhs_uncommon = rhs->__type_descriptor->__uncommon;
-      if (rhs_uncommon == NULL)
+      newTypeAssertionError (NULL,
+			     rhs_descriptor,
+			     lhs_descriptor,
+			     NULL,
+			     rhs_descriptor->__reflection,
+			     lhs_descriptor->__reflection,
+			     lhs_methods[0].__name,
+			     &panic_arg);
+      __go_panic (panic_arg);
+    }
+
+  rhs_method_count = rhs_uncommon->__methods.__count;
+  p_rhs_method = ((const struct __go_method *)
+		  rhs_uncommon->__methods.__values);
+
+  methods = NULL;
+
+  for (i = 0; i < lhs_method_count; ++i)
+    {
+      const struct __go_interface_method *p_lhs_method;
+
+      p_lhs_method = &lhs_methods[i];
+
+      while (rhs_method_count > 0
+	     && (!__go_ptr_strings_equal (p_lhs_method->__name,
+					  p_rhs_method->__name)
+		 || !__go_ptr_strings_equal (p_lhs_method->__pkg_path,
+					     p_rhs_method->__pkg_path)))
 	{
-	  rhs_method_count = 0;
-	  p_rhs_method = NULL;
-	}
-      else
-	{
-	  rhs_method_count = rhs_uncommon->__methods.__count;
-	  p_rhs_method = ((const struct __go_method *)
-			  rhs_uncommon->__methods.__values);
+	  ++p_rhs_method;
+	  --rhs_method_count;
 	}
 
-      for (i = 0; i < lhs_method_count; ++i)
+      if (rhs_method_count == 0
+	  || !__go_type_descriptors_equal (p_lhs_method->__type,
+					   p_rhs_method->__mtype))
 	{
-	  const struct __go_interface_method *p_lhs_method;
+	  struct __go_empty_interface panic_arg;
 
-	  p_lhs_method = &lhs_methods[i];
+	  if (methods != NULL)
+	    __go_free (methods);
 
-	  while (rhs_method_count > 0
-		 && (!__go_ptr_strings_equal (p_lhs_method->__name,
-					      p_rhs_method->__name)
-		     || !__go_ptr_strings_equal (p_lhs_method->__pkg_path,
-						 p_rhs_method->__pkg_path)))
-	    {
-	      ++p_rhs_method;
-	      --rhs_method_count;
-	    }
+	  if (may_fail)
+	    return NULL;
 
-	  if (rhs_method_count == 0
-	      || !__go_type_descriptors_equal (p_lhs_method->__type,
-					       p_rhs_method->__mtype))
-	    {
-	      struct __go_interface *panic_arg;
+	  newTypeAssertionError (NULL,
+				 rhs_descriptor,
+				 lhs_descriptor,
+				 NULL,
+				 rhs_descriptor->__reflection,
+				 lhs_descriptor->__reflection,
+				 p_lhs_method->__name,
+				 &panic_arg);
+	  __go_panic (panic_arg);
+	}
 
-	      if (success != NULL)
-		{
-		  *success = 0;
-		  return NULL;
-		}
+      if (methods == NULL)
+	{
+	  methods = (const void **) __go_alloc ((lhs_method_count + 1)
+						* sizeof (void *));
 
-	      newTypeAssertionError(NULL,
-				    rhs->__type_descriptor,
-				    lhs_descriptor,
-				    NULL,
-				    rhs->__type_descriptor->__reflection,
-				    lhs_descriptor->__reflection,
-				    p_lhs_method->__name,
-				    &panic_arg);
-	      __go_panic (panic_arg);
-	    }
+	  /* The first field in the method table is always the type of
+	     the object.  */
+	  methods[0] = rhs_descriptor;
+	}
 
-	  methods[i] = p_rhs_method->__function;
-	}
+      methods[i + 1] = p_rhs_method->__function;
     }
 
-  ret = (struct __go_interface *) __go_alloc (sizeof (struct __go_interface));
-  ret->__type_descriptor = rhs->__type_descriptor;
-  ret->__methods = methods;
-  ret->__object = rhs->__object;
+  return methods;
+}
 
-  if (success != NULL)
-    *success = 1;
+/* This is called by the compiler to convert a value from one
+   interface type to another.  */
 
-  return ret;
+void *
+__go_convert_interface (const struct __go_type_descriptor *lhs_descriptor,
+			const struct __go_type_descriptor *rhs_descriptor)
+{
+  return __go_convert_interface_2 (lhs_descriptor, rhs_descriptor, 0);
 }
diff -r 86c1bd582754 libgo/runtime/go-deferred-recover.c
--- a/libgo/runtime/go-deferred-recover.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/go-deferred-recover.c	Wed Jul 28 09:05:23 2010 -0700
@@ -75,17 +75,18 @@ 
    because you are not permitted to take the address of a predeclared
    function like recover.  */
 
-struct __go_interface *
+struct __go_empty_interface
 __go_deferred_recover ()
 {
-  struct __go_defer_stack *d;
+  if (__go_panic_defer == NULL
+      || __go_panic_defer->__defer == NULL
+      || __go_panic_defer->__defer->__panic != __go_panic_defer->__panic)
+    {
+      struct __go_empty_interface ret;
 
-  if (__go_panic_defer == NULL)
-    return NULL;
-  d = __go_panic_defer->__defer;
-  if (d == NULL)
-    return 0;
-  if (d->__panic != __go_panic_defer->__panic)
-    return 0;
+      ret.__type_descriptor = NULL;
+      ret.__object = NULL;
+      return ret;
+    }
   return __go_recover();
 }
diff -r 86c1bd582754 libgo/runtime/go-eface-compare.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/go-eface-compare.c	Wed Jul 28 09:05:23 2010 -0700
@@ -0,0 +1,32 @@ 
+/* go-eface-compare.c -- compare two empty values.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "interface.h"
+
+/* Compare two interface values.  Return 0 for equal, not zero for not
+   equal (return value is like strcmp).  */
+
+int
+__go_empty_interface_compare (struct __go_empty_interface left,
+			      struct __go_empty_interface right)
+{
+  const struct __go_type_descriptor *left_descriptor;
+
+  left_descriptor = left.__type_descriptor;
+  if (left_descriptor == NULL && right.__type_descriptor == NULL)
+    return 0;
+  if (left_descriptor == NULL || right.__type_descriptor == NULL)
+    return 1;
+  if (!__go_type_descriptors_equal (left_descriptor,
+				    right.__type_descriptor))
+    return 1;
+  if (__go_is_pointer_type (left_descriptor))
+    return left.__object == right.__object ? 0 : 1;
+  if (!left_descriptor->__equalfn (left.__object, right.__object,
+				   left_descriptor->__size))
+    return 1;
+  return 0;
+}
diff -r 86c1bd582754 libgo/runtime/go-interface-compare.c
--- a/libgo/runtime/go-interface-compare.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/go-interface-compare.c	Wed Jul 28 09:05:23 2010 -0700
@@ -4,34 +4,28 @@ 
    Use of this source code is governed by a BSD-style
    license that can be found in the LICENSE file.  */
 
-#include <assert.h>
-#include <stddef.h>
-#include <stdlib.h>
-
 #include "interface.h"
 
 /* Compare two interface values.  Return 0 for equal, not zero for not
    equal (return value is like strcmp).  */
 
 int
-__go_interface_compare (const void *left_arg, const void* right_arg)
+__go_interface_compare (struct __go_interface left,
+			struct __go_interface right)
 {
-  const struct __go_interface *left =
-    (const struct __go_interface *) left_arg;
-  const struct __go_interface *right =
-    (const struct __go_interface *) right_arg;
+  const struct __go_type_descriptor *left_descriptor;
 
-  if (left == NULL && right == NULL)
+  if (left.__methods == NULL && right.__methods == NULL)
     return 0;
-  if (left == NULL || right == NULL)
+  if (left.__methods == NULL || right.__methods == NULL)
     return 1;
-  if (!__go_type_descriptors_equal (left->__type_descriptor,
-				    right->__type_descriptor))
+  left_descriptor = left.__methods[0];
+  if (!__go_type_descriptors_equal (left_descriptor, right.__methods[0]))
     return 1;
-  if (__go_is_pointer_type (left->__type_descriptor))
-    return left->__object == right->__object ? 0 : 1;
-  if (!left->__type_descriptor->__equalfn (left->__object, right->__object,
-					   left->__type_descriptor->__size))
+  if (__go_is_pointer_type (left_descriptor))
+    return left.__object == right.__object ? 0 : 1;
+  if (!left_descriptor->__equalfn (left.__object, right.__object,
+				   left_descriptor->__size))
     return 1;
   return 0;
 }
diff -r 86c1bd582754 libgo/runtime/go-interface-to-object.c
--- a/libgo/runtime/go-interface-to-object.c	Wed Jul 28 07:31:16 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@ 
-/* go-interface-to-object.c -- get an object from an interface.
-
-   Copyright 2009 The Go Authors. All rights reserved.
-   Use of this source code is governed by a BSD-style
-   license that can be found in the LICENSE file.  */
-
-#include <assert.h>
-
-#include "interface.h"
-#include "go-panic.h"
-
-/* Get an object from an interface.  This checks that the types match,
-   and crashes if they don't.  */
-
-void
-__go_interface_to_object (void *result,
-			  const struct __go_type_descriptor *lhs_descriptor,
-			  size_t object_size, const void *rhs_arg)
-{
-  const struct __go_interface *rhs = (const struct __go_interface *) rhs_arg;
-
-  assert (!__go_is_pointer_type (lhs_descriptor));
-
-  if (rhs == NULL)
-    {
-      __builtin_memset (result, 0, object_size);
-      return;
-    }
-
-  if ((rhs->__type_descriptor != lhs_descriptor
-       && !__go_type_descriptors_equal (rhs->__type_descriptor,
-					lhs_descriptor))
-      || rhs->__type_descriptor->__size != object_size)
-    {
-      struct __go_interface *panic_arg;
-
-      newTypeAssertionError(NULL, rhs->__type_descriptor, lhs_descriptor,
-			    NULL, rhs->__type_descriptor->__reflection,
-			    lhs_descriptor->__reflection, NULL, &panic_arg);
-      __go_panic(panic_arg);
-    }
-  __builtin_memcpy (result, rhs->__object, object_size);
-}
diff -r 86c1bd582754 libgo/runtime/go-interface-to-pointer.c
--- a/libgo/runtime/go-interface-to-pointer.c	Wed Jul 28 07:31:16 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@ 
-/* go-interface-to-pointer.c -- get a pointer from an interface.
-
-   Copyright 2009 The Go Authors. All rights reserved.
-   Use of this source code is governed by a BSD-style
-   license that can be found in the LICENSE file.  */
-
-#include <assert.h>
-
-#include "go-panic.h"
-#include "interface.h"
-
-/* Get a pointer from an interface.  This checks that the types match,
-   and crashes if they don't.  */
-
-void *
-__go_interface_to_pointer (const struct __go_type_descriptor *lhs_descriptor,
-			   const void *rhs_arg)
-{
-  const struct __go_interface *rhs = (const struct __go_interface *) rhs_arg;
-
-  assert (__go_is_pointer_type (lhs_descriptor));
-
-  if (rhs == NULL)
-    return NULL;
-
-  if (rhs->__type_descriptor != lhs_descriptor
-      && !__go_type_descriptors_equal (rhs->__type_descriptor, lhs_descriptor)
-      && lhs_descriptor->__code != GO_UNSAFE_POINTER
-      && rhs->__type_descriptor->__code != GO_UNSAFE_POINTER)
-    {
-      struct __go_interface *panic_arg;
-
-      newTypeAssertionError(NULL, rhs->__type_descriptor, lhs_descriptor,
-			    NULL, rhs->__type_descriptor->__reflection,
-			    lhs_descriptor->__reflection, NULL, &panic_arg);
-      __go_panic(panic_arg);
-    }
-  return rhs->__object;
-}
diff -r 86c1bd582754 libgo/runtime/go-new-interface-object.c
--- a/libgo/runtime/go-new-interface-object.c	Wed Jul 28 07:31:16 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@ 
-/* go-new-interface-object.c -- make a new interface from a non-pointer.
-
-   Copyright 2009 The Go Authors. All rights reserved.
-   Use of this source code is governed by a BSD-style
-   license that can be found in the LICENSE file.  */
-
-#include <assert.h>
-
-#include "go-alloc.h"
-#include "interface.h"
-
-/* Allocate a new interface for a type which is not represented as a
-   pointer.  OBJECT points to the value.  */
-
-struct __go_interface *
-__go_new_interface_object (const struct __go_type_descriptor *type_descriptor,
-			   void *methods, size_t object_size,
-			   const void *object)
-{
-  struct __go_interface *ret;
-
-  assert (!__go_is_pointer_type (type_descriptor));
-  assert (object_size == type_descriptor->__size);
-  ret = __go_alloc (sizeof (struct __go_interface));
-  ret->__type_descriptor = type_descriptor;
-  ret->__methods = methods;
-  ret->__object = __go_alloc (object_size);
-  /* FIXME: Set reference count.  */
-  __builtin_memcpy (ret->__object, object, object_size);
-  return ret;
-}
diff -r 86c1bd582754 libgo/runtime/go-new-interface-pointer.c
--- a/libgo/runtime/go-new-interface-pointer.c	Wed Jul 28 07:31:16 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@ 
-/* go-new-interface-pointer.c -- make a new interface from a pointer value.
-
-   Copyright 2009 The Go Authors. All rights reserved.
-   Use of this source code is governed by a BSD-style
-   license that can be found in the LICENSE file.  */
-
-#include <assert.h>
-
-#include "go-alloc.h"
-#include "interface.h"
-
-/* Allocate a new interface for a type which is represented as a
-   pointer.  OBJECT is the value to be stored in the interface.  */
-
-struct __go_interface *
-__go_new_interface_pointer (const struct __go_type_descriptor *type_descriptor,
-			    void *methods, void *object)
-{
-  struct __go_interface *ret;
-
-  assert (__go_is_pointer_type (type_descriptor));
-  ret = __go_alloc (sizeof (struct __go_interface));
-  ret->__type_descriptor = type_descriptor;
-  ret->__methods = methods;
-  ret->__object = object;
-
-  return ret;
-}
diff -r 86c1bd582754 libgo/runtime/go-panic.c
--- a/libgo/runtime/go-panic.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/go-panic.c	Wed Jul 28 09:05:23 2010 -0700
@@ -36,7 +36,7 @@ 
    function.  */
 
 void
-__go_panic (struct __go_interface *arg)
+__go_panic (struct __go_empty_interface arg)
 {
   struct __go_panic_stack *n;
 
@@ -109,7 +109,7 @@ 
   size_t len;
   unsigned char *sdata;
   struct __go_string s;
-  struct __go_interface *arg;
+  struct __go_empty_interface arg;
 
   len = __builtin_strlen (msg);
   sdata = mallocgc (len, RefNoPointers, 0, 0);
diff -r 86c1bd582754 libgo/runtime/go-panic.h
--- a/libgo/runtime/go-panic.h	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/go-panic.h	Wed Jul 28 09:05:23 2010 -0700
@@ -7,7 +7,8 @@ 
 #ifndef LIBGO_GO_PANIC_H
 #define LIBGO_GO_PANIC_H
 
-struct __go_interface;
+#include "interface.h"
+
 struct __go_string;
 struct __go_type_descriptor;
 struct __go_defer_stack;
@@ -20,7 +21,7 @@ 
   struct __go_panic_stack *__next;
 
   /* The value associated with this panic.  */
-  struct __go_interface *__arg;
+  struct __go_empty_interface __arg;
 
   /* Whether this panic has been recovered.  */
   _Bool __was_recovered;
@@ -60,7 +61,7 @@ 
 #undef __thread
 #endif
 
-extern void __go_panic (struct __go_interface *)
+extern void __go_panic (struct __go_empty_interface)
   __attribute__ ((noreturn));
 
 extern void __go_panic_msg (const char* msg)
@@ -68,7 +69,7 @@ 
 
 extern void __go_print_string (struct __go_string);
 
-extern struct __go_interface * __go_recover (void);
+extern struct __go_empty_interface __go_recover (void);
 
 extern void __go_unwind_stack (void);
 
@@ -81,13 +82,13 @@ 
 				  const struct __go_string *ps2,
 				  const struct __go_string *ps3,
 				  const struct __go_string *pmeth,
-				  struct __go_interface **ret)
+				  struct __go_empty_interface *ret)
   __asm__ ("libgo_runtime.runtime.NewTypeAssertionError");
 
-extern void newErrorString(struct __go_string, struct __go_interface **)
+extern void newErrorString(struct __go_string, struct __go_empty_interface *)
   __asm__ ("libgo_runtime.runtime.NewErrorString");
 
-extern void printany(struct __go_interface *)
+extern void printany(struct __go_empty_interface)
   __asm__ ("libgo_runtime.runtime.Printany");
 
 #endif /* !defined(LIBGO_GO_PANIC_H) */
diff -r 86c1bd582754 libgo/runtime/go-print.c
--- a/libgo/runtime/go-print.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/go-print.c	Wed Jul 28 09:05:23 2010 -0700
@@ -10,6 +10,7 @@ 
 #include "array.h"
 #include "go-panic.h"
 #include "go-string.h"
+#include "interface.h"
 
 /* This implements the various little functions which are called by
    the predeclared functions print/println/panic/panicln.  */
@@ -74,6 +75,18 @@ 
 }
 
 void
+__go_print_empty_interface (struct __go_empty_interface e)
+{
+  printf ("(%p,%p)", e.__type_descriptor, e.__object);
+}
+
+void
+__go_print_interface (struct __go_interface i)
+{
+  printf ("(%p,%p)", i.__methods, i.__object);
+}
+
+void
 __go_print_slice (struct __go_open_array val)
 {
   printf ("[%d/%d]%p", val.__count, val.__capacity, val.__values);
diff -r 86c1bd582754 libgo/runtime/go-recover.c
--- a/libgo/runtime/go-recover.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/go-recover.c	Wed Jul 28 09:05:23 2010 -0700
@@ -48,17 +48,22 @@ 
 /* This is only called when it is valid for the caller to recover the
    value on top of the panic stack, if there is one.  */
 
-struct __go_interface *
+struct __go_empty_interface
 __go_recover ()
 {
   struct __go_panic_stack *p;
 
-  if (__go_panic_defer == NULL)
-    return NULL;
+  if (__go_panic_defer == NULL
+      || __go_panic_defer->__panic == NULL
+      || __go_panic_defer->__panic->__was_recovered)
+    {
+      struct __go_empty_interface ret;
+
+      ret.__type_descriptor = NULL;
+      ret.__object = NULL;
+      return ret;
+    }
   p = __go_panic_defer->__panic;
-  if (p == NULL || p->__was_recovered)
-    return NULL;
-
   p->__was_recovered = 1;
   return p->__arg;
 }
diff -r 86c1bd582754 libgo/runtime/go-reflect-call.c
--- a/libgo/runtime/go-reflect-call.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/go-reflect-call.c	Wed Jul 28 09:05:23 2010 -0700
@@ -102,6 +102,23 @@ 
   return ret;
 }
 
+/* Return an ffi_type for a Go interface type.  This describes the
+   __go_interface and __go_empty_interface structs.  */
+
+static ffi_type *
+go_interface_to_ffi (void)
+{
+  ffi_type *ret;
+
+  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+  ret->type = FFI_TYPE_STRUCT;
+  ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
+  ret->elements[0] = &ffi_type_pointer;
+  ret->elements[1] = &ffi_type_pointer;
+  ret->elements[2] = NULL;
+  return ret;
+}
+
 /* Return an ffi_type for a type described by a
    __go_type_descriptor.  */
 
@@ -167,9 +184,10 @@ 
       return go_struct_to_ffi ((const struct __go_struct_type *) descriptor);
     case GO_STRING:
       return go_string_to_ffi ();
+    case GO_INTERFACE:
+      return go_interface_to_ffi ();
     case GO_CHAN:
     case GO_FUNC:
-    case GO_INTERFACE:
     case GO_MAP:
     case GO_PTR:
     case GO_UNSAFE_POINTER:
diff -r 86c1bd582754 libgo/runtime/go-reflect.c
--- a/libgo/runtime/go-reflect.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/go-reflect.c	Wed Jul 28 09:05:23 2010 -0700
@@ -150,50 +150,48 @@ 
 
 struct reflect_ret
 {
-  struct __go_interface *rettype;
+  struct __go_empty_interface rettype;
   void *addr;
 };
 
-struct reflect_ret Reflect (const struct __go_interface *)
+struct reflect_ret Reflect (struct __go_empty_interface)
   asm ("libgo_unsafe.unsafe.Reflect");
 
 struct reflect_ret
-Reflect (const struct __go_interface *p)
+Reflect (struct __go_empty_interface e)
 {
   struct reflect_ret ret;
 
-  if (p == NULL)
+  if (e.__type_descriptor == NULL)
     {
-      ret.rettype = NULL;
+      ret.rettype.__type_descriptor = NULL;
+      ret.rettype.__object = NULL;
       ret.addr = NULL;
     }
   else
     {
       size_t size;
 
-      ret.rettype = ((struct __go_interface *)
-		     __go_alloc (sizeof (struct __go_interface)));
-      ret.rettype->__type_descriptor =
-	get_descriptor (p->__type_descriptor->__code);
-      ret.rettype->__methods = NULL;
+      ret.rettype.__type_descriptor =
+	get_descriptor (e.__type_descriptor->__code);
 
       /* This memcpy is really just an assignment of a const pointer
 	 to a non-const pointer.  FIXME: We should canonicalize this
 	 pointer, so that for a given type we always return the same
 	 pointer.  */
-      __builtin_memcpy (&ret.rettype->__object, &p->__type_descriptor,
+      __builtin_memcpy (&ret.rettype.__object, &e.__type_descriptor,
 			sizeof (void *));
 
       /* Make a copy of the value.  */
-      size = p->__type_descriptor->__size;
+      size = e.__type_descriptor->__size;
       if (size <= sizeof (uint64_t))
 	ret.addr = __go_alloc (sizeof (uint64_t));
       else
 	ret.addr = __go_alloc (size);
-      if (__go_is_pointer_type (p->__type_descriptor))
-	*(void **) ret.addr = p->__object;
+      if (__go_is_pointer_type (e.__type_descriptor))
+	*(void **) ret.addr = e.__object;
       else
-	__builtin_memcpy (ret.addr, p->__object, size);
+	__builtin_memcpy (ret.addr, e.__object, size);
     }
 
   return ret;
@@ -201,29 +199,29 @@ 
 
 /* Implement unsafe.Typeof.  */
 
-struct __go_interface *Typeof (const struct __go_interface *)
+struct __go_empty_interface Typeof (struct __go_empty_interface)
   asm ("libgo_unsafe.unsafe.Typeof");
 
-struct __go_interface *
-Typeof (const struct __go_interface *p)
+struct __go_empty_interface
+Typeof (const struct __go_empty_interface e)
 {
-  if (p == NULL)
-    return NULL;
+  struct __go_empty_interface ret;
+
+  if (e.__type_descriptor == NULL)
+    {
+      ret.__type_descriptor = NULL;
+      ret.__object = NULL;
+    }
   else
     {
-      struct __go_interface *ret;
-
-      ret = ((struct __go_interface *)
-	     __go_alloc (sizeof (struct __go_interface)));
-      ret->__type_descriptor = get_descriptor (p->__type_descriptor->__code);
-      ret->__methods = NULL;
+      ret.__type_descriptor = get_descriptor (e.__type_descriptor->__code);
 
       /* This memcpy is really just an assignment of a const pointer
 	 to a non-const pointer.  FIXME: We should canonicalize this
 	 pointer, so that for a given type we always return the same
 	 pointer.  */
-      __builtin_memcpy (&ret->__object, &p->__type_descriptor, sizeof (void *));
+      __builtin_memcpy (&ret.__object, &e.__type_descriptor, sizeof (void *));
+    }
 
-      return ret;
-    }
+  return ret;
 }
diff -r 86c1bd582754 libgo/runtime/go-type-eface.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/go-type-eface.c	Wed Jul 28 09:05:23 2010 -0700
@@ -0,0 +1,55 @@ 
+/* go-type-eface.c -- hash and equality empty interface functions.
+
+   Copyright 2010 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+#include "interface.h"
+#include "go-type.h"
+
+/* A hash function for an empty interface.  */
+
+size_t
+__go_type_hash_empty_interface (const void *vval,
+				size_t key_size __attribute__ ((unused)))
+{
+  const struct __go_empty_interface *val;
+  const struct __go_type_descriptor *descriptor;
+  size_t size;
+
+  val = (const struct __go_empty_interface *) vval;
+  descriptor = val->__type_descriptor;
+  if (descriptor == NULL)
+    return 0;
+  size = descriptor->__size;
+  if (__go_is_pointer_type (descriptor))
+    return descriptor->__hashfn (&val->__object, size);
+  else
+    return descriptor->__hashfn (val->__object, size);
+}
+
+/* An equality function for an empty interface.  */
+
+_Bool
+__go_type_equal_empty_interface (const void *vv1, const void *vv2,
+				 size_t key_size __attribute__ ((unused)))
+{
+  const struct __go_empty_interface *v1;
+  const struct __go_empty_interface *v2;
+  const struct __go_type_descriptor* v1_descriptor;
+  const struct __go_type_descriptor* v2_descriptor;
+
+  v1 = (const struct __go_empty_interface *) vv1;
+  v2 = (const struct __go_empty_interface *) vv2;
+  v1_descriptor = v1->__type_descriptor;
+  v2_descriptor = v2->__type_descriptor;
+  if (v1_descriptor == NULL || v2_descriptor == NULL)
+    return v1_descriptor == v2_descriptor;
+  if (!__go_type_descriptors_equal (v1_descriptor, v2_descriptor))
+    return 0;
+  if (__go_is_pointer_type (v1_descriptor))
+    return v1->__object == v2->__object;
+  else
+    return v1_descriptor->__equalfn (v1->__object, v2->__object,
+				     v1_descriptor->__size);
+}
diff -r 86c1bd582754 libgo/runtime/go-type-interface.c
--- a/libgo/runtime/go-type-interface.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/go-type-interface.c	Wed Jul 28 09:05:23 2010 -0700
@@ -4,9 +4,6 @@ 
    Use of this source code is governed by a BSD-style
    license that can be found in the LICENSE file.  */
 
-#include <assert.h>
-#include <stddef.h>
-
 #include "interface.h"
 #include "go-type.h"
 
@@ -17,16 +14,18 @@ 
 			  size_t key_size __attribute__ ((unused)))
 {
   const struct __go_interface *val;
+  const struct __go_type_descriptor *descriptor;
   size_t size;
 
-  val = *(const struct __go_interface * const *) vval;
-  if (val == NULL)
+  val = (const struct __go_interface *) vval;
+  if (val->__methods == NULL)
     return 0;
-  size = val->__type_descriptor->__size;
-  if (__go_is_pointer_type (val->__type_descriptor))
-    return val->__type_descriptor->__hashfn (&val->__object, size);
+  descriptor = (const struct __go_type_descriptor *) val->__methods[0];
+  size = descriptor->__size;
+  if (__go_is_pointer_type (descriptor))
+    return descriptor->__hashfn (&val->__object, size);
   else
-    return val->__type_descriptor->__hashfn (val->__object, size);
+    return descriptor->__hashfn (val->__object, size);
 }
 
 /* An equality function for an interface.  */
@@ -37,17 +36,20 @@ 
 {
   const struct __go_interface *v1;
   const struct __go_interface *v2;
+  const struct __go_type_descriptor* v1_descriptor;
+  const struct __go_type_descriptor* v2_descriptor;
 
-  v1 = *(const struct __go_interface * const *) vv1;
-  v2 = *(const struct __go_interface * const *) vv2;
-  if (v1 == NULL || v2 == NULL)
-    return v1 == v2;
-  if (!__go_type_descriptors_equal (v1->__type_descriptor,
-				    v2->__type_descriptor))
+  v1 = (const struct __go_interface *) vv1;
+  v2 = (const struct __go_interface *) vv2;
+  if (v1->__methods == NULL || v2->__methods == NULL)
+    return v1->__methods == v2->__methods;
+  v1_descriptor = (const struct __go_type_descriptor *) v1->__methods[0];
+  v2_descriptor = (const struct __go_type_descriptor *) v2->__methods[0];
+  if (!__go_type_descriptors_equal (v1_descriptor, v2_descriptor))
     return 0;
-  if (__go_is_pointer_type (v1->__type_descriptor))
+  if (__go_is_pointer_type (v1_descriptor))
     return v1->__object == v2->__object;
   else
-    return v1->__type_descriptor->__equalfn (v1->__object, v2->__object,
-					     v1->__type_descriptor->__size);
+    return v1_descriptor->__equalfn (v1->__object, v2->__object,
+				     v1_descriptor->__size);
 }
diff -r 86c1bd582754 libgo/runtime/go-unreflect.c
--- a/libgo/runtime/go-unreflect.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/go-unreflect.c	Wed Jul 28 09:05:23 2010 -0700
@@ -10,22 +10,21 @@ 
 
 /* Implement unsafe.Unreflect.  */
 
-struct __go_interface *Unreflect (const struct __go_interface *type,
-				  void *object)
+struct __go_empty_interface Unreflect (struct __go_empty_interface type,
+				       void *object)
   asm ("libgo_unsafe.unsafe.Unreflect");
 
-struct __go_interface *
-Unreflect (const struct __go_interface *type, void *object)
+struct __go_empty_interface
+Unreflect (struct __go_empty_interface type, void *object)
 {
-  struct __go_interface *ret;
+  struct __go_empty_interface ret;
 
-  ret = (struct __go_interface *) __go_alloc (sizeof (struct __go_interface));
-  ret->__type_descriptor = type->__object;
-  ret->__methods = NULL;
-  // FIXME: Handle reference counts.
-  if (__go_is_pointer_type (ret->__type_descriptor))
-    ret->__object = *(void **) object;
+  /* FIXME: We should check __type_descriptor to verify that this is
+     really a type descriptor.  */
+  ret.__type_descriptor = type.__object;
+  if (__go_is_pointer_type (ret.__type_descriptor))
+    ret.__object = *(void **) object;
   else
-    ret->__object = object;
+    ret.__object = object;
   return ret;
 }
diff -r 86c1bd582754 libgo/runtime/go-unsafe-new.c
--- a/libgo/runtime/go-unsafe-new.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/go-unsafe-new.c	Wed Jul 28 09:05:23 2010 -0700
@@ -10,18 +10,18 @@ 
 
 /* Implement unsafe.New.  */
 
-void *New (const struct __go_interface *type) asm ("libgo_unsafe.unsafe.New");
+void *New (struct __go_empty_interface type) asm ("libgo_unsafe.unsafe.New");
 
 /* The dynamic type of the argument will be a pointer to a type
    descriptor.  */
 
 void *
-New (const struct __go_interface *type)
+New (struct __go_empty_interface type)
 {
-  const void *object;
   const struct __go_type_descriptor *descriptor;
 
-  object = type->__object;
-  descriptor = (const struct __go_type_descriptor *) object;
+  /* FIXME: We should check __type_descriptor to verify that this is
+     really a type descriptor.  */
+  descriptor = (const struct __go_type_descriptor *) type.__object;
   return __go_alloc (descriptor->__size);
 }
diff -r 86c1bd582754 libgo/runtime/go-unsafe-newarray.c
--- a/libgo/runtime/go-unsafe-newarray.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/go-unsafe-newarray.c	Wed Jul 28 09:05:23 2010 -0700
@@ -10,19 +10,19 @@ 
 
 /* Implement unsafe.NewArray.  */
 
-void *NewArray (const struct __go_interface *type, int n)
+void *NewArray (struct __go_empty_interface type, int n)
   asm ("libgo_unsafe.unsafe.NewArray");
 
 /* The dynamic type of the argument will be a pointer to a type
    descriptor.  */
 
 void *
-NewArray (const struct __go_interface *type, int n)
+NewArray (struct __go_empty_interface type, int n)
 {
-  const void *object;
   const struct __go_type_descriptor *descriptor;
 
-  object = type->__object;
-  descriptor = (const struct __go_type_descriptor *) object;
+  /* FIXME: We should check __type_descriptor to verify that this is
+     really a type descriptor.  */
+  descriptor = (const struct __go_type_descriptor *) type.__object;
   return __go_alloc (descriptor->__size * n);
 }
diff -r 86c1bd582754 libgo/runtime/go-unwind.c
--- a/libgo/runtime/go-unwind.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/go-unwind.c	Wed Jul 28 09:05:23 2010 -0700
@@ -65,7 +65,8 @@ 
       n = ((struct __go_panic_stack *)
 	   __go_alloc (sizeof (struct __go_panic_stack)));
 
-      n->__arg = NULL;
+      n->__arg.__type_descriptor = NULL;
+      n->__arg.__object = NULL;
       n->__was_recovered = 0;
       n->__is_foreign = 1;
       n->__next = __go_panic_defer->__panic;
diff -r 86c1bd582754 libgo/runtime/goc2c.c
--- a/libgo/runtime/goc2c.c	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/goc2c.c	Wed Jul 28 09:05:23 2010 -0700
@@ -336,9 +336,11 @@ 
 	for(i=0; type_table[i].name; i++)
 		if(strcmp(type_table[i].name, p) == 0)
 			return type_table[i].size;
-	fprintf(stderr, "%s:%u: unknown type %s\n", file, lineno, p);
-	exit(1);
-	return 0;
+	if(!gcc) {
+		fprintf(stderr, "%s:%u: unknown type %s\n", file, lineno, p);
+		exit(1);
+	}
+	return 1;
 }
 
 /* Read a list of parameters.  Each parameter is a name and a type.
diff -r 86c1bd582754 libgo/runtime/iface.goc
--- a/libgo/runtime/iface.goc	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/iface.goc	Wed Jul 28 09:05:23 2010 -0700
@@ -11,48 +11,121 @@ 
 typedef struct __go_type_descriptor descriptor;
 typedef const struct __go_type_descriptor const_descriptor;
 typedef struct __go_interface interface;
+typedef struct __go_empty_interface empty_interface;
 
 // Compare two type descriptors.
 func ifacetypeeq(a *descriptor, b *descriptor) (eq bool) {
 	eq = __go_type_descriptors_equal(a, b);
 }
 
-// Return the descriptor for an interface type.
-func ifacetype(i *interface) (d *const_descriptor) {
-	if (i == nil) {
+// Return the descriptor for an empty interface type.n
+func efacetype(e empty_interface) (d *const_descriptor) {
+	return e.__type_descriptor;
+}
+
+// Return the descriptor for a non-empty interface type.
+func ifacetype(i interface) (d *const_descriptor) {
+	if (i.__methods == nil) {
 		return nil;
 	}
-	d = i->__type_descriptor;
+	d = i.__methods[0];
 }
 
-// Convert an interface to a different interface type.
-func ifaceI2I2(inter *descriptor, i *interface) (ret *interface, ok bool) {
-	ret = __go_convert_interface(inter, i, &ok);
+// Convert an empty interface to an empty interface.
+func ifaceE2E2(e empty_interface) (ret empty_interface, ok bool) {
+	ret = e;
+	ok = ret.__type_descriptor != nil;
+}
+
+// Convert a non-empty interface to an empty interface.
+func ifaceI2E2(i interface) (ret empty_interface, ok bool) {
+	if (i.__methods == nil) {
+		ret.__type_descriptor = nil;
+		ret.__object = nil;
+		ok = 0;
+	} else {
+		ret.__type_descriptor = i.__methods[0];
+		ret.__object = i.__object;
+		ok = 1;
+	}
+}
+
+// Convert an empty interface to a non-empty interface.
+func ifaceE2I2(inter *descriptor, e empty_interface) (ret interface, ok bool) {
+	if (e.__type_descriptor == nil) {
+		ret.__methods = nil;
+		ret.__object = nil;
+		ok = 0;
+	} else {
+		ret.__methods = __go_convert_interface_2(inter,
+							 e.__type_descriptor,
+							 1);
+		ret.__object = e.__object;
+		ok = ret.__methods != nil;
+	}
+}
+
+// Convert a non-empty interface to a non-empty interface.
+func ifaceI2I2(inter *descriptor, i interface) (ret interface, ok bool) {
+	if (i.__methods == nil) {
+		ret.__methods = nil;
+		ret.__object = nil;
+		ok = 0;
+	} else {
+		ret.__methods = __go_convert_interface_2(inter,
+							 i.__methods[0], 1);
+		ret.__object = i.__object;
+		ok = ret.__methods != nil;
+	}
+}
+
+// Convert an empty interface to a pointer type.
+func ifaceE2T2P(inter *descriptor, e empty_interface) (ret *void, ok bool) {
+	if (!__go_type_descriptors_equal(inter, e.__type_descriptor)) {
+		ret = nil;
+		ok = 0;
+	} else {
+		ret = e.__object;
+		ok = 1;
+	}
+}
+
+// Convert a non-empty interface to a pointer type.
+func ifaceI2T2P(inter *descriptor, i interface) (ret *void, ok bool) {
+	if (i.__methods == nil
+	    || !__go_type_descriptors_equal(inter, i.__methods[0])) {
+		ret = nil;
+		ok = 0;
+	} else {
+		ret = i.__object;
+		ok = 1;
+	}
+}
+
+// Convert an empty interface to a non-pointer type.
+func ifaceE2T2(inter *descriptor, e empty_interface, ret *void) (ok bool) {
+	if (!__go_type_descriptors_equal(inter, e.__type_descriptor)) {
+		__builtin_memset(ret, 0, inter->__size);
+		ok = 0;
+	} else {
+		__builtin_memcpy(ret, e.__object, inter->__size);
+		ok = 1;
+	}
+}
+
+// Convert a non-empty interface to a non-pointer type.
+func ifaceI2T2(inter *descriptor, i interface, ret *void) (ok bool) {
+	if (i.__methods == nil
+	    || !__go_type_descriptors_equal(inter, i.__methods[0])) {
+		__builtin_memset(ret, 0, inter->__size);
+		ok = 0;
+	} else {
+		__builtin_memcpy(ret, i.__object, inter->__size);
+		ok = 1;
+	}
 }
 
 // Return whether we can convert an interface to a type.
 func ifaceI2Tp(to *descriptor, from *descriptor) (ok bool) {
 	ok = __go_can_convert_to_interface(to, from);
 }
-
-// Convert an interface to a pointer type.
-func ifaceI2T2P(inter *descriptor, i *interface) (ret *void, ok bool) {
-	if (i != nil && __go_type_descriptors_equal(inter, i->__type_descriptor)) {
-		ret = i->__object;
-		ok = 1;
-	} else {
-		ret = nil;
-		ok = 0;
-	}
-}
-
-// Convert an interface to a non-pointer type.
-func ifaceI2T2(inter *descriptor, i *interface, ret *void) (ok bool) {
-	if (i != nil && __go_type_descriptors_equal(inter, i->__type_descriptor)) {
-		__builtin_memcpy(ret, i->__object, inter->__size);
-		ok = 1;
-	} else {
-		__builtin_memset(ret, 0, inter->__size);
-		ok = 0;
-	}
-}
diff -r 86c1bd582754 libgo/runtime/interface.h
--- a/libgo/runtime/interface.h	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/interface.h	Wed Jul 28 09:05:23 2010 -0700
@@ -4,26 +4,23 @@ 
    Use of this source code is governed by a BSD-style
    license that can be found in the LICENSE file.  */
 
-#include <stddef.h>
-#include <stdint.h>
+#ifndef LIBGO_INTERFACE_H
+#define LIBGO_INTERFACE_H
 
 #include "go-type.h"
 
-/* An variable with an interface type is represented as a pointer to
-   this struct.  */
+/* A variable of interface type is an instance of this struct, if the
+   interface has any methods.  */
 
 struct __go_interface
 {
-  /* A pointer to the type descriptor for the dynamic type of the
-     object.  */
-  const struct __go_type_descriptor *__type_descriptor;
-
-  /* A pointer to the methods for the interface.  This is effectively
-     the vtable for this interface.  This is simply a list of pointers
-     to functions.  They are in the same order as the list in the
-     internal representation of the interface, which sorts them by
-     name.  */
-  const void* __methods;
+  /* A pointer to the interface method table.  The first pointer is
+     the type descriptor of the object.  Subsequent pointers are
+     pointers to functions.  This is effectively the vtable for this
+     interface.  The function pointers are in the same order as the
+     list in the internal representation of the interface, which sorts
+     them by name.  */
+  const void **__methods;
 
   /* The object.  If the object is a pointer--if the type descriptor
      code is GO_PTR or GO_UNSAFE_POINTER--then this field is the value
@@ -32,20 +29,29 @@ 
   void *__object;
 };
 
-extern struct __go_interface *
-__go_new_interface_pointer (const struct __go_type_descriptor *descriptor,
-			    void *methods, void *object);
+/* A variable of an empty interface type is an instance of this
+   struct.  */
 
-extern struct __go_interface *
-__go_new_interface_object (const struct __go_type_descriptor *descriptor,
-			   void *methods, size_t object_size,
-			   const void* object);
+struct __go_empty_interface
+{
+  /* The type descriptor of the object.  */
+  const struct __go_type_descriptor *__type_descriptor;
 
-extern struct __go_interface *
+  /* The object.  This is the same as __go_interface above.  */
+  void *__object;
+};
+
+extern void *
 __go_convert_interface (const struct __go_type_descriptor *,
-			const void *rhs,
-			_Bool *success);
+			const struct __go_type_descriptor *);
+
+extern void *
+__go_convert_interface_2 (const struct __go_type_descriptor *,
+			  const struct __go_type_descriptor *,
+			  _Bool may_fail);
 
 extern _Bool
 __go_can_convert_to_interface(const struct __go_type_descriptor *,
 			      const struct __go_type_descriptor *);
+
+#endif /* !defined(LIBGO_INTERFACE_H) */
diff -r 86c1bd582754 libgo/runtime/malloc.goc
--- a/libgo/runtime/malloc.goc	Wed Jul 28 07:31:16 2010 -0700
+++ b/libgo/runtime/malloc.goc	Wed Jul 28 09:05:23 2010 -0700
@@ -16,7 +16,7 @@ 
 #include "go-string.h"
 #include "interface.h"
 #include "go-type.h"
-typedef struct __go_interface* Eface;
+typedef struct __go_empty_interface Eface;
 typedef struct __go_type_descriptor Type;
 typedef struct __go_func_type FuncType;
 
@@ -297,34 +297,34 @@ 
 	uintptr size;
 	const FuncType *ft;
 
-	if(obj == nil) {
+	if(obj.__type_descriptor == nil) {
 		printf("runtime.SetFinalizer: first argument is nil interface\n");
 	throw:
 		throw("runtime.SetFinalizer");
 	}
-	if(obj->__type_descriptor->__code != GO_PTR) {
-		printf("runtime.SetFinalizer: first argument is %.*s, not pointer\n", (int)obj->__type_descriptor->__reflection->__length, obj->__type_descriptor->__reflection->__data);
+	if(obj.__type_descriptor->__code != GO_PTR) {
+		printf("runtime.SetFinalizer: first argument is %.*s, not pointer\n", (int)obj.__type_descriptor->__reflection->__length, obj.__type_descriptor->__reflection->__data);
 		goto throw;
 	}
-	if(!mlookup(obj->__object, &base, &size, nil, nil) || obj->__object != base) {
+	if(!mlookup(obj.__object, &base, &size, nil, nil) || obj.__object != base) {
 		printf("runtime.SetFinalizer: pointer not at beginning of allocated block\n");
 		goto throw;
 	}
 	ft = nil;
-	if(finalizer != nil) {
-		if(finalizer->__type_descriptor->__code != GO_FUNC) {
+	if(finalizer.__type_descriptor != nil) {
+		if(finalizer.__type_descriptor->__code != GO_FUNC) {
 		badfunc:
-		  printf("runtime.SetFinalizer: second argument is %.*s, not func(%.*s)\n", (int)finalizer->__type_descriptor->__reflection->__length, finalizer->__type_descriptor->__reflection->__data, (int)obj->__type_descriptor->__reflection->__length, obj->__type_descriptor->__reflection->__data);
+		  printf("runtime.SetFinalizer: second argument is %.*s, not func(%.*s)\n", (int)finalizer.__type_descriptor->__reflection->__length, finalizer.__type_descriptor->__reflection->__data, (int)obj.__type_descriptor->__reflection->__length, obj.__type_descriptor->__reflection->__data);
 			goto throw;
 		}
-		ft = (const FuncType*)finalizer->__type_descriptor;
-		if(ft->__dotdotdot || ft->__in.__count != 1 || !__go_type_descriptors_equal(*(Type**)ft->__in.__values, obj->__type_descriptor))
+		ft = (const FuncType*)finalizer.__type_descriptor;
+		if(ft->__dotdotdot || ft->__in.__count != 1 || !__go_type_descriptors_equal(*(Type**)ft->__in.__values, obj.__type_descriptor))
 			goto badfunc;
 
-		if(getfinalizer(obj->__object, 0)) {
+		if(getfinalizer(obj.__object, 0)) {
 			printf("runtime.SetFinalizer: finalizer already set");
 			goto throw;
 		}
 	}
-	addfinalizer(obj->__object, finalizer ? *(void**)finalizer->__object : nil, ft);
+	addfinalizer(obj.__object, finalizer.__type_descriptor != nil ? *(void**)finalizer.__object : nil, ft);
 }
diff -r 86c1bd582754 libgo/runtime/reflect.goc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/reflect.goc	Wed Jul 28 09:05:23 2010 -0700
@@ -0,0 +1,35 @@ 
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package reflect
+#include "go-type.h"
+#include "interface.h"
+#define nil NULL
+typedef unsigned char byte;
+
+typedef struct __go_interface Iface;
+typedef struct __go_empty_interface Eface;
+
+func setiface(typ *byte, x *byte, ret *byte) {
+	struct __go_interface_type *t;
+	const struct __go_type_descriptor* xt;
+
+	/* FIXME: We should check __type_descriptor to verify that
+	   this is really a type descriptor.  */
+	t = (struct __go_interface_type *)typ;
+	if(t->__methods.__count == 0) {
+		// already an empty interface
+		*(Eface*)ret = *(Eface*)x;
+		return;
+	}
+	xt = ((Eface*)x)->__type_descriptor;
+	if(xt == nil) {
+		// can assign nil to any interface
+		((Iface*)ret)->__methods = nil;
+		((Iface*)ret)->__object = nil;
+		return;
+	}
+	((Iface*)ret)->__methods = __go_convert_interface(&t->__common, xt);
+	((Iface*)ret)->__object = ((Eface*)x)->__object;
+}