valaddr = build_fold_addr_expr(tmp);
}
- tree descriptor = gogo->map_descriptor(mt);
+ tree descriptor = mt->map_descriptor_pointer(gogo, loc);
tree type_tree = type_to_tree(this->type_->get_backend(gogo));
if (type_tree == error_mark_node)
return build_constructor(slice_type_tree, init);
}
-// Build a map descriptor for a map of type MAPTYPE.
-
-tree
-Gogo::map_descriptor(Map_type* maptype)
-{
- if (this->map_descriptors_ == NULL)
- this->map_descriptors_ = new Map_descriptors(10);
-
- std::pair<const Map_type*, tree> val(maptype, NULL);
- std::pair<Map_descriptors::iterator, bool> ins =
- this->map_descriptors_->insert(val);
- Map_descriptors::iterator p = ins.first;
- if (!ins.second)
- {
- if (p->second == error_mark_node)
- return error_mark_node;
- go_assert(p->second != NULL_TREE && DECL_P(p->second));
- return build_fold_addr_expr(p->second);
- }
-
- Type* keytype = maptype->key_type();
- Type* valtype = maptype->val_type();
-
- std::string mangled_name = ("__go_map_" + maptype->mangled_name(this));
-
- tree id = get_identifier_from_string(mangled_name);
-
- // Get the type of the map descriptor. This is __go_map_descriptor
- // in libgo/map.h.
-
- tree struct_type = this->map_descriptor_type();
-
- // The map entry type is a struct with three fields. This struct is
- // specific to MAPTYPE. Build it.
-
- tree map_entry_type = make_node(RECORD_TYPE);
-
- Btype* bkey_type = keytype->get_backend(this);
- Btype* bval_type = valtype->get_backend(this);
- map_entry_type = Gogo::builtin_struct(NULL, "__map", map_entry_type, 3,
- "__next",
- build_pointer_type(map_entry_type),
- "__key",
- type_to_tree(bkey_type),
- "__val",
- type_to_tree(bval_type));
- if (map_entry_type == error_mark_node)
- {
- p->second = error_mark_node;
- return error_mark_node;
- }
-
- tree map_entry_key_field = DECL_CHAIN(TYPE_FIELDS(map_entry_type));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(map_entry_key_field)),
- "__key") == 0);
-
- tree map_entry_val_field = DECL_CHAIN(map_entry_key_field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(map_entry_val_field)),
- "__val") == 0);
-
- // Initialize the entries.
-
- tree map_descriptor_field = TYPE_FIELDS(struct_type);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(map_descriptor_field)),
- "__map_descriptor") == 0);
- tree entry_size_field = DECL_CHAIN(map_descriptor_field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(entry_size_field)),
- "__entry_size") == 0);
- tree key_offset_field = DECL_CHAIN(entry_size_field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(key_offset_field)),
- "__key_offset") == 0);
- tree val_offset_field = DECL_CHAIN(key_offset_field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(val_offset_field)),
- "__val_offset") == 0);
-
- VEC(constructor_elt, gc)* descriptor = VEC_alloc(constructor_elt, gc, 6);
-
- constructor_elt* elt = VEC_quick_push(constructor_elt, descriptor, NULL);
- elt->index = map_descriptor_field;
- elt->value = maptype->type_descriptor_pointer(this, BUILTINS_LOCATION);
-
- elt = VEC_quick_push(constructor_elt, descriptor, NULL);
- elt->index = entry_size_field;
- elt->value = TYPE_SIZE_UNIT(map_entry_type);
-
- elt = VEC_quick_push(constructor_elt, descriptor, NULL);
- elt->index = key_offset_field;
- elt->value = byte_position(map_entry_key_field);
-
- elt = VEC_quick_push(constructor_elt, descriptor, NULL);
- elt->index = val_offset_field;
- elt->value = byte_position(map_entry_val_field);
-
- tree constructor = build_constructor(struct_type, descriptor);
-
- tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, struct_type);
- TREE_STATIC(decl) = 1;
- TREE_USED(decl) = 1;
- TREE_READONLY(decl) = 1;
- TREE_CONSTANT(decl) = 1;
- DECL_INITIAL(decl) = constructor;
- make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
- resolve_unique_section(decl, 1, 0);
-
- rest_of_decl_compilation(decl, 1, 0);
-
- go_preserve_from_gc(decl);
- p->second = decl;
-
- return build_fold_addr_expr(decl);
-}
-
-// Return a tree for the type of a map descriptor. This is struct
-// __go_map_descriptor in libgo/runtime/map.h. This is the same for
-// all map types.
-
-tree
-Gogo::map_descriptor_type()
-{
- static tree struct_type;
- Type* tdt = Type::make_type_descriptor_type();
- tree dtype = type_to_tree(tdt->get_backend(this));
- dtype = build_qualified_type(dtype, TYPE_QUAL_CONST);
- return Gogo::builtin_struct(&struct_type, "__go_map_descriptor", NULL_TREE,
- 4,
- "__map_descriptor",
- build_pointer_type(dtype),
- "__entry_size",
- sizetype,
- "__key_offset",
- sizetype,
- "__val_offset",
- sizetype);
-}
-
// Build an interface method table for a type: a list of function
// pointers, one for each interface method. This is used for
// interfaces.
imports_(),
imported_unsafe_(false),
packages_(),
- map_descriptors_(NULL),
init_functions_(),
need_init_fn_(false),
init_fn_name_(),
Array_type::make_array_type_descriptor_type();
Array_type::make_slice_type_descriptor_type();
Map_type::make_map_type_descriptor_type();
+ Map_type::make_map_descriptor_type();
Channel_type::make_chan_type_descriptor_type();
Interface_type::make_interface_type_descriptor_type();
Type::convert_builtin_named_types(this);
slice_constructor(tree slice_type_tree, tree values, tree count,
tree capacity);
- // Build a map descriptor.
- tree
- map_descriptor(Map_type*);
-
- // Return a tree for the type of a map descriptor. This is struct
- // __go_map_descriptor in libgo/runtime/map.h. This is the same for
- // all map types.
- tree
- map_descriptor_type();
-
// Build required interface method tables.
void
build_interface_method_tables();
// Type used to map special names in the sys package.
typedef std::map<std::string, std::string> Sys_names;
- // Hash table mapping map types to map descriptor decls.
- typedef Unordered_map_hash(const Map_type*, tree, Type_hash_identical,
- Type_identical) Map_descriptors;
-
// The backend generator.
Backend* backend_;
// The package we are compiling.
// Mapping from package names we have seen to packages. This does
// not include the package we are compiling.
Packages packages_;
- // Mapping from map types to map descriptors.
- Map_descriptors* map_descriptors_;
// The functions named "init", if there are any.
std::vector<Named_object*> init_functions_;
// Whether we need a magic initialization function.
location);
}
- tree map_type = type_to_tree(this->get_backend(context->gogo()));
+ Gogo* gogo = context->gogo();
+ tree map_type = type_to_tree(this->get_backend(gogo));
static tree new_map_fndecl;
tree ret = Gogo::call_builtin(&new_map_fndecl,
2,
map_type,
TREE_TYPE(TYPE_FIELDS(TREE_TYPE(map_type))),
- context->gogo()->map_descriptor(this),
+ this->map_descriptor_pointer(gogo, location),
sizetype,
expr_tree);
if (ret == error_mark_node)
return Expression::make_struct_composite_literal(mtdt, vals, bloc);
}
+// A mapping from map types to map descriptors.
+
+Map_type::Map_descriptors Map_type::map_descriptors;
+
+// Build a map descriptor for this type. Return a pointer to it.
+
+tree
+Map_type::map_descriptor_pointer(Gogo* gogo, source_location location)
+{
+ Bvariable* bvar = this->map_descriptor(gogo);
+ tree var_tree = var_to_tree(bvar);
+ if (var_tree == error_mark_node)
+ return error_mark_node;
+ return build_fold_addr_expr_loc(location, var_tree);
+}
+
+// Build a map descriptor for this type.
+
+Bvariable*
+Map_type::map_descriptor(Gogo* gogo)
+{
+ std::pair<Map_type*, Bvariable*> val(this, NULL);
+ std::pair<Map_type::Map_descriptors::iterator, bool> ins =
+ Map_type::map_descriptors.insert(val);
+ if (!ins.second)
+ return ins.first->second;
+
+ Type* key_type = this->key_type_;
+ Type* val_type = this->val_type_;
+
+ // The map entry type is a struct with three fields. Build that
+ // struct so that we can get the offsets of the key and value within
+ // a map entry. The first field should technically be a pointer to
+ // this type itself, but since we only care about field offsets we
+ // just use pointer to bool.
+ Type* pbool = Type::make_pointer_type(Type::make_boolean_type());
+ Struct_type* map_entry_type =
+ Type::make_builtin_struct_type(3,
+ "__next", pbool,
+ "__key", key_type,
+ "__val", val_type);
+
+ Type* map_descriptor_type = Map_type::make_map_descriptor_type();
+
+ const Struct_field_list* fields =
+ map_descriptor_type->struct_type()->fields();
+
+ Expression_list* vals = new Expression_list();
+ vals->reserve(4);
+
+ source_location bloc = BUILTINS_LOCATION;
+
+ Struct_field_list::const_iterator p = fields->begin();
+
+ go_assert(p->field_name() == "__map_descriptor");
+ vals->push_back(Expression::make_type_descriptor(this, bloc));
+
+ ++p;
+ go_assert(p->field_name() == "__entry_size");
+ Expression::Type_info type_info = Expression::TYPE_INFO_SIZE;
+ vals->push_back(Expression::make_type_info(map_entry_type, type_info));
+
+ Struct_field_list::const_iterator pf = map_entry_type->fields()->begin();
+ ++pf;
+ go_assert(pf->field_name() == "__key");
+
+ ++p;
+ go_assert(p->field_name() == "__key_offset");
+ vals->push_back(Expression::make_struct_field_offset(map_entry_type, &*pf));
+
+ ++pf;
+ go_assert(pf->field_name() == "__val");
+
+ ++p;
+ go_assert(p->field_name() == "__val_offset");
+ vals->push_back(Expression::make_struct_field_offset(map_entry_type, &*pf));
+
+ ++p;
+ go_assert(p == fields->end());
+
+ Expression* initializer =
+ Expression::make_struct_composite_literal(map_descriptor_type, vals, bloc);
+
+ std::string mangled_name = "__go_map_" + this->mangled_name(gogo);
+ Btype* map_descriptor_btype = map_descriptor_type->get_backend(gogo);
+ Bvariable* bvar = gogo->backend()->immutable_struct(mangled_name, true,
+ map_descriptor_btype,
+ bloc);
+
+ Translate_context context(gogo, NULL, NULL, NULL);
+ context.set_is_const();
+ Bexpression* binitializer = tree_to_expr(initializer->get_tree(&context));
+
+ gogo->backend()->immutable_struct_set_init(bvar, mangled_name, true,
+ map_descriptor_btype, bloc,
+ binitializer);
+
+ ins.first->second = bvar;
+ return bvar;
+}
+
+// Build the type of a map descriptor. This must match the struct
+// __go_map_descriptor in libgo/runtime/map.h.
+
+Type*
+Map_type::make_map_descriptor_type()
+{
+ static Type* ret;
+ if (ret == NULL)
+ {
+ Type* ptdt = Type::make_type_descriptor_ptr_type();
+ Type* uintptr_type = Type::lookup_integer_type("uintptr");
+ Struct_type* sf =
+ Type::make_builtin_struct_type(4,
+ "__map_descriptor", ptdt,
+ "__entry_size", uintptr_type,
+ "__key_offset", uintptr_type,
+ "__val_offset", uintptr_type);
+ ret = Type::make_builtin_named_type("__go_map_descriptor", sf);
+ }
+ return ret;
+}
+
// Reflection string for a map.
void
static Type*
make_map_type_descriptor_type();
+ static Type*
+ make_map_descriptor_type();
+
+ // Build a map descriptor for this type. Return a pointer to it.
+ // The location is the location which causes us to need the
+ // descriptor.
+ tree
+ map_descriptor_pointer(Gogo* gogo, source_location);
+
protected:
int
do_traverse(Traverse*);
do_export(Export*) const;
private:
+ // Mapping from map types to map descriptors.
+ typedef Unordered_map_hash(const Map_type*, Bvariable*, Type_hash_identical,
+ Type_identical) Map_descriptors;
+ static Map_descriptors map_descriptors;
+
+ Bvariable*
+ map_descriptor(Gogo*);
+
// The key type.
Type* key_type_;
// The value type.
{
const struct __go_map_descriptor *descriptor;
const struct __go_type_descriptor *key_descriptor;
- size_t key_offset;
+ uintptr_t key_offset;
_Bool (*equalfn) (const void*, const void*, size_t);
size_t key_hash;
size_t key_size;
{
const struct __go_map_descriptor *descriptor;
const struct __go_type_descriptor *key_descriptor;
- size_t key_offset;
+ uintptr_t key_offset;
size_t key_size;
size_t (*hashfn) (const void *, size_t);
uintptr_t old_bucket_count;
{
const struct __go_map_descriptor *descriptor;
const struct __go_type_descriptor *key_descriptor;
- size_t key_offset;
+ uintptr_t key_offset;
_Bool (*equalfn) (const void*, const void*, size_t);
size_t key_hash;
size_t key_size;
key_type key;
value_type value;
This is the size of that struct. */
- size_t __entry_size;
+ uintptr_t __entry_size;
/* The offset of the key field in a map entry struct. */
- size_t __key_offset;
+ uintptr_t __key_offset;
/* The offset of the value field in a map entry struct (the value
field immediately follows the key field, but there may be some
bytes inserted for alignment). */
- size_t __val_offset;
+ uintptr_t __val_offset;
};
struct __go_map