mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-26 16:51:01 +08:00
compiler: Add precise type information on the heap.
* go-gcc.cc (Gcc_backend::implicit_variable): Remove init parameter. Add is_hidden parameter. (Gcc_backend::implicit_variable_set_init): New method. (Gcc_backend::implicit_variable_reference): New method. From-SVN: r214894
This commit is contained in:
parent
d2e4feca24
commit
f1d2ac4f84
@ -1,3 +1,10 @@
|
||||
2014-09-03 Chris Manghane <cmang@google.com>
|
||||
|
||||
* go-gcc.cc (Gcc_backend::implicit_variable): Remove init
|
||||
parameter. Add is_hidden parameter.
|
||||
(Gcc_backend::implicit_variable_set_init): New method.
|
||||
(Gcc_backend::implicit_variable_reference): New method.
|
||||
|
||||
2014-08-08 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* go-gcc.cc (Gcc_backend::compound_statement): Don't return
|
||||
|
@ -389,9 +389,16 @@ class Gcc_backend : public Backend
|
||||
Location, Bstatement**);
|
||||
|
||||
Bvariable*
|
||||
implicit_variable(const std::string&, Btype*, Bexpression*, bool, bool,
|
||||
implicit_variable(const std::string&, Btype*, bool, bool, bool,
|
||||
size_t);
|
||||
|
||||
void
|
||||
implicit_variable_set_init(Bvariable*, const std::string&, Btype*,
|
||||
bool, bool, bool, Bexpression*);
|
||||
|
||||
Bvariable*
|
||||
implicit_variable_reference(const std::string&, Btype*);
|
||||
|
||||
Bvariable*
|
||||
immutable_struct(const std::string&, bool, bool, Btype*, Location);
|
||||
|
||||
@ -2505,45 +2512,101 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
|
||||
|
||||
Bvariable*
|
||||
Gcc_backend::implicit_variable(const std::string& name, Btype* type,
|
||||
Bexpression* init, bool is_constant,
|
||||
bool is_hidden, bool is_constant,
|
||||
bool is_common, size_t alignment)
|
||||
{
|
||||
tree type_tree = type->get_tree();
|
||||
tree init_tree;
|
||||
if (init == NULL)
|
||||
init_tree = NULL_TREE;
|
||||
else
|
||||
init_tree = init->get_tree();
|
||||
if (type_tree == error_mark_node || init_tree == error_mark_node)
|
||||
if (type_tree == error_mark_node)
|
||||
return this->error_variable();
|
||||
|
||||
tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
|
||||
get_identifier_from_string(name), type_tree);
|
||||
DECL_EXTERNAL(decl) = 0;
|
||||
TREE_PUBLIC(decl) = 0;
|
||||
TREE_PUBLIC(decl) = !is_hidden;
|
||||
TREE_STATIC(decl) = 1;
|
||||
TREE_USED(decl) = 1;
|
||||
DECL_ARTIFICIAL(decl) = 1;
|
||||
if (is_common)
|
||||
{
|
||||
DECL_COMMON(decl) = 1;
|
||||
TREE_PUBLIC(decl) = 1;
|
||||
gcc_assert(init_tree == NULL_TREE);
|
||||
|
||||
// When the initializer for one implicit_variable refers to another,
|
||||
// it needs to know the visibility of the referenced struct so that
|
||||
// compute_reloc_for_constant will return the right value. On many
|
||||
// systems calling make_decl_one_only will mark the decl as weak,
|
||||
// which will change the return value of compute_reloc_for_constant.
|
||||
// We can't reliably call make_decl_one_only yet, because we don't
|
||||
// yet know the initializer. This issue doesn't arise in C because
|
||||
// Go initializers, unlike C initializers, can be indirectly
|
||||
// recursive. To ensure that compute_reloc_for_constant computes
|
||||
// the right value if some other initializer refers to this one, we
|
||||
// mark this symbol as weak here. We undo that below in
|
||||
// immutable_struct_set_init before calling mark_decl_one_only.
|
||||
DECL_WEAK(decl) = 1;
|
||||
}
|
||||
else if (is_constant)
|
||||
if (is_constant)
|
||||
{
|
||||
TREE_READONLY(decl) = 1;
|
||||
TREE_CONSTANT(decl) = 1;
|
||||
}
|
||||
DECL_INITIAL(decl) = init_tree;
|
||||
|
||||
if (alignment != 0)
|
||||
{
|
||||
DECL_ALIGN(decl) = alignment * BITS_PER_UNIT;
|
||||
DECL_USER_ALIGN(decl) = 1;
|
||||
}
|
||||
|
||||
rest_of_decl_compilation(decl, 1, 0);
|
||||
go_preserve_from_gc(decl);
|
||||
return new Bvariable(decl);
|
||||
}
|
||||
|
||||
// Set the initalizer for a variable created by implicit_variable.
|
||||
// This is where we finish compiling the variable.
|
||||
|
||||
void
|
||||
Gcc_backend::implicit_variable_set_init(Bvariable* var, const std::string&,
|
||||
Btype*, bool, bool, bool is_common,
|
||||
Bexpression* init)
|
||||
{
|
||||
tree decl = var->get_tree();
|
||||
tree init_tree;
|
||||
if (init == NULL)
|
||||
init_tree = NULL_TREE;
|
||||
else
|
||||
init_tree = init->get_tree();
|
||||
if (decl == error_mark_node || init_tree == error_mark_node)
|
||||
return;
|
||||
|
||||
DECL_INITIAL(decl) = init_tree;
|
||||
|
||||
// Now that DECL_INITIAL is set, we can't call make_decl_one_only.
|
||||
// See the comment where DECL_WEAK is set in implicit_variable.
|
||||
if (is_common)
|
||||
{
|
||||
DECL_WEAK(decl) = 0;
|
||||
make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
|
||||
}
|
||||
|
||||
resolve_unique_section(decl, 2, 1);
|
||||
|
||||
rest_of_decl_compilation(decl, 1, 0);
|
||||
}
|
||||
|
||||
// Return a reference to an implicit variable defined in another package.
|
||||
|
||||
Bvariable*
|
||||
Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype)
|
||||
{
|
||||
tree type_tree = btype->get_tree();
|
||||
if (type_tree == error_mark_node)
|
||||
return this->error_variable();
|
||||
|
||||
tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
|
||||
get_identifier_from_string(name), type_tree);
|
||||
DECL_EXTERNAL(decl) = 0;
|
||||
TREE_PUBLIC(decl) = 1;
|
||||
TREE_STATIC(decl) = 1;
|
||||
DECL_ARTIFICIAL(decl) = 1;
|
||||
go_preserve_from_gc(decl);
|
||||
return new Bvariable(decl);
|
||||
}
|
||||
|
||||
|
@ -545,24 +545,55 @@ class Backend
|
||||
Bstatement** pstatement) = 0;
|
||||
|
||||
// Create an implicit variable that is compiler-defined. This is
|
||||
// used when generating GC root variables, when storing the values
|
||||
// of a slice constructor, and for the zero value of types. NAME is
|
||||
// the name of the variable, either gc# for GC roots or C# for slice
|
||||
// initializers. TYPE is the type of the implicit variable with an
|
||||
// initial value INIT. IS_CONSTANT is true if the implicit variable
|
||||
// should be treated like it is immutable. For slice initializers,
|
||||
// if the values must be copied to the heap, the variable
|
||||
// IS_CONSTANT. IS_COMMON is true if the implicit variable should
|
||||
// used when generating GC data and roots, when storing the values
|
||||
// of a slice constructor, and for the zero value of types. This returns a
|
||||
// Bvariable because it corresponds to an initialized variable in C.
|
||||
//
|
||||
// NAME is the name to use for the initialized variable this will create.
|
||||
//
|
||||
// TYPE is the type of the implicit variable.
|
||||
//
|
||||
// IS_HIDDEN will be true if the descriptor should only be visible
|
||||
// within the current object.
|
||||
//
|
||||
// IS_CONSTANT is true if the implicit variable should be treated like it is
|
||||
// immutable. For slice initializers, if the values must be copied to the
|
||||
// heap, the variable IS_CONSTANT.
|
||||
//
|
||||
// IS_COMMON is true if the implicit variable should
|
||||
// be treated as a common variable (multiple definitions with
|
||||
// different sizes permitted in different object files, all merged
|
||||
// into the largest definition at link time); this will be true for
|
||||
// the zero value. If IS_COMMON is true, INIT will be NULL, and the
|
||||
// variable should be initialized to all zeros. If ALIGNMENT is not
|
||||
// zero, it is the desired alignment of the variable.
|
||||
// the zero value. IS_HIDDEN and IS_COMMON will never both be true.
|
||||
//
|
||||
// If ALIGNMENT is not zero, it is the desired alignment of the variable.
|
||||
virtual Bvariable*
|
||||
implicit_variable(const std::string& name, Btype* type, Bexpression* init,
|
||||
implicit_variable(const std::string& name, Btype* type, bool is_hidden,
|
||||
bool is_constant, bool is_common, size_t alignment) = 0;
|
||||
|
||||
|
||||
// Set the initial value of a variable created by implicit_variable.
|
||||
// This must be called even if there is no initializer, i.e., INIT is NULL.
|
||||
// The NAME, TYPE, IS_HIDDEN, IS_CONSTANT, and IS_COMMON parameters are
|
||||
// the same ones passed to implicit_variable. INIT will be a composite
|
||||
// literal of type TYPE. It will not contain any function calls or anything
|
||||
// else that can not be put into a read-only data section.
|
||||
// It may contain the address of variables created by implicit_variable.
|
||||
//
|
||||
// If IS_COMMON is true, INIT will be NULL, and the
|
||||
// variable should be initialized to all zeros.
|
||||
virtual void
|
||||
implicit_variable_set_init(Bvariable*, const std::string& name, Btype* type,
|
||||
bool is_hidden, bool is_constant, bool is_common,
|
||||
Bexpression* init) = 0;
|
||||
|
||||
// Create a reference to a named implicit variable defined in some other
|
||||
// package. This will be a variable created by a call to implicit_variable
|
||||
// with the same NAME and TYPE and with IS_COMMON passed as false. This
|
||||
// corresponds to an extern global variable in C.
|
||||
virtual Bvariable*
|
||||
implicit_variable_reference(const std::string& name, Btype* type) = 0;
|
||||
|
||||
// Create a named immutable initialized data structure. This is
|
||||
// used for type descriptors, map descriptors, and function
|
||||
// descriptors. This returns a Bvariable because it corresponds to
|
||||
|
@ -3440,6 +3440,9 @@ class Unsafe_type_conversion_expression : public Expression
|
||||
int
|
||||
do_traverse(Traverse* traverse);
|
||||
|
||||
bool
|
||||
do_is_immutable() const;
|
||||
|
||||
Type*
|
||||
do_type()
|
||||
{ return this->type_; }
|
||||
@ -3480,6 +3483,27 @@ Unsafe_type_conversion_expression::do_traverse(Traverse* traverse)
|
||||
return TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
// Return whether an unsafe type conversion is immutable.
|
||||
|
||||
bool
|
||||
Unsafe_type_conversion_expression::do_is_immutable() const
|
||||
{
|
||||
Type* type = this->type_;
|
||||
Type* expr_type = this->expr_->type();
|
||||
|
||||
if (type->interface_type() != NULL
|
||||
|| expr_type->interface_type() != NULL)
|
||||
return false;
|
||||
|
||||
if (!this->expr_->is_immutable())
|
||||
return false;
|
||||
|
||||
if (Type::are_convertible(type, expr_type, NULL))
|
||||
return true;
|
||||
|
||||
return type->is_basic_type() && expr_type->is_basic_type();
|
||||
}
|
||||
|
||||
// Convert to backend representation.
|
||||
|
||||
Bexpression*
|
||||
@ -4115,8 +4139,11 @@ Unary_expression::do_get_backend(Translate_context* context)
|
||||
&& !context->is_const());
|
||||
}
|
||||
Bvariable* implicit =
|
||||
gogo->backend()->implicit_variable(buf, btype, bexpr, copy_to_heap,
|
||||
gogo->backend()->implicit_variable(buf, btype, true, copy_to_heap,
|
||||
false, 0);
|
||||
gogo->backend()->implicit_variable_set_init(implicit, buf, btype,
|
||||
true, copy_to_heap, false,
|
||||
bexpr);
|
||||
bexpr = gogo->backend()->var_expression(implicit, loc);
|
||||
}
|
||||
else if ((this->expr_->is_composite_literal()
|
||||
@ -13987,6 +14014,65 @@ Expression::make_type_descriptor(Type* type, Location location)
|
||||
return new Type_descriptor_expression(type, location);
|
||||
}
|
||||
|
||||
// An expression which evaluates to a pointer to the Garbage Collection symbol
|
||||
// of a type.
|
||||
|
||||
class GC_symbol_expression : public Expression
|
||||
{
|
||||
public:
|
||||
GC_symbol_expression(Type* type)
|
||||
: Expression(EXPRESSION_GC_SYMBOL, Linemap::predeclared_location()),
|
||||
type_(type)
|
||||
{}
|
||||
|
||||
protected:
|
||||
Type*
|
||||
do_type()
|
||||
{ return Type::make_pointer_type(Type::make_void_type()); }
|
||||
|
||||
bool
|
||||
do_is_immutable() const
|
||||
{ return true; }
|
||||
|
||||
void
|
||||
do_determine_type(const Type_context*)
|
||||
{ }
|
||||
|
||||
Expression*
|
||||
do_copy()
|
||||
{ return this; }
|
||||
|
||||
Bexpression*
|
||||
do_get_backend(Translate_context* context)
|
||||
{ return this->type_->gc_symbol_pointer(context->gogo()); }
|
||||
|
||||
void
|
||||
do_dump_expression(Ast_dump_context*) const;
|
||||
|
||||
private:
|
||||
// The type which this gc symbol describes.
|
||||
Type* type_;
|
||||
};
|
||||
|
||||
// Dump ast representation for a gc symbol expression.
|
||||
|
||||
void
|
||||
GC_symbol_expression::do_dump_expression(
|
||||
Ast_dump_context* ast_dump_context) const
|
||||
{
|
||||
ast_dump_context->ostream() << "gcdata(";
|
||||
ast_dump_context->dump_type(this->type_);
|
||||
ast_dump_context->ostream() << ")";
|
||||
}
|
||||
|
||||
// Make a gc symbol expression.
|
||||
|
||||
Expression*
|
||||
Expression::make_gc_symbol(Type* type)
|
||||
{
|
||||
return new GC_symbol_expression(type);
|
||||
}
|
||||
|
||||
// An expression which evaluates to some characteristic of a type.
|
||||
// This is only used to initialize fields of a type descriptor. Using
|
||||
// a new expression class is slightly inefficient but gives us a good
|
||||
|
@ -103,6 +103,7 @@ class Expression
|
||||
EXPRESSION_HEAP,
|
||||
EXPRESSION_RECEIVE,
|
||||
EXPRESSION_TYPE_DESCRIPTOR,
|
||||
EXPRESSION_GC_SYMBOL,
|
||||
EXPRESSION_TYPE_INFO,
|
||||
EXPRESSION_SLICE_INFO,
|
||||
EXPRESSION_SLICE_VALUE,
|
||||
@ -349,6 +350,11 @@ class Expression
|
||||
static Expression*
|
||||
make_type_descriptor(Type* type, Location);
|
||||
|
||||
// Make an expression which evaluates to the address of the gc
|
||||
// symbol for TYPE.
|
||||
static Expression*
|
||||
make_gc_symbol(Type* type);
|
||||
|
||||
// Make an expression which evaluates to some characteristic of a
|
||||
// type. These are only used for type descriptors, so there is no
|
||||
// location parameter.
|
||||
@ -1512,6 +1518,10 @@ class Binary_expression : public Expression
|
||||
do_is_constant() const
|
||||
{ return this->left_->is_constant() && this->right_->is_constant(); }
|
||||
|
||||
bool
|
||||
do_is_immutable() const
|
||||
{ return this->left_->is_immutable() && this->right_->is_immutable(); }
|
||||
|
||||
bool
|
||||
do_numeric_constant_value(Numeric_constant*) const;
|
||||
|
||||
|
@ -655,9 +655,13 @@ Gogo::backend_zero_value()
|
||||
|
||||
Btype* barray_type = this->backend()->array_type(bbtype_type, blength);
|
||||
|
||||
return this->backend()->implicit_variable(this->zero_value_->name(),
|
||||
barray_type, NULL, true, true,
|
||||
this->zero_value_align_);
|
||||
std::string zname = this->zero_value_->name();
|
||||
Bvariable* zvar =
|
||||
this->backend()->implicit_variable(zname, barray_type, false,
|
||||
true, true, this->zero_value_align_);
|
||||
this->backend()->implicit_variable_set_init(zvar, zname, barray_type,
|
||||
false, true, true, NULL);
|
||||
return zvar;
|
||||
}
|
||||
|
||||
// Add statements to INIT_STMTS which run the initialization
|
||||
@ -6837,8 +6841,10 @@ Named_object::get_backend(Gogo* gogo, std::vector<Bexpression*>& const_decls,
|
||||
{
|
||||
named_type->
|
||||
type_descriptor_pointer(gogo, Linemap::predeclared_location());
|
||||
named_type->gc_symbol_pointer(gogo);
|
||||
Type* pn = Type::make_pointer_type(named_type);
|
||||
pn->type_descriptor_pointer(gogo, Linemap::predeclared_location());
|
||||
pn->gc_symbol_pointer(gogo);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -36,7 +36,8 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type,
|
||||
// Class Type.
|
||||
|
||||
Type::Type(Type_classification classification)
|
||||
: classification_(classification), btype_(NULL), type_descriptor_var_(NULL)
|
||||
: classification_(classification), btype_(NULL), type_descriptor_var_(NULL),
|
||||
gc_symbol_var_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1236,7 +1237,7 @@ Type::make_type_descriptor_var(Gogo* gogo)
|
||||
Type::type_descriptor_vars.insert(std::make_pair(this, bvnull));
|
||||
if (!ins.second)
|
||||
{
|
||||
// We've already build a type descriptor for this type.
|
||||
// We've already built a type descriptor for this type.
|
||||
this->type_descriptor_var_ = ins.first->second;
|
||||
return;
|
||||
}
|
||||
@ -1405,6 +1406,18 @@ Type::named_type_descriptor(Gogo* gogo, Type* type, Named_type* name)
|
||||
return type->do_type_descriptor(gogo, name);
|
||||
}
|
||||
|
||||
// Generate the GC symbol for this TYPE. VALS is the data so far in this
|
||||
// symbol; extra values will be appended in do_gc_symbol. OFFSET is the
|
||||
// offset into the symbol where the GC data is located. STACK_SIZE is the
|
||||
// size of the GC stack when dealing with array types.
|
||||
|
||||
void
|
||||
Type::gc_symbol(Gogo* gogo, Type* type, Expression_list** vals,
|
||||
Expression** offset, int stack_size)
|
||||
{
|
||||
type->do_gc_symbol(gogo, vals, offset, stack_size);
|
||||
}
|
||||
|
||||
// Make a builtin struct type from a list of fields. The fields are
|
||||
// pairs of a name and a type.
|
||||
|
||||
@ -1519,14 +1532,15 @@ Type::make_type_descriptor_type()
|
||||
// The type descriptor type.
|
||||
|
||||
Struct_type* type_descriptor_type =
|
||||
Type::make_builtin_struct_type(11,
|
||||
"Kind", uint8_type,
|
||||
Type::make_builtin_struct_type(12,
|
||||
"kind", uint8_type,
|
||||
"align", uint8_type,
|
||||
"fieldAlign", uint8_type,
|
||||
"size", uintptr_type,
|
||||
"hash", uint32_type,
|
||||
"hashfn", uintptr_type,
|
||||
"equalfn", uintptr_type,
|
||||
"gc", unsafe_pointer_type,
|
||||
"string", pointer_string_type,
|
||||
"", pointer_uncommon_type,
|
||||
"ptrToThis",
|
||||
@ -1973,7 +1987,7 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
|
||||
if (!this->has_pointer())
|
||||
runtime_type_kind |= RUNTIME_TYPE_KIND_NO_POINTERS;
|
||||
Struct_field_list::const_iterator p = fields->begin();
|
||||
go_assert(p->is_field_name("Kind"));
|
||||
go_assert(p->is_field_name("kind"));
|
||||
mpz_t iv;
|
||||
mpz_init_set_ui(iv, runtime_type_kind);
|
||||
vals->push_back(Expression::make_integer(&iv, p->type(), bloc));
|
||||
@ -2018,6 +2032,10 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
|
||||
vals->push_back(Expression::make_func_code_reference(hash_fn, bloc));
|
||||
vals->push_back(Expression::make_func_code_reference(equal_fn, bloc));
|
||||
|
||||
++p;
|
||||
go_assert(p->is_field_name("gc"));
|
||||
vals->push_back(Expression::make_gc_symbol(this));
|
||||
|
||||
++p;
|
||||
go_assert(p->is_field_name("string"));
|
||||
Expression* s = Expression::make_string((name != NULL
|
||||
@ -2067,6 +2085,160 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
|
||||
return Expression::make_struct_composite_literal(td_type, vals, bloc);
|
||||
}
|
||||
|
||||
// Return a pointer to the Garbage Collection information for this type.
|
||||
|
||||
Bexpression*
|
||||
Type::gc_symbol_pointer(Gogo* gogo)
|
||||
{
|
||||
Type* t = this->forwarded();
|
||||
if (t->named_type() != NULL && t->named_type()->is_alias())
|
||||
t = t->named_type()->real_type();
|
||||
if (t->gc_symbol_var_ == NULL)
|
||||
{
|
||||
t->make_gc_symbol_var(gogo);
|
||||
go_assert(t->gc_symbol_var_ != NULL);
|
||||
}
|
||||
Location bloc = Linemap::predeclared_location();
|
||||
Bexpression* var_expr =
|
||||
gogo->backend()->var_expression(t->gc_symbol_var_, bloc);
|
||||
return gogo->backend()->address_expression(var_expr, bloc);
|
||||
}
|
||||
|
||||
// A mapping from unnamed types to GC symbol variables.
|
||||
|
||||
Type::GC_symbol_vars Type::gc_symbol_vars;
|
||||
|
||||
// Build the GC symbol for this type.
|
||||
|
||||
void
|
||||
Type::make_gc_symbol_var(Gogo* gogo)
|
||||
{
|
||||
go_assert(this->gc_symbol_var_ == NULL);
|
||||
|
||||
Named_type* nt = this->named_type();
|
||||
|
||||
// We can have multiple instances of unnamed types and similar to type
|
||||
// descriptors, we only want to the emit the GC data once, so we use a
|
||||
// hash table.
|
||||
Bvariable** phash = NULL;
|
||||
if (nt == NULL)
|
||||
{
|
||||
Bvariable* bvnull = NULL;
|
||||
std::pair<GC_symbol_vars::iterator, bool> ins =
|
||||
Type::gc_symbol_vars.insert(std::make_pair(this, bvnull));
|
||||
if (!ins.second)
|
||||
{
|
||||
// We've already built a gc symbol for this type.
|
||||
this->gc_symbol_var_ = ins.first->second;
|
||||
return;
|
||||
}
|
||||
phash = &ins.first->second;
|
||||
}
|
||||
|
||||
std::string sym_name = this->type_descriptor_var_name(gogo, nt) + "$gc";
|
||||
|
||||
// Build the contents of the gc symbol.
|
||||
Expression* sym_init = this->gc_symbol_constructor(gogo);
|
||||
Btype* sym_btype = sym_init->type()->get_backend(gogo);
|
||||
|
||||
// If the type descriptor for this type is defined somewhere else, so is the
|
||||
// GC symbol.
|
||||
const Package* dummy;
|
||||
if (this->type_descriptor_defined_elsewhere(nt, &dummy))
|
||||
{
|
||||
this->gc_symbol_var_ =
|
||||
gogo->backend()->implicit_variable_reference(sym_name, sym_btype);
|
||||
if (phash != NULL)
|
||||
*phash = this->gc_symbol_var_;
|
||||
return;
|
||||
}
|
||||
|
||||
// See if this gc symbol can appear in multiple packages.
|
||||
bool is_common = false;
|
||||
if (nt != NULL)
|
||||
{
|
||||
// We create the symbol for a builtin type whenever we need
|
||||
// it.
|
||||
is_common = nt->is_builtin();
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is an unnamed type. The descriptor could be defined in
|
||||
// any package where it is needed, and the linker will pick one
|
||||
// descriptor to keep.
|
||||
is_common = true;
|
||||
}
|
||||
|
||||
// Since we are building the GC symbol in this package, we must create the
|
||||
// variable before converting the initializer to its backend representation
|
||||
// because the initializer may refer to the GC symbol for this type.
|
||||
this->gc_symbol_var_ =
|
||||
gogo->backend()->implicit_variable(sym_name, sym_btype, false, true, is_common, 0);
|
||||
if (phash != NULL)
|
||||
*phash = this->gc_symbol_var_;
|
||||
|
||||
Translate_context context(gogo, NULL, NULL, NULL);
|
||||
context.set_is_const();
|
||||
Bexpression* sym_binit = sym_init->get_backend(&context);
|
||||
gogo->backend()->implicit_variable_set_init(this->gc_symbol_var_, sym_name,
|
||||
sym_btype, false, true, is_common,
|
||||
sym_binit);
|
||||
}
|
||||
|
||||
// Return an array literal for the Garbage Collection information for this type.
|
||||
|
||||
Expression*
|
||||
Type::gc_symbol_constructor(Gogo* gogo)
|
||||
{
|
||||
Location bloc = Linemap::predeclared_location();
|
||||
|
||||
// The common GC Symbol data starts with the width of the type and ends
|
||||
// with the GC Opcode GC_END.
|
||||
// However, for certain types, the GC symbol may include extra information
|
||||
// before the ending opcode, so we pass the expression list into
|
||||
// Type::gc_symbol to allow it to add extra information as is necessary.
|
||||
Expression_list* vals = new Expression_list;
|
||||
|
||||
Type* uintptr_t = Type::lookup_integer_type("uintptr");
|
||||
// width
|
||||
vals->push_back(Expression::make_type_info(this,
|
||||
Expression::TYPE_INFO_SIZE));
|
||||
|
||||
mpz_t off;
|
||||
mpz_init_set_ui(off, 0UL);
|
||||
Expression* offset = Expression::make_integer(&off, uintptr_t, bloc);
|
||||
mpz_clear(off);
|
||||
|
||||
this->do_gc_symbol(gogo, &vals, &offset, 0);
|
||||
|
||||
mpz_t end;
|
||||
mpz_init_set_ui(end, GC_END);
|
||||
vals->push_back(Expression::make_integer(&end, uintptr_t, bloc));
|
||||
mpz_clear(end);
|
||||
|
||||
mpz_t lenval;
|
||||
mpz_init_set_ui(lenval, vals->size() + 1);
|
||||
Expression* len = Expression::make_integer(&lenval, NULL, bloc);
|
||||
mpz_clear(lenval);
|
||||
|
||||
Array_type* gc_symbol_type = Type::make_array_type(uintptr_t, len);
|
||||
return Expression::make_array_composite_literal(gc_symbol_type, vals, bloc);
|
||||
}
|
||||
|
||||
// Advance the OFFSET of the GC symbol by this type's width.
|
||||
|
||||
void
|
||||
Type::advance_gc_offset(Expression** offset)
|
||||
{
|
||||
if (this->is_error_type())
|
||||
return;
|
||||
|
||||
Location bloc = Linemap::predeclared_location();
|
||||
Expression* width =
|
||||
Expression::make_type_info(this, Expression::TYPE_INFO_SIZE);
|
||||
*offset = Expression::make_binary(OPERATOR_PLUS, *offset, width, bloc);
|
||||
}
|
||||
|
||||
// Return a composite literal for the uncommon type information for
|
||||
// this type. UNCOMMON_STRUCT_TYPE is the type of the uncommon type
|
||||
// struct. If name is not NULL, it is the name of the type. If
|
||||
@ -2497,6 +2669,10 @@ class Error_type : public Type
|
||||
do_reflection(Gogo*, std::string*) const
|
||||
{ go_assert(saw_errors()); }
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
|
||||
{ go_assert(saw_errors()); }
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string* ret) const
|
||||
{ ret->push_back('E'); }
|
||||
@ -2535,6 +2711,10 @@ class Void_type : public Type
|
||||
do_reflection(Gogo*, std::string*) const
|
||||
{ }
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
|
||||
{ }
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string* ret) const
|
||||
{ ret->push_back('v'); }
|
||||
@ -2573,6 +2753,9 @@ class Boolean_type : public Type
|
||||
do_reflection(Gogo*, std::string* ret) const
|
||||
{ ret->append("bool"); }
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string* ret) const
|
||||
{ ret->push_back('b'); }
|
||||
@ -2593,6 +2776,12 @@ Boolean_type::do_type_descriptor(Gogo* gogo, Named_type* name)
|
||||
}
|
||||
}
|
||||
|
||||
// Update the offset of the GC symbol.
|
||||
|
||||
void
|
||||
Boolean_type::do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
|
||||
{ this->advance_gc_offset(offset); }
|
||||
|
||||
Type*
|
||||
Type::make_boolean_type()
|
||||
{
|
||||
@ -3102,6 +3291,22 @@ String_type::do_reflection(Gogo*, std::string* ret) const
|
||||
ret->append("string");
|
||||
}
|
||||
|
||||
// Generate GC symbol for strings.
|
||||
|
||||
void
|
||||
String_type::do_gc_symbol(Gogo*, Expression_list** vals,
|
||||
Expression** offset, int)
|
||||
{
|
||||
Location bloc = Linemap::predeclared_location();
|
||||
Type* uintptr_type = Type::lookup_integer_type("uintptr");
|
||||
mpz_t opval;
|
||||
mpz_init_set_ui(opval, GC_STRING);
|
||||
(*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
|
||||
mpz_clear(opval);
|
||||
(*vals)->push_back(*offset);
|
||||
this->advance_gc_offset(offset);
|
||||
}
|
||||
|
||||
// Mangled name of a string type.
|
||||
|
||||
void
|
||||
@ -3172,6 +3377,10 @@ class Sink_type : public Type
|
||||
do_reflection(Gogo*, std::string*) const
|
||||
{ go_unreachable(); }
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
|
||||
{ go_unreachable(); }
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string*) const
|
||||
{ go_unreachable(); }
|
||||
@ -3754,6 +3963,25 @@ Function_type::do_reflection(Gogo* gogo, std::string* ret) const
|
||||
}
|
||||
}
|
||||
|
||||
// Generate GC symbol for a function type.
|
||||
|
||||
void
|
||||
Function_type::do_gc_symbol(Gogo*, Expression_list** vals,
|
||||
Expression** offset, int)
|
||||
{
|
||||
Location bloc = Linemap::predeclared_location();
|
||||
Type* uintptr_type = Type::lookup_integer_type("uintptr");
|
||||
|
||||
// We use GC_APTR here because we do not currently have a way to describe the
|
||||
// the type of the possible function closure. FIXME.
|
||||
mpz_t opval;
|
||||
mpz_init_set_ui(opval, GC_APTR);
|
||||
(*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
|
||||
mpz_clear(opval);
|
||||
(*vals)->push_back(*offset);
|
||||
this->advance_gc_offset(offset);
|
||||
}
|
||||
|
||||
// Mangled name.
|
||||
|
||||
void
|
||||
@ -4156,6 +4384,26 @@ Pointer_type::do_reflection(Gogo* gogo, std::string* ret) const
|
||||
this->append_reflection(this->to_type_, gogo, ret);
|
||||
}
|
||||
|
||||
// Generate GC symbol for pointer types.
|
||||
|
||||
void
|
||||
Pointer_type::do_gc_symbol(Gogo*, Expression_list** vals,
|
||||
Expression** offset, int)
|
||||
{
|
||||
Location loc = Linemap::predeclared_location();
|
||||
Type* uintptr_type = Type::lookup_integer_type("uintptr");
|
||||
|
||||
mpz_t opval;
|
||||
mpz_init_set_ui(opval, this->to_type_->has_pointer() ? GC_PTR : GC_APTR);
|
||||
(*vals)->push_back(Expression::make_integer(&opval, uintptr_type, loc));
|
||||
mpz_clear(opval);
|
||||
(*vals)->push_back(*offset);
|
||||
|
||||
if (this->to_type_->has_pointer())
|
||||
(*vals)->push_back(Expression::make_gc_symbol(this->to_type_));
|
||||
this->advance_gc_offset(offset);
|
||||
}
|
||||
|
||||
// Mangled name.
|
||||
|
||||
void
|
||||
@ -4235,6 +4483,10 @@ class Nil_type : public Type
|
||||
do_reflection(Gogo*, std::string*) const
|
||||
{ go_unreachable(); }
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
|
||||
{ go_unreachable(); }
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string* ret) const
|
||||
{ ret->push_back('n'); }
|
||||
@ -4292,6 +4544,10 @@ class Call_multiple_result_type : public Type
|
||||
do_reflection(Gogo*, std::string*) const
|
||||
{ go_assert(saw_errors()); }
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
|
||||
{ go_unreachable(); }
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string*) const
|
||||
{ go_assert(saw_errors()); }
|
||||
@ -5319,6 +5575,27 @@ Struct_type::do_reflection(Gogo* gogo, std::string* ret) const
|
||||
ret->push_back('}');
|
||||
}
|
||||
|
||||
// Generate GC symbol for struct types.
|
||||
|
||||
void
|
||||
Struct_type::do_gc_symbol(Gogo* gogo, Expression_list** vals,
|
||||
Expression** offset, int stack_size)
|
||||
{
|
||||
Location bloc = Linemap::predeclared_location();
|
||||
const Struct_field_list* sfl = this->fields();
|
||||
for (Struct_field_list::const_iterator p = sfl->begin();
|
||||
p != sfl->end();
|
||||
++p)
|
||||
{
|
||||
Expression* field_offset =
|
||||
Expression::make_struct_field_offset(this, &*p);
|
||||
Expression* o =
|
||||
Expression::make_binary(OPERATOR_PLUS, *offset, field_offset, bloc);
|
||||
Type::gc_symbol(gogo, p->type(), vals, &o, stack_size);
|
||||
}
|
||||
this->advance_gc_offset(offset);
|
||||
}
|
||||
|
||||
// Mangled name.
|
||||
|
||||
void
|
||||
@ -6204,6 +6481,115 @@ Array_type::do_reflection(Gogo* gogo, std::string* ret) const
|
||||
this->append_reflection(this->element_type_, gogo, ret);
|
||||
}
|
||||
|
||||
// GC Symbol construction for array types.
|
||||
|
||||
void
|
||||
Array_type::do_gc_symbol(Gogo* gogo, Expression_list** vals,
|
||||
Expression** offset, int stack_size)
|
||||
{
|
||||
if (this->length_ == NULL)
|
||||
this->slice_gc_symbol(gogo, vals, offset, stack_size);
|
||||
else
|
||||
this->array_gc_symbol(gogo, vals, offset, stack_size);
|
||||
}
|
||||
|
||||
// Generate the GC Symbol for a slice.
|
||||
|
||||
void
|
||||
Array_type::slice_gc_symbol(Gogo* gogo, Expression_list** vals,
|
||||
Expression** offset, int)
|
||||
{
|
||||
Location bloc = Linemap::predeclared_location();
|
||||
|
||||
// Differentiate between slices with zero-length and non-zero-length values.
|
||||
Type* element_type = this->element_type();
|
||||
Btype* ebtype = element_type->get_backend(gogo);
|
||||
size_t element_size = gogo->backend()->type_size(ebtype);
|
||||
|
||||
Type* uintptr_type = Type::lookup_integer_type("uintptr");
|
||||
mpz_t opval;
|
||||
mpz_init_set_ui(opval, element_size == 0 ? GC_APTR : GC_SLICE);
|
||||
(*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
|
||||
mpz_clear(opval);
|
||||
(*vals)->push_back(*offset);
|
||||
|
||||
if (element_size != 0)
|
||||
(*vals)->push_back(Expression::make_gc_symbol(element_type));
|
||||
this->advance_gc_offset(offset);
|
||||
}
|
||||
|
||||
// Generate the GC symbol for an array.
|
||||
|
||||
void
|
||||
Array_type::array_gc_symbol(Gogo* gogo, Expression_list** vals,
|
||||
Expression** offset, int stack_size)
|
||||
{
|
||||
Location bloc = Linemap::predeclared_location();
|
||||
|
||||
Numeric_constant nc;
|
||||
unsigned long bound;
|
||||
if (!this->length_->numeric_constant_value(&nc)
|
||||
|| nc.to_unsigned_long(&bound) == Numeric_constant::NC_UL_NOTINT)
|
||||
go_assert(saw_errors());
|
||||
|
||||
Btype* pbtype = gogo->backend()->pointer_type(gogo->backend()->void_type());
|
||||
size_t pwidth = gogo->backend()->type_size(pbtype);
|
||||
size_t iwidth = gogo->backend()->type_size(this->get_backend(gogo));
|
||||
|
||||
Type* element_type = this->element_type();
|
||||
if (bound < 1 || !element_type->has_pointer())
|
||||
this->advance_gc_offset(offset);
|
||||
else if (bound == 1 || iwidth <= 4 * pwidth)
|
||||
{
|
||||
for (unsigned int i = 0; i < bound; ++i)
|
||||
Type::gc_symbol(gogo, element_type, vals, offset, stack_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Type* uintptr_type = Type::lookup_integer_type("uintptr");
|
||||
|
||||
mpz_t op;
|
||||
if (stack_size < GC_STACK_CAPACITY)
|
||||
{
|
||||
mpz_init_set_ui(op, GC_ARRAY_START);
|
||||
(*vals)->push_back(Expression::make_integer(&op, uintptr_type, bloc));
|
||||
mpz_clear(op);
|
||||
(*vals)->push_back(*offset);
|
||||
Expression* uintptr_len =
|
||||
Expression::make_cast(uintptr_type, this->length_, bloc);
|
||||
(*vals)->push_back(uintptr_len);
|
||||
|
||||
Expression* width =
|
||||
Expression::make_type_info(element_type,
|
||||
Expression::TYPE_INFO_SIZE);
|
||||
(*vals)->push_back(width);
|
||||
|
||||
mpz_t zero;
|
||||
mpz_init_set_ui(zero, 0UL);
|
||||
Expression* offset2 =
|
||||
Expression::make_integer(&zero, uintptr_type, bloc);
|
||||
mpz_clear(zero);
|
||||
|
||||
Type::gc_symbol(gogo, element_type, vals, &offset2, stack_size + 1);
|
||||
mpz_init_set_ui(op, GC_ARRAY_NEXT);
|
||||
(*vals)->push_back(Expression::make_integer(&op, uintptr_type, bloc));
|
||||
}
|
||||
else
|
||||
{
|
||||
mpz_init_set_ui(op, GC_REGION);
|
||||
(*vals)->push_back(Expression::make_integer(&op, uintptr_type, bloc));
|
||||
(*vals)->push_back(*offset);
|
||||
|
||||
Expression* width =
|
||||
Expression::make_type_info(this, Expression::TYPE_INFO_SIZE);
|
||||
(*vals)->push_back(width);
|
||||
(*vals)->push_back(Expression::make_gc_symbol(this));
|
||||
}
|
||||
mpz_clear(op);
|
||||
this->advance_gc_offset(offset);
|
||||
}
|
||||
}
|
||||
|
||||
// Mangled name.
|
||||
|
||||
void
|
||||
@ -6513,6 +6899,24 @@ Map_type::do_reflection(Gogo* gogo, std::string* ret) const
|
||||
this->append_reflection(this->val_type_, gogo, ret);
|
||||
}
|
||||
|
||||
// Generate GC symbol for a map.
|
||||
|
||||
void
|
||||
Map_type::do_gc_symbol(Gogo*, Expression_list** vals,
|
||||
Expression** offset, int)
|
||||
{
|
||||
// TODO(cmang): Generate GC data for the Map elements.
|
||||
Location bloc = Linemap::predeclared_location();
|
||||
Type* uintptr_type = Type::lookup_integer_type("uintptr");
|
||||
|
||||
mpz_t opval;
|
||||
mpz_init_set_ui(opval, GC_APTR);
|
||||
(*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
|
||||
mpz_clear(opval);
|
||||
(*vals)->push_back(*offset);
|
||||
this->advance_gc_offset(offset);
|
||||
}
|
||||
|
||||
// Mangled name for a map.
|
||||
|
||||
void
|
||||
@ -6686,6 +7090,30 @@ Channel_type::do_reflection(Gogo* gogo, std::string* ret) const
|
||||
this->append_reflection(this->element_type_, gogo, ret);
|
||||
}
|
||||
|
||||
// Generate GC symbol for channels.
|
||||
|
||||
void
|
||||
Channel_type::do_gc_symbol(Gogo*, Expression_list** vals,
|
||||
Expression** offset, int)
|
||||
{
|
||||
Location bloc = Linemap::predeclared_location();
|
||||
Type* uintptr_type = Type::lookup_integer_type("uintptr");
|
||||
|
||||
mpz_t opval;
|
||||
mpz_init_set_ui(opval, GC_CHAN_PTR);
|
||||
(*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
|
||||
mpz_clear(opval);
|
||||
(*vals)->push_back(*offset);
|
||||
|
||||
Type* unsafeptr_type = Type::make_pointer_type(Type::make_void_type());
|
||||
Expression* type_descriptor =
|
||||
Expression::make_type_descriptor(this, bloc);
|
||||
type_descriptor =
|
||||
Expression::make_unsafe_cast(unsafeptr_type, type_descriptor, bloc);
|
||||
(*vals)->push_back(type_descriptor);
|
||||
this->advance_gc_offset(offset);
|
||||
}
|
||||
|
||||
// Mangled name.
|
||||
|
||||
void
|
||||
@ -7574,6 +8002,24 @@ Interface_type::do_reflection(Gogo* gogo, std::string* ret) const
|
||||
ret->append("}");
|
||||
}
|
||||
|
||||
// Generate GC symbol for interface types.
|
||||
|
||||
void
|
||||
Interface_type::do_gc_symbol(Gogo*, Expression_list** vals,
|
||||
Expression** offset, int)
|
||||
{
|
||||
Location bloc = Linemap::predeclared_location();
|
||||
Type* uintptr_type = Type::lookup_integer_type("uintptr");
|
||||
|
||||
mpz_t opval;
|
||||
mpz_init_set_ui(opval, this->is_empty() ? GC_EFACE : GC_IFACE);
|
||||
(*vals)->push_back(Expression::make_integer(&opval, uintptr_type,
|
||||
bloc));
|
||||
mpz_clear(opval);
|
||||
(*vals)->push_back(*offset);
|
||||
this->advance_gc_offset(offset);
|
||||
}
|
||||
|
||||
// Mangled name.
|
||||
|
||||
void
|
||||
@ -8810,6 +9256,20 @@ Named_type::do_reflection(Gogo* gogo, std::string* ret) const
|
||||
ret->append(Gogo::unpack_hidden_name(this->named_object_->name()));
|
||||
}
|
||||
|
||||
// Generate GC symbol for named types.
|
||||
|
||||
void
|
||||
Named_type::do_gc_symbol(Gogo* gogo, Expression_list** vals,
|
||||
Expression** offset, int stack)
|
||||
{
|
||||
if (!this->seen_)
|
||||
{
|
||||
this->seen_ = true;
|
||||
Type::gc_symbol(gogo, this->real_type(), vals, offset, stack);
|
||||
this->seen_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the mangled name.
|
||||
|
||||
void
|
||||
|
@ -83,6 +83,28 @@ static const int RUNTIME_TYPE_KIND_UNSAFE_POINTER = 26;
|
||||
|
||||
static const int RUNTIME_TYPE_KIND_NO_POINTERS = (1 << 7);
|
||||
|
||||
// GC instruction opcodes. These must match the values in libgo/runtime/mgc0.h.
|
||||
enum GC_Opcode
|
||||
{
|
||||
GC_END = 0, // End of object, loop or subroutine.
|
||||
GC_PTR, // A typed pointer.
|
||||
GC_APTR, // Pointer to an arbitrary object.
|
||||
GC_ARRAY_START, // Start an array with a fixed length.
|
||||
GC_ARRAY_NEXT, // The next element of an array.
|
||||
GC_CALL, // Call a subroutine.
|
||||
GC_CHAN_PTR, // Go channel.
|
||||
GC_STRING, // Go string.
|
||||
GC_EFACE, // interface{}.
|
||||
GC_IFACE, // interface{...}.
|
||||
GC_SLICE, // Go slice.
|
||||
GC_REGION, // A region/part of the current object.
|
||||
|
||||
GC_NUM_INSTR // Number of instruction opcodes
|
||||
};
|
||||
|
||||
// The GC Stack Capacity must match the value in libgo/runtime/mgc0.h.
|
||||
static const int GC_STACK_CAPACITY = 8;
|
||||
|
||||
// To build the complete list of methods for a named type we need to
|
||||
// gather all methods from anonymous fields. Those methods may
|
||||
// require an arbitrary set of indirections and field offsets. There
|
||||
@ -911,6 +933,10 @@ class Type
|
||||
Bexpression*
|
||||
type_descriptor_pointer(Gogo* gogo, Location);
|
||||
|
||||
// Build the Garbage Collection symbol for this type. Return a pointer to it.
|
||||
Bexpression*
|
||||
gc_symbol_pointer(Gogo* gogo);
|
||||
|
||||
// Return the type reflection string for this type.
|
||||
std::string
|
||||
reflection(Gogo*) const;
|
||||
@ -995,6 +1021,9 @@ class Type
|
||||
virtual Expression*
|
||||
do_type_descriptor(Gogo*, Named_type* name) = 0;
|
||||
|
||||
virtual void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int) = 0;
|
||||
|
||||
virtual void
|
||||
do_reflection(Gogo*, std::string*) const = 0;
|
||||
|
||||
@ -1050,6 +1079,22 @@ class Type
|
||||
type_descriptor_constructor(Gogo*, int runtime_type_kind, Named_type*,
|
||||
const Methods*, bool only_value_methods);
|
||||
|
||||
// Generate the GC symbol for this TYPE. VALS is the data so far in this
|
||||
// symbol; extra values will be appended in do_gc_symbol. OFFSET is the
|
||||
// offset into the symbol where the GC data is located. STACK_SIZE is the
|
||||
// size of the GC stack when dealing with array types.
|
||||
static void
|
||||
gc_symbol(Gogo*, Type* type, Expression_list** vals, Expression** offset,
|
||||
int stack_size);
|
||||
|
||||
// Build a composite literal for the GC symbol of this type.
|
||||
Expression*
|
||||
gc_symbol_constructor(Gogo*);
|
||||
|
||||
// Advance the OFFSET of the GC symbol by the size of this type.
|
||||
void
|
||||
advance_gc_offset(Expression** offset);
|
||||
|
||||
// For the benefit of child class reflection string generation.
|
||||
void
|
||||
append_reflection(const Type* type, Gogo* gogo, std::string* ret) const
|
||||
@ -1126,6 +1171,16 @@ class Type
|
||||
void
|
||||
make_type_descriptor_var(Gogo*);
|
||||
|
||||
// Map unnamed types to type descriptor decls.
|
||||
typedef Unordered_map_hash(const Type*, Bvariable*, Type_hash_identical,
|
||||
Type_identical) GC_symbol_vars;
|
||||
|
||||
static GC_symbol_vars gc_symbol_vars;
|
||||
|
||||
// Build the GC symbol for this type.
|
||||
void
|
||||
make_gc_symbol_var(Gogo*);
|
||||
|
||||
// Return the name of the type descriptor variable. If NAME is not
|
||||
// NULL, it is the name to use.
|
||||
std::string
|
||||
@ -1253,6 +1308,9 @@ class Type
|
||||
// The type descriptor for this type. This starts out as NULL and
|
||||
// is filled in as needed.
|
||||
Bvariable* type_descriptor_var_;
|
||||
// The GC symbol for this type. This starts out as NULL and
|
||||
// is filled in as needed.
|
||||
Bvariable* gc_symbol_var_;
|
||||
};
|
||||
|
||||
// Type hash table operations.
|
||||
@ -1506,6 +1564,10 @@ protected:
|
||||
void
|
||||
do_reflection(Gogo*, std::string*) const;
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
|
||||
{ this->advance_gc_offset(offset); }
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string*) const;
|
||||
|
||||
@ -1583,6 +1645,10 @@ class Float_type : public Type
|
||||
void
|
||||
do_reflection(Gogo*, std::string*) const;
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
|
||||
{ this->advance_gc_offset(offset); }
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string*) const;
|
||||
|
||||
@ -1652,6 +1718,10 @@ class Complex_type : public Type
|
||||
void
|
||||
do_reflection(Gogo*, std::string*) const;
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
|
||||
{ this->advance_gc_offset(offset); }
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string*) const;
|
||||
|
||||
@ -1701,6 +1771,9 @@ class String_type : public Type
|
||||
void
|
||||
do_reflection(Gogo*, std::string*) const;
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string* ret) const;
|
||||
|
||||
@ -1836,6 +1909,9 @@ class Function_type : public Type
|
||||
void
|
||||
do_reflection(Gogo*, std::string*) const;
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string*) const;
|
||||
|
||||
@ -1952,6 +2028,9 @@ class Pointer_type : public Type
|
||||
void
|
||||
do_reflection(Gogo*, std::string*) const;
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string*) const;
|
||||
|
||||
@ -2250,6 +2329,9 @@ class Struct_type : public Type
|
||||
void
|
||||
do_reflection(Gogo*, std::string*) const;
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string*) const;
|
||||
|
||||
@ -2392,6 +2474,9 @@ class Array_type : public Type
|
||||
void
|
||||
do_reflection(Gogo*, std::string*) const;
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string*) const;
|
||||
|
||||
@ -2408,6 +2493,12 @@ class Array_type : public Type
|
||||
Expression*
|
||||
slice_type_descriptor(Gogo*, Named_type*);
|
||||
|
||||
void
|
||||
slice_gc_symbol(Gogo*, Expression_list**, Expression**, int);
|
||||
|
||||
void
|
||||
array_gc_symbol(Gogo*, Expression_list**, Expression**, int);
|
||||
|
||||
// The type of elements of the array.
|
||||
Type* element_type_;
|
||||
// The number of elements. This may be NULL.
|
||||
@ -2484,6 +2575,9 @@ class Map_type : public Type
|
||||
void
|
||||
do_reflection(Gogo*, std::string*) const;
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string*) const;
|
||||
|
||||
@ -2570,6 +2664,9 @@ class Channel_type : public Type
|
||||
void
|
||||
do_reflection(Gogo*, std::string*) const;
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string*) const;
|
||||
|
||||
@ -2703,6 +2800,9 @@ class Interface_type : public Type
|
||||
void
|
||||
do_reflection(Gogo*, std::string*) const;
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string*) const;
|
||||
|
||||
@ -2988,6 +3088,10 @@ class Named_type : public Type
|
||||
void
|
||||
do_reflection(Gogo*, std::string*) const;
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo* gogo, Expression_list** vals, Expression** offset,
|
||||
int stack);
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string* ret) const;
|
||||
|
||||
@ -3132,6 +3236,11 @@ class Forward_declaration_type : public Type
|
||||
void
|
||||
do_reflection(Gogo*, std::string*) const;
|
||||
|
||||
void
|
||||
do_gc_symbol(Gogo* gogo, Expression_list** vals, Expression** offset,
|
||||
int stack_size)
|
||||
{ Type::gc_symbol(gogo, this->real_type(), vals, offset, stack_size); }
|
||||
|
||||
void
|
||||
do_mangled_name(Gogo*, std::string* ret) const;
|
||||
|
||||
|
@ -255,6 +255,7 @@ type rtype struct {
|
||||
hashfn uintptr // hash function code
|
||||
equalfn uintptr // equality function code
|
||||
|
||||
gc unsafe.Pointer // garbage collection data
|
||||
string *string // string form; unnecessary but undeniably useful
|
||||
*uncommonType // (relatively) uncommon fields
|
||||
ptrToThis *rtype // type for pointer to this type, if used in binary or has methods
|
||||
@ -1130,6 +1131,18 @@ func (t *rtype) ptrTo() *rtype {
|
||||
p.zero = unsafe.Pointer(&make([]byte, p.size)[0])
|
||||
p.elem = t
|
||||
|
||||
if t.kind&kindNoPointers != 0 {
|
||||
p.gc = unsafe.Pointer(&ptrDataGCProg)
|
||||
} else {
|
||||
p.gc = unsafe.Pointer(&ptrGC{
|
||||
width: p.size,
|
||||
op: _GC_PTR,
|
||||
off: 0,
|
||||
elemgc: t.gc,
|
||||
end: _GC_END,
|
||||
})
|
||||
}
|
||||
|
||||
q := canonicalize(&p.rtype)
|
||||
p = (*ptrType)(unsafe.Pointer(q.(*rtype)))
|
||||
|
||||
@ -1471,8 +1484,16 @@ func ChanOf(dir ChanDir, t Type) Type {
|
||||
ch.ptrToThis = nil
|
||||
ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0])
|
||||
|
||||
ch.gc = unsafe.Pointer(&chanGC{
|
||||
width: ch.size,
|
||||
op: _GC_CHAN_PTR,
|
||||
off: 0,
|
||||
typ: &ch.rtype,
|
||||
end: _GC_END,
|
||||
})
|
||||
|
||||
// INCORRECT. Uncomment to check that TestChanOfGC fails when ch.gc is wrong.
|
||||
//ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END})
|
||||
// ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END})
|
||||
|
||||
return cachePut(ckey, &ch.rtype)
|
||||
}
|
||||
@ -1524,10 +1545,13 @@ func MapOf(key, elem Type) Type {
|
||||
// width: unsafe.Sizeof(uintptr(0)),
|
||||
// op: _GC_PTR,
|
||||
// off: 0,
|
||||
// elemgc: mt.hmap.gc,
|
||||
// elemgc: nil,
|
||||
// end: _GC_END,
|
||||
// })
|
||||
|
||||
// TODO(cmang): Generate GC data for Map elements.
|
||||
mt.gc = unsafe.Pointer(&ptrDataGCProg)
|
||||
|
||||
// INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues
|
||||
// fail when mt.gc is wrong.
|
||||
//mt.gc = unsafe.Pointer(&badGC{width: mt.size, end: _GC_END})
|
||||
@ -1593,8 +1617,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
|
||||
|
||||
// Take the GC program for "t" and append it to the GC program "gc".
|
||||
func appendGCProgram(gc []uintptr, t *rtype) []uintptr {
|
||||
// p := t.gc
|
||||
var p unsafe.Pointer
|
||||
p := t.gc
|
||||
p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size
|
||||
loop:
|
||||
for {
|
||||
@ -1707,8 +1730,20 @@ func SliceOf(t Type) Type {
|
||||
slice.ptrToThis = nil
|
||||
slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0])
|
||||
|
||||
if typ.size == 0 {
|
||||
slice.gc = unsafe.Pointer(&sliceEmptyGCProg)
|
||||
} else {
|
||||
slice.gc = unsafe.Pointer(&sliceGC{
|
||||
width: slice.size,
|
||||
op: _GC_SLICE,
|
||||
off: 0,
|
||||
elemgc: typ.gc,
|
||||
end: _GC_END,
|
||||
})
|
||||
}
|
||||
|
||||
// INCORRECT. Uncomment to check that TestSliceOfOfGC fails when slice.gc is wrong.
|
||||
//slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END})
|
||||
// slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END})
|
||||
|
||||
return cachePut(ckey, &slice.rtype)
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ package runtime
|
||||
import "unsafe"
|
||||
|
||||
type rtype struct {
|
||||
Kind uint8
|
||||
kind uint8
|
||||
align uint8
|
||||
fieldAlign uint8
|
||||
size uintptr
|
||||
@ -24,6 +24,7 @@ type rtype struct {
|
||||
hashfn func(unsafe.Pointer, uintptr) uintptr
|
||||
equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
|
||||
|
||||
gc unsafe.Pointer
|
||||
string *string
|
||||
*uncommonType
|
||||
ptrToThis *rtype
|
||||
|
@ -59,7 +59,7 @@ struct String;
|
||||
#define GO_CODE_MASK 0x7f
|
||||
|
||||
/* For each Go type the compiler constructs one of these structures.
|
||||
This is used for type reflectin, interfaces, maps, and reference
|
||||
This is used for type reflection, interfaces, maps, and reference
|
||||
counting. */
|
||||
|
||||
struct __go_type_descriptor
|
||||
@ -93,6 +93,9 @@ struct __go_type_descriptor
|
||||
size of this type, and returns whether the values are equal. */
|
||||
_Bool (*__equalfn) (const void *, const void *, uintptr_t);
|
||||
|
||||
/* The garbage collection data. */
|
||||
const uintptr *__gc;
|
||||
|
||||
/* A string describing this type. This is only used for
|
||||
debugging. */
|
||||
const struct String *__reflection;
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "runtime.h"
|
||||
#include "go-type.h"
|
||||
#include "mgc0.h"
|
||||
|
||||
/* A pointer with a zero value. */
|
||||
static void *zero_pointer;
|
||||
@ -20,6 +21,9 @@ static void *zero_pointer;
|
||||
extern const struct __go_type_descriptor unsafe_Pointer
|
||||
__asm__ (GOSYM_PREFIX "__go_tdn_unsafe.Pointer");
|
||||
|
||||
extern const uintptr unsafe_Pointer_gc[]
|
||||
__asm__ (GOSYM_PREFIX "__go_tdn_unsafe.Pointer$gc");
|
||||
|
||||
/* Used to determine the field alignment. */
|
||||
struct field_align
|
||||
{
|
||||
@ -35,6 +39,8 @@ static const String reflection_string =
|
||||
sizeof REFLECTION - 1
|
||||
};
|
||||
|
||||
const uintptr unsafe_Pointer_gc[] = {8, GC_APTR, 0, GC_END};
|
||||
|
||||
const struct __go_type_descriptor unsafe_Pointer =
|
||||
{
|
||||
/* __code */
|
||||
@ -51,6 +57,8 @@ const struct __go_type_descriptor unsafe_Pointer =
|
||||
__go_type_hash_identity,
|
||||
/* __equalfn */
|
||||
__go_type_equal_identity,
|
||||
/* __gc */
|
||||
unsafe_Pointer_gc,
|
||||
/* __reflection */
|
||||
&reflection_string,
|
||||
/* __uncommon */
|
||||
@ -94,6 +102,8 @@ const struct __go_ptr_type pointer_unsafe_Pointer =
|
||||
__go_type_hash_identity,
|
||||
/* __equalfn */
|
||||
__go_type_equal_identity,
|
||||
/* __gc */
|
||||
unsafe_Pointer_gc,
|
||||
/* __reflection */
|
||||
&preflection_string,
|
||||
/* __uncommon */
|
||||
|
@ -181,7 +181,7 @@ struct Finalizer
|
||||
FuncVal *fn;
|
||||
void *arg;
|
||||
const struct __go_func_type *ft;
|
||||
const struct __go_ptr_type *ot;
|
||||
const PtrType *ot;
|
||||
};
|
||||
|
||||
typedef struct FinBlock FinBlock;
|
||||
@ -403,8 +403,6 @@ struct BufferList
|
||||
};
|
||||
static BufferList bufferList[MaxGcproc];
|
||||
|
||||
static Type *itabtype;
|
||||
|
||||
static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj);
|
||||
|
||||
// flushptrbuf moves data from the PtrTarget buffer to the work buffer.
|
||||
@ -649,23 +647,22 @@ flushobjbuf(Scanbuf *sbuf)
|
||||
// Program that scans the whole block and treats every block element as a potential pointer
|
||||
static uintptr defaultProg[2] = {PtrSize, GC_DEFAULT_PTR};
|
||||
|
||||
#if 0
|
||||
// Hchan program
|
||||
static uintptr chanProg[2] = {0, GC_CHAN};
|
||||
#endif
|
||||
|
||||
// Local variables of a program fragment or loop
|
||||
typedef struct Frame Frame;
|
||||
struct Frame {
|
||||
uintptr count, elemsize, b;
|
||||
uintptr *loop_or_ret;
|
||||
const uintptr *loop_or_ret;
|
||||
};
|
||||
|
||||
// Sanity check for the derived type info objti.
|
||||
static void
|
||||
checkptr(void *obj, uintptr objti)
|
||||
{
|
||||
uintptr type, tisize, i, x;
|
||||
uintptr *pc1, type, tisize, i, j, x;
|
||||
const uintptr *pc2;
|
||||
byte *objstart;
|
||||
Type *t;
|
||||
MSpan *s;
|
||||
@ -703,9 +700,8 @@ checkptr(void *obj, uintptr objti)
|
||||
(runtime_strcmp((const char *)t->string->str, (const char*)"unsafe.Pointer") &&
|
||||
// Runtime and gc think differently about closures.
|
||||
runtime_strstr((const char *)t->string->str, (const char*)"struct { F uintptr") != (const char *)t->string->str)) {
|
||||
#if 0
|
||||
pc1 = (uintptr*)objti;
|
||||
pc2 = (uintptr*)t->gc;
|
||||
pc2 = (const uintptr*)t->__gc;
|
||||
// A simple best-effort check until first GC_END.
|
||||
for(j = 1; pc1[j] != GC_END && pc2[j] != GC_END; j++) {
|
||||
if(pc1[j] != pc2[j]) {
|
||||
@ -714,7 +710,6 @@ checkptr(void *obj, uintptr objti)
|
||||
runtime_throw("invalid gc type info");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -728,11 +723,10 @@ static void
|
||||
scanblock(Workbuf *wbuf, bool keepworking)
|
||||
{
|
||||
byte *b, *arena_start, *arena_used;
|
||||
uintptr n, i, end_b, elemsize, size, ti, objti, count, /* type, */ nobj;
|
||||
uintptr *pc, precise_type, nominal_size;
|
||||
#if 0
|
||||
uintptr *chan_ret, chancap;
|
||||
#endif
|
||||
uintptr n, i, end_b, elemsize, size, ti, objti, count, type, nobj;
|
||||
uintptr precise_type, nominal_size;
|
||||
const uintptr *pc, *chan_ret;
|
||||
uintptr chancap;
|
||||
void *obj;
|
||||
const Type *t, *et;
|
||||
Slice *sliceptr;
|
||||
@ -742,10 +736,8 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
Scanbuf sbuf;
|
||||
Eface *eface;
|
||||
Iface *iface;
|
||||
#if 0
|
||||
Hchan *chan;
|
||||
ChanType *chantype;
|
||||
#endif
|
||||
const ChanType *chantype;
|
||||
Obj *wp;
|
||||
|
||||
if(sizeof(Workbuf) % WorkbufSize != 0)
|
||||
@ -782,11 +774,9 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
sbuf.nobj = nobj;
|
||||
|
||||
// (Silence the compiler)
|
||||
#if 0
|
||||
chan = nil;
|
||||
chantype = nil;
|
||||
chan_ret = nil;
|
||||
#endif
|
||||
|
||||
goto next_block;
|
||||
|
||||
@ -800,7 +790,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
runtime_xadd64(&gcstats.obj.cnt, 1);
|
||||
}
|
||||
|
||||
if(ti != 0 && false) {
|
||||
if(ti != 0) {
|
||||
if(Debug > 1) {
|
||||
runtime_printf("scanblock %p %D ti %p\n", b, (int64)n, ti);
|
||||
}
|
||||
@ -826,11 +816,10 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
runtime_throw("invalid gc type info");
|
||||
}
|
||||
}
|
||||
} else if(UseSpanType && false) {
|
||||
} else if(UseSpanType) {
|
||||
if(CollectStats)
|
||||
runtime_xadd64(&gcstats.obj.notype, 1);
|
||||
|
||||
#if 0
|
||||
type = runtime_gettype(b);
|
||||
if(type != 0) {
|
||||
if(CollectStats)
|
||||
@ -839,13 +828,13 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
t = (Type*)(type & ~(uintptr)(PtrSize-1));
|
||||
switch(type & (PtrSize-1)) {
|
||||
case TypeInfo_SingleObject:
|
||||
pc = (uintptr*)t->gc;
|
||||
pc = (const uintptr*)t->__gc;
|
||||
precise_type = true; // type information about 'b' is precise
|
||||
stack_top.count = 1;
|
||||
stack_top.elemsize = pc[0];
|
||||
break;
|
||||
case TypeInfo_Array:
|
||||
pc = (uintptr*)t->gc;
|
||||
pc = (const uintptr*)t->__gc;
|
||||
if(pc[0] == 0)
|
||||
goto next_block;
|
||||
precise_type = true; // type information about 'b' is precise
|
||||
@ -855,7 +844,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
break;
|
||||
case TypeInfo_Chan:
|
||||
chan = (Hchan*)b;
|
||||
chantype = (ChanType*)t;
|
||||
chantype = (const ChanType*)t;
|
||||
chan_ret = nil;
|
||||
pc = chanProg;
|
||||
break;
|
||||
@ -872,7 +861,6 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
if(Debug > 1)
|
||||
runtime_printf("scanblock %p %D unknown type\n", b, (int64)n);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
pc = defaultProg;
|
||||
if(Debug > 1)
|
||||
@ -954,7 +942,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
|
||||
// eface->__object
|
||||
if((byte*)eface->__object >= arena_start && (byte*)eface->__object < arena_used) {
|
||||
if(t->__size <= sizeof(void*)) {
|
||||
if(__go_is_pointer_type(t)) {
|
||||
if((t->__code & KindNoPointers))
|
||||
continue;
|
||||
|
||||
@ -965,13 +953,11 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
// dgcsym1 in case TPTR32/case TPTR64. See rationale there.
|
||||
et = ((const PtrType*)t)->elem;
|
||||
if(!(et->__code & KindNoPointers))
|
||||
// objti = (uintptr)((const PtrType*)t)->elem->gc;
|
||||
objti = 0;
|
||||
objti = (uintptr)((const PtrType*)t)->elem->__gc;
|
||||
}
|
||||
} else {
|
||||
obj = eface->__object;
|
||||
// objti = (uintptr)t->gc;
|
||||
objti = 0;
|
||||
objti = (uintptr)t->__gc;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -986,16 +972,15 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
|
||||
// iface->tab
|
||||
if((byte*)iface->tab >= arena_start && (byte*)iface->tab < arena_used) {
|
||||
*sbuf.ptr.pos++ = (PtrTarget){iface->tab, /* (uintptr)itabtype->gc */ 0};
|
||||
*sbuf.ptr.pos++ = (PtrTarget){iface->tab, 0};
|
||||
if(sbuf.ptr.pos == sbuf.ptr.end)
|
||||
flushptrbuf(&sbuf);
|
||||
}
|
||||
|
||||
// iface->data
|
||||
if((byte*)iface->__object >= arena_start && (byte*)iface->__object < arena_used) {
|
||||
// t = iface->tab->type;
|
||||
t = nil;
|
||||
if(t->__size <= sizeof(void*)) {
|
||||
t = (const Type*)iface->tab[0];
|
||||
if(__go_is_pointer_type(t)) {
|
||||
if((t->__code & KindNoPointers))
|
||||
continue;
|
||||
|
||||
@ -1006,13 +991,11 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
// dgcsym1 in case TPTR32/case TPTR64. See rationale there.
|
||||
et = ((const PtrType*)t)->elem;
|
||||
if(!(et->__code & KindNoPointers))
|
||||
// objti = (uintptr)((const PtrType*)t)->elem->gc;
|
||||
objti = 0;
|
||||
objti = (uintptr)((const PtrType*)t)->elem->__gc;
|
||||
}
|
||||
} else {
|
||||
obj = iface->__object;
|
||||
// objti = (uintptr)t->gc;
|
||||
objti = 0;
|
||||
objti = (uintptr)t->__gc;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1092,7 +1075,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
// Stack push.
|
||||
*stack_ptr-- = stack_top;
|
||||
stack_top = (Frame){1, 0, stack_top.b + pc[1], pc+3 /*return address*/};
|
||||
pc = (uintptr*)((byte*)pc + *(int32*)(pc+2)); // target of the CALL instruction
|
||||
pc = (const uintptr*)((const byte*)pc + *(const int32*)(pc+2)); // target of the CALL instruction
|
||||
continue;
|
||||
|
||||
case GC_REGION:
|
||||
@ -1108,7 +1091,6 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
flushobjbuf(&sbuf);
|
||||
continue;
|
||||
|
||||
#if 0
|
||||
case GC_CHAN_PTR:
|
||||
chan = *(Hchan**)(stack_top.b + pc[1]);
|
||||
if(Debug > 2 && chan != nil)
|
||||
@ -1141,8 +1123,8 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
// in-use part of the circular buffer is scanned.
|
||||
// (Channel routines zero the unused part, so the current
|
||||
// code does not lead to leaks, it's just a little inefficient.)
|
||||
*sbuf.obj.pos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->size,
|
||||
(uintptr)chantype->elem->gc | PRECISE | LOOP};
|
||||
*sbuf.obj.pos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->__size,
|
||||
(uintptr)chantype->elem->__gc | PRECISE | LOOP};
|
||||
if(sbuf.obj.pos == sbuf.obj.end)
|
||||
flushobjbuf(&sbuf);
|
||||
}
|
||||
@ -1151,7 +1133,6 @@ scanblock(Workbuf *wbuf, bool keepworking)
|
||||
goto next_block;
|
||||
pc = chan_ret;
|
||||
continue;
|
||||
#endif
|
||||
|
||||
default:
|
||||
runtime_printf("runtime: invalid GC instruction %p at %p\n", pc[0], pc);
|
||||
@ -1828,7 +1809,7 @@ runtime_MSpan_Sweep(MSpan *s)
|
||||
}
|
||||
|
||||
// State of background sweep.
|
||||
// Pretected by gclock.
|
||||
// Protected by gclock.
|
||||
static struct
|
||||
{
|
||||
G* g;
|
||||
@ -2260,12 +2241,6 @@ gc(struct gc_args *args)
|
||||
work.markfor = runtime_parforalloc(MaxGcproc);
|
||||
m->locks--;
|
||||
|
||||
if(itabtype == nil) {
|
||||
// get C pointer to the Go type "itab"
|
||||
// runtime_gc_itab_ptr(&eface);
|
||||
// itabtype = ((PtrType*)eface.__type_descriptor)->elem;
|
||||
}
|
||||
|
||||
t1 = 0;
|
||||
if(runtime_debug.gctrace)
|
||||
t1 = runtime_nanotime();
|
||||
|
@ -800,7 +800,7 @@ uintptr runtime_memlimit(void);
|
||||
|
||||
enum
|
||||
{
|
||||
UseSpanType = 0,
|
||||
UseSpanType = 1,
|
||||
};
|
||||
|
||||
#define runtime_setitimer setitimer
|
||||
|
Loading…
x
Reference in New Issue
Block a user