@@ -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,
@@ -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.
@@ -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);
@@ -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;
@@ -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.
@@ -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)
@@ -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;
}
@@ -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
@@ -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 $@
@@ -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
@@ -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
}
@@ -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) */
@@ -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);
+}
@@ -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);
+ }
+}
@@ -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);
}
@@ -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();
}
@@ -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;
+}
@@ -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;
}
@@ -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);
-}
@@ -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;
-}
@@ -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;
-}
@@ -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;
-}
@@ -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);
@@ -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) */
@@ -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);
@@ -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;
}
@@ -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:
@@ -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;
}
@@ -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);
+}
@@ -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);
}
@@ -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;
}
@@ -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);
}
@@ -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);
}
@@ -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;
@@ -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.
@@ -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;
- }
-}
@@ -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) */
@@ -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);
}
@@ -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;
+}